ruby-lsp 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +10 -9
- data/exe/ruby-lsp-check +5 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +131 -23
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +72 -43
- data/lib/ruby_indexer/test/method_test.rb +80 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +15 -6
- data/lib/ruby_lsp/document.rb +10 -1
- data/lib/ruby_lsp/global_state.rb +1 -1
- data/lib/ruby_lsp/internal.rb +1 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
- data/lib/ruby_lsp/listeners/completion.rb +73 -4
- data/lib/ruby_lsp/listeners/definition.rb +73 -17
- data/lib/ruby_lsp/listeners/document_symbol.rb +49 -5
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +57 -0
- data/lib/ruby_lsp/requests/completion.rb +6 -0
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +6 -0
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/rename.rb +14 -4
- data/lib/ruby_lsp/requests/support/common.rb +1 -5
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +42 -7
- data/lib/ruby_lsp/setup_bundler.rb +54 -46
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +22 -0
- data/lib/ruby_lsp/utils.rb +3 -0
- metadata +7 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -97,6 +97,12 @@ module RubyLsp
|
|
97
97
|
:on_instance_variable_operator_write_node_enter,
|
98
98
|
:on_instance_variable_or_write_node_enter,
|
99
99
|
:on_instance_variable_target_node_enter,
|
100
|
+
:on_class_variable_and_write_node_enter,
|
101
|
+
:on_class_variable_operator_write_node_enter,
|
102
|
+
:on_class_variable_or_write_node_enter,
|
103
|
+
:on_class_variable_read_node_enter,
|
104
|
+
:on_class_variable_target_node_enter,
|
105
|
+
:on_class_variable_write_node_enter,
|
100
106
|
)
|
101
107
|
end
|
102
108
|
|
@@ -110,13 +116,14 @@ module RubyLsp
|
|
110
116
|
name = constant_name(node)
|
111
117
|
return if name.nil?
|
112
118
|
|
119
|
+
range = range_from_location(node.location)
|
113
120
|
candidates = @index.constant_completion_candidates(name, @node_context.nesting)
|
114
121
|
candidates.each do |entries|
|
115
122
|
complete_name = T.must(entries.first).name
|
116
123
|
@response_builder << build_entry_completion(
|
117
124
|
complete_name,
|
118
125
|
name,
|
119
|
-
|
126
|
+
range,
|
120
127
|
entries,
|
121
128
|
top_level?(complete_name),
|
122
129
|
)
|
@@ -246,6 +253,36 @@ module RubyLsp
|
|
246
253
|
handle_instance_variable_completion(node.name.to_s, node.location)
|
247
254
|
end
|
248
255
|
|
256
|
+
sig { params(node: Prism::ClassVariableAndWriteNode).void }
|
257
|
+
def on_class_variable_and_write_node_enter(node)
|
258
|
+
handle_class_variable_completion(node.name.to_s, node.name_loc)
|
259
|
+
end
|
260
|
+
|
261
|
+
sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
|
262
|
+
def on_class_variable_operator_write_node_enter(node)
|
263
|
+
handle_class_variable_completion(node.name.to_s, node.name_loc)
|
264
|
+
end
|
265
|
+
|
266
|
+
sig { params(node: Prism::ClassVariableOrWriteNode).void }
|
267
|
+
def on_class_variable_or_write_node_enter(node)
|
268
|
+
handle_class_variable_completion(node.name.to_s, node.name_loc)
|
269
|
+
end
|
270
|
+
|
271
|
+
sig { params(node: Prism::ClassVariableTargetNode).void }
|
272
|
+
def on_class_variable_target_node_enter(node)
|
273
|
+
handle_class_variable_completion(node.name.to_s, node.location)
|
274
|
+
end
|
275
|
+
|
276
|
+
sig { params(node: Prism::ClassVariableReadNode).void }
|
277
|
+
def on_class_variable_read_node_enter(node)
|
278
|
+
handle_class_variable_completion(node.name.to_s, node.location)
|
279
|
+
end
|
280
|
+
|
281
|
+
sig { params(node: Prism::ClassVariableWriteNode).void }
|
282
|
+
def on_class_variable_write_node_enter(node)
|
283
|
+
handle_class_variable_completion(node.name.to_s, node.name_loc)
|
284
|
+
end
|
285
|
+
|
249
286
|
private
|
250
287
|
|
251
288
|
sig { params(name: String, range: Interface::Range).void }
|
@@ -326,6 +363,37 @@ module RubyLsp
|
|
326
363
|
end
|
327
364
|
end
|
328
365
|
|
366
|
+
sig { params(name: String, location: Prism::Location).void }
|
367
|
+
def handle_class_variable_completion(name, location)
|
368
|
+
type = @type_inferrer.infer_receiver_type(@node_context)
|
369
|
+
return unless type
|
370
|
+
|
371
|
+
range = range_from_location(location)
|
372
|
+
|
373
|
+
@index.class_variable_completion_candidates(name, type.name).each do |entry|
|
374
|
+
variable_name = entry.name
|
375
|
+
|
376
|
+
label_details = Interface::CompletionItemLabelDetails.new(
|
377
|
+
description: entry.file_name,
|
378
|
+
)
|
379
|
+
|
380
|
+
@response_builder << Interface::CompletionItem.new(
|
381
|
+
label: variable_name,
|
382
|
+
label_details: label_details,
|
383
|
+
text_edit: Interface::TextEdit.new(
|
384
|
+
range: range,
|
385
|
+
new_text: variable_name,
|
386
|
+
),
|
387
|
+
kind: Constant::CompletionItemKind::FIELD,
|
388
|
+
data: {
|
389
|
+
owner_name: entry.owner&.name,
|
390
|
+
},
|
391
|
+
)
|
392
|
+
end
|
393
|
+
rescue RubyIndexer::Index::NonExistingNamespaceError
|
394
|
+
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
395
|
+
end
|
396
|
+
|
329
397
|
sig { params(name: String, location: Prism::Location).void }
|
330
398
|
def handle_instance_variable_completion(name, location)
|
331
399
|
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
@@ -335,6 +403,7 @@ module RubyLsp
|
|
335
403
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
336
404
|
return unless type
|
337
405
|
|
406
|
+
range = range_from_location(location)
|
338
407
|
@index.instance_variable_completion_candidates(name, type.name).each do |entry|
|
339
408
|
variable_name = entry.name
|
340
409
|
|
@@ -346,7 +415,7 @@ module RubyLsp
|
|
346
415
|
label: variable_name,
|
347
416
|
label_details: label_details,
|
348
417
|
text_edit: Interface::TextEdit.new(
|
349
|
-
range:
|
418
|
+
range: range,
|
350
419
|
new_text: variable_name,
|
351
420
|
),
|
352
421
|
kind: Constant::CompletionItemKind::FIELD,
|
@@ -368,9 +437,9 @@ module RubyLsp
|
|
368
437
|
|
369
438
|
return unless path_node_to_complete.is_a?(Prism::StringNode)
|
370
439
|
|
371
|
-
|
440
|
+
matched_uris = @index.search_require_paths(path_node_to_complete.content)
|
372
441
|
|
373
|
-
|
442
|
+
matched_uris.map!(&:require_path).sort!.each do |path|
|
374
443
|
@response_builder << build_completion(T.must(path), path_node_to_complete)
|
375
444
|
end
|
376
445
|
end
|
@@ -55,6 +55,12 @@ module RubyLsp
|
|
55
55
|
:on_symbol_node_enter,
|
56
56
|
:on_super_node_enter,
|
57
57
|
:on_forwarding_super_node_enter,
|
58
|
+
:on_class_variable_and_write_node_enter,
|
59
|
+
:on_class_variable_operator_write_node_enter,
|
60
|
+
:on_class_variable_or_write_node_enter,
|
61
|
+
:on_class_variable_read_node_enter,
|
62
|
+
:on_class_variable_target_node_enter,
|
63
|
+
:on_class_variable_write_node_enter,
|
58
64
|
)
|
59
65
|
end
|
60
66
|
|
@@ -196,6 +202,36 @@ module RubyLsp
|
|
196
202
|
handle_super_node_definition
|
197
203
|
end
|
198
204
|
|
205
|
+
sig { params(node: Prism::ClassVariableAndWriteNode).void }
|
206
|
+
def on_class_variable_and_write_node_enter(node)
|
207
|
+
handle_class_variable_definition(node.name.to_s)
|
208
|
+
end
|
209
|
+
|
210
|
+
sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
|
211
|
+
def on_class_variable_operator_write_node_enter(node)
|
212
|
+
handle_class_variable_definition(node.name.to_s)
|
213
|
+
end
|
214
|
+
|
215
|
+
sig { params(node: Prism::ClassVariableOrWriteNode).void }
|
216
|
+
def on_class_variable_or_write_node_enter(node)
|
217
|
+
handle_class_variable_definition(node.name.to_s)
|
218
|
+
end
|
219
|
+
|
220
|
+
sig { params(node: Prism::ClassVariableTargetNode).void }
|
221
|
+
def on_class_variable_target_node_enter(node)
|
222
|
+
handle_class_variable_definition(node.name.to_s)
|
223
|
+
end
|
224
|
+
|
225
|
+
sig { params(node: Prism::ClassVariableReadNode).void }
|
226
|
+
def on_class_variable_read_node_enter(node)
|
227
|
+
handle_class_variable_definition(node.name.to_s)
|
228
|
+
end
|
229
|
+
|
230
|
+
sig { params(node: Prism::ClassVariableWriteNode).void }
|
231
|
+
def on_class_variable_write_node_enter(node)
|
232
|
+
handle_class_variable_definition(node.name.to_s)
|
233
|
+
end
|
234
|
+
|
199
235
|
private
|
200
236
|
|
201
237
|
sig { void }
|
@@ -223,7 +259,7 @@ module RubyLsp
|
|
223
259
|
location = entry.location
|
224
260
|
|
225
261
|
@response_builder << Interface::Location.new(
|
226
|
-
uri:
|
262
|
+
uri: entry.uri.to_s,
|
227
263
|
range: Interface::Range.new(
|
228
264
|
start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
|
229
265
|
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
|
@@ -232,6 +268,24 @@ module RubyLsp
|
|
232
268
|
end
|
233
269
|
end
|
234
270
|
|
271
|
+
sig { params(name: String).void }
|
272
|
+
def handle_class_variable_definition(name)
|
273
|
+
type = @type_inferrer.infer_receiver_type(@node_context)
|
274
|
+
return unless type
|
275
|
+
|
276
|
+
entries = @index.resolve_class_variable(name, type.name)
|
277
|
+
return unless entries
|
278
|
+
|
279
|
+
entries.each do |entry|
|
280
|
+
@response_builder << Interface::Location.new(
|
281
|
+
uri: entry.uri.to_s,
|
282
|
+
range: range_from_location(entry.location),
|
283
|
+
)
|
284
|
+
end
|
285
|
+
rescue RubyIndexer::Index::NonExistingNamespaceError
|
286
|
+
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
287
|
+
end
|
288
|
+
|
235
289
|
sig { params(name: String).void }
|
236
290
|
def handle_instance_variable_definition(name)
|
237
291
|
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
@@ -248,7 +302,7 @@ module RubyLsp
|
|
248
302
|
location = entry.location
|
249
303
|
|
250
304
|
@response_builder << Interface::Location.new(
|
251
|
-
uri:
|
305
|
+
uri: entry.uri.to_s,
|
252
306
|
range: Interface::Range.new(
|
253
307
|
start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
|
254
308
|
end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
|
@@ -275,11 +329,11 @@ module RubyLsp
|
|
275
329
|
return unless methods
|
276
330
|
|
277
331
|
methods.each do |target_method|
|
278
|
-
|
279
|
-
next if sorbet_level_true_or_higher?(@sorbet_level) && not_in_dependencies?(
|
332
|
+
uri = target_method.uri
|
333
|
+
next if sorbet_level_true_or_higher?(@sorbet_level) && not_in_dependencies?(T.must(uri.full_path))
|
280
334
|
|
281
335
|
@response_builder << Interface::LocationLink.new(
|
282
|
-
target_uri:
|
336
|
+
target_uri: uri.to_s,
|
283
337
|
target_range: range_from_location(target_method.location),
|
284
338
|
target_selection_range: range_from_location(target_method.name_location),
|
285
339
|
)
|
@@ -290,20 +344,22 @@ module RubyLsp
|
|
290
344
|
def handle_require_definition(node, message)
|
291
345
|
case message
|
292
346
|
when :require
|
293
|
-
entry = @index.search_require_paths(node.content).find do |
|
294
|
-
|
347
|
+
entry = @index.search_require_paths(node.content).find do |uri|
|
348
|
+
uri.require_path == node.content
|
295
349
|
end
|
296
350
|
|
297
351
|
if entry
|
298
352
|
candidate = entry.full_path
|
299
353
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
354
|
+
if candidate
|
355
|
+
@response_builder << Interface::Location.new(
|
356
|
+
uri: URI::Generic.from_path(path: candidate).to_s,
|
357
|
+
range: Interface::Range.new(
|
358
|
+
start: Interface::Position.new(line: 0, character: 0),
|
359
|
+
end: Interface::Position.new(line: 0, character: 0),
|
360
|
+
),
|
361
|
+
)
|
362
|
+
end
|
307
363
|
end
|
308
364
|
when :require_relative
|
309
365
|
required_file = "#{node.content}.rb"
|
@@ -346,11 +402,11 @@ module RubyLsp
|
|
346
402
|
# If the project has Sorbet, then we only want to handle go to definition for constants defined in gems, as an
|
347
403
|
# additional behavior on top of jumping to RBIs. The only sigil where Sorbet cannot handle constants is typed
|
348
404
|
# ignore
|
349
|
-
|
350
|
-
next if @sorbet_level != RubyDocument::SorbetLevel::Ignore && not_in_dependencies?(
|
405
|
+
uri = entry.uri
|
406
|
+
next if @sorbet_level != RubyDocument::SorbetLevel::Ignore && not_in_dependencies?(T.must(uri.full_path))
|
351
407
|
|
352
408
|
@response_builder << Interface::LocationLink.new(
|
353
|
-
target_uri:
|
409
|
+
target_uri: uri.to_s,
|
354
410
|
target_range: range_from_location(entry.location),
|
355
411
|
target_selection_range: range_from_location(entry.name_location),
|
356
412
|
)
|
@@ -41,6 +41,10 @@ module RubyLsp
|
|
41
41
|
:on_module_node_enter,
|
42
42
|
:on_module_node_leave,
|
43
43
|
:on_instance_variable_write_node_enter,
|
44
|
+
:on_instance_variable_target_node_enter,
|
45
|
+
:on_instance_variable_operator_write_node_enter,
|
46
|
+
:on_instance_variable_or_write_node_enter,
|
47
|
+
:on_instance_variable_and_write_node_enter,
|
44
48
|
:on_class_variable_write_node_enter,
|
45
49
|
:on_singleton_class_node_enter,
|
46
50
|
:on_singleton_class_node_leave,
|
@@ -249,21 +253,61 @@ module RubyLsp
|
|
249
253
|
@response_builder.pop
|
250
254
|
end
|
251
255
|
|
256
|
+
sig { params(node: Prism::ClassVariableWriteNode).void }
|
257
|
+
def on_class_variable_write_node_enter(node)
|
258
|
+
create_document_symbol(
|
259
|
+
name: node.name.to_s,
|
260
|
+
kind: Constant::SymbolKind::VARIABLE,
|
261
|
+
range_location: node.name_loc,
|
262
|
+
selection_range_location: node.name_loc,
|
263
|
+
)
|
264
|
+
end
|
265
|
+
|
252
266
|
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
253
267
|
def on_instance_variable_write_node_enter(node)
|
254
268
|
create_document_symbol(
|
255
269
|
name: node.name.to_s,
|
256
|
-
kind: Constant::SymbolKind::
|
270
|
+
kind: Constant::SymbolKind::FIELD,
|
257
271
|
range_location: node.name_loc,
|
258
272
|
selection_range_location: node.name_loc,
|
259
273
|
)
|
260
274
|
end
|
261
275
|
|
262
|
-
sig { params(node: Prism::
|
263
|
-
def
|
276
|
+
sig { params(node: Prism::InstanceVariableTargetNode).void }
|
277
|
+
def on_instance_variable_target_node_enter(node)
|
264
278
|
create_document_symbol(
|
265
279
|
name: node.name.to_s,
|
266
|
-
kind: Constant::SymbolKind::
|
280
|
+
kind: Constant::SymbolKind::FIELD,
|
281
|
+
range_location: node.location,
|
282
|
+
selection_range_location: node.location,
|
283
|
+
)
|
284
|
+
end
|
285
|
+
|
286
|
+
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
287
|
+
def on_instance_variable_operator_write_node_enter(node)
|
288
|
+
create_document_symbol(
|
289
|
+
name: node.name.to_s,
|
290
|
+
kind: Constant::SymbolKind::FIELD,
|
291
|
+
range_location: node.name_loc,
|
292
|
+
selection_range_location: node.name_loc,
|
293
|
+
)
|
294
|
+
end
|
295
|
+
|
296
|
+
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
297
|
+
def on_instance_variable_or_write_node_enter(node)
|
298
|
+
create_document_symbol(
|
299
|
+
name: node.name.to_s,
|
300
|
+
kind: Constant::SymbolKind::FIELD,
|
301
|
+
range_location: node.name_loc,
|
302
|
+
selection_range_location: node.name_loc,
|
303
|
+
)
|
304
|
+
end
|
305
|
+
|
306
|
+
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
307
|
+
def on_instance_variable_and_write_node_enter(node)
|
308
|
+
create_document_symbol(
|
309
|
+
name: node.name.to_s,
|
310
|
+
kind: Constant::SymbolKind::FIELD,
|
267
311
|
range_location: node.name_loc,
|
268
312
|
selection_range_location: node.name_loc,
|
269
313
|
)
|
@@ -296,7 +340,7 @@ module RubyLsp
|
|
296
340
|
).returns(Interface::DocumentSymbol)
|
297
341
|
end
|
298
342
|
def create_document_symbol(name:, kind:, range_location:, selection_range_location:)
|
299
|
-
name = "<blank>" if name.empty?
|
343
|
+
name = "<blank>" if name.strip.empty?
|
300
344
|
symbol = Interface::DocumentSymbol.new(
|
301
345
|
name: name,
|
302
346
|
kind: kind,
|
@@ -195,7 +195,7 @@ module RubyLsp
|
|
195
195
|
def push_comment_ranges
|
196
196
|
# Group comments that are on consecutive lines and then push ranges for each group that has at least 2 comments
|
197
197
|
@comments.chunk_while do |this, other|
|
198
|
-
this.location.end_line + 1 == other.location.start_line
|
198
|
+
this.location.end_line + 1 == other.location.start_line && !this.trailing? && !other.trailing?
|
199
199
|
end.each do |chunk|
|
200
200
|
next if chunk.length == 1
|
201
201
|
|
@@ -31,6 +31,12 @@ module RubyLsp
|
|
31
31
|
Prism::SuperNode,
|
32
32
|
Prism::ForwardingSuperNode,
|
33
33
|
Prism::YieldNode,
|
34
|
+
Prism::ClassVariableAndWriteNode,
|
35
|
+
Prism::ClassVariableOperatorWriteNode,
|
36
|
+
Prism::ClassVariableOrWriteNode,
|
37
|
+
Prism::ClassVariableReadNode,
|
38
|
+
Prism::ClassVariableTargetNode,
|
39
|
+
Prism::ClassVariableWriteNode,
|
34
40
|
],
|
35
41
|
T::Array[T.class_of(Prism::Node)],
|
36
42
|
)
|
@@ -85,6 +91,12 @@ module RubyLsp
|
|
85
91
|
:on_string_node_enter,
|
86
92
|
:on_interpolated_string_node_enter,
|
87
93
|
:on_yield_node_enter,
|
94
|
+
:on_class_variable_and_write_node_enter,
|
95
|
+
:on_class_variable_operator_write_node_enter,
|
96
|
+
:on_class_variable_or_write_node_enter,
|
97
|
+
:on_class_variable_read_node_enter,
|
98
|
+
:on_class_variable_target_node_enter,
|
99
|
+
:on_class_variable_write_node_enter,
|
88
100
|
)
|
89
101
|
end
|
90
102
|
|
@@ -215,6 +227,36 @@ module RubyLsp
|
|
215
227
|
handle_keyword_documentation(node.keyword)
|
216
228
|
end
|
217
229
|
|
230
|
+
sig { params(node: Prism::ClassVariableAndWriteNode).void }
|
231
|
+
def on_class_variable_and_write_node_enter(node)
|
232
|
+
handle_class_variable_hover(node.name.to_s)
|
233
|
+
end
|
234
|
+
|
235
|
+
sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
|
236
|
+
def on_class_variable_operator_write_node_enter(node)
|
237
|
+
handle_class_variable_hover(node.name.to_s)
|
238
|
+
end
|
239
|
+
|
240
|
+
sig { params(node: Prism::ClassVariableOrWriteNode).void }
|
241
|
+
def on_class_variable_or_write_node_enter(node)
|
242
|
+
handle_class_variable_hover(node.name.to_s)
|
243
|
+
end
|
244
|
+
|
245
|
+
sig { params(node: Prism::ClassVariableTargetNode).void }
|
246
|
+
def on_class_variable_target_node_enter(node)
|
247
|
+
handle_class_variable_hover(node.name.to_s)
|
248
|
+
end
|
249
|
+
|
250
|
+
sig { params(node: Prism::ClassVariableReadNode).void }
|
251
|
+
def on_class_variable_read_node_enter(node)
|
252
|
+
handle_class_variable_hover(node.name.to_s)
|
253
|
+
end
|
254
|
+
|
255
|
+
sig { params(node: Prism::ClassVariableWriteNode).void }
|
256
|
+
def on_class_variable_write_node_enter(node)
|
257
|
+
handle_class_variable_hover(node.name.to_s)
|
258
|
+
end
|
259
|
+
|
218
260
|
private
|
219
261
|
|
220
262
|
sig { params(node: T.any(Prism::InterpolatedStringNode, Prism::StringNode)).void }
|
@@ -317,6 +359,21 @@ module RubyLsp
|
|
317
359
|
end
|
318
360
|
end
|
319
361
|
|
362
|
+
sig { params(name: String).void }
|
363
|
+
def handle_class_variable_hover(name)
|
364
|
+
type = @type_inferrer.infer_receiver_type(@node_context)
|
365
|
+
return unless type
|
366
|
+
|
367
|
+
entries = @index.resolve_class_variable(name, type.name)
|
368
|
+
return unless entries
|
369
|
+
|
370
|
+
categorized_markdown_from_index_entries(name, entries).each do |category, content|
|
371
|
+
@response_builder.push(content, category: category)
|
372
|
+
end
|
373
|
+
rescue RubyIndexer::Index::NonExistingNamespaceError
|
374
|
+
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
375
|
+
end
|
376
|
+
|
320
377
|
sig { params(name: String, location: Prism::Location).void }
|
321
378
|
def generate_hover(name, location)
|
322
379
|
entries = @index.resolve(name, @node_context.nesting)
|
@@ -62,6 +62,12 @@ module RubyLsp
|
|
62
62
|
Prism::InstanceVariableOrWriteNode,
|
63
63
|
Prism::InstanceVariableTargetNode,
|
64
64
|
Prism::InstanceVariableWriteNode,
|
65
|
+
Prism::ClassVariableAndWriteNode,
|
66
|
+
Prism::ClassVariableOperatorWriteNode,
|
67
|
+
Prism::ClassVariableOrWriteNode,
|
68
|
+
Prism::ClassVariableReadNode,
|
69
|
+
Prism::ClassVariableTargetNode,
|
70
|
+
Prism::ClassVariableWriteNode,
|
65
71
|
],
|
66
72
|
code_units_cache: document.code_units_cache,
|
67
73
|
)
|
@@ -49,7 +49,8 @@ module RubyLsp
|
|
49
49
|
if owner_name
|
50
50
|
entries = entries.select do |entry|
|
51
51
|
(entry.is_a?(RubyIndexer::Entry::Member) || entry.is_a?(RubyIndexer::Entry::InstanceVariable) ||
|
52
|
-
entry.is_a?(RubyIndexer::Entry::MethodAlias)
|
52
|
+
entry.is_a?(RubyIndexer::Entry::MethodAlias) || entry.is_a?(RubyIndexer::Entry::ClassVariable)) &&
|
53
|
+
entry.owner&.name == owner_name
|
53
54
|
end
|
54
55
|
end
|
55
56
|
|
@@ -56,6 +56,12 @@ module RubyLsp
|
|
56
56
|
Prism::StringNode,
|
57
57
|
Prism::SuperNode,
|
58
58
|
Prism::ForwardingSuperNode,
|
59
|
+
Prism::ClassVariableAndWriteNode,
|
60
|
+
Prism::ClassVariableOperatorWriteNode,
|
61
|
+
Prism::ClassVariableOrWriteNode,
|
62
|
+
Prism::ClassVariableReadNode,
|
63
|
+
Prism::ClassVariableTargetNode,
|
64
|
+
Prism::ClassVariableWriteNode,
|
59
65
|
],
|
60
66
|
code_units_cache: document.code_units_cache,
|
61
67
|
)
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# The
|
7
|
+
# [prepare_rename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename)
|
8
|
+
# # request checks the validity of a rename operation at a given location.
|
9
|
+
class PrepareRename < Request
|
10
|
+
extend T::Sig
|
11
|
+
include Support::Common
|
12
|
+
|
13
|
+
sig do
|
14
|
+
params(
|
15
|
+
document: RubyDocument,
|
16
|
+
position: T::Hash[Symbol, T.untyped],
|
17
|
+
).void
|
18
|
+
end
|
19
|
+
def initialize(document, position)
|
20
|
+
super()
|
21
|
+
@document = document
|
22
|
+
@position = T.let(position, T::Hash[Symbol, Integer])
|
23
|
+
end
|
24
|
+
|
25
|
+
sig { override.returns(T.nilable(Interface::Range)) }
|
26
|
+
def perform
|
27
|
+
char_position = @document.create_scanner.find_char_position(@position)
|
28
|
+
|
29
|
+
node_context = RubyDocument.locate(
|
30
|
+
@document.parse_result.value,
|
31
|
+
char_position,
|
32
|
+
node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
|
33
|
+
code_units_cache: @document.code_units_cache,
|
34
|
+
)
|
35
|
+
target = node_context.node
|
36
|
+
parent = node_context.parent
|
37
|
+
return if !target || target.is_a?(Prism::ProgramNode)
|
38
|
+
|
39
|
+
if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
|
40
|
+
target = determine_target(
|
41
|
+
target,
|
42
|
+
parent,
|
43
|
+
@position,
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
range_from_location(target.location)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -66,7 +66,7 @@ module RubyLsp
|
|
66
66
|
Interface::TypeHierarchyItem.new(
|
67
67
|
name: first_entry.name,
|
68
68
|
kind: kind_for_entry(first_entry),
|
69
|
-
uri:
|
69
|
+
uri: first_entry.uri.to_s,
|
70
70
|
range: range,
|
71
71
|
selection_range: range,
|
72
72
|
),
|
@@ -12,6 +12,15 @@ module RubyLsp
|
|
12
12
|
|
13
13
|
class InvalidNameError < StandardError; end
|
14
14
|
|
15
|
+
class << self
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
sig { returns(Interface::RenameOptions) }
|
19
|
+
def provider
|
20
|
+
Interface::RenameOptions.new(prepare_provider: true)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
sig do
|
16
25
|
params(
|
17
26
|
global_state: GlobalState,
|
@@ -106,7 +115,9 @@ module RubyLsp
|
|
106
115
|
|
107
116
|
T.must(@global_state.index[fully_qualified_name]).each do |entry|
|
108
117
|
# Do not rename files that are not part of the workspace
|
109
|
-
|
118
|
+
uri = entry.uri
|
119
|
+
file_path = T.must(uri.full_path)
|
120
|
+
next unless file_path.start_with?(@global_state.workspace_path)
|
110
121
|
|
111
122
|
case entry
|
112
123
|
when RubyIndexer::Entry::Class, RubyIndexer::Entry::Module, RubyIndexer::Entry::Constant,
|
@@ -117,13 +128,12 @@ module RubyLsp
|
|
117
128
|
if "#{file_name}.rb" == entry.file_name
|
118
129
|
new_file_name = file_from_constant_name(T.must(@new_name.split("::").last))
|
119
130
|
|
120
|
-
old_uri = URI::Generic.from_path(path: entry.file_path).to_s
|
121
131
|
new_uri = URI::Generic.from_path(path: File.join(
|
122
|
-
File.dirname(
|
132
|
+
File.dirname(file_path),
|
123
133
|
"#{new_file_name}.rb",
|
124
134
|
)).to_s
|
125
135
|
|
126
|
-
document_changes << Interface::RenameFile.new(kind: "rename", old_uri:
|
136
|
+
document_changes << Interface::RenameFile.new(kind: "rename", old_uri: uri.to_s, new_uri: new_uri)
|
127
137
|
end
|
128
138
|
end
|
129
139
|
end
|
@@ -93,11 +93,7 @@ module RubyLsp
|
|
93
93
|
# based, which is why instead of the usual subtraction of 1 to line numbers, we are actually adding 1 to
|
94
94
|
# columns. The format for VS Code file URIs is
|
95
95
|
# `file:///path/to/file.rb#Lstart_line,start_column-end_line,end_column`
|
96
|
-
uri =
|
97
|
-
path: entry.file_path,
|
98
|
-
fragment: "L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}",
|
99
|
-
)
|
100
|
-
|
96
|
+
uri = "#{entry.uri}#L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}"
|
101
97
|
definitions << "[#{entry.file_name}](#{uri})"
|
102
98
|
content << "\n\n#{entry.comments}" unless entry.comments.empty?
|
103
99
|
end
|
@@ -65,7 +65,7 @@ module RubyLsp
|
|
65
65
|
Interface::TypeHierarchyItem.new(
|
66
66
|
name: entry.name,
|
67
67
|
kind: kind_for_entry(entry),
|
68
|
-
uri:
|
68
|
+
uri: entry.uri.to_s,
|
69
69
|
range: range_from_location(entry.location),
|
70
70
|
selection_range: range_from_location(entry.name_location),
|
71
71
|
detail: entry.file_name,
|
@@ -21,7 +21,8 @@ module RubyLsp
|
|
21
21
|
sig { override.returns(T::Array[Interface::WorkspaceSymbol]) }
|
22
22
|
def perform
|
23
23
|
@index.fuzzy_search(@query).filter_map do |entry|
|
24
|
-
|
24
|
+
uri = entry.uri
|
25
|
+
file_path = T.must(uri.full_path)
|
25
26
|
|
26
27
|
# We only show symbols declared in the workspace
|
27
28
|
in_dependencies = !not_in_dependencies?(file_path)
|
@@ -43,7 +44,7 @@ module RubyLsp
|
|
43
44
|
container_name: container.join("::"),
|
44
45
|
kind: kind,
|
45
46
|
location: Interface::Location.new(
|
46
|
-
uri:
|
47
|
+
uri: uri.to_s,
|
47
48
|
range: Interface::Range.new(
|
48
49
|
start: Interface::Position.new(line: loc.start_line - 1, character: loc.start_column),
|
49
50
|
end: Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
@@ -5,7 +5,7 @@ def compose(raw_initialize)
|
|
5
5
|
require_relative "../setup_bundler"
|
6
6
|
require "json"
|
7
7
|
require "uri"
|
8
|
-
|
8
|
+
require "ruby_indexer/lib/ruby_indexer/uri"
|
9
9
|
|
10
10
|
initialize_request = JSON.parse(raw_initialize, symbolize_names: true)
|
11
11
|
workspace_uri = initialize_request.dig(:params, :workspaceFolders, 0, :uri)
|