ruby-lsp 0.14.4 → 0.14.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/lib/ruby_indexer/lib/ruby_indexer/collector.rb +21 -0
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +16 -0
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +3 -2
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +46 -0
- data/lib/ruby_indexer/test/index_test.rb +5 -0
- data/lib/ruby_lsp/addon.rb +6 -0
- data/lib/ruby_lsp/executor.rb +12 -9
- data/lib/ruby_lsp/listeners/code_lens.rb +54 -10
- data/lib/ruby_lsp/listeners/completion.rb +8 -7
- data/lib/ruby_lsp/requests/completion.rb +1 -1
- data/lib/ruby_lsp/requests/definition.rb +7 -1
- data/lib/ruby_lsp/requests/hover.rb +5 -1
- data/lib/ruby_lsp/requests/request.rb +51 -0
- data/lib/ruby_lsp/requests/support/common.rb +9 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +6 -3
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- 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: 7c364aee0d80e6187f66e8eb6d50d7cdd21ffb129e0a0b17c9dc7bd5d8a18cad
|
4
|
+
data.tar.gz: 65964ec1d89f10adf9bcbf113efed6d43a977b669abe51182e90dd9870032623
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 971af8a3c02903597143a8ec49915eead6bc0f65a0175e4a443e381d671dd4a88f776a26f62af1bd69ee7dc3f478b36bef122febbfaed7656907eb1a6a7a3354
|
7
|
+
data.tar.gz: 15148c1c3765390f9bb92dbafe7043ac15b22de6b5c415c424a063f4742026d92831d84bcde2013ab742c4a889dc16d666d4ec5d18863d0db8acf793ce87f0a6
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.14.
|
1
|
+
0.14.6
|
@@ -152,6 +152,8 @@ module RubyIndexer
|
|
152
152
|
handle_attribute(node, reader: false, writer: true)
|
153
153
|
when :attr_accessor
|
154
154
|
handle_attribute(node, reader: true, writer: true)
|
155
|
+
when :include
|
156
|
+
handle_include(node)
|
155
157
|
end
|
156
158
|
end
|
157
159
|
|
@@ -350,5 +352,24 @@ module RubyIndexer
|
|
350
352
|
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @current_owner) if writer
|
351
353
|
end
|
352
354
|
end
|
355
|
+
|
356
|
+
sig { params(node: Prism::CallNode).void }
|
357
|
+
def handle_include(node)
|
358
|
+
return unless @current_owner
|
359
|
+
|
360
|
+
arguments = node.arguments&.arguments
|
361
|
+
return unless arguments
|
362
|
+
|
363
|
+
names = arguments.filter_map do |node|
|
364
|
+
if node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
|
365
|
+
node.full_name
|
366
|
+
end
|
367
|
+
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
|
368
|
+
# TO DO: add MissingNodesInConstantPathError when released in Prism
|
369
|
+
# If a constant path reference is dynamic or missing parts, we can't
|
370
|
+
# index it
|
371
|
+
end
|
372
|
+
@current_owner.included_modules.concat(names)
|
373
|
+
end
|
353
374
|
end
|
354
375
|
end
|
@@ -20,7 +20,7 @@ module RubyIndexer
|
|
20
20
|
def initialize
|
21
21
|
@excluded_gems = T.let(initial_excluded_gems, T::Array[String])
|
22
22
|
@included_gems = T.let([], T::Array[String])
|
23
|
-
@excluded_patterns = T.let([File.join("**", "*_test.rb")], T::Array[String])
|
23
|
+
@excluded_patterns = T.let([File.join("**", "*_test.rb"), File.join("**", "tmp", "**", "*")], T::Array[String])
|
24
24
|
path = Bundler.settings["path"]
|
25
25
|
@excluded_patterns << File.join(File.expand_path(path, Dir.pwd), "**", "*.rb") if path
|
26
26
|
|
@@ -40,6 +40,22 @@ module RubyIndexer
|
|
40
40
|
|
41
41
|
abstract!
|
42
42
|
|
43
|
+
sig { returns(T::Array[String]) }
|
44
|
+
attr_accessor :included_modules
|
45
|
+
|
46
|
+
sig do
|
47
|
+
params(
|
48
|
+
name: String,
|
49
|
+
file_path: String,
|
50
|
+
location: Prism::Location,
|
51
|
+
comments: T::Array[String],
|
52
|
+
).void
|
53
|
+
end
|
54
|
+
def initialize(name, file_path, location, comments)
|
55
|
+
super(name, file_path, location, comments)
|
56
|
+
@included_modules = T.let([], T::Array[String])
|
57
|
+
end
|
58
|
+
|
43
59
|
sig { returns(String) }
|
44
60
|
def short_name
|
45
61
|
T.must(@name.split("::").last)
|
@@ -191,8 +191,9 @@ module RubyIndexer
|
|
191
191
|
|
192
192
|
require_path = indexable_path.require_path
|
193
193
|
@require_paths_tree.insert(require_path, indexable_path) if require_path
|
194
|
-
rescue Errno::EISDIR
|
195
|
-
# If `path` is a directory, just ignore it and continue indexing
|
194
|
+
rescue Errno::EISDIR, Errno::ENOENT
|
195
|
+
# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
|
196
|
+
# it
|
196
197
|
end
|
197
198
|
|
198
199
|
# Follows aliases in a namespace. The algorithm keeps checking if the name is an alias and then recursively follows
|
@@ -281,5 +281,51 @@ module RubyIndexer
|
|
281
281
|
final_thing = T.must(@index["FinalThing"].first)
|
282
282
|
assert_equal("Something::Baz", final_thing.parent_class)
|
283
283
|
end
|
284
|
+
|
285
|
+
def test_keeping_track_of_included_modules
|
286
|
+
index(<<~RUBY)
|
287
|
+
class Foo
|
288
|
+
# valid syntaxes that we can index
|
289
|
+
include A1
|
290
|
+
self.include A2
|
291
|
+
include A3, A4
|
292
|
+
self.include A5, A6
|
293
|
+
|
294
|
+
# valid syntaxes that we cannot index because of their dynamic nature
|
295
|
+
include some_variable_or_method_call
|
296
|
+
self.include some_variable_or_method_call
|
297
|
+
|
298
|
+
def something
|
299
|
+
include A7 # We should not index this because of this dynamic nature
|
300
|
+
end
|
301
|
+
|
302
|
+
# Valid inner class syntax definition with its own modules included
|
303
|
+
class Qux
|
304
|
+
include Corge
|
305
|
+
self.include Corge
|
306
|
+
include Baz
|
307
|
+
|
308
|
+
include some_variable_or_method_call
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
class ConstantPathReferences
|
313
|
+
include Foo::Bar
|
314
|
+
self.include Foo::Bar2
|
315
|
+
|
316
|
+
include dynamic::Bar
|
317
|
+
include Foo::
|
318
|
+
end
|
319
|
+
RUBY
|
320
|
+
|
321
|
+
foo = T.must(@index["Foo"][0])
|
322
|
+
assert_equal(["A1", "A2", "A3", "A4", "A5", "A6"], foo.included_modules)
|
323
|
+
|
324
|
+
qux = T.must(@index["Foo::Qux"][0])
|
325
|
+
assert_equal(["Corge", "Corge", "Baz"], qux.included_modules)
|
326
|
+
|
327
|
+
constant_path_references = T.must(@index["ConstantPathReferences"][0])
|
328
|
+
assert_equal(["Foo::Bar", "Foo::Bar2"], constant_path_references.included_modules)
|
329
|
+
end
|
284
330
|
end
|
285
331
|
end
|
@@ -308,5 +308,10 @@ module RubyIndexer
|
|
308
308
|
|
309
309
|
refute_empty(@index.instance_variable_get(:@entries))
|
310
310
|
end
|
311
|
+
|
312
|
+
def test_index_single_does_not_fail_for_non_existing_file
|
313
|
+
@index.index_single(IndexablePath.new(nil, "/fake/path/foo.rb"))
|
314
|
+
assert_empty(@index.instance_variable_get(:@entries))
|
315
|
+
end
|
311
316
|
end
|
312
317
|
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -27,6 +27,8 @@ module RubyLsp
|
|
27
27
|
|
28
28
|
@addons = T.let([], T::Array[Addon])
|
29
29
|
@addon_classes = T.let([], T::Array[T.class_of(Addon)])
|
30
|
+
# Addon instances that have declared a handler to accept file watcher events
|
31
|
+
@file_watcher_addons = T.let([], T::Array[Addon])
|
30
32
|
|
31
33
|
class << self
|
32
34
|
extend T::Sig
|
@@ -34,6 +36,9 @@ module RubyLsp
|
|
34
36
|
sig { returns(T::Array[Addon]) }
|
35
37
|
attr_accessor :addons
|
36
38
|
|
39
|
+
sig { returns(T::Array[Addon]) }
|
40
|
+
attr_accessor :file_watcher_addons
|
41
|
+
|
37
42
|
sig { returns(T::Array[T.class_of(Addon)]) }
|
38
43
|
attr_reader :addon_classes
|
39
44
|
|
@@ -57,6 +62,7 @@ module RubyLsp
|
|
57
62
|
|
58
63
|
# Instantiate all discovered addon classes
|
59
64
|
self.addons = addon_classes.map(&:new)
|
65
|
+
self.file_watcher_addons = addons.select { |addon| addon.respond_to?(:workspace_did_change_watched_files) }
|
60
66
|
|
61
67
|
# Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
|
62
68
|
# fail to boot the server
|
data/lib/ruby_lsp/executor.rb
CHANGED
@@ -229,20 +229,23 @@ module RubyLsp
|
|
229
229
|
end
|
230
230
|
end
|
231
231
|
|
232
|
+
Addon.file_watcher_addons.each { |addon| T.unsafe(addon).workspace_did_change_watched_files(changes) }
|
232
233
|
VOID
|
233
234
|
end
|
234
235
|
|
235
236
|
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
236
237
|
def workspace_dependencies
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
238
|
+
Bundler.with_original_env do
|
239
|
+
definition = Bundler.definition
|
240
|
+
dep_keys = definition.locked_deps.keys.to_set
|
241
|
+
definition.specs.map do |spec|
|
242
|
+
{
|
243
|
+
name: spec.name,
|
244
|
+
version: spec.version,
|
245
|
+
path: spec.full_gem_path,
|
246
|
+
dependency: dep_keys.include?(spec.name),
|
247
|
+
}
|
248
|
+
end
|
246
249
|
end
|
247
250
|
rescue Bundler::GemfileNotFound
|
248
251
|
[]
|
@@ -22,6 +22,7 @@ module RubyLsp
|
|
22
22
|
SUPPORTED_TEST_LIBRARIES = T.let(["minitest", "test-unit"], T::Array[String])
|
23
23
|
DESCRIBE_KEYWORD = T.let(:describe, Symbol)
|
24
24
|
IT_KEYWORD = T.let(:it, Symbol)
|
25
|
+
DYNAMIC_REFERENCE_MARKER = T.let("<dynamic_reference>", String)
|
25
26
|
|
26
27
|
sig do
|
27
28
|
params(
|
@@ -44,6 +45,8 @@ module RubyLsp
|
|
44
45
|
self,
|
45
46
|
:on_class_node_enter,
|
46
47
|
:on_class_node_leave,
|
48
|
+
:on_module_node_enter,
|
49
|
+
:on_module_node_leave,
|
47
50
|
:on_def_node_enter,
|
48
51
|
:on_call_node_enter,
|
49
52
|
:on_call_node_leave,
|
@@ -60,7 +63,7 @@ module RubyLsp
|
|
60
63
|
add_test_code_lens(
|
61
64
|
node,
|
62
65
|
name: class_name,
|
63
|
-
command: generate_test_command(
|
66
|
+
command: generate_test_command(group_stack: @group_stack),
|
64
67
|
kind: :group,
|
65
68
|
)
|
66
69
|
end
|
@@ -88,13 +91,27 @@ module RubyLsp
|
|
88
91
|
add_test_code_lens(
|
89
92
|
node,
|
90
93
|
name: method_name,
|
91
|
-
command: generate_test_command(method_name: method_name,
|
94
|
+
command: generate_test_command(method_name: method_name, group_stack: @group_stack),
|
92
95
|
kind: :example,
|
93
96
|
)
|
94
97
|
end
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
101
|
+
sig { params(node: Prism::ModuleNode).void }
|
102
|
+
def on_module_node_enter(node)
|
103
|
+
if (path = namespace_constant_name(node))
|
104
|
+
@group_stack.push(path)
|
105
|
+
else
|
106
|
+
@group_stack.push(DYNAMIC_REFERENCE_MARKER)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
sig { params(node: Prism::ModuleNode).void }
|
111
|
+
def on_module_node_leave(node)
|
112
|
+
@group_stack.pop
|
113
|
+
end
|
114
|
+
|
98
115
|
sig { params(node: Prism::CallNode).void }
|
99
116
|
def on_call_node_enter(node)
|
100
117
|
name = node.name
|
@@ -181,18 +198,45 @@ module RubyLsp
|
|
181
198
|
)
|
182
199
|
end
|
183
200
|
|
184
|
-
sig
|
185
|
-
|
201
|
+
sig do
|
202
|
+
params(
|
203
|
+
group_stack: T::Array[String],
|
204
|
+
spec_name: T.nilable(String),
|
205
|
+
method_name: T.nilable(String),
|
206
|
+
).returns(String)
|
207
|
+
end
|
208
|
+
def generate_test_command(group_stack: [], spec_name: nil, method_name: nil)
|
186
209
|
command = BASE_COMMAND + T.must(@path)
|
187
210
|
|
188
211
|
case DependencyDetector.instance.detected_test_library
|
189
212
|
when "minitest"
|
190
|
-
|
191
|
-
|
213
|
+
last_dynamic_reference_index = group_stack.rindex(DYNAMIC_REFERENCE_MARKER)
|
214
|
+
command += if last_dynamic_reference_index
|
215
|
+
# In cases where the test path looks like `foo::Bar`
|
216
|
+
# the best we can do is match everything to the right of it.
|
217
|
+
# Tests are classes, dynamic references are only a thing for modules,
|
218
|
+
# so there must be something to the left of the available path.
|
219
|
+
group_stack = T.must(group_stack[last_dynamic_reference_index + 1..])
|
220
|
+
if method_name
|
221
|
+
" --name " + "/::#{Shellwords.escape(group_stack.join("::") + "#" + method_name)}$/"
|
222
|
+
else
|
223
|
+
# When clicking on a CodeLens for `Test`, `(#|::)` will match all tests
|
224
|
+
# that are registered on the class itself (matches after `#`) and all tests
|
225
|
+
# that are nested inside of that class in other modules/classes (matches after `::`)
|
226
|
+
" --name " + "\"/::#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
|
227
|
+
end
|
228
|
+
elsif method_name
|
229
|
+
# We know the entire path, do an exact match
|
230
|
+
" --name " + Shellwords.escape(group_stack.join("::") + "#" + method_name)
|
231
|
+
elsif spec_name
|
232
|
+
" --name " + "/#{Shellwords.escape(spec_name)}/"
|
192
233
|
else
|
193
|
-
|
234
|
+
# Execute all tests of the selected class and tests in
|
235
|
+
# modules/classes nested inside of that class
|
236
|
+
" --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
|
194
237
|
end
|
195
238
|
when "test-unit"
|
239
|
+
group_name = T.must(group_stack.last)
|
196
240
|
command += " --testcase " + "/#{Shellwords.escape(group_name)}/"
|
197
241
|
|
198
242
|
if method_name
|
@@ -214,8 +258,8 @@ module RubyLsp
|
|
214
258
|
name = case first_argument
|
215
259
|
when Prism::StringNode
|
216
260
|
first_argument.content
|
217
|
-
when Prism::ConstantReadNode
|
218
|
-
first_argument
|
261
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
262
|
+
constant_name(first_argument)
|
219
263
|
end
|
220
264
|
|
221
265
|
return unless name
|
@@ -223,7 +267,7 @@ module RubyLsp
|
|
223
267
|
add_test_code_lens(
|
224
268
|
node,
|
225
269
|
name: name,
|
226
|
-
command: generate_test_command(
|
270
|
+
command: generate_test_command(spec_name: name),
|
227
271
|
kind: kind,
|
228
272
|
)
|
229
273
|
end
|
@@ -100,8 +100,6 @@ module RubyLsp
|
|
100
100
|
|
101
101
|
sig { params(node: Prism::CallNode).void }
|
102
102
|
def on_call_node_enter(node)
|
103
|
-
return if @typechecker_enabled
|
104
|
-
|
105
103
|
name = node.message
|
106
104
|
return unless name
|
107
105
|
|
@@ -111,7 +109,7 @@ module RubyLsp
|
|
111
109
|
when "require_relative"
|
112
110
|
complete_require_relative(node)
|
113
111
|
else
|
114
|
-
complete_self_receiver_method(node, name) if self_receiver?(node)
|
112
|
+
complete_self_receiver_method(node, name) if !@typechecker_enabled && self_receiver?(node)
|
115
113
|
end
|
116
114
|
end
|
117
115
|
|
@@ -142,14 +140,17 @@ module RubyLsp
|
|
142
140
|
|
143
141
|
origin_dir = Pathname.new(@uri.to_standardized_path).dirname
|
144
142
|
|
145
|
-
|
143
|
+
content = path_node_to_complete.content
|
146
144
|
# if the path is not a directory, glob all possible next characters
|
147
145
|
# for example ../somethi| (where | is the cursor position)
|
148
146
|
# should find files for ../somethi*/
|
149
|
-
path_query
|
150
|
-
|
147
|
+
path_query = if content.end_with?("/") || content.empty?
|
148
|
+
"#{content}**/*.rb"
|
149
|
+
else
|
150
|
+
"{#{content}*/**/*.rb,**/#{content}*.rb}"
|
151
|
+
end
|
151
152
|
|
152
|
-
Dir.glob(path_query, base: origin_dir).sort!.each do |path|
|
153
|
+
Dir.glob(path_query, File::FNM_PATHNAME | File::FNM_EXTGLOB, base: origin_dir).sort!.each do |path|
|
153
154
|
@response_builder << build_completion(
|
154
155
|
path.delete_suffix(".rb"),
|
155
156
|
path_node_to_complete,
|
@@ -49,7 +49,13 @@ module RubyLsp
|
|
49
49
|
node_types: [Prism::CallNode, Prism::ConstantReadNode, Prism::ConstantPathNode],
|
50
50
|
)
|
51
51
|
|
52
|
-
|
52
|
+
if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
|
53
|
+
target = determine_target(
|
54
|
+
target,
|
55
|
+
parent,
|
56
|
+
position,
|
57
|
+
)
|
58
|
+
end
|
53
59
|
|
54
60
|
Listeners::Definition.new(@response_builder, document.uri, nesting, index, dispatcher, typechecker_enabled)
|
55
61
|
|
@@ -50,7 +50,11 @@ module RubyLsp
|
|
50
50
|
if (Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
|
51
51
|
!Listeners::Hover::ALLOWED_TARGETS.include?(@target.class)) ||
|
52
52
|
(parent.is_a?(Prism::ConstantPathNode) && @target.is_a?(Prism::ConstantReadNode))
|
53
|
-
@target =
|
53
|
+
@target = determine_target(
|
54
|
+
T.must(@target),
|
55
|
+
T.must(parent),
|
56
|
+
position,
|
57
|
+
)
|
54
58
|
end
|
55
59
|
|
56
60
|
# Don't need to instantiate any listeners if there's no target
|
@@ -12,6 +12,57 @@ module RubyLsp
|
|
12
12
|
|
13
13
|
sig { abstract.returns(T.anything) }
|
14
14
|
def perform; end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Checks if a location covers a position
|
19
|
+
sig { params(location: Prism::Location, position: T.untyped).returns(T::Boolean) }
|
20
|
+
def cover?(location, position)
|
21
|
+
start_covered =
|
22
|
+
location.start_line - 1 < position[:line] ||
|
23
|
+
(
|
24
|
+
location.start_line - 1 == position[:line] &&
|
25
|
+
location.start_column <= position[:character]
|
26
|
+
)
|
27
|
+
end_covered =
|
28
|
+
location.end_line - 1 > position[:line] ||
|
29
|
+
(
|
30
|
+
location.end_line - 1 == position[:line] &&
|
31
|
+
location.end_column >= position[:character]
|
32
|
+
)
|
33
|
+
start_covered && end_covered
|
34
|
+
end
|
35
|
+
|
36
|
+
# Based on a constant node target, a constant path node parent and a position, this method will find the exact
|
37
|
+
# portion of the constant path that matches the requested position, for higher precision in hover and
|
38
|
+
# definition. For example:
|
39
|
+
#
|
40
|
+
# ```ruby
|
41
|
+
# Foo::Bar::Baz
|
42
|
+
# # ^ Going to definition here should go to Foo::Bar::Baz
|
43
|
+
# # ^ Going to definition here should go to Foo::Bar
|
44
|
+
# #^ Going to definition here should go to Foo
|
45
|
+
# ```
|
46
|
+
sig do
|
47
|
+
params(
|
48
|
+
target: Prism::Node,
|
49
|
+
parent: Prism::Node,
|
50
|
+
position: T::Hash[Symbol, Integer],
|
51
|
+
).returns(Prism::Node)
|
52
|
+
end
|
53
|
+
def determine_target(target, parent, position)
|
54
|
+
return target unless parent.is_a?(Prism::ConstantPathNode)
|
55
|
+
|
56
|
+
target = T.let(parent, Prism::Node)
|
57
|
+
parent = T.let(T.cast(target, Prism::ConstantPathNode).parent, T.nilable(Prism::Node))
|
58
|
+
|
59
|
+
while parent && cover?(parent.location, position)
|
60
|
+
target = parent
|
61
|
+
parent = target.is_a?(Prism::ConstantPathNode) ? target.parent : nil
|
62
|
+
end
|
63
|
+
|
64
|
+
target
|
65
|
+
end
|
15
66
|
end
|
16
67
|
end
|
17
68
|
end
|
@@ -147,6 +147,15 @@ module RubyLsp
|
|
147
147
|
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError
|
148
148
|
nil
|
149
149
|
end
|
150
|
+
|
151
|
+
sig { params(node: T.any(Prism::ModuleNode, Prism::ClassNode)).returns(T.nilable(String)) }
|
152
|
+
def namespace_constant_name(node)
|
153
|
+
path = node.constant_path
|
154
|
+
case path
|
155
|
+
when Prism::ConstantPathNode, Prism::ConstantReadNode, Prism::ConstantPathTargetNode
|
156
|
+
constant_name(path)
|
157
|
+
end
|
158
|
+
end
|
150
159
|
end
|
151
160
|
end
|
152
161
|
end
|
@@ -40,6 +40,9 @@ module RubyLsp
|
|
40
40
|
|
41
41
|
sig { returns(Interface::Diagnostic) }
|
42
42
|
def to_lsp_diagnostic
|
43
|
+
# highlighted_area contains the begin and end position of the first line
|
44
|
+
# This ensures that multiline offenses don't clutter the editor
|
45
|
+
highlighted = @offense.highlighted_area
|
43
46
|
Interface::Diagnostic.new(
|
44
47
|
message: message,
|
45
48
|
source: "RuboCop",
|
@@ -49,11 +52,11 @@ module RubyLsp
|
|
49
52
|
range: Interface::Range.new(
|
50
53
|
start: Interface::Position.new(
|
51
54
|
line: @offense.line - 1,
|
52
|
-
character:
|
55
|
+
character: highlighted.begin_pos,
|
53
56
|
),
|
54
57
|
end: Interface::Position.new(
|
55
|
-
line: @offense.
|
56
|
-
character:
|
58
|
+
line: @offense.line - 1,
|
59
|
+
character: highlighted.end_pos,
|
57
60
|
),
|
58
61
|
),
|
59
62
|
data: {
|
@@ -13,6 +13,10 @@ rescue LoadError
|
|
13
13
|
raise StandardError, "Incompatible RuboCop version. Ruby LSP requires >= 1.4.0"
|
14
14
|
end
|
15
15
|
|
16
|
+
if RuboCop.const_defined?(:LSP) # This condition will be removed when requiring RuboCop >= 1.61.
|
17
|
+
RuboCop::LSP.enable
|
18
|
+
end
|
19
|
+
|
16
20
|
module RubyLsp
|
17
21
|
module Requests
|
18
22
|
module Support
|
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.14.
|
4
|
+
version: 0.14.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|