ruby-lsp 0.22.0 → 0.23.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 +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)
|