ruby-lsp 0.14.5 → 0.15.0
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 +1 -16
- data/exe/ruby-lsp-check +13 -22
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +21 -0
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +12 -24
- 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/configuration_test.rb +2 -11
- data/lib/ruby_indexer/test/index_test.rb +5 -0
- data/lib/ruby_lsp/addon.rb +18 -5
- data/lib/ruby_lsp/base_server.rb +147 -0
- data/lib/ruby_lsp/document.rb +0 -5
- data/lib/ruby_lsp/{requests/support/dependency_detector.rb → global_state.rb} +30 -9
- data/lib/ruby_lsp/internal.rb +2 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +66 -18
- data/lib/ruby_lsp/listeners/completion.rb +13 -14
- data/lib/ruby_lsp/listeners/definition.rb +4 -3
- data/lib/ruby_lsp/listeners/document_symbol.rb +91 -3
- data/lib/ruby_lsp/listeners/hover.rb +6 -5
- data/lib/ruby_lsp/listeners/signature_help.rb +7 -4
- data/lib/ruby_lsp/load_sorbet.rb +62 -0
- data/lib/ruby_lsp/requests/code_lens.rb +4 -3
- data/lib/ruby_lsp/requests/completion.rb +15 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +56 -0
- data/lib/ruby_lsp/requests/definition.rb +18 -5
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/hover.rb +9 -5
- data/lib/ruby_lsp/requests/request.rb +51 -0
- data/lib/ruby_lsp/requests/signature_help.rb +4 -3
- data/lib/ruby_lsp/requests/support/common.rb +25 -5
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +4 -0
- data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/server.rb +756 -142
- data/lib/ruby_lsp/store.rb +0 -8
- data/lib/ruby_lsp/test_helper.rb +45 -0
- data/lib/ruby_lsp/utils.rb +68 -33
- metadata +8 -5
- data/lib/ruby_lsp/executor.rb +0 -612
@@ -22,16 +22,19 @@ 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(
|
28
29
|
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
30
|
+
global_state: GlobalState,
|
29
31
|
uri: URI::Generic,
|
30
32
|
dispatcher: Prism::Dispatcher,
|
31
33
|
).void
|
32
34
|
end
|
33
|
-
def initialize(response_builder, uri, dispatcher)
|
35
|
+
def initialize(response_builder, global_state, uri, dispatcher)
|
34
36
|
@response_builder = response_builder
|
37
|
+
@global_state = global_state
|
35
38
|
@uri = T.let(uri, URI::Generic)
|
36
39
|
@path = T.let(uri.to_standardized_path, T.nilable(String))
|
37
40
|
# visibility_stack is a stack of [current_visibility, previous_visibility]
|
@@ -44,6 +47,8 @@ module RubyLsp
|
|
44
47
|
self,
|
45
48
|
:on_class_node_enter,
|
46
49
|
:on_class_node_leave,
|
50
|
+
:on_module_node_enter,
|
51
|
+
:on_module_node_leave,
|
47
52
|
:on_def_node_enter,
|
48
53
|
:on_call_node_enter,
|
49
54
|
:on_call_node_leave,
|
@@ -60,7 +65,7 @@ module RubyLsp
|
|
60
65
|
add_test_code_lens(
|
61
66
|
node,
|
62
67
|
name: class_name,
|
63
|
-
command: generate_test_command(
|
68
|
+
command: generate_test_command(group_stack: @group_stack),
|
64
69
|
kind: :group,
|
65
70
|
)
|
66
71
|
end
|
@@ -88,13 +93,27 @@ module RubyLsp
|
|
88
93
|
add_test_code_lens(
|
89
94
|
node,
|
90
95
|
name: method_name,
|
91
|
-
command: generate_test_command(method_name: method_name,
|
96
|
+
command: generate_test_command(method_name: method_name, group_stack: @group_stack),
|
92
97
|
kind: :example,
|
93
98
|
)
|
94
99
|
end
|
95
100
|
end
|
96
101
|
end
|
97
102
|
|
103
|
+
sig { params(node: Prism::ModuleNode).void }
|
104
|
+
def on_module_node_enter(node)
|
105
|
+
if (path = namespace_constant_name(node))
|
106
|
+
@group_stack.push(path)
|
107
|
+
else
|
108
|
+
@group_stack.push(DYNAMIC_REFERENCE_MARKER)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
sig { params(node: Prism::ModuleNode).void }
|
113
|
+
def on_module_node_leave(node)
|
114
|
+
@group_stack.pop
|
115
|
+
end
|
116
|
+
|
98
117
|
sig { params(node: Prism::CallNode).void }
|
99
118
|
def on_call_node_enter(node)
|
100
119
|
name = node.name
|
@@ -139,7 +158,7 @@ module RubyLsp
|
|
139
158
|
sig { params(node: Prism::Node, name: String, command: String, kind: Symbol).void }
|
140
159
|
def add_test_code_lens(node, name:, command:, kind:)
|
141
160
|
# don't add code lenses if the test library is not supported or unknown
|
142
|
-
return unless SUPPORTED_TEST_LIBRARIES.include?(
|
161
|
+
return unless SUPPORTED_TEST_LIBRARIES.include?(@global_state.test_library) && @path
|
143
162
|
|
144
163
|
arguments = [
|
145
164
|
@path,
|
@@ -181,18 +200,45 @@ module RubyLsp
|
|
181
200
|
)
|
182
201
|
end
|
183
202
|
|
184
|
-
sig
|
185
|
-
|
203
|
+
sig do
|
204
|
+
params(
|
205
|
+
group_stack: T::Array[String],
|
206
|
+
spec_name: T.nilable(String),
|
207
|
+
method_name: T.nilable(String),
|
208
|
+
).returns(String)
|
209
|
+
end
|
210
|
+
def generate_test_command(group_stack: [], spec_name: nil, method_name: nil)
|
186
211
|
command = BASE_COMMAND + T.must(@path)
|
187
212
|
|
188
|
-
case
|
213
|
+
case @global_state.test_library
|
189
214
|
when "minitest"
|
190
|
-
|
191
|
-
|
215
|
+
last_dynamic_reference_index = group_stack.rindex(DYNAMIC_REFERENCE_MARKER)
|
216
|
+
command += if last_dynamic_reference_index
|
217
|
+
# In cases where the test path looks like `foo::Bar`
|
218
|
+
# the best we can do is match everything to the right of it.
|
219
|
+
# Tests are classes, dynamic references are only a thing for modules,
|
220
|
+
# so there must be something to the left of the available path.
|
221
|
+
group_stack = T.must(group_stack[last_dynamic_reference_index + 1..])
|
222
|
+
if method_name
|
223
|
+
" --name " + "/::#{Shellwords.escape(group_stack.join("::") + "#" + method_name)}$/"
|
224
|
+
else
|
225
|
+
# When clicking on a CodeLens for `Test`, `(#|::)` will match all tests
|
226
|
+
# that are registered on the class itself (matches after `#`) and all tests
|
227
|
+
# that are nested inside of that class in other modules/classes (matches after `::`)
|
228
|
+
" --name " + "\"/::#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
|
229
|
+
end
|
230
|
+
elsif method_name
|
231
|
+
# We know the entire path, do an exact match
|
232
|
+
" --name " + Shellwords.escape(group_stack.join("::") + "#" + method_name)
|
233
|
+
elsif spec_name
|
234
|
+
" --name " + "/#{Shellwords.escape(spec_name)}/"
|
192
235
|
else
|
193
|
-
|
236
|
+
# Execute all tests of the selected class and tests in
|
237
|
+
# modules/classes nested inside of that class
|
238
|
+
" --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
|
194
239
|
end
|
195
240
|
when "test-unit"
|
241
|
+
group_name = T.must(group_stack.last)
|
196
242
|
command += " --testcase " + "/#{Shellwords.escape(group_name)}/"
|
197
243
|
|
198
244
|
if method_name
|
@@ -214,18 +260,20 @@ module RubyLsp
|
|
214
260
|
name = case first_argument
|
215
261
|
when Prism::StringNode
|
216
262
|
first_argument.content
|
217
|
-
when Prism::ConstantReadNode
|
218
|
-
first_argument
|
263
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
264
|
+
constant_name(first_argument)
|
219
265
|
end
|
220
266
|
|
221
267
|
return unless name
|
222
268
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
269
|
+
if @path
|
270
|
+
add_test_code_lens(
|
271
|
+
node,
|
272
|
+
name: name,
|
273
|
+
command: generate_test_command(spec_name: name),
|
274
|
+
kind: kind,
|
275
|
+
)
|
276
|
+
end
|
229
277
|
end
|
230
278
|
end
|
231
279
|
end
|
@@ -10,16 +10,17 @@ module RubyLsp
|
|
10
10
|
sig do
|
11
11
|
params(
|
12
12
|
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
13
|
-
|
13
|
+
global_state: GlobalState,
|
14
14
|
nesting: T::Array[String],
|
15
15
|
typechecker_enabled: T::Boolean,
|
16
16
|
dispatcher: Prism::Dispatcher,
|
17
17
|
uri: URI::Generic,
|
18
18
|
).void
|
19
19
|
end
|
20
|
-
def initialize(response_builder,
|
20
|
+
def initialize(response_builder, global_state, nesting, typechecker_enabled, dispatcher, uri) # rubocop:disable Metrics/ParameterLists
|
21
21
|
@response_builder = response_builder
|
22
|
-
@
|
22
|
+
@global_state = global_state
|
23
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
23
24
|
@nesting = nesting
|
24
25
|
@typechecker_enabled = typechecker_enabled
|
25
26
|
@uri = uri
|
@@ -35,7 +36,7 @@ module RubyLsp
|
|
35
36
|
# Handle completion on regular constant references (e.g. `Bar`)
|
36
37
|
sig { params(node: Prism::ConstantReadNode).void }
|
37
38
|
def on_constant_read_node_enter(node)
|
38
|
-
return if
|
39
|
+
return if @global_state.typechecker
|
39
40
|
|
40
41
|
name = constant_name(node)
|
41
42
|
return if name.nil?
|
@@ -56,7 +57,7 @@ module RubyLsp
|
|
56
57
|
# Handle completion on namespaced constant references (e.g. `Foo::Bar`)
|
57
58
|
sig { params(node: Prism::ConstantPathNode).void }
|
58
59
|
def on_constant_path_node_enter(node)
|
59
|
-
return if
|
60
|
+
return if @global_state.typechecker
|
60
61
|
|
61
62
|
name = constant_name(node)
|
62
63
|
return if name.nil?
|
@@ -77,7 +78,10 @@ module RubyLsp
|
|
77
78
|
|
78
79
|
real_namespace = @index.follow_aliased_namespace(T.must(namespace_entries.first).name)
|
79
80
|
|
80
|
-
candidates = @index.prefix_search(
|
81
|
+
candidates = @index.prefix_search(
|
82
|
+
"#{real_namespace}::#{incomplete_name}",
|
83
|
+
top_level_reference ? [] : @nesting,
|
84
|
+
)
|
81
85
|
candidates.each do |entries|
|
82
86
|
# The only time we may have a private constant reference from outside of the namespace is if we're dealing
|
83
87
|
# with ConstantPath and the entry name doesn't start with the current nesting
|
@@ -124,7 +128,9 @@ module RubyLsp
|
|
124
128
|
|
125
129
|
return unless path_node_to_complete.is_a?(Prism::StringNode)
|
126
130
|
|
127
|
-
@index.search_require_paths(path_node_to_complete.content)
|
131
|
+
matched_indexable_paths = @index.search_require_paths(path_node_to_complete.content)
|
132
|
+
|
133
|
+
matched_indexable_paths.map!(&:require_path).sort!.each do |path|
|
128
134
|
@response_builder << build_completion(T.must(path), path_node_to_complete)
|
129
135
|
end
|
130
136
|
end
|
@@ -284,13 +290,6 @@ module RubyLsp
|
|
284
290
|
new_text: insertion_text,
|
285
291
|
),
|
286
292
|
kind: kind,
|
287
|
-
label_details: Interface::CompletionItemLabelDetails.new(
|
288
|
-
description: entries.map(&:file_name).join(","),
|
289
|
-
),
|
290
|
-
documentation: Interface::MarkupContent.new(
|
291
|
-
kind: "markdown",
|
292
|
-
value: markdown_from_index_entries(real_name, entries),
|
293
|
-
),
|
294
293
|
)
|
295
294
|
end
|
296
295
|
|
@@ -10,18 +10,19 @@ module RubyLsp
|
|
10
10
|
sig do
|
11
11
|
params(
|
12
12
|
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
|
13
|
+
global_state: GlobalState,
|
13
14
|
uri: URI::Generic,
|
14
15
|
nesting: T::Array[String],
|
15
|
-
index: RubyIndexer::Index,
|
16
16
|
dispatcher: Prism::Dispatcher,
|
17
17
|
typechecker_enabled: T::Boolean,
|
18
18
|
).void
|
19
19
|
end
|
20
|
-
def initialize(response_builder, uri, nesting,
|
20
|
+
def initialize(response_builder, global_state, uri, nesting, dispatcher, typechecker_enabled) # rubocop:disable Metrics/ParameterLists
|
21
21
|
@response_builder = response_builder
|
22
|
+
@global_state = global_state
|
23
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
22
24
|
@uri = uri
|
23
25
|
@nesting = nesting
|
24
|
-
@index = index
|
25
26
|
@typechecker_enabled = typechecker_enabled
|
26
27
|
|
27
28
|
dispatcher.register(
|
@@ -12,17 +12,20 @@ module RubyLsp
|
|
12
12
|
sig do
|
13
13
|
params(
|
14
14
|
response_builder: ResponseBuilders::DocumentSymbol,
|
15
|
+
uri: URI::Generic,
|
15
16
|
dispatcher: Prism::Dispatcher,
|
16
17
|
).void
|
17
18
|
end
|
18
|
-
def initialize(response_builder, dispatcher)
|
19
|
+
def initialize(response_builder, uri, dispatcher)
|
19
20
|
@response_builder = response_builder
|
21
|
+
@uri = uri
|
20
22
|
|
21
23
|
dispatcher.register(
|
22
24
|
self,
|
23
25
|
:on_class_node_enter,
|
24
26
|
:on_class_node_leave,
|
25
27
|
:on_call_node_enter,
|
28
|
+
:on_call_node_leave,
|
26
29
|
:on_constant_path_write_node_enter,
|
27
30
|
:on_constant_write_node_enter,
|
28
31
|
:on_constant_path_or_write_node_enter,
|
@@ -79,10 +82,24 @@ module RubyLsp
|
|
79
82
|
|
80
83
|
sig { params(node: Prism::CallNode).void }
|
81
84
|
def on_call_node_enter(node)
|
82
|
-
|
85
|
+
node_name = node.name
|
86
|
+
if ATTR_ACCESSORS.include?(node_name)
|
83
87
|
handle_attr_accessor(node)
|
84
|
-
elsif
|
88
|
+
elsif node_name == :alias_method
|
85
89
|
handle_alias_method(node)
|
90
|
+
elsif node_name == :namespace
|
91
|
+
handle_rake_namespace(node)
|
92
|
+
elsif node_name == :task
|
93
|
+
handle_rake_task(node)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
sig { params(node: Prism::CallNode).void }
|
98
|
+
def on_call_node_leave(node)
|
99
|
+
return unless rake?
|
100
|
+
|
101
|
+
if node.name == :namespace && !node.receiver
|
102
|
+
@response_builder.pop
|
86
103
|
end
|
87
104
|
end
|
88
105
|
|
@@ -279,6 +296,7 @@ module RubyLsp
|
|
279
296
|
).returns(Interface::DocumentSymbol)
|
280
297
|
end
|
281
298
|
def create_document_symbol(name:, kind:, range_location:, selection_range_location:)
|
299
|
+
name = "<blank>" if name.empty?
|
282
300
|
symbol = Interface::DocumentSymbol.new(
|
283
301
|
name: name,
|
284
302
|
kind: kind,
|
@@ -357,6 +375,76 @@ module RubyLsp
|
|
357
375
|
)
|
358
376
|
end
|
359
377
|
end
|
378
|
+
|
379
|
+
sig { params(node: Prism::CallNode).void }
|
380
|
+
def handle_rake_namespace(node)
|
381
|
+
return unless rake?
|
382
|
+
return if node.receiver
|
383
|
+
|
384
|
+
arguments = node.arguments
|
385
|
+
return unless arguments
|
386
|
+
|
387
|
+
name_argument = arguments.arguments.first
|
388
|
+
return unless name_argument
|
389
|
+
|
390
|
+
name = case name_argument
|
391
|
+
when Prism::StringNode then name_argument.content
|
392
|
+
when Prism::SymbolNode then name_argument.value
|
393
|
+
end
|
394
|
+
|
395
|
+
return if name.nil? || name.empty?
|
396
|
+
|
397
|
+
@response_builder << create_document_symbol(
|
398
|
+
name: name,
|
399
|
+
kind: Constant::SymbolKind::MODULE,
|
400
|
+
range_location: name_argument.location,
|
401
|
+
selection_range_location: name_argument.location,
|
402
|
+
)
|
403
|
+
end
|
404
|
+
|
405
|
+
sig { params(node: Prism::CallNode).void }
|
406
|
+
def handle_rake_task(node)
|
407
|
+
return unless rake?
|
408
|
+
return if node.receiver
|
409
|
+
|
410
|
+
arguments = node.arguments
|
411
|
+
return unless arguments
|
412
|
+
|
413
|
+
name_argument = arguments.arguments.first
|
414
|
+
return unless name_argument
|
415
|
+
|
416
|
+
name = case name_argument
|
417
|
+
when Prism::StringNode then name_argument.content
|
418
|
+
when Prism::SymbolNode then name_argument.value
|
419
|
+
when Prism::KeywordHashNode
|
420
|
+
first_element = name_argument.elements.first
|
421
|
+
if first_element.is_a?(Prism::AssocNode)
|
422
|
+
key = first_element.key
|
423
|
+
case key
|
424
|
+
when Prism::StringNode then key.content
|
425
|
+
when Prism::SymbolNode then key.value
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
return if name.nil? || name.empty?
|
431
|
+
|
432
|
+
create_document_symbol(
|
433
|
+
name: name,
|
434
|
+
kind: Constant::SymbolKind::METHOD,
|
435
|
+
range_location: name_argument.location,
|
436
|
+
selection_range_location: name_argument.location,
|
437
|
+
)
|
438
|
+
end
|
439
|
+
|
440
|
+
sig { returns(T::Boolean) }
|
441
|
+
def rake?
|
442
|
+
if (path = @uri.to_standardized_path)
|
443
|
+
path.match?(/(Rakefile|\.rake)$/)
|
444
|
+
else
|
445
|
+
false
|
446
|
+
end
|
447
|
+
end
|
360
448
|
end
|
361
449
|
end
|
362
450
|
end
|
@@ -28,18 +28,19 @@ module RubyLsp
|
|
28
28
|
sig do
|
29
29
|
params(
|
30
30
|
response_builder: ResponseBuilders::Hover,
|
31
|
+
global_state: GlobalState,
|
31
32
|
uri: URI::Generic,
|
32
33
|
nesting: T::Array[String],
|
33
|
-
index: RubyIndexer::Index,
|
34
34
|
dispatcher: Prism::Dispatcher,
|
35
35
|
typechecker_enabled: T::Boolean,
|
36
36
|
).void
|
37
37
|
end
|
38
|
-
def initialize(response_builder, uri, nesting,
|
38
|
+
def initialize(response_builder, global_state, uri, nesting, dispatcher, typechecker_enabled) # rubocop:disable Metrics/ParameterLists
|
39
39
|
@response_builder = response_builder
|
40
|
+
@global_state = global_state
|
41
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
40
42
|
@path = T.let(uri.to_standardized_path, T.nilable(String))
|
41
43
|
@nesting = nesting
|
42
|
-
@index = index
|
43
44
|
@typechecker_enabled = typechecker_enabled
|
44
45
|
|
45
46
|
dispatcher.register(
|
@@ -63,14 +64,14 @@ module RubyLsp
|
|
63
64
|
|
64
65
|
sig { params(node: Prism::ConstantWriteNode).void }
|
65
66
|
def on_constant_write_node_enter(node)
|
66
|
-
return if
|
67
|
+
return if @global_state.typechecker
|
67
68
|
|
68
69
|
generate_hover(node.name.to_s, node.name_loc)
|
69
70
|
end
|
70
71
|
|
71
72
|
sig { params(node: Prism::ConstantPathNode).void }
|
72
73
|
def on_constant_path_node_enter(node)
|
73
|
-
return if
|
74
|
+
return if @global_state.typechecker
|
74
75
|
|
75
76
|
name = constant_name(node)
|
76
77
|
return if name.nil?
|
@@ -10,21 +10,24 @@ module RubyLsp
|
|
10
10
|
sig do
|
11
11
|
params(
|
12
12
|
response_builder: ResponseBuilders::SignatureHelp,
|
13
|
+
global_state: GlobalState,
|
13
14
|
nesting: T::Array[String],
|
14
|
-
index: RubyIndexer::Index,
|
15
15
|
dispatcher: Prism::Dispatcher,
|
16
|
+
typechecker_enabled: T::Boolean,
|
16
17
|
).void
|
17
18
|
end
|
18
|
-
def initialize(response_builder, nesting,
|
19
|
+
def initialize(response_builder, global_state, nesting, dispatcher, typechecker_enabled)
|
20
|
+
@typechecker_enabled = typechecker_enabled
|
19
21
|
@response_builder = response_builder
|
22
|
+
@global_state = global_state
|
23
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
20
24
|
@nesting = nesting
|
21
|
-
@index = index
|
22
25
|
dispatcher.register(self, :on_call_node_enter)
|
23
26
|
end
|
24
27
|
|
25
28
|
sig { params(node: Prism::CallNode).void }
|
26
29
|
def on_call_node_enter(node)
|
27
|
-
return if
|
30
|
+
return if @typechecker_enabled
|
28
31
|
return unless self_receiver?(node)
|
29
32
|
|
30
33
|
message = node.message
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "sorbet-runtime"
|
5
|
+
|
6
|
+
begin
|
7
|
+
T::Configuration.default_checked_level = :never
|
8
|
+
# Suppresses call validation errors
|
9
|
+
T::Configuration.call_validation_error_handler = ->(*) {}
|
10
|
+
# Suppresses errors caused by T.cast, T.let, T.must, etc.
|
11
|
+
T::Configuration.inline_type_error_handler = ->(*) {}
|
12
|
+
# Suppresses errors caused by incorrect parameter ordering
|
13
|
+
T::Configuration.sig_validation_error_handler = ->(*) {}
|
14
|
+
rescue
|
15
|
+
# Need this rescue so that if another gem has
|
16
|
+
# already set the checked level by the time we
|
17
|
+
# get to it, we don't fail outright.
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
module RubyLsp
|
22
|
+
# No-op all inline type assertions defined in T
|
23
|
+
module InlineTypeAssertions
|
24
|
+
def absurd(value)
|
25
|
+
value
|
26
|
+
end
|
27
|
+
|
28
|
+
def any(type_a, type_b, *types)
|
29
|
+
T::Types::Union.new([type_a, type_b, *types])
|
30
|
+
end
|
31
|
+
|
32
|
+
def assert_type!(value, type, checked: true)
|
33
|
+
value
|
34
|
+
end
|
35
|
+
|
36
|
+
def bind(value, type, checked: true)
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
def cast(value, type, checked: true)
|
41
|
+
value
|
42
|
+
end
|
43
|
+
|
44
|
+
def let(value, type, checked: true)
|
45
|
+
value
|
46
|
+
end
|
47
|
+
|
48
|
+
def must(arg)
|
49
|
+
arg
|
50
|
+
end
|
51
|
+
|
52
|
+
def nilable(type)
|
53
|
+
T::Types::Union.new([type, T::Utils::Nilable::NIL_TYPE])
|
54
|
+
end
|
55
|
+
|
56
|
+
def unsafe(value)
|
57
|
+
value
|
58
|
+
end
|
59
|
+
|
60
|
+
T.singleton_class.prepend(self)
|
61
|
+
end
|
62
|
+
end
|
@@ -34,20 +34,21 @@ module RubyLsp
|
|
34
34
|
|
35
35
|
sig do
|
36
36
|
params(
|
37
|
+
global_state: GlobalState,
|
37
38
|
uri: URI::Generic,
|
38
39
|
dispatcher: Prism::Dispatcher,
|
39
40
|
).void
|
40
41
|
end
|
41
|
-
def initialize(uri, dispatcher)
|
42
|
+
def initialize(global_state, uri, dispatcher)
|
42
43
|
@response_builder = T.let(
|
43
44
|
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens].new,
|
44
45
|
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
45
46
|
)
|
46
47
|
super()
|
47
|
-
Listeners::CodeLens.new(@response_builder, uri, dispatcher)
|
48
|
+
Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
|
48
49
|
|
49
50
|
Addon.addons.each do |addon|
|
50
|
-
addon.create_code_lens_listener(@response_builder, uri, dispatcher)
|
51
|
+
addon.create_code_lens_listener(@response_builder, global_state, uri, dispatcher)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -33,7 +33,7 @@ module RubyLsp
|
|
33
33
|
sig { returns(Interface::CompletionOptions) }
|
34
34
|
def provider
|
35
35
|
Interface::CompletionOptions.new(
|
36
|
-
resolve_provider:
|
36
|
+
resolve_provider: true,
|
37
37
|
trigger_characters: ["/", "\"", "'"],
|
38
38
|
completion_item: {
|
39
39
|
labelDetailsSupport: true,
|
@@ -45,13 +45,13 @@ module RubyLsp
|
|
45
45
|
sig do
|
46
46
|
params(
|
47
47
|
document: Document,
|
48
|
-
|
48
|
+
global_state: GlobalState,
|
49
49
|
position: T::Hash[Symbol, T.untyped],
|
50
50
|
typechecker_enabled: T::Boolean,
|
51
51
|
dispatcher: Prism::Dispatcher,
|
52
52
|
).void
|
53
53
|
end
|
54
|
-
def initialize(document,
|
54
|
+
def initialize(document, global_state, position, typechecker_enabled, dispatcher)
|
55
55
|
super()
|
56
56
|
@target = T.let(nil, T.nilable(Prism::Node))
|
57
57
|
@dispatcher = dispatcher
|
@@ -68,7 +68,18 @@ module RubyLsp
|
|
68
68
|
ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
69
69
|
)
|
70
70
|
|
71
|
-
Listeners::Completion.new(
|
71
|
+
Listeners::Completion.new(
|
72
|
+
@response_builder,
|
73
|
+
global_state,
|
74
|
+
nesting,
|
75
|
+
typechecker_enabled,
|
76
|
+
dispatcher,
|
77
|
+
document.uri,
|
78
|
+
)
|
79
|
+
|
80
|
+
Addon.addons.each do |addon|
|
81
|
+
addon.create_completion_listener(@response_builder, global_state, nesting, dispatcher, document.uri)
|
82
|
+
end
|
72
83
|
|
73
84
|
return unless matched && parent
|
74
85
|
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# 
|
7
|
+
#
|
8
|
+
# The [completionItem/resolve](https://microsoft.github.io/language-server-protocol/specification#completionItem_resolve)
|
9
|
+
# request provides additional information about the currently selected completion. Specifically, the `labelDetails`
|
10
|
+
# and `documentation` fields are provided, which are omitted from the completion items returned by
|
11
|
+
# `textDocument/completion`.
|
12
|
+
#
|
13
|
+
# The `labelDetails` field lists the files where the completion item is defined, and the `documentation` field
|
14
|
+
# includes any available documentation for those definitions.
|
15
|
+
#
|
16
|
+
# At most 10 definitions are included, to ensure low latency during request processing and rendering the completion
|
17
|
+
# item.
|
18
|
+
#
|
19
|
+
# # Example
|
20
|
+
#
|
21
|
+
# ```ruby
|
22
|
+
# A # -> as the user cycles through completion items, the documentation will be resolved and displayed
|
23
|
+
# ```
|
24
|
+
class CompletionResolve < Request
|
25
|
+
extend T::Sig
|
26
|
+
include Requests::Support::Common
|
27
|
+
|
28
|
+
# set a limit on the number of documentation entries returned, to avoid rendering performance issues
|
29
|
+
# https://github.com/Shopify/ruby-lsp/pull/1798
|
30
|
+
MAX_DOCUMENTATION_ENTRIES = 10
|
31
|
+
|
32
|
+
sig { params(global_state: GlobalState, item: T::Hash[Symbol, T.untyped]).void }
|
33
|
+
def initialize(global_state, item)
|
34
|
+
super()
|
35
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
36
|
+
@item = item
|
37
|
+
end
|
38
|
+
|
39
|
+
sig { override.returns(Interface::CompletionItem) }
|
40
|
+
def perform
|
41
|
+
label = @item[:label]
|
42
|
+
entries = @index[label] || []
|
43
|
+
Interface::CompletionItem.new(
|
44
|
+
label: label,
|
45
|
+
label_details: Interface::CompletionItemLabelDetails.new(
|
46
|
+
description: entries.take(MAX_DOCUMENTATION_ENTRIES).map(&:file_name).join(","),
|
47
|
+
),
|
48
|
+
documentation: Interface::MarkupContent.new(
|
49
|
+
kind: "markdown",
|
50
|
+
value: markdown_from_index_entries(label, entries, MAX_DOCUMENTATION_ENTRIES),
|
51
|
+
),
|
52
|
+
)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|