ruby-lsp 0.26.9 → 0.27.0.beta2
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/declaration_listener.rb +2 -2
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +8 -8
- data/lib/ruby_indexer/ruby_indexer.rb +0 -1
- data/lib/ruby_lsp/addon.rb +19 -19
- data/lib/ruby_lsp/global_state.rb +11 -2
- data/lib/ruby_lsp/internal.rb +6 -1
- data/lib/ruby_lsp/listeners/definition.rb +65 -99
- data/lib/ruby_lsp/listeners/document_link.rb +4 -0
- data/lib/ruby_lsp/listeners/hover.rb +258 -123
- data/lib/ruby_lsp/listeners/spec_style.rb +6 -1
- data/lib/ruby_lsp/listeners/test_discovery.rb +21 -14
- data/lib/ruby_lsp/listeners/test_style.rb +20 -8
- data/lib/ruby_lsp/node_context.rb +32 -9
- data/lib/ruby_lsp/requests/completion_resolve.rb +9 -13
- data/lib/ruby_lsp/requests/discover_tests.rb +5 -41
- data/lib/ruby_lsp/requests/hover.rb +2 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +4 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +66 -22
- data/lib/ruby_lsp/requests/references.rb +170 -70
- data/lib/ruby_lsp/requests/rename.rb +64 -72
- data/lib/ruby_lsp/requests/request.rb +3 -33
- data/lib/ruby_lsp/requests/support/common.rb +53 -0
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +82 -46
- data/lib/ruby_lsp/requests/workspace_symbol.rb +15 -37
- data/lib/ruby_lsp/rubydex/declaration.rb +48 -0
- data/lib/ruby_lsp/rubydex/definition.rb +257 -0
- data/lib/ruby_lsp/rubydex/reference.rb +21 -0
- data/lib/ruby_lsp/server.rb +82 -8
- data/lib/ruby_lsp/store.rb +0 -6
- data/lib/ruby_lsp/test_helper.rb +3 -0
- data/lib/ruby_lsp/type_inferrer.rb +111 -31
- metadata +18 -5
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +0 -335
- data/lib/ruby_lsp/static_docs.rb +0 -20
- data/static_docs/break.md +0 -103
- data/static_docs/yield.md +0 -81
|
@@ -6,91 +6,95 @@ module RubyLsp
|
|
|
6
6
|
class Hover
|
|
7
7
|
include Requests::Support::Common
|
|
8
8
|
|
|
9
|
-
ALLOWED_TARGETS = [
|
|
10
|
-
Prism::BreakNode,
|
|
11
|
-
Prism::CallNode,
|
|
12
|
-
Prism::ConstantReadNode,
|
|
13
|
-
Prism::ConstantWriteNode,
|
|
14
|
-
Prism::ConstantPathNode,
|
|
15
|
-
Prism::GlobalVariableAndWriteNode,
|
|
16
|
-
Prism::GlobalVariableOperatorWriteNode,
|
|
17
|
-
Prism::GlobalVariableOrWriteNode,
|
|
18
|
-
Prism::GlobalVariableReadNode,
|
|
19
|
-
Prism::GlobalVariableTargetNode,
|
|
20
|
-
Prism::GlobalVariableWriteNode,
|
|
21
|
-
Prism::InstanceVariableReadNode,
|
|
22
|
-
Prism::InstanceVariableAndWriteNode,
|
|
23
|
-
Prism::InstanceVariableOperatorWriteNode,
|
|
24
|
-
Prism::InstanceVariableOrWriteNode,
|
|
25
|
-
Prism::InstanceVariableTargetNode,
|
|
26
|
-
Prism::InstanceVariableWriteNode,
|
|
27
|
-
Prism::SymbolNode,
|
|
28
|
-
Prism::StringNode,
|
|
29
|
-
Prism::InterpolatedStringNode,
|
|
30
|
-
Prism::SuperNode,
|
|
31
|
-
Prism::ForwardingSuperNode,
|
|
32
|
-
Prism::YieldNode,
|
|
33
|
-
Prism::ClassVariableAndWriteNode,
|
|
34
|
-
Prism::ClassVariableOperatorWriteNode,
|
|
35
|
-
Prism::ClassVariableOrWriteNode,
|
|
36
|
-
Prism::ClassVariableReadNode,
|
|
37
|
-
Prism::ClassVariableTargetNode,
|
|
38
|
-
Prism::ClassVariableWriteNode,
|
|
39
|
-
] #: Array[singleton(Prism::Node)]
|
|
40
|
-
|
|
41
9
|
ALLOWED_REMOTE_PROVIDERS = [
|
|
42
10
|
"https://github.com",
|
|
43
11
|
"https://gitlab.com",
|
|
44
12
|
].freeze #: Array[String]
|
|
45
13
|
|
|
46
|
-
#: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
|
|
47
|
-
def initialize(response_builder, global_state, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
|
|
14
|
+
#: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level, Hash[Symbol, untyped] position) -> void
|
|
15
|
+
def initialize(response_builder, global_state, uri, node_context, dispatcher, sorbet_level, position) # rubocop:disable Metrics/ParameterLists
|
|
48
16
|
@response_builder = response_builder
|
|
49
17
|
@global_state = global_state
|
|
50
18
|
@index = global_state.index #: RubyIndexer::Index
|
|
19
|
+
@graph = global_state.graph #: Rubydex::Graph
|
|
51
20
|
@type_inferrer = global_state.type_inferrer #: TypeInferrer
|
|
52
21
|
@path = uri.to_standardized_path #: String?
|
|
53
22
|
@node_context = node_context
|
|
54
23
|
@sorbet_level = sorbet_level
|
|
24
|
+
@position = position
|
|
55
25
|
|
|
56
26
|
dispatcher.register(
|
|
57
27
|
self,
|
|
28
|
+
:on_alias_global_variable_node_enter,
|
|
29
|
+
:on_alias_method_node_enter,
|
|
30
|
+
:on_and_node_enter,
|
|
31
|
+
:on_begin_node_enter,
|
|
32
|
+
:on_block_node_enter,
|
|
58
33
|
:on_break_node_enter,
|
|
34
|
+
:on_call_node_enter,
|
|
35
|
+
:on_case_match_node_enter,
|
|
36
|
+
:on_case_node_enter,
|
|
37
|
+
:on_class_node_enter,
|
|
38
|
+
:on_singleton_class_node_enter,
|
|
39
|
+
:on_lambda_node_enter,
|
|
40
|
+
:on_class_variable_and_write_node_enter,
|
|
41
|
+
:on_class_variable_operator_write_node_enter,
|
|
42
|
+
:on_class_variable_or_write_node_enter,
|
|
43
|
+
:on_class_variable_read_node_enter,
|
|
44
|
+
:on_class_variable_target_node_enter,
|
|
45
|
+
:on_class_variable_write_node_enter,
|
|
46
|
+
:on_constant_path_node_enter,
|
|
59
47
|
:on_constant_read_node_enter,
|
|
60
48
|
:on_constant_write_node_enter,
|
|
61
|
-
:
|
|
62
|
-
:
|
|
49
|
+
:on_def_node_enter,
|
|
50
|
+
:on_defined_node_enter,
|
|
51
|
+
:on_else_node_enter,
|
|
52
|
+
:on_ensure_node_enter,
|
|
53
|
+
:on_false_node_enter,
|
|
54
|
+
:on_for_node_enter,
|
|
55
|
+
:on_forwarding_super_node_enter,
|
|
63
56
|
:on_global_variable_and_write_node_enter,
|
|
64
57
|
:on_global_variable_operator_write_node_enter,
|
|
65
58
|
:on_global_variable_or_write_node_enter,
|
|
66
59
|
:on_global_variable_read_node_enter,
|
|
67
60
|
:on_global_variable_target_node_enter,
|
|
68
61
|
:on_global_variable_write_node_enter,
|
|
69
|
-
:
|
|
70
|
-
:
|
|
62
|
+
:on_if_node_enter,
|
|
63
|
+
:on_in_node_enter,
|
|
71
64
|
:on_instance_variable_and_write_node_enter,
|
|
72
65
|
:on_instance_variable_operator_write_node_enter,
|
|
73
66
|
:on_instance_variable_or_write_node_enter,
|
|
67
|
+
:on_instance_variable_read_node_enter,
|
|
74
68
|
:on_instance_variable_target_node_enter,
|
|
75
|
-
:
|
|
76
|
-
:on_forwarding_super_node_enter,
|
|
77
|
-
:on_string_node_enter,
|
|
69
|
+
:on_instance_variable_write_node_enter,
|
|
78
70
|
:on_interpolated_string_node_enter,
|
|
71
|
+
:on_module_node_enter,
|
|
72
|
+
:on_next_node_enter,
|
|
73
|
+
:on_nil_node_enter,
|
|
74
|
+
:on_or_node_enter,
|
|
75
|
+
:on_post_execution_node_enter,
|
|
76
|
+
:on_pre_execution_node_enter,
|
|
77
|
+
:on_redo_node_enter,
|
|
78
|
+
:on_rescue_modifier_node_enter,
|
|
79
|
+
:on_rescue_node_enter,
|
|
80
|
+
:on_retry_node_enter,
|
|
81
|
+
:on_return_node_enter,
|
|
82
|
+
:on_self_node_enter,
|
|
83
|
+
:on_source_encoding_node_enter,
|
|
84
|
+
:on_source_file_node_enter,
|
|
85
|
+
:on_source_line_node_enter,
|
|
86
|
+
:on_string_node_enter,
|
|
87
|
+
:on_super_node_enter,
|
|
88
|
+
:on_true_node_enter,
|
|
89
|
+
:on_undef_node_enter,
|
|
90
|
+
:on_unless_node_enter,
|
|
91
|
+
:on_until_node_enter,
|
|
92
|
+
:on_when_node_enter,
|
|
93
|
+
:on_while_node_enter,
|
|
79
94
|
:on_yield_node_enter,
|
|
80
|
-
:on_class_variable_and_write_node_enter,
|
|
81
|
-
:on_class_variable_operator_write_node_enter,
|
|
82
|
-
:on_class_variable_or_write_node_enter,
|
|
83
|
-
:on_class_variable_read_node_enter,
|
|
84
|
-
:on_class_variable_target_node_enter,
|
|
85
|
-
:on_class_variable_write_node_enter,
|
|
86
95
|
)
|
|
87
96
|
end
|
|
88
97
|
|
|
89
|
-
#: (Prism::BreakNode node) -> void
|
|
90
|
-
def on_break_node_enter(node)
|
|
91
|
-
handle_keyword_documentation(node.keyword)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
98
|
#: (Prism::StringNode node) -> void
|
|
95
99
|
def on_string_node_enter(node)
|
|
96
100
|
if @path && File.basename(@path) == GEMFILE_NAME
|
|
@@ -143,6 +147,12 @@ module RubyLsp
|
|
|
143
147
|
message = node.message
|
|
144
148
|
return unless message
|
|
145
149
|
|
|
150
|
+
# `not x` is parsed as a call to `!` whose message_loc slices to "not"
|
|
151
|
+
if node.name == :! && message == "not"
|
|
152
|
+
handle_keyword_documentation("not")
|
|
153
|
+
return
|
|
154
|
+
end
|
|
155
|
+
|
|
146
156
|
handle_method_hover(message)
|
|
147
157
|
end
|
|
148
158
|
|
|
@@ -178,77 +188,208 @@ module RubyLsp
|
|
|
178
188
|
|
|
179
189
|
#: (Prism::InstanceVariableReadNode node) -> void
|
|
180
190
|
def on_instance_variable_read_node_enter(node)
|
|
181
|
-
|
|
191
|
+
handle_variable_hover(node.name.to_s)
|
|
182
192
|
end
|
|
183
193
|
|
|
184
194
|
#: (Prism::InstanceVariableWriteNode node) -> void
|
|
185
195
|
def on_instance_variable_write_node_enter(node)
|
|
186
|
-
|
|
196
|
+
handle_variable_hover(node.name.to_s)
|
|
187
197
|
end
|
|
188
198
|
|
|
189
199
|
#: (Prism::InstanceVariableAndWriteNode node) -> void
|
|
190
200
|
def on_instance_variable_and_write_node_enter(node)
|
|
191
|
-
|
|
201
|
+
handle_variable_hover(node.name.to_s)
|
|
192
202
|
end
|
|
193
203
|
|
|
194
204
|
#: (Prism::InstanceVariableOperatorWriteNode node) -> void
|
|
195
205
|
def on_instance_variable_operator_write_node_enter(node)
|
|
196
|
-
|
|
206
|
+
handle_variable_hover(node.name.to_s)
|
|
197
207
|
end
|
|
198
208
|
|
|
199
209
|
#: (Prism::InstanceVariableOrWriteNode node) -> void
|
|
200
210
|
def on_instance_variable_or_write_node_enter(node)
|
|
201
|
-
|
|
211
|
+
handle_variable_hover(node.name.to_s)
|
|
202
212
|
end
|
|
203
213
|
|
|
204
214
|
#: (Prism::InstanceVariableTargetNode node) -> void
|
|
205
215
|
def on_instance_variable_target_node_enter(node)
|
|
206
|
-
|
|
216
|
+
handle_variable_hover(node.name.to_s)
|
|
207
217
|
end
|
|
208
218
|
|
|
209
219
|
#: (Prism::SuperNode node) -> void
|
|
210
220
|
def on_super_node_enter(node)
|
|
211
|
-
handle_super_node_hover
|
|
221
|
+
handle_super_node_hover(node.keyword_loc)
|
|
212
222
|
end
|
|
213
223
|
|
|
214
224
|
#: (Prism::ForwardingSuperNode node) -> void
|
|
215
225
|
def on_forwarding_super_node_enter(node)
|
|
216
|
-
handle_super_node_hover
|
|
226
|
+
handle_super_node_hover(node.location)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
#: (Prism::AliasGlobalVariableNode) -> void
|
|
230
|
+
def on_alias_global_variable_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
231
|
+
|
|
232
|
+
#: (Prism::AliasMethodNode) -> void
|
|
233
|
+
def on_alias_method_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
234
|
+
|
|
235
|
+
#: (Prism::AndNode) -> void
|
|
236
|
+
def on_and_node_enter(node) = handle_keyword_at_location(node.operator_loc)
|
|
237
|
+
|
|
238
|
+
#: (Prism::BeginNode) -> void
|
|
239
|
+
def on_begin_node_enter(node) = handle_keyword_at_location(node.begin_keyword_loc, node.end_keyword_loc)
|
|
240
|
+
|
|
241
|
+
#: (Prism::BlockNode) -> void
|
|
242
|
+
def on_block_node_enter(node) = handle_keyword_at_location(node.opening_loc, node.closing_loc)
|
|
243
|
+
|
|
244
|
+
#: (Prism::BreakNode) -> void
|
|
245
|
+
def on_break_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
246
|
+
|
|
247
|
+
#: (Prism::CaseMatchNode) -> void
|
|
248
|
+
def on_case_match_node_enter(node) = handle_keyword_at_location(node.case_keyword_loc, node.end_keyword_loc)
|
|
249
|
+
|
|
250
|
+
#: (Prism::CaseNode) -> void
|
|
251
|
+
def on_case_node_enter(node) = handle_keyword_at_location(node.case_keyword_loc, node.end_keyword_loc)
|
|
252
|
+
|
|
253
|
+
#: (Prism::ClassNode) -> void
|
|
254
|
+
def on_class_node_enter(node) = handle_keyword_at_location(node.class_keyword_loc, node.end_keyword_loc)
|
|
255
|
+
|
|
256
|
+
#: (Prism::SingletonClassNode) -> void
|
|
257
|
+
def on_singleton_class_node_enter(node)
|
|
258
|
+
handle_keyword_at_location(node.class_keyword_loc, node.end_keyword_loc)
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
#: (Prism::LambdaNode) -> void
|
|
262
|
+
def on_lambda_node_enter(node) = handle_keyword_at_location(node.opening_loc, node.closing_loc)
|
|
263
|
+
|
|
264
|
+
#: (Prism::DefNode) -> void
|
|
265
|
+
def on_def_node_enter(node) = handle_keyword_at_location(node.def_keyword_loc, node.end_keyword_loc)
|
|
266
|
+
|
|
267
|
+
#: (Prism::DefinedNode) -> void
|
|
268
|
+
def on_defined_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
269
|
+
|
|
270
|
+
#: (Prism::ElseNode) -> void
|
|
271
|
+
def on_else_node_enter(node) = handle_keyword_at_location(node.else_keyword_loc, node.end_keyword_loc)
|
|
272
|
+
|
|
273
|
+
#: (Prism::EnsureNode) -> void
|
|
274
|
+
def on_ensure_node_enter(node) = handle_keyword_at_location(node.ensure_keyword_loc, node.end_keyword_loc)
|
|
275
|
+
|
|
276
|
+
#: (Prism::FalseNode) -> void
|
|
277
|
+
def on_false_node_enter(node) = handle_keyword_at_location(node.location)
|
|
278
|
+
|
|
279
|
+
#: (Prism::ForNode) -> void
|
|
280
|
+
def on_for_node_enter(node)
|
|
281
|
+
handle_keyword_at_location(
|
|
282
|
+
node.for_keyword_loc,
|
|
283
|
+
node.in_keyword_loc,
|
|
284
|
+
node.do_keyword_loc,
|
|
285
|
+
node.end_keyword_loc,
|
|
286
|
+
)
|
|
217
287
|
end
|
|
218
288
|
|
|
219
|
-
#: (Prism::
|
|
220
|
-
def
|
|
221
|
-
|
|
289
|
+
#: (Prism::IfNode) -> void
|
|
290
|
+
def on_if_node_enter(node)
|
|
291
|
+
handle_keyword_at_location(node.if_keyword_loc, node.then_keyword_loc, node.end_keyword_loc)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
#: (Prism::InNode) -> void
|
|
295
|
+
def on_in_node_enter(node) = handle_keyword_at_location(node.in_loc, node.then_loc)
|
|
296
|
+
|
|
297
|
+
#: (Prism::ModuleNode) -> void
|
|
298
|
+
def on_module_node_enter(node) = handle_keyword_at_location(node.module_keyword_loc, node.end_keyword_loc)
|
|
299
|
+
|
|
300
|
+
#: (Prism::NextNode) -> void
|
|
301
|
+
def on_next_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
302
|
+
|
|
303
|
+
#: (Prism::NilNode) -> void
|
|
304
|
+
def on_nil_node_enter(node) = handle_keyword_at_location(node.location)
|
|
305
|
+
|
|
306
|
+
#: (Prism::OrNode) -> void
|
|
307
|
+
def on_or_node_enter(node) = handle_keyword_at_location(node.operator_loc)
|
|
308
|
+
|
|
309
|
+
#: (Prism::PostExecutionNode) -> void
|
|
310
|
+
def on_post_execution_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
311
|
+
|
|
312
|
+
#: (Prism::PreExecutionNode) -> void
|
|
313
|
+
def on_pre_execution_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
314
|
+
|
|
315
|
+
#: (Prism::RedoNode) -> void
|
|
316
|
+
def on_redo_node_enter(node) = handle_keyword_at_location(node.location)
|
|
317
|
+
|
|
318
|
+
#: (Prism::RescueModifierNode) -> void
|
|
319
|
+
def on_rescue_modifier_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
320
|
+
|
|
321
|
+
#: (Prism::RescueNode) -> void
|
|
322
|
+
def on_rescue_node_enter(node) = handle_keyword_at_location(node.keyword_loc, node.then_keyword_loc)
|
|
323
|
+
|
|
324
|
+
#: (Prism::RetryNode) -> void
|
|
325
|
+
def on_retry_node_enter(node) = handle_keyword_at_location(node.location)
|
|
326
|
+
|
|
327
|
+
#: (Prism::ReturnNode) -> void
|
|
328
|
+
def on_return_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
329
|
+
|
|
330
|
+
#: (Prism::SelfNode) -> void
|
|
331
|
+
def on_self_node_enter(node) = handle_keyword_at_location(node.location)
|
|
332
|
+
|
|
333
|
+
#: (Prism::SourceEncodingNode) -> void
|
|
334
|
+
def on_source_encoding_node_enter(node) = handle_keyword_at_location(node.location)
|
|
335
|
+
|
|
336
|
+
#: (Prism::SourceFileNode) -> void
|
|
337
|
+
def on_source_file_node_enter(node) = handle_keyword_at_location(node.location)
|
|
338
|
+
|
|
339
|
+
#: (Prism::SourceLineNode) -> void
|
|
340
|
+
def on_source_line_node_enter(node) = handle_keyword_at_location(node.location)
|
|
341
|
+
|
|
342
|
+
#: (Prism::TrueNode) -> void
|
|
343
|
+
def on_true_node_enter(node) = handle_keyword_at_location(node.location)
|
|
344
|
+
|
|
345
|
+
#: (Prism::UndefNode) -> void
|
|
346
|
+
def on_undef_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
347
|
+
|
|
348
|
+
#: (Prism::UnlessNode) -> void
|
|
349
|
+
def on_unless_node_enter(node)
|
|
350
|
+
handle_keyword_at_location(node.keyword_loc, node.then_keyword_loc, node.end_keyword_loc)
|
|
222
351
|
end
|
|
223
352
|
|
|
353
|
+
#: (Prism::UntilNode) -> void
|
|
354
|
+
def on_until_node_enter(node) = handle_keyword_at_location(node.keyword_loc, node.do_keyword_loc, node.closing_loc)
|
|
355
|
+
|
|
356
|
+
#: (Prism::WhenNode) -> void
|
|
357
|
+
def on_when_node_enter(node) = handle_keyword_at_location(node.keyword_loc, node.then_keyword_loc)
|
|
358
|
+
|
|
359
|
+
#: (Prism::WhileNode) -> void
|
|
360
|
+
def on_while_node_enter(node) = handle_keyword_at_location(node.keyword_loc, node.do_keyword_loc, node.closing_loc)
|
|
361
|
+
|
|
362
|
+
#: (Prism::YieldNode) -> void
|
|
363
|
+
def on_yield_node_enter(node) = handle_keyword_at_location(node.keyword_loc)
|
|
364
|
+
|
|
224
365
|
#: (Prism::ClassVariableAndWriteNode node) -> void
|
|
225
366
|
def on_class_variable_and_write_node_enter(node)
|
|
226
|
-
|
|
367
|
+
handle_variable_hover(node.name.to_s)
|
|
227
368
|
end
|
|
228
369
|
|
|
229
370
|
#: (Prism::ClassVariableOperatorWriteNode node) -> void
|
|
230
371
|
def on_class_variable_operator_write_node_enter(node)
|
|
231
|
-
|
|
372
|
+
handle_variable_hover(node.name.to_s)
|
|
232
373
|
end
|
|
233
374
|
|
|
234
375
|
#: (Prism::ClassVariableOrWriteNode node) -> void
|
|
235
376
|
def on_class_variable_or_write_node_enter(node)
|
|
236
|
-
|
|
377
|
+
handle_variable_hover(node.name.to_s)
|
|
237
378
|
end
|
|
238
379
|
|
|
239
380
|
#: (Prism::ClassVariableTargetNode node) -> void
|
|
240
381
|
def on_class_variable_target_node_enter(node)
|
|
241
|
-
|
|
382
|
+
handle_variable_hover(node.name.to_s)
|
|
242
383
|
end
|
|
243
384
|
|
|
244
385
|
#: (Prism::ClassVariableReadNode node) -> void
|
|
245
386
|
def on_class_variable_read_node_enter(node)
|
|
246
|
-
|
|
387
|
+
handle_variable_hover(node.name.to_s)
|
|
247
388
|
end
|
|
248
389
|
|
|
249
390
|
#: (Prism::ClassVariableWriteNode node) -> void
|
|
250
391
|
def on_class_variable_write_node_enter(node)
|
|
251
|
-
|
|
392
|
+
handle_variable_hover(node.name.to_s)
|
|
252
393
|
end
|
|
253
394
|
|
|
254
395
|
private
|
|
@@ -278,27 +419,37 @@ module RubyLsp
|
|
|
278
419
|
end
|
|
279
420
|
end
|
|
280
421
|
|
|
281
|
-
#: (String
|
|
282
|
-
def handle_keyword_documentation(
|
|
283
|
-
|
|
284
|
-
return unless
|
|
422
|
+
#: (String) -> void
|
|
423
|
+
def handle_keyword_documentation(name)
|
|
424
|
+
keyword = @graph.keyword(name)
|
|
425
|
+
return unless keyword
|
|
285
426
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
@response_builder.push("```ruby\n#{keyword}\n```", category: :title)
|
|
289
|
-
@response_builder.push("[Read more](#{doc_uri})", category: :links)
|
|
290
|
-
@response_builder.push(content, category: :documentation)
|
|
427
|
+
@response_builder.push("```ruby\n#{keyword.name}\n```", category: :title)
|
|
428
|
+
@response_builder.push(keyword.documentation, category: :documentation)
|
|
291
429
|
end
|
|
292
430
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
431
|
+
# Push keyword documentation when the cursor is on one of the provided locations. The keyword name is taken from
|
|
432
|
+
# the covering location's slice so that operator forms (`&&`, `||`, `{`, `}`, ternary `? :`) yield no hover —
|
|
433
|
+
# their slice is not a keyword in the Rubydex graph.
|
|
434
|
+
#
|
|
435
|
+
#: (*Prism::Location?) -> void
|
|
436
|
+
def handle_keyword_at_location(*locations)
|
|
437
|
+
loc = locations.find { |l| l && covers_position?(l, @position) }
|
|
438
|
+
return unless loc
|
|
439
|
+
|
|
440
|
+
handle_keyword_documentation(loc.slice)
|
|
441
|
+
end
|
|
297
442
|
|
|
298
|
-
|
|
299
|
-
|
|
443
|
+
#: (Prism::Location keyword_location) -> void
|
|
444
|
+
def handle_super_node_hover(keyword_location)
|
|
445
|
+
# Sorbet can handle the inherited-method hover on typed true or higher, but it does not surface keyword docs, so
|
|
446
|
+
# we still push those
|
|
447
|
+
unless @sorbet_level.true_or_higher?
|
|
448
|
+
surrounding_method = @node_context.surrounding_method
|
|
449
|
+
handle_method_hover(surrounding_method.name, inherited_only: true) if surrounding_method
|
|
450
|
+
end
|
|
300
451
|
|
|
301
|
-
|
|
452
|
+
handle_keyword_at_location(keyword_location)
|
|
302
453
|
end
|
|
303
454
|
|
|
304
455
|
#: (String message, ?inherited_only: bool) -> void
|
|
@@ -324,62 +475,46 @@ module RubyLsp
|
|
|
324
475
|
end
|
|
325
476
|
end
|
|
326
477
|
|
|
327
|
-
#: (String name) -> void
|
|
328
|
-
def handle_instance_variable_hover(name)
|
|
329
|
-
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
|
330
|
-
# to provide all features for them
|
|
331
|
-
return if @sorbet_level.strict?
|
|
332
|
-
|
|
333
|
-
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
334
|
-
return unless type
|
|
335
|
-
|
|
336
|
-
entries = @index.resolve_instance_variable(name, type.name)
|
|
337
|
-
return unless entries
|
|
338
|
-
|
|
339
|
-
categorized_markdown_from_index_entries(name, entries).each do |category, content|
|
|
340
|
-
@response_builder.push(content, category: category)
|
|
341
|
-
end
|
|
342
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
343
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
344
|
-
end
|
|
345
|
-
|
|
346
478
|
#: (String name) -> void
|
|
347
479
|
def handle_global_variable_hover(name)
|
|
348
|
-
|
|
349
|
-
return unless
|
|
480
|
+
declaration = @graph[name]
|
|
481
|
+
return unless declaration
|
|
350
482
|
|
|
351
|
-
|
|
483
|
+
categorized_markdown_from_definitions(name, declaration.definitions).each do |category, content|
|
|
352
484
|
@response_builder.push(content, category: category)
|
|
353
485
|
end
|
|
354
486
|
end
|
|
355
487
|
|
|
488
|
+
# Handle class or instance variables. We collect all definitions across the ancestors of the type
|
|
489
|
+
#
|
|
356
490
|
#: (String name) -> void
|
|
357
|
-
def
|
|
491
|
+
def handle_variable_hover(name)
|
|
492
|
+
# Sorbet enforces that all variables be declared on typed strict or higher, which means it will be able to
|
|
493
|
+
# provide all features for them
|
|
494
|
+
return if @sorbet_level.strict?
|
|
495
|
+
|
|
358
496
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
359
497
|
return unless type
|
|
360
498
|
|
|
361
|
-
|
|
362
|
-
return unless
|
|
499
|
+
owner = @graph[type.name]
|
|
500
|
+
return unless owner.is_a?(Rubydex::Namespace)
|
|
363
501
|
|
|
364
|
-
|
|
365
|
-
|
|
502
|
+
owner.ancestors.each do |ancestor|
|
|
503
|
+
member = ancestor.member(name)
|
|
504
|
+
next unless member
|
|
505
|
+
|
|
506
|
+
categorized_markdown_from_definitions(member.name, member.definitions).each do |category, content|
|
|
507
|
+
@response_builder.push(content, category: category)
|
|
508
|
+
end
|
|
366
509
|
end
|
|
367
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
368
|
-
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
|
369
510
|
end
|
|
370
511
|
|
|
371
512
|
#: (String name, Prism::Location location) -> void
|
|
372
513
|
def generate_hover(name, location)
|
|
373
|
-
|
|
374
|
-
return unless
|
|
375
|
-
|
|
376
|
-
# We should only show hover for private constants if the constant is defined in the same namespace as the
|
|
377
|
-
# reference
|
|
378
|
-
first_entry = entries.first #: as !nil
|
|
379
|
-
full_name = first_entry.name
|
|
380
|
-
return if first_entry.private? && full_name != "#{@node_context.fully_qualified_name}::#{name}"
|
|
514
|
+
declaration = @graph.resolve_constant(name, @node_context.nesting)
|
|
515
|
+
return unless declaration
|
|
381
516
|
|
|
382
|
-
|
|
517
|
+
categorized_markdown_from_definitions(declaration.name, declaration.definitions).each do |category, content|
|
|
383
518
|
@response_builder.push(content, category: category)
|
|
384
519
|
end
|
|
385
520
|
end
|
|
@@ -34,7 +34,7 @@ module RubyLsp
|
|
|
34
34
|
#: (Prism::ClassNode) -> void
|
|
35
35
|
def on_class_node_enter(node) # rubocop:disable RubyLsp/UseRegisterWithHandlerMethod
|
|
36
36
|
with_test_ancestor_tracking(node) do |name, ancestors|
|
|
37
|
-
@spec_group_id_stack << (
|
|
37
|
+
@spec_group_id_stack << (spec_group?(ancestors, name) ? ClassGroup.new(name) : nil)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
40
40
|
|
|
@@ -81,6 +81,11 @@ module RubyLsp
|
|
|
81
81
|
|
|
82
82
|
private
|
|
83
83
|
|
|
84
|
+
#: (Array[String], String) -> bool
|
|
85
|
+
def spec_group?(ancestors, fully_qualified_name)
|
|
86
|
+
fully_qualified_name != "Minitest::Spec" && ancestors.include?("Minitest::Spec")
|
|
87
|
+
end
|
|
88
|
+
|
|
84
89
|
#: (Prism::CallNode) -> void
|
|
85
90
|
def handle_describe(node)
|
|
86
91
|
# Describes will include the nesting of all classes and all outer describes as part of its ID, unlike classes
|
|
@@ -13,7 +13,7 @@ module RubyLsp
|
|
|
13
13
|
def initialize(response_builder, global_state, uri)
|
|
14
14
|
@response_builder = response_builder
|
|
15
15
|
@uri = uri
|
|
16
|
-
@
|
|
16
|
+
@graph = global_state.graph #: Rubydex::Graph
|
|
17
17
|
@visibility_stack = [:public] #: Array[Symbol]
|
|
18
18
|
@nesting = [] #: Array[String]
|
|
19
19
|
end
|
|
@@ -64,22 +64,29 @@ module RubyLsp
|
|
|
64
64
|
superclass = node.superclass
|
|
65
65
|
|
|
66
66
|
begin
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
67
|
+
declaration = @graph[fully_qualified_name]
|
|
68
|
+
|
|
69
|
+
unless declaration.is_a?(Rubydex::Namespace)
|
|
70
|
+
# When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
|
|
71
|
+
# provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
|
|
72
|
+
return [superclass&.slice].compact
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
ancestors = declaration.ancestors.map(&:name)
|
|
76
|
+
superclass_ref = declaration.definitions
|
|
77
|
+
.filter_map { |d| d.superclass if d.is_a?(Rubydex::ClassDefinition) }
|
|
78
|
+
.find { |ref| !ref.is_a?(Rubydex::ResolvedConstantReference) || ref.declaration.name != "Object" }
|
|
79
|
+
|
|
80
|
+
# If we couldn't resolve the parent class, then artificially inject it into the ancestors
|
|
81
|
+
if superclass_ref.is_a?(Rubydex::UnresolvedConstantReference) && superclass
|
|
82
|
+
insert_index = ancestors.index(fully_qualified_name) #: as !nil
|
|
83
|
+
insert_index += 1
|
|
84
|
+
ancestors.insert(insert_index, superclass.slice)
|
|
85
|
+
return ancestors
|
|
76
86
|
end
|
|
77
87
|
|
|
88
|
+
# If the parent class is properly resolved or if there isn't one, then just use the ancestors
|
|
78
89
|
ancestors
|
|
79
|
-
rescue RubyIndexer::Index::NonExistingNamespaceError
|
|
80
|
-
# When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
|
|
81
|
-
# provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
|
|
82
|
-
[superclass&.slice].compact
|
|
83
90
|
end
|
|
84
91
|
end
|
|
85
92
|
|
|
@@ -174,9 +174,10 @@ module RubyLsp
|
|
|
174
174
|
#: (Prism::ClassNode node) -> void
|
|
175
175
|
def on_class_node_enter(node) # rubocop:disable RubyLsp/UseRegisterWithHandlerMethod
|
|
176
176
|
with_test_ancestor_tracking(node) do |name, ancestors|
|
|
177
|
-
|
|
177
|
+
is_test_unit = test_unit_group?(ancestors, name)
|
|
178
|
+
@framework = :test_unit if is_test_unit
|
|
178
179
|
|
|
179
|
-
if
|
|
180
|
+
if is_test_unit || non_declarative_minitest?(ancestors, name)
|
|
180
181
|
test_item = Requests::Support::TestItem.new(
|
|
181
182
|
name,
|
|
182
183
|
name,
|
|
@@ -259,17 +260,28 @@ module RubyLsp
|
|
|
259
260
|
@parent_stack[index] #: as Requests::Support::TestItem | ResponseBuilders::TestCollection
|
|
260
261
|
end
|
|
261
262
|
|
|
262
|
-
#: (Array[String]
|
|
263
|
+
#: (Array[String], String) -> bool
|
|
264
|
+
def test_unit_group?(ancestors, fully_qualified_name)
|
|
265
|
+
fully_qualified_name != "Test::Unit::TestCase" && ancestors.include?("Test::Unit::TestCase")
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
#: (Array[String], String) -> bool
|
|
263
269
|
def non_declarative_minitest?(attached_ancestors, fully_qualified_name)
|
|
270
|
+
return false if ["Minitest::Spec", "Minitest::Test", "ActiveSupport::TestCase"].include?(fully_qualified_name)
|
|
264
271
|
return false unless attached_ancestors.include?("Minitest::Test")
|
|
265
272
|
|
|
266
273
|
# We only support regular Minitest tests. The declarative syntax provided by ActiveSupport is handled by the
|
|
267
274
|
# Rails add-on
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
true
|
|
275
|
+
|
|
276
|
+
declaration = @graph[fully_qualified_name]
|
|
277
|
+
# If we don't find the fully qualified name in the graph, it means there's a dynamic portion in the test class
|
|
278
|
+
# definition. In that case, if the ancestors did include `Minitest::Test`, we always assume it's a test
|
|
279
|
+
return true unless declaration.is_a?(Rubydex::Namespace)
|
|
280
|
+
|
|
281
|
+
singleton = declaration.singleton_class
|
|
282
|
+
return !singleton.ancestors.map(&:name).include?("ActiveSupport::Testing::Declarative") if singleton
|
|
283
|
+
|
|
284
|
+
!attached_ancestors.include?("ActiveSupport::TestCase")
|
|
273
285
|
end
|
|
274
286
|
end
|
|
275
287
|
end
|