ruby-lsp 0.23.15 → 0.26.9
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 +17 -14
- data/exe/ruby-lsp-check +0 -4
- data/exe/ruby-lsp-launcher +41 -14
- data/exe/ruby-lsp-test-exec +6 -0
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +0 -1
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +0 -1
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +4 -3
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +42 -20
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +1 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +49 -62
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +84 -74
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +6 -9
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +9 -14
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +12 -8
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +4 -4
- data/lib/ruby_lsp/addon.rb +44 -15
- data/lib/ruby_lsp/base_server.rb +56 -37
- data/lib/ruby_lsp/client_capabilities.rb +6 -1
- data/lib/ruby_lsp/document.rb +174 -62
- data/lib/ruby_lsp/erb_document.rb +10 -8
- data/lib/ruby_lsp/global_state.rb +86 -33
- data/lib/ruby_lsp/internal.rb +6 -3
- data/lib/ruby_lsp/listeners/completion.rb +22 -11
- data/lib/ruby_lsp/listeners/definition.rb +41 -21
- data/lib/ruby_lsp/listeners/document_highlight.rb +26 -1
- data/lib/ruby_lsp/listeners/document_link.rb +64 -28
- data/lib/ruby_lsp/listeners/hover.rb +27 -16
- data/lib/ruby_lsp/listeners/inlay_hints.rb +5 -3
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +2 -2
- data/lib/ruby_lsp/listeners/signature_help.rb +2 -2
- data/lib/ruby_lsp/listeners/spec_style.rb +155 -79
- data/lib/ruby_lsp/listeners/test_discovery.rb +39 -21
- data/lib/ruby_lsp/listeners/test_style.rb +75 -35
- data/lib/ruby_lsp/rbs_document.rb +3 -6
- data/lib/ruby_lsp/requests/code_action_resolve.rb +83 -58
- data/lib/ruby_lsp/requests/code_actions.rb +20 -5
- data/lib/ruby_lsp/requests/code_lens.rb +27 -6
- data/lib/ruby_lsp/requests/completion.rb +3 -3
- data/lib/ruby_lsp/requests/completion_resolve.rb +8 -6
- data/lib/ruby_lsp/requests/definition.rb +4 -7
- data/lib/ruby_lsp/requests/discover_tests.rb +2 -2
- data/lib/ruby_lsp/requests/document_highlight.rb +2 -2
- data/lib/ruby_lsp/requests/document_link.rb +1 -1
- data/lib/ruby_lsp/requests/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/go_to_relevant_file.rb +64 -12
- data/lib/ruby_lsp/requests/hover.rb +3 -6
- data/lib/ruby_lsp/requests/inlay_hints.rb +4 -4
- data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
- data/lib/ruby_lsp/requests/prepare_rename.rb +1 -1
- data/lib/ruby_lsp/requests/references.rb +10 -21
- data/lib/ruby_lsp/requests/rename.rb +9 -10
- data/lib/ruby_lsp/requests/request.rb +8 -8
- data/lib/ruby_lsp/requests/selection_ranges.rb +2 -2
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +2 -2
- data/lib/ruby_lsp/requests/signature_help.rb +2 -2
- data/lib/ruby_lsp/requests/support/annotation.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +9 -12
- data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
- data/lib/ruby_lsp/requests/support/package_url.rb +414 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +7 -1
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -2
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -3
- data/lib/ruby_lsp/requests/support/source_uri.rb +7 -4
- data/lib/ruby_lsp/requests/support/test_item.rb +7 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +20 -12
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +1 -4
- data/lib/ruby_lsp/response_builders/document_symbol.rb +2 -3
- data/lib/ruby_lsp/response_builders/hover.rb +1 -4
- data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +4 -5
- data/lib/ruby_lsp/response_builders/signature_help.rb +1 -2
- data/lib/ruby_lsp/response_builders/test_collection.rb +29 -3
- data/lib/ruby_lsp/ruby_document.rb +14 -42
- data/lib/ruby_lsp/scripts/compose_bundle.rb +3 -3
- data/lib/ruby_lsp/scripts/compose_bundle_windows.rb +3 -1
- data/lib/ruby_lsp/server.rb +173 -130
- data/lib/ruby_lsp/setup_bundler.rb +114 -47
- data/lib/ruby_lsp/static_docs.rb +1 -0
- data/lib/ruby_lsp/store.rb +6 -16
- data/lib/ruby_lsp/test_helper.rb +1 -4
- data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +121 -17
- data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +65 -25
- data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +16 -18
- data/lib/ruby_lsp/utils.rb +102 -13
- data/static_docs/break.md +103 -0
- metadata +8 -33
- data/lib/ruby_indexer/test/class_variables_test.rb +0 -140
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +0 -770
- data/lib/ruby_indexer/test/configuration_test.rb +0 -280
- data/lib/ruby_indexer/test/constant_test.rb +0 -402
- data/lib/ruby_indexer/test/enhancements_test.rb +0 -325
- data/lib/ruby_indexer/test/global_variable_test.rb +0 -49
- data/lib/ruby_indexer/test/index_test.rb +0 -2190
- data/lib/ruby_indexer/test/instance_variables_test.rb +0 -240
- data/lib/ruby_indexer/test/method_test.rb +0 -973
- data/lib/ruby_indexer/test/prefix_tree_test.rb +0 -150
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +0 -380
- data/lib/ruby_indexer/test/reference_finder_test.rb +0 -330
- data/lib/ruby_indexer/test/test_case.rb +0 -51
- data/lib/ruby_indexer/test/uri_test.rb +0 -85
- data/lib/ruby_lsp/load_sorbet.rb +0 -62
|
@@ -50,7 +50,7 @@ module RubyLsp
|
|
|
50
50
|
"__LINE__",
|
|
51
51
|
].freeze
|
|
52
52
|
|
|
53
|
-
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, GlobalState global_state, NodeContext node_context,
|
|
53
|
+
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, GlobalState global_state, NodeContext node_context, SorbetLevel sorbet_level, Prism::Dispatcher dispatcher, URI::Generic uri, String? trigger_character) -> void
|
|
54
54
|
def initialize( # rubocop:disable Metrics/ParameterLists
|
|
55
55
|
response_builder,
|
|
56
56
|
global_state,
|
|
@@ -100,7 +100,7 @@ module RubyLsp
|
|
|
100
100
|
def on_constant_read_node_enter(node)
|
|
101
101
|
# The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
|
|
102
102
|
# no sigil, Sorbet will still provide completion for constants
|
|
103
|
-
return
|
|
103
|
+
return unless @sorbet_level.ignore?
|
|
104
104
|
|
|
105
105
|
name = RubyIndexer::Index.constant_name(node)
|
|
106
106
|
return if name.nil?
|
|
@@ -125,7 +125,7 @@ module RubyLsp
|
|
|
125
125
|
def on_constant_path_node_enter(node)
|
|
126
126
|
# The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
|
|
127
127
|
# no sigil, Sorbet will still provide completion for constants
|
|
128
|
-
return
|
|
128
|
+
return unless @sorbet_level.ignore?
|
|
129
129
|
|
|
130
130
|
name = begin
|
|
131
131
|
node.full_name
|
|
@@ -143,7 +143,7 @@ module RubyLsp
|
|
|
143
143
|
def on_call_node_enter(node)
|
|
144
144
|
# The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
|
|
145
145
|
# no sigil, Sorbet will still provide completion for constants
|
|
146
|
-
if @sorbet_level
|
|
146
|
+
if @sorbet_level.ignore?
|
|
147
147
|
receiver = node.receiver
|
|
148
148
|
|
|
149
149
|
# When writing `Foo::`, the AST assigns a method call node (because you can use that syntax to invoke
|
|
@@ -390,7 +390,7 @@ module RubyLsp
|
|
|
390
390
|
def handle_instance_variable_completion(name, location)
|
|
391
391
|
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
|
392
392
|
# to provide all features for them
|
|
393
|
-
return if @sorbet_level
|
|
393
|
+
return if @sorbet_level.strict?
|
|
394
394
|
|
|
395
395
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
396
396
|
return unless type
|
|
@@ -445,11 +445,14 @@ module RubyLsp
|
|
|
445
445
|
return unless arguments_node
|
|
446
446
|
|
|
447
447
|
path_node_to_complete = arguments_node.arguments.first
|
|
448
|
-
|
|
449
448
|
return unless path_node_to_complete.is_a?(Prism::StringNode)
|
|
450
449
|
|
|
451
|
-
|
|
450
|
+
# If the file is unsaved (e.g.: untitled:Untitled-1), we can't provide relative completion as we don't know
|
|
451
|
+
# where the user intends to save it
|
|
452
|
+
full_path = @uri.to_standardized_path
|
|
453
|
+
return unless full_path
|
|
452
454
|
|
|
455
|
+
origin_dir = Pathname.new(full_path).dirname
|
|
453
456
|
content = path_node_to_complete.content
|
|
454
457
|
# if the path is not a directory, glob all possible next characters
|
|
455
458
|
# for example ../somethi| (where | is the cursor position)
|
|
@@ -475,13 +478,13 @@ module RubyLsp
|
|
|
475
478
|
def complete_methods(node, name)
|
|
476
479
|
# If the node has a receiver, then we don't need to provide local nor keyword completions. Sorbet can provide
|
|
477
480
|
# local and keyword completion for any file with a Sorbet level of true or higher
|
|
478
|
-
if
|
|
481
|
+
if !@sorbet_level.true_or_higher? && !node.receiver
|
|
479
482
|
add_local_completions(node, name)
|
|
480
483
|
add_keyword_completions(node, name)
|
|
481
484
|
end
|
|
482
485
|
|
|
483
486
|
# Sorbet can provide completion for methods invoked on self on typed true or higher files
|
|
484
|
-
return if
|
|
487
|
+
return if @sorbet_level.true_or_higher? && self_receiver?(node)
|
|
485
488
|
|
|
486
489
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
487
490
|
return unless type
|
|
@@ -512,10 +515,18 @@ module RubyLsp
|
|
|
512
515
|
external_references = @node_context.fully_qualified_name != type.name
|
|
513
516
|
|
|
514
517
|
@index.method_completion_candidates(method_name, type.name).each do |entry|
|
|
515
|
-
next if entry.visibility !=
|
|
518
|
+
next if entry.visibility != :public && external_references
|
|
516
519
|
|
|
517
520
|
entry_name = entry.name
|
|
518
521
|
owner_name = entry.owner&.name
|
|
522
|
+
new_text = entry_name
|
|
523
|
+
|
|
524
|
+
if entry_name.end_with?("=")
|
|
525
|
+
method_name = entry_name.delete_suffix("=")
|
|
526
|
+
|
|
527
|
+
# For writer methods, format as assignment and prefix "self." when no receiver is specified
|
|
528
|
+
new_text = node.receiver.nil? ? "self.#{method_name} = " : "#{method_name} = "
|
|
529
|
+
end
|
|
519
530
|
|
|
520
531
|
label_details = Interface::CompletionItemLabelDetails.new(
|
|
521
532
|
description: entry.file_name,
|
|
@@ -525,7 +536,7 @@ module RubyLsp
|
|
|
525
536
|
label: entry_name,
|
|
526
537
|
filter_text: entry_name,
|
|
527
538
|
label_details: label_details,
|
|
528
|
-
text_edit: Interface::TextEdit.new(range: range, new_text:
|
|
539
|
+
text_edit: Interface::TextEdit.new(range: range, new_text: new_text),
|
|
529
540
|
kind: Constant::CompletionItemKind::METHOD,
|
|
530
541
|
data: {
|
|
531
542
|
owner_name: owner_name,
|
|
@@ -8,7 +8,7 @@ module RubyLsp
|
|
|
8
8
|
|
|
9
9
|
MAX_NUMBER_OF_DEFINITION_CANDIDATES_WITHOUT_RECEIVER = 10
|
|
10
10
|
|
|
11
|
-
#: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, GlobalState global_state,
|
|
11
|
+
#: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, GlobalState global_state, Symbol language_id, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
|
|
12
12
|
def initialize(response_builder, global_state, language_id, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
|
|
13
13
|
@response_builder = response_builder
|
|
14
14
|
@global_state = global_state
|
|
@@ -53,7 +53,7 @@ module RubyLsp
|
|
|
53
53
|
#: (Prism::CallNode node) -> void
|
|
54
54
|
def on_call_node_enter(node)
|
|
55
55
|
# Sorbet can handle go to definition for methods invoked on self on typed true or higher
|
|
56
|
-
return if
|
|
56
|
+
return if @sorbet_level.true_or_higher? && self_receiver?(node)
|
|
57
57
|
|
|
58
58
|
message = node.message
|
|
59
59
|
return unless message
|
|
@@ -62,7 +62,7 @@ module RubyLsp
|
|
|
62
62
|
|
|
63
63
|
# Until we can properly infer the receiver type in erb files (maybe with ruby-lsp-rails),
|
|
64
64
|
# treating method calls' type as `nil` will allow users to get some completion support first
|
|
65
|
-
if @language_id ==
|
|
65
|
+
if @language_id == :erb && inferrer_receiver_type&.name == "Object"
|
|
66
66
|
inferrer_receiver_type = nil
|
|
67
67
|
end
|
|
68
68
|
|
|
@@ -71,24 +71,26 @@ module RubyLsp
|
|
|
71
71
|
|
|
72
72
|
#: (Prism::StringNode node) -> void
|
|
73
73
|
def on_string_node_enter(node)
|
|
74
|
-
enclosing_call
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
74
|
+
with_enclosing_call(node) do |enclosing_call, name|
|
|
75
|
+
case name
|
|
76
|
+
when :require, :require_relative
|
|
77
|
+
handle_require_definition(node, name)
|
|
78
|
+
when :send, :public_send
|
|
79
|
+
handle_send_or_public_send_definition(enclosing_call, node) { node.content }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
81
82
|
end
|
|
82
83
|
|
|
83
84
|
#: (Prism::SymbolNode node) -> void
|
|
84
85
|
def on_symbol_node_enter(node)
|
|
85
|
-
enclosing_call
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
86
|
+
with_enclosing_call(node) do |enclosing_call, name|
|
|
87
|
+
case name
|
|
88
|
+
when :autoload
|
|
89
|
+
handle_autoload_definition(enclosing_call)
|
|
90
|
+
when :send, :public_send
|
|
91
|
+
handle_send_or_public_send_definition(enclosing_call, node) { node.unescaped }
|
|
92
|
+
end
|
|
93
|
+
end
|
|
92
94
|
end
|
|
93
95
|
|
|
94
96
|
#: (Prism::BlockArgumentNode node) -> void
|
|
@@ -220,10 +222,28 @@ module RubyLsp
|
|
|
220
222
|
|
|
221
223
|
private
|
|
222
224
|
|
|
225
|
+
#: (Prism::Node node) { (Prism::CallNode, Symbol) -> void } -> void
|
|
226
|
+
def with_enclosing_call(node, &block)
|
|
227
|
+
enclosing_call = @node_context.call_node
|
|
228
|
+
return unless enclosing_call
|
|
229
|
+
|
|
230
|
+
block.call(enclosing_call, enclosing_call.name)
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
#: (Prism::CallNode enclosing_call, Prism::Node node) { -> String } -> void
|
|
234
|
+
def handle_send_or_public_send_definition(enclosing_call, node, &block)
|
|
235
|
+
first_argument = enclosing_call.arguments&.arguments&.first
|
|
236
|
+
return unless first_argument.eql?(node)
|
|
237
|
+
|
|
238
|
+
method_name = block.call
|
|
239
|
+
|
|
240
|
+
handle_method_definition(method_name, nil)
|
|
241
|
+
end
|
|
242
|
+
|
|
223
243
|
#: -> void
|
|
224
244
|
def handle_super_node_definition
|
|
225
245
|
# Sorbet can handle super hover on typed true or higher
|
|
226
|
-
return if
|
|
246
|
+
return if @sorbet_level.true_or_higher?
|
|
227
247
|
|
|
228
248
|
surrounding_method = @node_context.surrounding_method
|
|
229
249
|
return unless surrounding_method
|
|
@@ -276,7 +296,7 @@ module RubyLsp
|
|
|
276
296
|
def handle_instance_variable_definition(name)
|
|
277
297
|
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
|
278
298
|
# to provide all features for them
|
|
279
|
-
return if @sorbet_level
|
|
299
|
+
return if @sorbet_level.strict?
|
|
280
300
|
|
|
281
301
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
282
302
|
return unless type
|
|
@@ -317,7 +337,7 @@ module RubyLsp
|
|
|
317
337
|
methods.each do |target_method|
|
|
318
338
|
uri = target_method.uri
|
|
319
339
|
full_path = uri.full_path
|
|
320
|
-
next if
|
|
340
|
+
next if @sorbet_level.true_or_higher? && (!full_path || not_in_dependencies?(full_path))
|
|
321
341
|
|
|
322
342
|
@response_builder << Interface::LocationLink.new(
|
|
323
343
|
target_uri: uri.to_s,
|
|
@@ -392,7 +412,7 @@ module RubyLsp
|
|
|
392
412
|
uri = entry.uri
|
|
393
413
|
full_path = uri.full_path
|
|
394
414
|
|
|
395
|
-
if
|
|
415
|
+
if !@sorbet_level.ignore? && (!full_path || not_in_dependencies?(full_path))
|
|
396
416
|
next
|
|
397
417
|
end
|
|
398
418
|
|
|
@@ -92,7 +92,8 @@ module RubyLsp
|
|
|
92
92
|
Prism::RequiredParameterNode, Prism::RestParameterNode
|
|
93
93
|
[target, node_value(target)]
|
|
94
94
|
when Prism::ModuleNode, Prism::ClassNode, Prism::SingletonClassNode, Prism::DefNode, Prism::CaseNode,
|
|
95
|
-
Prism::WhileNode, Prism::UntilNode, Prism::ForNode, Prism::IfNode, Prism::UnlessNode
|
|
95
|
+
Prism::WhileNode, Prism::UntilNode, Prism::ForNode, Prism::IfNode, Prism::UnlessNode, Prism::BlockNode,
|
|
96
|
+
Prism::LambdaNode, Prism::BeginNode
|
|
96
97
|
[target, nil]
|
|
97
98
|
end
|
|
98
99
|
|
|
@@ -157,6 +158,9 @@ module RubyLsp
|
|
|
157
158
|
:on_for_node_enter,
|
|
158
159
|
:on_if_node_enter,
|
|
159
160
|
:on_unless_node_enter,
|
|
161
|
+
:on_block_node_enter,
|
|
162
|
+
:on_lambda_node_enter,
|
|
163
|
+
:on_begin_node_enter,
|
|
160
164
|
)
|
|
161
165
|
end
|
|
162
166
|
end
|
|
@@ -551,6 +555,27 @@ module RubyLsp
|
|
|
551
555
|
add_matching_end_highlights(node.keyword_loc, node.end_keyword_loc)
|
|
552
556
|
end
|
|
553
557
|
|
|
558
|
+
#: (Prism::BlockNode node) -> void
|
|
559
|
+
def on_block_node_enter(node)
|
|
560
|
+
return unless @target.is_a?(Prism::BlockNode)
|
|
561
|
+
|
|
562
|
+
add_matching_end_highlights(node.opening_loc, node.closing_loc)
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
#: (Prism::LambdaNode node) -> void
|
|
566
|
+
def on_lambda_node_enter(node)
|
|
567
|
+
return unless @target.is_a?(Prism::LambdaNode)
|
|
568
|
+
|
|
569
|
+
add_matching_end_highlights(node.opening_loc, node.closing_loc)
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
#: (Prism::BeginNode node) -> void
|
|
573
|
+
def on_begin_node_enter(node)
|
|
574
|
+
return unless @target.is_a?(Prism::BeginNode)
|
|
575
|
+
|
|
576
|
+
add_matching_end_highlights(node.begin_keyword_loc, node.end_keyword_loc)
|
|
577
|
+
end
|
|
578
|
+
|
|
554
579
|
private
|
|
555
580
|
|
|
556
581
|
#: (Prism::Node node, Array[singleton(Prism::Node)] classes) -> bool?
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "ruby_lsp/requests/support/source_uri"
|
|
5
|
+
require "ruby_lsp/requests/support/package_url"
|
|
5
6
|
|
|
6
7
|
module RubyLsp
|
|
7
8
|
module Listeners
|
|
@@ -59,6 +60,7 @@ module RubyLsp
|
|
|
59
60
|
@lines_to_comments = comments.to_h do |comment|
|
|
60
61
|
[comment.location.end_line, comment]
|
|
61
62
|
end #: Hash[Integer, Prism::Comment]
|
|
63
|
+
@sig_comments = {} #: Hash[Integer, Prism::Comment]
|
|
62
64
|
|
|
63
65
|
dispatcher.register(
|
|
64
66
|
self,
|
|
@@ -67,9 +69,20 @@ module RubyLsp
|
|
|
67
69
|
:on_module_node_enter,
|
|
68
70
|
:on_constant_write_node_enter,
|
|
69
71
|
:on_constant_path_write_node_enter,
|
|
72
|
+
:on_call_node_enter,
|
|
70
73
|
)
|
|
71
74
|
end
|
|
72
75
|
|
|
76
|
+
#: (Prism::CallNode node) -> void
|
|
77
|
+
def on_call_node_enter(node)
|
|
78
|
+
return unless node.name == :sig
|
|
79
|
+
|
|
80
|
+
comment = @lines_to_comments[node.location.start_line - 1]
|
|
81
|
+
return unless comment
|
|
82
|
+
|
|
83
|
+
@sig_comments[node.location.end_line] = comment
|
|
84
|
+
end
|
|
85
|
+
|
|
73
86
|
#: (Prism::DefNode node) -> void
|
|
74
87
|
def on_def_node_enter(node)
|
|
75
88
|
extract_document_link(node)
|
|
@@ -99,58 +112,81 @@ module RubyLsp
|
|
|
99
112
|
|
|
100
113
|
#: (Prism::Node node) -> void
|
|
101
114
|
def extract_document_link(node)
|
|
102
|
-
comment = @lines_to_comments[node.location.start_line - 1]
|
|
115
|
+
comment = @lines_to_comments[node.location.start_line - 1] || @sig_comments[node.location.start_line - 1]
|
|
103
116
|
return unless comment
|
|
104
117
|
|
|
105
|
-
match = comment.location.slice.match(%r{source://.*#\d
|
|
118
|
+
match = comment.location.slice.match(%r{(source://.*#\d+|pkg:gem/.*#.*)$})
|
|
106
119
|
return unless match
|
|
107
120
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
121
|
+
uri_string = match[0] #: as !nil
|
|
122
|
+
|
|
123
|
+
file_path, line_number = if uri_string.start_with?("pkg:gem/")
|
|
124
|
+
parse_package_url(uri_string)
|
|
125
|
+
else
|
|
126
|
+
parse_source_uri(uri_string)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
return unless file_path
|
|
130
|
+
|
|
131
|
+
@response_builder << Interface::DocumentLink.new(
|
|
132
|
+
range: range_from_location(comment.location),
|
|
133
|
+
target: "file://#{file_path}##{line_number}",
|
|
134
|
+
tooltip: "Jump to #{file_path}##{line_number}",
|
|
117
135
|
)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
#: (String uri_string) -> [String, String]?
|
|
139
|
+
def parse_package_url(uri_string)
|
|
140
|
+
purl = PackageURL.parse(uri_string) #: as PackageURL?
|
|
141
|
+
return unless purl
|
|
142
|
+
|
|
143
|
+
gem_version = resolve_version(purl.version, purl.name)
|
|
144
|
+
return if gem_version.nil?
|
|
145
|
+
|
|
146
|
+
path, line_number = purl.subpath.split(":", 2)
|
|
147
|
+
return unless path
|
|
148
|
+
|
|
149
|
+
gem_name = purl.name
|
|
150
|
+
file_path = self.class.gem_paths.dig(gem_name, gem_version, CGI.unescape(path))
|
|
151
|
+
return if file_path.nil?
|
|
152
|
+
|
|
153
|
+
[file_path, line_number]
|
|
154
|
+
rescue PackageURL::InvalidPackageURL
|
|
155
|
+
nil
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
#: (String uri_string) -> [String, String]?
|
|
159
|
+
def parse_source_uri(uri_string)
|
|
160
|
+
uri = begin
|
|
161
|
+
URI(uri_string)
|
|
162
|
+
rescue URI::Error
|
|
163
|
+
nil
|
|
164
|
+
end #: as URI::Source?
|
|
118
165
|
return unless uri
|
|
119
166
|
|
|
120
|
-
gem_version = resolve_version(uri)
|
|
167
|
+
gem_version = resolve_version(uri.gem_version, uri.gem_name)
|
|
121
168
|
return if gem_version.nil?
|
|
122
169
|
|
|
123
170
|
path = uri.path
|
|
124
171
|
return unless path
|
|
125
172
|
|
|
126
|
-
|
|
127
|
-
return unless gem_name
|
|
128
|
-
|
|
129
|
-
file_path = self.class.gem_paths.dig(gem_name, gem_version, CGI.unescape(path))
|
|
173
|
+
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(path))
|
|
130
174
|
return if file_path.nil?
|
|
131
175
|
|
|
132
|
-
|
|
133
|
-
range: range_from_location(comment.location),
|
|
134
|
-
target: "file://#{file_path}##{uri.line_number}",
|
|
135
|
-
tooltip: "Jump to #{file_path}##{uri.line_number}",
|
|
136
|
-
)
|
|
176
|
+
[file_path, uri.line_number || "0"]
|
|
137
177
|
end
|
|
138
178
|
|
|
139
179
|
# Try to figure out the gem version for a source:// link. The order of precedence is:
|
|
140
180
|
# 1. The version in the URI
|
|
141
181
|
# 2. The version in the RBI file name
|
|
142
182
|
# 3. The version from the gemspec
|
|
143
|
-
#: (
|
|
144
|
-
def resolve_version(
|
|
145
|
-
version = uri.gem_version
|
|
183
|
+
#: (String? version, String? gem_name) -> String?
|
|
184
|
+
def resolve_version(version, gem_name)
|
|
146
185
|
return version unless version.nil? || version.empty?
|
|
147
186
|
|
|
148
187
|
return @gem_version unless @gem_version.nil? || @gem_version.empty?
|
|
149
188
|
|
|
150
|
-
gem_name
|
|
151
|
-
return unless gem_name
|
|
152
|
-
|
|
153
|
-
GEM_TO_VERSION_MAP[gem_name]
|
|
189
|
+
GEM_TO_VERSION_MAP[gem_name.to_s]
|
|
154
190
|
end
|
|
155
191
|
end
|
|
156
192
|
end
|
|
@@ -7,6 +7,7 @@ module RubyLsp
|
|
|
7
7
|
include Requests::Support::Common
|
|
8
8
|
|
|
9
9
|
ALLOWED_TARGETS = [
|
|
10
|
+
Prism::BreakNode,
|
|
10
11
|
Prism::CallNode,
|
|
11
12
|
Prism::ConstantReadNode,
|
|
12
13
|
Prism::ConstantWriteNode,
|
|
@@ -42,7 +43,7 @@ module RubyLsp
|
|
|
42
43
|
"https://gitlab.com",
|
|
43
44
|
].freeze #: Array[String]
|
|
44
45
|
|
|
45
|
-
#: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher,
|
|
46
|
+
#: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
|
|
46
47
|
def initialize(response_builder, global_state, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
|
|
47
48
|
@response_builder = response_builder
|
|
48
49
|
@global_state = global_state
|
|
@@ -54,6 +55,7 @@ module RubyLsp
|
|
|
54
55
|
|
|
55
56
|
dispatcher.register(
|
|
56
57
|
self,
|
|
58
|
+
:on_break_node_enter,
|
|
57
59
|
:on_constant_read_node_enter,
|
|
58
60
|
:on_constant_write_node_enter,
|
|
59
61
|
:on_constant_path_node_enter,
|
|
@@ -84,8 +86,21 @@ module RubyLsp
|
|
|
84
86
|
)
|
|
85
87
|
end
|
|
86
88
|
|
|
89
|
+
#: (Prism::BreakNode node) -> void
|
|
90
|
+
def on_break_node_enter(node)
|
|
91
|
+
handle_keyword_documentation(node.keyword)
|
|
92
|
+
end
|
|
93
|
+
|
|
87
94
|
#: (Prism::StringNode node) -> void
|
|
88
95
|
def on_string_node_enter(node)
|
|
96
|
+
if @path && File.basename(@path) == GEMFILE_NAME
|
|
97
|
+
call_node = @node_context.call_node
|
|
98
|
+
if call_node && call_node.name == :gem && call_node.arguments&.arguments&.first == node
|
|
99
|
+
generate_gem_hover(call_node)
|
|
100
|
+
return
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
89
104
|
generate_heredoc_hover(node)
|
|
90
105
|
end
|
|
91
106
|
|
|
@@ -96,7 +111,7 @@ module RubyLsp
|
|
|
96
111
|
|
|
97
112
|
#: (Prism::ConstantReadNode node) -> void
|
|
98
113
|
def on_constant_read_node_enter(node)
|
|
99
|
-
return
|
|
114
|
+
return unless @sorbet_level.ignore?
|
|
100
115
|
|
|
101
116
|
name = RubyIndexer::Index.constant_name(node)
|
|
102
117
|
return if name.nil?
|
|
@@ -106,14 +121,14 @@ module RubyLsp
|
|
|
106
121
|
|
|
107
122
|
#: (Prism::ConstantWriteNode node) -> void
|
|
108
123
|
def on_constant_write_node_enter(node)
|
|
109
|
-
return
|
|
124
|
+
return unless @sorbet_level.ignore?
|
|
110
125
|
|
|
111
126
|
generate_hover(node.name.to_s, node.name_loc)
|
|
112
127
|
end
|
|
113
128
|
|
|
114
129
|
#: (Prism::ConstantPathNode node) -> void
|
|
115
130
|
def on_constant_path_node_enter(node)
|
|
116
|
-
return
|
|
131
|
+
return unless @sorbet_level.ignore?
|
|
117
132
|
|
|
118
133
|
name = RubyIndexer::Index.constant_name(node)
|
|
119
134
|
return if name.nil?
|
|
@@ -123,12 +138,7 @@ module RubyLsp
|
|
|
123
138
|
|
|
124
139
|
#: (Prism::CallNode node) -> void
|
|
125
140
|
def on_call_node_enter(node)
|
|
126
|
-
if @
|
|
127
|
-
generate_gem_hover(node)
|
|
128
|
-
return
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
return if sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
|
|
141
|
+
return if @sorbet_level.true_or_higher? && self_receiver?(node)
|
|
132
142
|
|
|
133
143
|
message = node.message
|
|
134
144
|
return unless message
|
|
@@ -273,17 +283,17 @@ module RubyLsp
|
|
|
273
283
|
content = KEYWORD_DOCS[keyword]
|
|
274
284
|
return unless content
|
|
275
285
|
|
|
276
|
-
|
|
286
|
+
doc_uri = URI::Generic.from_path(path: File.join(STATIC_DOCS_PATH, "#{keyword}.md"))
|
|
277
287
|
|
|
278
288
|
@response_builder.push("```ruby\n#{keyword}\n```", category: :title)
|
|
279
|
-
@response_builder.push("[Read more](#{
|
|
289
|
+
@response_builder.push("[Read more](#{doc_uri})", category: :links)
|
|
280
290
|
@response_builder.push(content, category: :documentation)
|
|
281
291
|
end
|
|
282
292
|
|
|
283
293
|
#: -> void
|
|
284
294
|
def handle_super_node_hover
|
|
285
295
|
# Sorbet can handle super hover on typed true or higher
|
|
286
|
-
return if
|
|
296
|
+
return if @sorbet_level.true_or_higher?
|
|
287
297
|
|
|
288
298
|
surrounding_method = @node_context.surrounding_method
|
|
289
299
|
return unless surrounding_method
|
|
@@ -318,7 +328,7 @@ module RubyLsp
|
|
|
318
328
|
def handle_instance_variable_hover(name)
|
|
319
329
|
# Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
|
|
320
330
|
# to provide all features for them
|
|
321
|
-
return if @sorbet_level
|
|
331
|
+
return if @sorbet_level.strict?
|
|
322
332
|
|
|
323
333
|
type = @type_inferrer.infer_receiver_type(@node_context)
|
|
324
334
|
return unless type
|
|
@@ -366,9 +376,10 @@ module RubyLsp
|
|
|
366
376
|
# We should only show hover for private constants if the constant is defined in the same namespace as the
|
|
367
377
|
# reference
|
|
368
378
|
first_entry = entries.first #: as !nil
|
|
369
|
-
|
|
379
|
+
full_name = first_entry.name
|
|
380
|
+
return if first_entry.private? && full_name != "#{@node_context.fully_qualified_name}::#{name}"
|
|
370
381
|
|
|
371
|
-
categorized_markdown_from_index_entries(
|
|
382
|
+
categorized_markdown_from_index_entries(full_name, entries).each do |category, content|
|
|
372
383
|
@response_builder.push(content, category: category)
|
|
373
384
|
end
|
|
374
385
|
end
|
|
@@ -8,10 +8,12 @@ module RubyLsp
|
|
|
8
8
|
|
|
9
9
|
RESCUE_STRING_LENGTH = "rescue".length #: Integer
|
|
10
10
|
|
|
11
|
-
#: (ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint]
|
|
12
|
-
def initialize(
|
|
11
|
+
#: (GlobalState, ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint], Prism::Dispatcher) -> void
|
|
12
|
+
def initialize(global_state, response_builder, dispatcher)
|
|
13
13
|
@response_builder = response_builder
|
|
14
|
-
@hints_configuration =
|
|
14
|
+
@hints_configuration = ( # rubocop:disable Style/RedundantParentheses
|
|
15
|
+
global_state.feature_configuration(:inlayHint) #: as !nil
|
|
16
|
+
) #: RequestConfig
|
|
15
17
|
|
|
16
18
|
dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
|
|
17
19
|
end
|
|
@@ -94,7 +94,7 @@ module RubyLsp
|
|
|
94
94
|
|
|
95
95
|
#: (Prism::MatchWriteNode node) -> void
|
|
96
96
|
def on_match_write_node_leave(node)
|
|
97
|
-
@inside_regex_capture =
|
|
97
|
+
@inside_regex_capture = false if node.call.message == "=~"
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
#: (Prism::DefNode node) -> void
|
|
@@ -162,7 +162,7 @@ module RubyLsp
|
|
|
162
162
|
|
|
163
163
|
#: (Prism::SelfNode node) -> void
|
|
164
164
|
def on_self_node_enter(node)
|
|
165
|
-
@response_builder.add_token(node.location, :variable, [:
|
|
165
|
+
@response_builder.add_token(node.location, :variable, [:defaultLibrary])
|
|
166
166
|
end
|
|
167
167
|
|
|
168
168
|
#: (Prism::LocalVariableWriteNode node) -> void
|
|
@@ -6,7 +6,7 @@ module RubyLsp
|
|
|
6
6
|
class SignatureHelp
|
|
7
7
|
include Requests::Support::Common
|
|
8
8
|
|
|
9
|
-
#: (ResponseBuilders::SignatureHelp response_builder, GlobalState global_state, NodeContext node_context, Prism::Dispatcher dispatcher,
|
|
9
|
+
#: (ResponseBuilders::SignatureHelp response_builder, GlobalState global_state, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
|
|
10
10
|
def initialize(response_builder, global_state, node_context, dispatcher, sorbet_level)
|
|
11
11
|
@sorbet_level = sorbet_level
|
|
12
12
|
@response_builder = response_builder
|
|
@@ -19,7 +19,7 @@ module RubyLsp
|
|
|
19
19
|
|
|
20
20
|
#: (Prism::CallNode node) -> void
|
|
21
21
|
def on_call_node_enter(node)
|
|
22
|
-
return if
|
|
22
|
+
return if @sorbet_level.true_or_higher?
|
|
23
23
|
|
|
24
24
|
message = node.message
|
|
25
25
|
return unless message
|