ruby-lsp 0.23.4 → 0.23.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp-launcher +9 -6
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +11 -3
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +56 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +19 -0
- data/lib/ruby_indexer/test/reference_finder_test.rb +63 -0
- data/lib/ruby_lsp/client_capabilities.rb +7 -1
- data/lib/ruby_lsp/global_state.rb +28 -3
- data/lib/ruby_lsp/listeners/document_highlight.rb +3 -2
- data/lib/ruby_lsp/listeners/document_link.rb +11 -2
- data/lib/ruby_lsp/load_sorbet.rb +3 -3
- data/lib/ruby_lsp/requests/references.rb +26 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +3 -3
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -13
- data/lib/ruby_lsp/server.rb +15 -12
- data/lib/ruby_lsp/utils.rb +7 -3
- 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: 563db8ddc06dc53f37db5ea4a42a48b7af8ed5bb2639c42e87e3c2bdd7fe38d1
|
4
|
+
data.tar.gz: a1820031a007e14c42600fd897e43fad044f26e05f02e117c806821cdc46e9d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d28983a474a7b32486f20df65ec2a808ddf2be31bc0c4d7d62ae1c3fa24448b28699917d23b6f4f00045ff45e25aeff1e27c6a27d40c6a7dc6887be630f8828
|
7
|
+
data.tar.gz: d10bd35268476cd2b2d319405dd58433d32df48a621cf4d45555cafb6e293d3bc4b3844afe7bf6dc0d39e68a5f5a7be70b935874796a3852a68ac5c61c592709
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.23.
|
1
|
+
0.23.6
|
data/exe/ruby-lsp-launcher
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
# !!!!!!!
|
8
8
|
|
9
9
|
setup_error = nil
|
10
|
+
install_error = nil
|
10
11
|
|
11
12
|
# Read the initialize request before even starting the server. We need to do this to figure out the workspace URI.
|
12
13
|
# Editors are not required to spawn the language server process on the same directory as the workspace URI, so we need
|
@@ -45,12 +46,6 @@ rescue Errno::ECHILD
|
|
45
46
|
# In theory, the child process can finish before we even get to the wait call, but that is not an error
|
46
47
|
end
|
47
48
|
|
48
|
-
error_path = File.join(".ruby-lsp", "install_error")
|
49
|
-
|
50
|
-
install_error = if File.exist?(error_path)
|
51
|
-
Marshal.load(File.read(error_path))
|
52
|
-
end
|
53
|
-
|
54
49
|
begin
|
55
50
|
bundle_env_path = File.join(".ruby-lsp", "bundle_env")
|
56
51
|
# We can't require `bundler/setup` because that file prematurely exits the process if setup fails. However, we can't
|
@@ -67,6 +62,14 @@ begin
|
|
67
62
|
|
68
63
|
require "bundler"
|
69
64
|
Bundler.ui.level = :silent
|
65
|
+
|
66
|
+
# This Marshal load can only happen after requiring Bundler because it will load a custom error class from Bundler
|
67
|
+
# itself. If we try to load before requiring, the class will not be defined and loading will fail
|
68
|
+
error_path = File.join(".ruby-lsp", "install_error")
|
69
|
+
install_error = if File.exist?(error_path)
|
70
|
+
Marshal.load(File.read(error_path))
|
71
|
+
end
|
72
|
+
|
70
73
|
Bundler.setup
|
71
74
|
$stderr.puts("Composed Bundle set up successfully")
|
72
75
|
end
|
@@ -143,7 +143,7 @@ module RubyIndexer
|
|
143
143
|
|
144
144
|
if current_owner
|
145
145
|
expression = node.expression
|
146
|
-
name = (expression.is_a?(Prism::SelfNode) ? "<Class:#{
|
146
|
+
name = (expression.is_a?(Prism::SelfNode) ? "<Class:#{last_name_in_stack}>" : "<Class:#{expression.slice}>")
|
147
147
|
real_nesting = actual_nesting(name)
|
148
148
|
|
149
149
|
existing_entries = T.cast(@index[real_nesting.join("::")], T.nilable(T::Array[Entry::SingletonClass]))
|
@@ -376,7 +376,6 @@ module RubyIndexer
|
|
376
376
|
))
|
377
377
|
|
378
378
|
@owner_stack << singleton
|
379
|
-
@stack << "<Class:#{@stack.last}>"
|
380
379
|
end
|
381
380
|
end
|
382
381
|
|
@@ -386,7 +385,6 @@ module RubyIndexer
|
|
386
385
|
|
387
386
|
if node.receiver.is_a?(Prism::SelfNode)
|
388
387
|
@owner_stack.pop
|
389
|
-
@stack.pop
|
390
388
|
end
|
391
389
|
end
|
392
390
|
|
@@ -1127,5 +1125,15 @@ module RubyIndexer
|
|
1127
1125
|
@index.add(entry)
|
1128
1126
|
@stack << short_name
|
1129
1127
|
end
|
1128
|
+
|
1129
|
+
# Returns the last name in the stack not as we found it, but in terms of declared constants. For example, if the
|
1130
|
+
# last entry in the stack is a compact namespace like `Foo::Bar`, then the last name is `Bar`
|
1131
|
+
sig { returns(T.nilable(String)) }
|
1132
|
+
def last_name_in_stack
|
1133
|
+
name = @stack.last
|
1134
|
+
return unless name
|
1135
|
+
|
1136
|
+
name.split("::").last
|
1137
|
+
end
|
1130
1138
|
end
|
1131
1139
|
end
|
@@ -37,6 +37,19 @@ module RubyIndexer
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
+
class InstanceVariableTarget < Target
|
41
|
+
extend T::Sig
|
42
|
+
|
43
|
+
sig { returns(String) }
|
44
|
+
attr_reader :name
|
45
|
+
|
46
|
+
sig { params(name: String).void }
|
47
|
+
def initialize(name)
|
48
|
+
super()
|
49
|
+
@name = name
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
class Reference
|
41
54
|
extend T::Sig
|
42
55
|
|
@@ -94,6 +107,12 @@ module RubyIndexer
|
|
94
107
|
:on_constant_or_write_node_enter,
|
95
108
|
:on_constant_and_write_node_enter,
|
96
109
|
:on_constant_operator_write_node_enter,
|
110
|
+
:on_instance_variable_read_node_enter,
|
111
|
+
:on_instance_variable_write_node_enter,
|
112
|
+
:on_instance_variable_and_write_node_enter,
|
113
|
+
:on_instance_variable_operator_write_node_enter,
|
114
|
+
:on_instance_variable_or_write_node_enter,
|
115
|
+
:on_instance_variable_target_node_enter,
|
97
116
|
:on_call_node_enter,
|
98
117
|
)
|
99
118
|
end
|
@@ -262,6 +281,36 @@ module RubyIndexer
|
|
262
281
|
end
|
263
282
|
end
|
264
283
|
|
284
|
+
sig { params(node: Prism::InstanceVariableReadNode).void }
|
285
|
+
def on_instance_variable_read_node_enter(node)
|
286
|
+
collect_instance_variable_references(node.name.to_s, node.location, false)
|
287
|
+
end
|
288
|
+
|
289
|
+
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
290
|
+
def on_instance_variable_write_node_enter(node)
|
291
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
292
|
+
end
|
293
|
+
|
294
|
+
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
295
|
+
def on_instance_variable_and_write_node_enter(node)
|
296
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
297
|
+
end
|
298
|
+
|
299
|
+
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
300
|
+
def on_instance_variable_operator_write_node_enter(node)
|
301
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
302
|
+
end
|
303
|
+
|
304
|
+
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
305
|
+
def on_instance_variable_or_write_node_enter(node)
|
306
|
+
collect_instance_variable_references(node.name.to_s, node.name_loc, true)
|
307
|
+
end
|
308
|
+
|
309
|
+
sig { params(node: Prism::InstanceVariableTargetNode).void }
|
310
|
+
def on_instance_variable_target_node_enter(node)
|
311
|
+
collect_instance_variable_references(node.name.to_s, node.location, true)
|
312
|
+
end
|
313
|
+
|
265
314
|
sig { params(node: Prism::CallNode).void }
|
266
315
|
def on_call_node_enter(node)
|
267
316
|
if @target.is_a?(MethodTarget) && (name = node.name.to_s) == @target.method_name
|
@@ -305,6 +354,13 @@ module RubyIndexer
|
|
305
354
|
end
|
306
355
|
end
|
307
356
|
|
357
|
+
sig { params(name: String, location: Prism::Location, declaration: T::Boolean).void }
|
358
|
+
def collect_instance_variable_references(name, location, declaration)
|
359
|
+
return unless @target.is_a?(InstanceVariableTarget) && name == @target.name
|
360
|
+
|
361
|
+
@references << Reference.new(name, location, declaration: declaration)
|
362
|
+
end
|
363
|
+
|
308
364
|
sig do
|
309
365
|
params(
|
310
366
|
node: T.any(
|
@@ -647,5 +647,24 @@ module RubyIndexer
|
|
647
647
|
entry = @index["Foo"].first
|
648
648
|
assert_empty(entry.comments)
|
649
649
|
end
|
650
|
+
|
651
|
+
def test_singleton_inside_compact_namespace
|
652
|
+
index(<<~RUBY)
|
653
|
+
module Foo::Bar
|
654
|
+
class << self
|
655
|
+
def baz; end
|
656
|
+
end
|
657
|
+
end
|
658
|
+
RUBY
|
659
|
+
|
660
|
+
# Verify we didn't index the incorrect name
|
661
|
+
assert_nil(@index["Foo::Bar::<Class:Foo::Bar>"])
|
662
|
+
|
663
|
+
# Verify we indexed the correct name
|
664
|
+
assert_entry("Foo::Bar::<Class:Bar>", Entry::SingletonClass, "/fake/path/foo.rb:1-2:3-5")
|
665
|
+
|
666
|
+
method = @index["baz"]&.first
|
667
|
+
assert_equal("Foo::Bar::<Class:Bar>", method.owner.name)
|
668
|
+
end
|
650
669
|
end
|
651
670
|
end
|
@@ -216,6 +216,64 @@ module RubyIndexer
|
|
216
216
|
assert_equal(11, refs[2].location.start_line)
|
217
217
|
end
|
218
218
|
|
219
|
+
def test_finds_instance_variable_read_references
|
220
|
+
refs = find_instance_variable_references("@foo", <<~RUBY)
|
221
|
+
class Foo
|
222
|
+
def foo
|
223
|
+
@foo
|
224
|
+
end
|
225
|
+
end
|
226
|
+
RUBY
|
227
|
+
assert_equal(1, refs.size)
|
228
|
+
|
229
|
+
assert_equal("@foo", refs[0].name)
|
230
|
+
assert_equal(3, refs[0].location.start_line)
|
231
|
+
end
|
232
|
+
|
233
|
+
def test_finds_instance_variable_write_references
|
234
|
+
refs = find_instance_variable_references("@foo", <<~RUBY)
|
235
|
+
class Foo
|
236
|
+
def write
|
237
|
+
@foo = 1
|
238
|
+
@foo &&= 2
|
239
|
+
@foo ||= 3
|
240
|
+
@foo += 4
|
241
|
+
@foo, @bar = []
|
242
|
+
end
|
243
|
+
end
|
244
|
+
RUBY
|
245
|
+
assert_equal(5, refs.size)
|
246
|
+
|
247
|
+
assert_equal(["@foo"], refs.map(&:name).uniq)
|
248
|
+
assert_equal(3, refs[0].location.start_line)
|
249
|
+
assert_equal(4, refs[1].location.start_line)
|
250
|
+
assert_equal(5, refs[2].location.start_line)
|
251
|
+
assert_equal(6, refs[3].location.start_line)
|
252
|
+
assert_equal(7, refs[4].location.start_line)
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_finds_instance_variable_references_ignore_context
|
256
|
+
refs = find_instance_variable_references("@name", <<~RUBY)
|
257
|
+
class Foo
|
258
|
+
def name
|
259
|
+
@name = "foo"
|
260
|
+
end
|
261
|
+
end
|
262
|
+
class Bar
|
263
|
+
def name
|
264
|
+
@name = "bar"
|
265
|
+
end
|
266
|
+
end
|
267
|
+
RUBY
|
268
|
+
assert_equal(2, refs.size)
|
269
|
+
|
270
|
+
assert_equal("@name", refs[0].name)
|
271
|
+
assert_equal(3, refs[0].location.start_line)
|
272
|
+
|
273
|
+
assert_equal("@name", refs[1].name)
|
274
|
+
assert_equal(8, refs[1].location.start_line)
|
275
|
+
end
|
276
|
+
|
219
277
|
private
|
220
278
|
|
221
279
|
def find_const_references(const_name, source)
|
@@ -228,6 +286,11 @@ module RubyIndexer
|
|
228
286
|
find_references(target, source)
|
229
287
|
end
|
230
288
|
|
289
|
+
def find_instance_variable_references(instance_variable_name, source)
|
290
|
+
target = ReferenceFinder::InstanceVariableTarget.new(instance_variable_name)
|
291
|
+
find_references(target, source)
|
292
|
+
end
|
293
|
+
|
231
294
|
def find_references(target, source)
|
232
295
|
file_path = "/fake.rb"
|
233
296
|
index = Index.new
|
@@ -11,7 +11,8 @@ module RubyLsp
|
|
11
11
|
attr_reader :supports_watching_files,
|
12
12
|
:supports_request_delegation,
|
13
13
|
:window_show_message_supports_extra_properties,
|
14
|
-
:supports_progress
|
14
|
+
:supports_progress,
|
15
|
+
:supports_diagnostic_refresh
|
15
16
|
|
16
17
|
sig { void }
|
17
18
|
def initialize
|
@@ -32,6 +33,9 @@ module RubyLsp
|
|
32
33
|
|
33
34
|
# The editor supports displaying progress requests
|
34
35
|
@supports_progress = T.let(false, T::Boolean)
|
36
|
+
|
37
|
+
# The editor supports server initiated refresh for diagnostics
|
38
|
+
@supports_diagnostic_refresh = T.let(false, T::Boolean)
|
35
39
|
end
|
36
40
|
|
37
41
|
sig { params(capabilities: T::Hash[Symbol, T.untyped]).void }
|
@@ -57,6 +61,8 @@ module RubyLsp
|
|
57
61
|
|
58
62
|
progress = capabilities.dig(:window, :workDoneProgress)
|
59
63
|
@supports_progress = progress if progress
|
64
|
+
|
65
|
+
@supports_diagnostic_refresh = workspace_capabilities.dig(:diagnostics, :refreshSupport) || false
|
60
66
|
end
|
61
67
|
|
62
68
|
sig { returns(T::Boolean) }
|
@@ -94,6 +94,8 @@ module RubyLsp
|
|
94
94
|
@workspace_uri = URI(workspace_uri) if workspace_uri
|
95
95
|
|
96
96
|
specified_formatter = options.dig(:initializationOptions, :formatter)
|
97
|
+
rubocop_has_addon = defined?(::RuboCop::Version::STRING) &&
|
98
|
+
Gem::Requirement.new(">= 1.70.0").satisfied_by?(Gem::Version.new(::RuboCop::Version::STRING))
|
97
99
|
|
98
100
|
if specified_formatter
|
99
101
|
@formatter = specified_formatter
|
@@ -101,6 +103,12 @@ module RubyLsp
|
|
101
103
|
if specified_formatter != "auto"
|
102
104
|
notifications << Notification.window_log_message("Using formatter specified by user: #{@formatter}")
|
103
105
|
end
|
106
|
+
|
107
|
+
# If the user had originally configured to use `rubocop`, but their version doesn't provide the add-on yet,
|
108
|
+
# fallback to the internal integration
|
109
|
+
if specified_formatter == "rubocop" && !rubocop_has_addon
|
110
|
+
@formatter = "rubocop_internal"
|
111
|
+
end
|
104
112
|
end
|
105
113
|
|
106
114
|
if @formatter == "auto"
|
@@ -109,6 +117,23 @@ module RubyLsp
|
|
109
117
|
end
|
110
118
|
|
111
119
|
specified_linters = options.dig(:initializationOptions, :linters)
|
120
|
+
|
121
|
+
if specified_formatter == "rubocop" || specified_linters&.include?("rubocop")
|
122
|
+
notifications << Notification.window_log_message(<<~MESSAGE, type: Constant::MessageType::WARNING)
|
123
|
+
Formatter is configured to be `rubocop`. As of RuboCop v1.70.0, this identifier activates the add-on
|
124
|
+
implemented in the rubocop gem itself instead of the internal integration provided by the Ruby LSP.
|
125
|
+
|
126
|
+
If you wish to use the internal integration, please configure the formatter as `rubocop_internal`.
|
127
|
+
MESSAGE
|
128
|
+
end
|
129
|
+
|
130
|
+
# If the user had originally configured to use `rubocop`, but their version doesn't provide the add-on yet,
|
131
|
+
# fall back to the internal integration
|
132
|
+
if specified_linters&.include?("rubocop") && !rubocop_has_addon
|
133
|
+
specified_linters.delete("rubocop")
|
134
|
+
specified_linters << "rubocop_internal"
|
135
|
+
end
|
136
|
+
|
112
137
|
@linters = specified_linters || detect_linters(direct_dependencies, all_dependencies)
|
113
138
|
|
114
139
|
notifications << if specified_linters
|
@@ -185,13 +210,13 @@ module RubyLsp
|
|
185
210
|
sig { params(direct_dependencies: T::Array[String], all_dependencies: T::Array[String]).returns(String) }
|
186
211
|
def detect_formatter(direct_dependencies, all_dependencies)
|
187
212
|
# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.
|
188
|
-
return "
|
213
|
+
return "rubocop_internal" if direct_dependencies.any?(/^rubocop/)
|
189
214
|
|
190
215
|
syntax_tree_is_direct_dependency = direct_dependencies.include?("syntax_tree")
|
191
216
|
return "syntax_tree" if syntax_tree_is_direct_dependency
|
192
217
|
|
193
218
|
rubocop_is_transitive_dependency = all_dependencies.include?("rubocop")
|
194
|
-
return "
|
219
|
+
return "rubocop_internal" if dot_rubocop_yml_present && rubocop_is_transitive_dependency
|
195
220
|
|
196
221
|
"none"
|
197
222
|
end
|
@@ -203,7 +228,7 @@ module RubyLsp
|
|
203
228
|
linters = []
|
204
229
|
|
205
230
|
if dependencies.any?(/^rubocop/) || (all_dependencies.include?("rubocop") && dot_rubocop_yml_present)
|
206
|
-
linters << "
|
231
|
+
linters << "rubocop_internal"
|
207
232
|
end
|
208
233
|
|
209
234
|
linters
|
@@ -120,7 +120,7 @@ module RubyLsp
|
|
120
120
|
[target, node_value(target)]
|
121
121
|
when Prism::ModuleNode, Prism::ClassNode, Prism::SingletonClassNode, Prism::DefNode, Prism::CaseNode,
|
122
122
|
Prism::WhileNode, Prism::UntilNode, Prism::ForNode, Prism::IfNode, Prism::UnlessNode
|
123
|
-
target
|
123
|
+
[target, nil]
|
124
124
|
end
|
125
125
|
|
126
126
|
@target = T.let(highlight_target, T.nilable(Prism::Node))
|
@@ -620,7 +620,8 @@ module RubyLsp
|
|
620
620
|
|
621
621
|
sig { params(keyword_loc: T.nilable(Prism::Location), end_loc: T.nilable(Prism::Location)).void }
|
622
622
|
def add_matching_end_highlights(keyword_loc, end_loc)
|
623
|
-
return unless keyword_loc && end_loc
|
623
|
+
return unless keyword_loc && end_loc
|
624
|
+
return unless end_loc.length.positive?
|
624
625
|
return unless covers_target_position?(keyword_loc) || covers_target_position?(end_loc)
|
625
626
|
|
626
627
|
add_highlight(Constant::DocumentHighlightKind::TEXT, keyword_loc)
|
@@ -128,7 +128,13 @@ module RubyLsp
|
|
128
128
|
gem_version = resolve_version(uri)
|
129
129
|
return if gem_version.nil?
|
130
130
|
|
131
|
-
|
131
|
+
path = uri.path
|
132
|
+
return unless path
|
133
|
+
|
134
|
+
gem_name = uri.gem_name
|
135
|
+
return unless gem_name
|
136
|
+
|
137
|
+
file_path = self.class.gem_paths.dig(gem_name, gem_version, CGI.unescape(path))
|
132
138
|
return if file_path.nil?
|
133
139
|
|
134
140
|
@response_builder << Interface::DocumentLink.new(
|
@@ -149,7 +155,10 @@ module RubyLsp
|
|
149
155
|
|
150
156
|
return @gem_version unless @gem_version.nil? || @gem_version.empty?
|
151
157
|
|
152
|
-
|
158
|
+
gem_name = uri.gem_name
|
159
|
+
return unless gem_name
|
160
|
+
|
161
|
+
GEM_TO_VERSION_MAP[gem_name]
|
153
162
|
end
|
154
163
|
end
|
155
164
|
end
|
data/lib/ruby_lsp/load_sorbet.rb
CHANGED
@@ -6,11 +6,11 @@ require "sorbet-runtime"
|
|
6
6
|
begin
|
7
7
|
T::Configuration.default_checked_level = :never
|
8
8
|
# Suppresses call validation errors
|
9
|
-
T::Configuration.call_validation_error_handler = ->(*) {}
|
9
|
+
T::Configuration.call_validation_error_handler = ->(*arg) {}
|
10
10
|
# Suppresses errors caused by T.cast, T.let, T.must, etc.
|
11
|
-
T::Configuration.inline_type_error_handler = ->(*) {}
|
11
|
+
T::Configuration.inline_type_error_handler = ->(*arg) {}
|
12
12
|
# Suppresses errors caused by incorrect parameter ordering
|
13
|
-
T::Configuration.sig_validation_error_handler = ->(*) {}
|
13
|
+
T::Configuration.sig_validation_error_handler = ->(*arg) {}
|
14
14
|
rescue
|
15
15
|
# Need this rescue so that if another gem has
|
16
16
|
# already set the checked level by the time we
|
@@ -39,6 +39,12 @@ module RubyLsp
|
|
39
39
|
Prism::ConstantReadNode,
|
40
40
|
Prism::ConstantPathNode,
|
41
41
|
Prism::ConstantPathTargetNode,
|
42
|
+
Prism::InstanceVariableAndWriteNode,
|
43
|
+
Prism::InstanceVariableOperatorWriteNode,
|
44
|
+
Prism::InstanceVariableOrWriteNode,
|
45
|
+
Prism::InstanceVariableReadNode,
|
46
|
+
Prism::InstanceVariableTargetNode,
|
47
|
+
Prism::InstanceVariableWriteNode,
|
42
48
|
Prism::CallNode,
|
43
49
|
Prism::DefNode,
|
44
50
|
],
|
@@ -62,6 +68,12 @@ module RubyLsp
|
|
62
68
|
Prism::ConstantReadNode,
|
63
69
|
Prism::ConstantPathNode,
|
64
70
|
Prism::ConstantPathTargetNode,
|
71
|
+
Prism::InstanceVariableAndWriteNode,
|
72
|
+
Prism::InstanceVariableOperatorWriteNode,
|
73
|
+
Prism::InstanceVariableOrWriteNode,
|
74
|
+
Prism::InstanceVariableReadNode,
|
75
|
+
Prism::InstanceVariableTargetNode,
|
76
|
+
Prism::InstanceVariableWriteNode,
|
65
77
|
Prism::CallNode,
|
66
78
|
Prism::DefNode,
|
67
79
|
),
|
@@ -97,6 +109,12 @@ module RubyLsp
|
|
97
109
|
Prism::ConstantReadNode,
|
98
110
|
Prism::ConstantPathNode,
|
99
111
|
Prism::ConstantPathTargetNode,
|
112
|
+
Prism::InstanceVariableAndWriteNode,
|
113
|
+
Prism::InstanceVariableOperatorWriteNode,
|
114
|
+
Prism::InstanceVariableOrWriteNode,
|
115
|
+
Prism::InstanceVariableReadNode,
|
116
|
+
Prism::InstanceVariableTargetNode,
|
117
|
+
Prism::InstanceVariableWriteNode,
|
100
118
|
Prism::CallNode,
|
101
119
|
Prism::DefNode,
|
102
120
|
),
|
@@ -114,6 +132,14 @@ module RubyLsp
|
|
114
132
|
|
115
133
|
fully_qualified_name = T.must(entries.first).name
|
116
134
|
RubyIndexer::ReferenceFinder::ConstTarget.new(fully_qualified_name)
|
135
|
+
when
|
136
|
+
Prism::InstanceVariableAndWriteNode,
|
137
|
+
Prism::InstanceVariableOperatorWriteNode,
|
138
|
+
Prism::InstanceVariableOrWriteNode,
|
139
|
+
Prism::InstanceVariableReadNode,
|
140
|
+
Prism::InstanceVariableTargetNode,
|
141
|
+
Prism::InstanceVariableWriteNode
|
142
|
+
RubyIndexer::ReferenceFinder::InstanceVariableTarget.new(target_node.name.to_s)
|
117
143
|
when Prism::CallNode, Prism::DefNode
|
118
144
|
RubyIndexer::ReferenceFinder::MethodTarget.new(target_node.name.to_s)
|
119
145
|
end
|
@@ -31,7 +31,7 @@ module RubyLsp
|
|
31
31
|
|
32
32
|
# TODO: avoid passing document once we have alternative ways to get at
|
33
33
|
# encoding and file source
|
34
|
-
sig { params(document: RubyDocument, offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
|
34
|
+
sig { params(document: RubyDocument, offense: ::RuboCop::Cop::Offense, uri: URI::Generic).void }
|
35
35
|
def initialize(document, offense, uri)
|
36
36
|
@document = document
|
37
37
|
@offense = offense
|
@@ -48,7 +48,7 @@ module RubyLsp
|
|
48
48
|
code_actions
|
49
49
|
end
|
50
50
|
|
51
|
-
sig { params(config: RuboCop::Config).returns(Interface::Diagnostic) }
|
51
|
+
sig { params(config: ::RuboCop::Config).returns(Interface::Diagnostic) }
|
52
52
|
def to_lsp_diagnostic(config)
|
53
53
|
# highlighted_area contains the begin and end position of the first line
|
54
54
|
# This ensures that multiline offenses don't clutter the editor
|
@@ -90,7 +90,7 @@ module RubyLsp
|
|
90
90
|
RUBOCOP_TO_LSP_SEVERITY[@offense.severity.name]
|
91
91
|
end
|
92
92
|
|
93
|
-
sig { params(config: RuboCop::Config).returns(T.nilable(Interface::CodeDescription)) }
|
93
|
+
sig { params(config: ::RuboCop::Config).returns(T.nilable(Interface::CodeDescription)) }
|
94
94
|
def code_description(config)
|
95
95
|
cop = RuboCopRunner.find_cop_by_name(@offense.cop_name)
|
96
96
|
return unless cop
|
@@ -40,10 +40,10 @@ module RubyLsp
|
|
40
40
|
For more details, run RuboCop on the command line.
|
41
41
|
EOS
|
42
42
|
|
43
|
-
sig { params(rubocop_error: T.any(RuboCop::ErrorWithAnalyzedFileLocation, StandardError)).void }
|
43
|
+
sig { params(rubocop_error: T.any(::RuboCop::ErrorWithAnalyzedFileLocation, StandardError)).void }
|
44
44
|
def initialize(rubocop_error)
|
45
45
|
message = case rubocop_error
|
46
|
-
when RuboCop::ErrorWithAnalyzedFileLocation
|
46
|
+
when ::RuboCop::ErrorWithAnalyzedFileLocation
|
47
47
|
format(MESSAGE, "for the #{rubocop_error.cop.name} cop")
|
48
48
|
when StandardError
|
49
49
|
format(MESSAGE, rubocop_error.message)
|
@@ -53,7 +53,7 @@ module RubyLsp
|
|
53
53
|
end
|
54
54
|
|
55
55
|
# :nodoc:
|
56
|
-
class RuboCopRunner < RuboCop::Runner
|
56
|
+
class RuboCopRunner < ::RuboCop::Runner
|
57
57
|
extend T::Sig
|
58
58
|
|
59
59
|
class ConfigurationError < StandardError; end
|
@@ -68,14 +68,14 @@ module RubyLsp
|
|
68
68
|
T::Array[String],
|
69
69
|
)
|
70
70
|
|
71
|
-
sig { returns(T::Array[RuboCop::Cop::Offense]) }
|
71
|
+
sig { returns(T::Array[::RuboCop::Cop::Offense]) }
|
72
72
|
attr_reader :offenses
|
73
73
|
|
74
74
|
sig { returns(::RuboCop::Config) }
|
75
75
|
attr_reader :config_for_working_directory
|
76
76
|
|
77
77
|
begin
|
78
|
-
RuboCop::Options.new.parse(["--raise-cop-error"])
|
78
|
+
::RuboCop::Options.new.parse(["--raise-cop-error"])
|
79
79
|
DEFAULT_ARGS << "--raise-cop-error"
|
80
80
|
rescue OptionParser::InvalidOption
|
81
81
|
# older versions of RuboCop don't support this flag
|
@@ -85,7 +85,7 @@ module RubyLsp
|
|
85
85
|
sig { params(args: String).void }
|
86
86
|
def initialize(*args)
|
87
87
|
@options = T.let({}, T::Hash[Symbol, T.untyped])
|
88
|
-
@offenses = T.let([], T::Array[RuboCop::Cop::Offense])
|
88
|
+
@offenses = T.let([], T::Array[::RuboCop::Cop::Offense])
|
89
89
|
@errors = T.let([], T::Array[String])
|
90
90
|
@warnings = T.let([], T::Array[String])
|
91
91
|
|
@@ -113,9 +113,9 @@ module RubyLsp
|
|
113
113
|
# RuboCop rescues interrupts and then sets the `@aborting` variable to true. We don't want them to be rescued,
|
114
114
|
# so here we re-raise in case RuboCop received an interrupt.
|
115
115
|
raise Interrupt if aborting?
|
116
|
-
rescue RuboCop::Runner::InfiniteCorrectionLoop => error
|
116
|
+
rescue ::RuboCop::Runner::InfiniteCorrectionLoop => error
|
117
117
|
raise Formatting::Error, error.message
|
118
|
-
rescue RuboCop::ValidationError => error
|
118
|
+
rescue ::RuboCop::ValidationError => error
|
119
119
|
raise ConfigurationError, error.message
|
120
120
|
rescue StandardError => error
|
121
121
|
raise InternalRuboCopError, error
|
@@ -129,25 +129,25 @@ module RubyLsp
|
|
129
129
|
class << self
|
130
130
|
extend T::Sig
|
131
131
|
|
132
|
-
sig { params(cop_name: String).returns(T.nilable(T.class_of(RuboCop::Cop::Base))) }
|
132
|
+
sig { params(cop_name: String).returns(T.nilable(T.class_of(::RuboCop::Cop::Base))) }
|
133
133
|
def find_cop_by_name(cop_name)
|
134
134
|
cop_registry[cop_name]&.first
|
135
135
|
end
|
136
136
|
|
137
137
|
private
|
138
138
|
|
139
|
-
sig { returns(T::Hash[String, [T.class_of(RuboCop::Cop::Base)]]) }
|
139
|
+
sig { returns(T::Hash[String, [T.class_of(::RuboCop::Cop::Base)]]) }
|
140
140
|
def cop_registry
|
141
141
|
@cop_registry ||= T.let(
|
142
|
-
RuboCop::Cop::Registry.global.to_h,
|
143
|
-
T.nilable(T::Hash[String, [T.class_of(RuboCop::Cop::Base)]]),
|
142
|
+
::RuboCop::Cop::Registry.global.to_h,
|
143
|
+
T.nilable(T::Hash[String, [T.class_of(::RuboCop::Cop::Base)]]),
|
144
144
|
)
|
145
145
|
end
|
146
146
|
end
|
147
147
|
|
148
148
|
private
|
149
149
|
|
150
|
-
sig { params(_file: String, offenses: T::Array[RuboCop::Cop::Offense]).void }
|
150
|
+
sig { params(_file: String, offenses: T::Array[::RuboCop::Cop::Offense]).void }
|
151
151
|
def file_finished(_file, offenses)
|
152
152
|
@offenses = offenses
|
153
153
|
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -338,8 +338,8 @@ module RubyLsp
|
|
338
338
|
unless @setup_error
|
339
339
|
if defined?(Requests::Support::RuboCopFormatter)
|
340
340
|
begin
|
341
|
-
@global_state.register_formatter("
|
342
|
-
rescue RuboCop::Error => e
|
341
|
+
@global_state.register_formatter("rubocop_internal", Requests::Support::RuboCopFormatter.new)
|
342
|
+
rescue ::RuboCop::Error => e
|
343
343
|
# The user may have provided unknown config switches in .rubocop or
|
344
344
|
# is trying to load a non-existent config file.
|
345
345
|
send_message(Notification.window_show_message(
|
@@ -1039,16 +1039,20 @@ module RubyLsp
|
|
1039
1039
|
def handle_rubocop_config_change(uri)
|
1040
1040
|
return unless defined?(Requests::Support::RuboCopFormatter)
|
1041
1041
|
|
1042
|
-
|
1043
|
-
@global_state.register_formatter("
|
1042
|
+
# Register a new runner to reload configurations
|
1043
|
+
@global_state.register_formatter("rubocop_internal", Requests::Support::RuboCopFormatter.new)
|
1044
1044
|
|
1045
|
-
# Clear all
|
1046
|
-
# hash cannot be mutated during iteration or that will throw an error
|
1045
|
+
# Clear all document caches for pull diagnostics
|
1047
1046
|
@global_state.synchronize do
|
1048
|
-
@store.each do |
|
1049
|
-
|
1047
|
+
@store.each do |_uri, document|
|
1048
|
+
document.cache_set("textDocument/diagnostic", Document::EMPTY_CACHE)
|
1050
1049
|
end
|
1051
1050
|
end
|
1051
|
+
|
1052
|
+
# Request a pull diagnostic refresh from the editor
|
1053
|
+
if @global_state.client_capabilities.supports_diagnostic_refresh
|
1054
|
+
send_message(Request.new(id: @current_request_id, method: "workspace/diagnostic/refresh", params: nil))
|
1055
|
+
end
|
1052
1056
|
end
|
1053
1057
|
|
1054
1058
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
@@ -1211,16 +1215,15 @@ module RubyLsp
|
|
1211
1215
|
sig { void }
|
1212
1216
|
def check_formatter_is_available
|
1213
1217
|
return if @setup_error
|
1214
|
-
# Warn of an unavailable `formatter` setting, e.g. `
|
1215
|
-
|
1216
|
-
return unless @global_state.formatter == "rubocop"
|
1218
|
+
# Warn of an unavailable `formatter` setting, e.g. `rubocop_internal` on a project which doesn't have RuboCop.
|
1219
|
+
return unless @global_state.formatter == "rubocop_internal"
|
1217
1220
|
|
1218
1221
|
unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
1219
1222
|
@global_state.formatter = "none"
|
1220
1223
|
|
1221
1224
|
send_message(
|
1222
1225
|
Notification.window_show_message(
|
1223
|
-
"Ruby LSP formatter is set to `
|
1226
|
+
"Ruby LSP formatter is set to `rubocop_internal` but RuboCop was not found in the Gemfile or gemspec.",
|
1224
1227
|
type: Constant::MessageType::ERROR,
|
1225
1228
|
),
|
1226
1229
|
)
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
end,
|
26
26
|
String,
|
27
27
|
)
|
28
|
-
GUESSED_TYPES_URL = "https://shopify.github.io/ruby-lsp
|
28
|
+
GUESSED_TYPES_URL = "https://shopify.github.io/ruby-lsp/#guessed-types"
|
29
29
|
|
30
30
|
# Request delegation for embedded languages is not yet standardized into the language server specification. Here we
|
31
31
|
# use this custom error class as a way to return a signal to the client that the request should be delegated to the
|
@@ -162,7 +162,9 @@ module RubyLsp
|
|
162
162
|
|
163
163
|
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
164
164
|
def to_hash
|
165
|
-
{ method: @method
|
165
|
+
hash = { method: @method }
|
166
|
+
hash[:params] = T.unsafe(@params).to_hash if @params
|
167
|
+
hash
|
166
168
|
end
|
167
169
|
end
|
168
170
|
|
@@ -206,7 +208,9 @@ module RubyLsp
|
|
206
208
|
|
207
209
|
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
208
210
|
def to_hash
|
209
|
-
{ id: @id, method: @method
|
211
|
+
hash = { id: @id, method: @method }
|
212
|
+
hash[:params] = T.unsafe(@params).to_hash if @params
|
213
|
+
hash
|
210
214
|
end
|
211
215
|
end
|
212
216
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.23.
|
4
|
+
version: 0.23.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
bindir: exe
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-01-
|
10
|
+
date: 2025-01-16 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: language_server-protocol
|