ruby-lsp 0.16.2 → 0.16.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/ruby_lsp/base_server.rb +4 -2
- data/lib/ruby_lsp/document.rb +6 -6
- data/lib/ruby_lsp/global_state.rb +47 -7
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +0 -3
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +0 -3
- data/lib/ruby_lsp/server.rb +25 -30
- data/lib/ruby_lsp/setup_bundler.rb +13 -1
- data/lib/ruby_lsp/store.rb +3 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94d4dfcda701bdf2ea1dd04e2a271572a139fe3d716e1bd535e2c05bcc9b3d23
|
4
|
+
data.tar.gz: b79dfc816bf027e733fa5f44db3e2d1039ae860f9dee88fe996ab1a27089d467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9de1f73feba2284c75294542a0e9ae1196f092004fe83ef815b2e08a1b404daceebc0b3f6f8f59149f936c8f7414821942556bee522776a909c071765dcc3443
|
7
|
+
data.tar.gz: b7617a6d508a94e5a06b8d39acb4d2bcc28d02832b19ab8567ed58b6b297aa3fc450dd0a116257fe91fc9545683550456c0d712fc32dc3f3ff716e2cdca2985e
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.16.
|
1
|
+
0.16.4
|
data/lib/ruby_lsp/base_server.rb
CHANGED
@@ -59,9 +59,11 @@ module RubyLsp
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
#
|
63
|
-
#
|
62
|
+
# The following requests need to be executed in the main thread directly to avoid concurrency issues. Everything
|
63
|
+
# else is pushed into the incoming queue
|
64
64
|
case method
|
65
|
+
when "initialize", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
66
|
+
process_message(message)
|
65
67
|
when "shutdown"
|
66
68
|
$stderr.puts("Shutting down Ruby LSP...")
|
67
69
|
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -20,13 +20,13 @@ module RubyLsp
|
|
20
20
|
sig { returns(URI::Generic) }
|
21
21
|
attr_reader :uri
|
22
22
|
|
23
|
-
sig { returns(
|
23
|
+
sig { returns(Encoding) }
|
24
24
|
attr_reader :encoding
|
25
25
|
|
26
|
-
sig { params(source: String, version: Integer, uri: URI::Generic, encoding:
|
27
|
-
def initialize(source:, version:, uri:, encoding:
|
26
|
+
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: Encoding).void }
|
27
|
+
def initialize(source:, version:, uri:, encoding: Encoding::UTF_8)
|
28
28
|
@cache = T.let({}, T::Hash[String, T.untyped])
|
29
|
-
@encoding = T.let(encoding,
|
29
|
+
@encoding = T.let(encoding, Encoding)
|
30
30
|
@source = T.let(source, String)
|
31
31
|
@version = T.let(version, Integer)
|
32
32
|
@uri = T.let(uri, URI::Generic)
|
@@ -187,7 +187,7 @@ module RubyLsp
|
|
187
187
|
# After character 0xFFFF, UTF-16 considers characters to have length 2 and we have to account for that
|
188
188
|
SURROGATE_PAIR_START = T.let(0xFFFF, Integer)
|
189
189
|
|
190
|
-
sig { params(source: String, encoding:
|
190
|
+
sig { params(source: String, encoding: Encoding).void }
|
191
191
|
def initialize(source, encoding)
|
192
192
|
@current_line = T.let(0, Integer)
|
193
193
|
@pos = T.let(0, Integer)
|
@@ -209,7 +209,7 @@ module RubyLsp
|
|
209
209
|
# need to adjust for surrogate pairs
|
210
210
|
requested_position = @pos + position[:character]
|
211
211
|
|
212
|
-
if @encoding ==
|
212
|
+
if @encoding == Encoding::UTF_16LE
|
213
213
|
requested_position -= utf_16_character_position_correction(@pos, requested_position)
|
214
214
|
end
|
215
215
|
|
@@ -17,15 +17,23 @@ module RubyLsp
|
|
17
17
|
sig { returns(RubyIndexer::Index) }
|
18
18
|
attr_reader :index
|
19
19
|
|
20
|
+
sig { returns(Encoding) }
|
21
|
+
attr_reader :encoding
|
22
|
+
|
23
|
+
sig { returns(T::Boolean) }
|
24
|
+
attr_reader :supports_watching_files
|
25
|
+
|
20
26
|
sig { void }
|
21
27
|
def initialize
|
22
28
|
@workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
29
|
+
@encoding = T.let(Encoding::UTF_8, Encoding)
|
23
30
|
|
24
31
|
@formatter = T.let("auto", String)
|
25
32
|
@test_library = T.let(detect_test_library, String)
|
26
33
|
@typechecker = T.let(detect_typechecker, T::Boolean)
|
27
34
|
@index = T.let(RubyIndexer::Index.new, RubyIndexer::Index)
|
28
35
|
@supported_formatters = T.let({}, T::Hash[String, Requests::Support::Formatter])
|
36
|
+
@supports_watching_files = T.let(false, T::Boolean)
|
29
37
|
end
|
30
38
|
|
31
39
|
sig { params(identifier: String, instance: Requests::Support::Formatter).void }
|
@@ -46,6 +54,22 @@ module RubyLsp
|
|
46
54
|
specified_formatter = options.dig(:initializationOptions, :formatter)
|
47
55
|
@formatter = specified_formatter if specified_formatter
|
48
56
|
@formatter = detect_formatter if @formatter == "auto"
|
57
|
+
|
58
|
+
encodings = options.dig(:capabilities, :general, :positionEncodings)
|
59
|
+
@encoding = if !encodings || encodings.empty?
|
60
|
+
Encoding::UTF_16LE
|
61
|
+
elsif encodings.include?(Constant::PositionEncodingKind::UTF8)
|
62
|
+
Encoding::UTF_8
|
63
|
+
elsif encodings.include?(Constant::PositionEncodingKind::UTF16)
|
64
|
+
Encoding::UTF_16LE
|
65
|
+
else
|
66
|
+
Encoding::UTF_32
|
67
|
+
end
|
68
|
+
|
69
|
+
file_watching_caps = options.dig(:capabilities, :workspace, :didChangeWatchedFiles)
|
70
|
+
if file_watching_caps&.dig(:dynamicRegistration) && file_watching_caps&.dig(:relativePatternSupport)
|
71
|
+
@supports_watching_files = true
|
72
|
+
end
|
49
73
|
end
|
50
74
|
|
51
75
|
sig { returns(String) }
|
@@ -53,6 +77,25 @@ module RubyLsp
|
|
53
77
|
T.must(@workspace_uri.to_standardized_path)
|
54
78
|
end
|
55
79
|
|
80
|
+
sig { returns(String) }
|
81
|
+
def encoding_name
|
82
|
+
case @encoding
|
83
|
+
when Encoding::UTF_8
|
84
|
+
Constant::PositionEncodingKind::UTF8
|
85
|
+
when Encoding::UTF_16LE
|
86
|
+
Constant::PositionEncodingKind::UTF16
|
87
|
+
else
|
88
|
+
Constant::PositionEncodingKind::UTF32
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
sig { params(gem_pattern: Regexp).returns(T::Boolean) }
|
93
|
+
def direct_dependency?(gem_pattern)
|
94
|
+
dependencies.any?(gem_pattern)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
56
99
|
sig { returns(String) }
|
57
100
|
def detect_formatter
|
58
101
|
# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.
|
@@ -70,8 +113,10 @@ module RubyLsp
|
|
70
113
|
if direct_dependency?(/^rspec/)
|
71
114
|
"rspec"
|
72
115
|
# A Rails app may have a dependency on minitest, but we would instead want to use the Rails test runner provided
|
73
|
-
# by ruby-lsp-rails.
|
74
|
-
|
116
|
+
# by ruby-lsp-rails. A Rails app doesn't need to depend on the rails gem itself, individual components like
|
117
|
+
# activestorage may be added to the gemfile so that other components aren't downloaded. Check for the presence
|
118
|
+
# of bin/rails to support these cases.
|
119
|
+
elsif File.exist?(File.join(workspace_path, "bin/rails"))
|
75
120
|
"rails"
|
76
121
|
# NOTE: Intentionally ends with $ to avoid mis-matching minitest-reporters, etc. in a Rails app.
|
77
122
|
elsif direct_dependency?(/^minitest$/)
|
@@ -83,11 +128,6 @@ module RubyLsp
|
|
83
128
|
end
|
84
129
|
end
|
85
130
|
|
86
|
-
sig { params(gem_pattern: Regexp).returns(T::Boolean) }
|
87
|
-
def direct_dependency?(gem_pattern)
|
88
|
-
dependencies.any?(gem_pattern)
|
89
|
-
end
|
90
|
-
|
91
131
|
sig { returns(T::Boolean) }
|
92
132
|
def detect_typechecker
|
93
133
|
return false if ENV["RUBY_LSP_BYPASS_TYPECHECKER"]
|
@@ -163,7 +163,7 @@ module RubyLsp
|
|
163
163
|
|
164
164
|
sig { params(line: String).returns(Integer) }
|
165
165
|
def length_of_line(line)
|
166
|
-
if @document.encoding ==
|
166
|
+
if @document.encoding == Encoding::UTF_16LE
|
167
167
|
line_length = 0
|
168
168
|
line.codepoints.each do |codepoint|
|
169
169
|
line_length += 1
|
@@ -3,15 +3,12 @@
|
|
3
3
|
|
4
4
|
return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
5
5
|
|
6
|
-
require "singleton"
|
7
|
-
|
8
6
|
module RubyLsp
|
9
7
|
module Requests
|
10
8
|
module Support
|
11
9
|
class RuboCopFormatter
|
12
10
|
extend T::Sig
|
13
11
|
include Formatter
|
14
|
-
include Singleton
|
15
12
|
|
16
13
|
sig { void }
|
17
14
|
def initialize
|
@@ -8,15 +8,12 @@ rescue LoadError
|
|
8
8
|
return
|
9
9
|
end
|
10
10
|
|
11
|
-
require "singleton"
|
12
|
-
|
13
11
|
module RubyLsp
|
14
12
|
module Requests
|
15
13
|
module Support
|
16
14
|
# :nodoc:
|
17
15
|
class SyntaxTreeFormatter
|
18
16
|
extend T::Sig
|
19
|
-
include Singleton
|
20
17
|
include Support::Formatter
|
21
18
|
|
22
19
|
sig { void }
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -118,15 +118,6 @@ module RubyLsp
|
|
118
118
|
client_name = options.dig(:clientInfo, :name)
|
119
119
|
@store.client_name = client_name if client_name
|
120
120
|
|
121
|
-
encodings = options.dig(:capabilities, :general, :positionEncodings)
|
122
|
-
@store.encoding = if encodings.nil? || encodings.empty?
|
123
|
-
Constant::PositionEncodingKind::UTF16
|
124
|
-
elsif encodings.include?(Constant::PositionEncodingKind::UTF8)
|
125
|
-
Constant::PositionEncodingKind::UTF8
|
126
|
-
else
|
127
|
-
encodings.first
|
128
|
-
end
|
129
|
-
|
130
121
|
progress = options.dig(:capabilities, :window, :workDoneProgress)
|
131
122
|
@store.supports_progress = progress.nil? ? true : progress
|
132
123
|
configured_features = options.dig(:initializationOptions, :enabledFeatures)
|
@@ -168,7 +159,7 @@ module RubyLsp
|
|
168
159
|
change: Constant::TextDocumentSyncKind::INCREMENTAL,
|
169
160
|
open_close: true,
|
170
161
|
),
|
171
|
-
position_encoding: @
|
162
|
+
position_encoding: @global_state.encoding_name,
|
172
163
|
selection_range_provider: enabled_features["selectionRanges"],
|
173
164
|
hover_provider: hover_provider,
|
174
165
|
document_symbol_provider: document_symbol_provider,
|
@@ -196,11 +187,8 @@ module RubyLsp
|
|
196
187
|
|
197
188
|
send_message(Result.new(id: message[:id], response: response))
|
198
189
|
|
199
|
-
# Dynamically registered capabilities
|
200
|
-
file_watching_caps = options.dig(:capabilities, :workspace, :didChangeWatchedFiles)
|
201
|
-
|
202
190
|
# Not every client supports dynamic registration or file watching
|
203
|
-
if
|
191
|
+
if global_state.supports_watching_files
|
204
192
|
send_message(
|
205
193
|
Request.new(
|
206
194
|
id: @current_request_id,
|
@@ -257,10 +245,10 @@ module RubyLsp
|
|
257
245
|
end
|
258
246
|
|
259
247
|
if defined?(Requests::Support::RuboCopFormatter)
|
260
|
-
@global_state.register_formatter("rubocop", Requests::Support::RuboCopFormatter.
|
248
|
+
@global_state.register_formatter("rubocop", Requests::Support::RuboCopFormatter.new)
|
261
249
|
end
|
262
250
|
if defined?(Requests::Support::SyntaxTreeFormatter)
|
263
|
-
@global_state.register_formatter("syntax_tree", Requests::Support::SyntaxTreeFormatter.
|
251
|
+
@global_state.register_formatter("syntax_tree", Requests::Support::SyntaxTreeFormatter.new)
|
264
252
|
end
|
265
253
|
|
266
254
|
perform_initial_indexing(indexing_config)
|
@@ -269,25 +257,31 @@ module RubyLsp
|
|
269
257
|
|
270
258
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
271
259
|
def text_document_did_open(message)
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
260
|
+
@mutex.synchronize do
|
261
|
+
text_document = message.dig(:params, :textDocument)
|
262
|
+
@store.set(
|
263
|
+
uri: text_document[:uri],
|
264
|
+
source: text_document[:text],
|
265
|
+
version: text_document[:version],
|
266
|
+
encoding: @global_state.encoding,
|
267
|
+
)
|
268
|
+
end
|
277
269
|
end
|
278
270
|
|
279
271
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
280
272
|
def text_document_did_close(message)
|
281
|
-
|
282
|
-
|
273
|
+
@mutex.synchronize do
|
274
|
+
uri = message.dig(:params, :textDocument, :uri)
|
275
|
+
@store.delete(uri)
|
283
276
|
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
277
|
+
# Clear diagnostics for the closed file, so that they no longer appear in the problems tab
|
278
|
+
send_message(
|
279
|
+
Notification.new(
|
280
|
+
method: "textDocument/publishDiagnostics",
|
281
|
+
params: Interface::PublishDiagnosticsParams.new(uri: uri.to_s, diagnostics: []),
|
282
|
+
),
|
283
|
+
)
|
284
|
+
end
|
291
285
|
end
|
292
286
|
|
293
287
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
@@ -616,6 +610,7 @@ module RubyLsp
|
|
616
610
|
uri = URI(change[:uri])
|
617
611
|
file_path = uri.to_standardized_path
|
618
612
|
next if file_path.nil? || File.directory?(file_path)
|
613
|
+
next unless file_path.end_with?(".rb")
|
619
614
|
|
620
615
|
load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
|
621
616
|
indexable = RubyIndexer::IndexablePath.new(load_path_entry, file_path)
|
@@ -19,6 +19,7 @@ module RubyLsp
|
|
19
19
|
extend T::Sig
|
20
20
|
|
21
21
|
class BundleNotLocked < StandardError; end
|
22
|
+
class BundleInstallFailure < StandardError; end
|
22
23
|
|
23
24
|
FOUR_HOURS = T.let(4 * 60 * 60, Integer)
|
24
25
|
|
@@ -49,6 +50,7 @@ module RubyLsp
|
|
49
50
|
@last_updated_path = T.let(@custom_dir + "last_updated", Pathname)
|
50
51
|
|
51
52
|
@dependencies = T.let(load_dependencies, T::Hash[String, T.untyped])
|
53
|
+
@retry = T.let(false, T::Boolean)
|
52
54
|
end
|
53
55
|
|
54
56
|
# Sets up the custom bundle and returns the `BUNDLE_GEMFILE`, `BUNDLE_PATH` and `BUNDLE_APP_CONFIG` that should be
|
@@ -224,7 +226,17 @@ module RubyLsp
|
|
224
226
|
# Add bundle update
|
225
227
|
$stderr.puts("Ruby LSP> Running bundle install for the custom bundle. This may take a while...")
|
226
228
|
$stderr.puts("Ruby LSP> Command: #{command}")
|
227
|
-
|
229
|
+
|
230
|
+
# Try to run the bundle install or update command. If that fails, it normally means that the custom lockfile is in
|
231
|
+
# a bad state that no longer reflects the top level one. In that case, we can remove the whole directory, try
|
232
|
+
# another time and give up if it fails again
|
233
|
+
if !system(env, command) && !@retry && @custom_dir.exist?
|
234
|
+
@retry = true
|
235
|
+
@custom_dir.rmtree
|
236
|
+
$stderr.puts("Ruby LSP> Running bundle install failed. Trying to re-generate the custom bundle from scratch")
|
237
|
+
return setup!
|
238
|
+
end
|
239
|
+
|
228
240
|
[bundle_gemfile.to_s, expanded_path, env["BUNDLE_APP_CONFIG"]]
|
229
241
|
end
|
230
242
|
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -5,9 +5,6 @@ module RubyLsp
|
|
5
5
|
class Store
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
sig { returns(String) }
|
9
|
-
attr_accessor :encoding
|
10
|
-
|
11
8
|
sig { returns(T::Boolean) }
|
12
9
|
attr_accessor :supports_progress
|
13
10
|
|
@@ -23,7 +20,6 @@ module RubyLsp
|
|
23
20
|
sig { void }
|
24
21
|
def initialize
|
25
22
|
@state = T.let({}, T::Hash[String, Document])
|
26
|
-
@encoding = T.let(Constant::PositionEncodingKind::UTF8, String)
|
27
23
|
@supports_progress = T.let(true, T::Boolean)
|
28
24
|
@experimental_features = T.let(false, T::Boolean)
|
29
25
|
@features_configuration = T.let(
|
@@ -49,9 +45,9 @@ module RubyLsp
|
|
49
45
|
T.must(@state[uri.to_s])
|
50
46
|
end
|
51
47
|
|
52
|
-
sig { params(uri: URI::Generic, source: String, version: Integer).void }
|
53
|
-
def set(uri:, source:, version:)
|
54
|
-
document = RubyDocument.new(source: source, version: version, uri: uri, encoding:
|
48
|
+
sig { params(uri: URI::Generic, source: String, version: Integer, encoding: Encoding).void }
|
49
|
+
def set(uri:, source:, version:, encoding: Encoding::UTF_8)
|
50
|
+
document = RubyDocument.new(source: source, version: version, uri: uri, encoding: encoding)
|
55
51
|
@state[uri.to_s] = document
|
56
52
|
end
|
57
53
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.16.
|
4
|
+
version: 0.16.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-04-
|
11
|
+
date: 2024-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|