ruby-lsp 0.23.16 → 0.23.17

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +16 -19
  4. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +0 -3
  5. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +9 -19
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +32 -68
  7. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +1 -10
  8. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +4 -4
  9. data/lib/ruby_indexer/test/index_test.rb +7 -0
  10. data/lib/ruby_indexer/test/method_test.rb +7 -7
  11. data/lib/ruby_indexer/test/rbs_indexer_test.rb +4 -3
  12. data/lib/ruby_indexer/test/test_case.rb +7 -1
  13. data/lib/ruby_lsp/document.rb +1 -9
  14. data/lib/ruby_lsp/erb_document.rb +2 -2
  15. data/lib/ruby_lsp/listeners/completion.rb +8 -8
  16. data/lib/ruby_lsp/listeners/definition.rb +7 -7
  17. data/lib/ruby_lsp/listeners/document_link.rb +7 -10
  18. data/lib/ruby_lsp/listeners/hover.rb +10 -9
  19. data/lib/ruby_lsp/listeners/signature_help.rb +2 -2
  20. data/lib/ruby_lsp/listeners/spec_style.rb +11 -11
  21. data/lib/ruby_lsp/listeners/test_style.rb +10 -5
  22. data/lib/ruby_lsp/rbs_document.rb +2 -2
  23. data/lib/ruby_lsp/requests/code_action_resolve.rb +44 -39
  24. data/lib/ruby_lsp/requests/code_lens.rb +15 -3
  25. data/lib/ruby_lsp/requests/completion.rb +2 -2
  26. data/lib/ruby_lsp/requests/definition.rb +3 -4
  27. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  28. data/lib/ruby_lsp/requests/document_link.rb +1 -1
  29. data/lib/ruby_lsp/requests/folding_ranges.rb +1 -1
  30. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +0 -2
  31. data/lib/ruby_lsp/requests/hover.rb +1 -1
  32. data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
  33. data/lib/ruby_lsp/requests/references.rb +1 -16
  34. data/lib/ruby_lsp/requests/rename.rb +1 -4
  35. data/lib/ruby_lsp/requests/request.rb +2 -1
  36. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  37. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  38. data/lib/ruby_lsp/requests/support/annotation.rb +1 -1
  39. data/lib/ruby_lsp/requests/support/common.rb +0 -5
  40. data/lib/ruby_lsp/requests/support/test_item.rb +6 -0
  41. data/lib/ruby_lsp/response_builders/document_symbol.rb +1 -1
  42. data/lib/ruby_lsp/response_builders/test_collection.rb +37 -0
  43. data/lib/ruby_lsp/ruby_document.rb +2 -32
  44. data/lib/ruby_lsp/server.rb +36 -21
  45. data/lib/ruby_lsp/store.rb +6 -6
  46. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +31 -4
  47. data/lib/ruby_lsp/utils.rb +43 -0
  48. metadata +1 -1
@@ -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, RubyDocument::SorbetLevel sorbet_level, Prism::Dispatcher dispatcher, URI::Generic uri, String? trigger_character) -> void
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 if @sorbet_level != RubyDocument::SorbetLevel::Ignore
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 if @sorbet_level != RubyDocument::SorbetLevel::Ignore
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 == RubyDocument::SorbetLevel::Ignore
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 == RubyDocument::SorbetLevel::Strict
393
+ return if @sorbet_level.strict?
394
394
 
395
395
  type = @type_inferrer.infer_receiver_type(@node_context)
396
396
  return unless type
@@ -475,13 +475,13 @@ module RubyLsp
475
475
  def complete_methods(node, name)
476
476
  # If the node has a receiver, then we don't need to provide local nor keyword completions. Sorbet can provide
477
477
  # local and keyword completion for any file with a Sorbet level of true or higher
478
- if !sorbet_level_true_or_higher?(@sorbet_level) && !node.receiver
478
+ if !@sorbet_level.true_or_higher? && !node.receiver
479
479
  add_local_completions(node, name)
480
480
  add_keyword_completions(node, name)
481
481
  end
482
482
 
483
483
  # Sorbet can provide completion for methods invoked on self on typed true or higher files
484
- return if sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
484
+ return if @sorbet_level.true_or_higher? && self_receiver?(node)
485
485
 
486
486
  type = @type_inferrer.infer_receiver_type(@node_context)
487
487
  return unless type
@@ -512,7 +512,7 @@ module RubyLsp
512
512
  external_references = @node_context.fully_qualified_name != type.name
513
513
 
514
514
  @index.method_completion_candidates(method_name, type.name).each do |entry|
515
- next if entry.visibility != RubyIndexer::Entry::Visibility::PUBLIC && external_references
515
+ next if entry.visibility != :public && external_references
516
516
 
517
517
  entry_name = entry.name
518
518
  owner_name = entry.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, Document::LanguageId language_id, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, RubyDocument::SorbetLevel sorbet_level) -> void
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 sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
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 == Document::LanguageId::ERB && inferrer_receiver_type&.name == "Object"
65
+ if @language_id == :erb && inferrer_receiver_type&.name == "Object"
66
66
  inferrer_receiver_type = nil
67
67
  end
68
68
 
@@ -223,7 +223,7 @@ module RubyLsp
223
223
  #: -> void
224
224
  def handle_super_node_definition
225
225
  # Sorbet can handle super hover on typed true or higher
226
- return if sorbet_level_true_or_higher?(@sorbet_level)
226
+ return if @sorbet_level.true_or_higher?
227
227
 
228
228
  surrounding_method = @node_context.surrounding_method
229
229
  return unless surrounding_method
@@ -276,7 +276,7 @@ module RubyLsp
276
276
  def handle_instance_variable_definition(name)
277
277
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
278
278
  # to provide all features for them
279
- return if @sorbet_level == RubyDocument::SorbetLevel::Strict
279
+ return if @sorbet_level.strict?
280
280
 
281
281
  type = @type_inferrer.infer_receiver_type(@node_context)
282
282
  return unless type
@@ -317,7 +317,7 @@ module RubyLsp
317
317
  methods.each do |target_method|
318
318
  uri = target_method.uri
319
319
  full_path = uri.full_path
320
- next if sorbet_level_true_or_higher?(@sorbet_level) && (!full_path || not_in_dependencies?(full_path))
320
+ next if @sorbet_level.true_or_higher? && (!full_path || not_in_dependencies?(full_path))
321
321
 
322
322
  @response_builder << Interface::LocationLink.new(
323
323
  target_uri: uri.to_s,
@@ -392,7 +392,7 @@ module RubyLsp
392
392
  uri = entry.uri
393
393
  full_path = uri.full_path
394
394
 
395
- if @sorbet_level != RubyDocument::SorbetLevel::Ignore && (!full_path || not_in_dependencies?(full_path))
395
+ if !@sorbet_level.ignore? && (!full_path || not_in_dependencies?(full_path))
396
396
  next
397
397
  end
398
398
 
@@ -105,16 +105,13 @@ module RubyLsp
105
105
  match = comment.location.slice.match(%r{source://.*#\d+$})
106
106
  return unless match
107
107
 
108
- uri = T.cast(
109
- begin
110
- URI(
111
- match[0], #: as !nil
112
- )
113
- rescue URI::Error
114
- nil
115
- end,
116
- T.nilable(URI::Source),
117
- )
108
+ uri = begin
109
+ URI(
110
+ match[0], #: as !nil
111
+ )
112
+ rescue URI::Error
113
+ nil
114
+ end #: as URI::Source?
118
115
  return unless uri
119
116
 
120
117
  gem_version = resolve_version(uri)
@@ -42,7 +42,7 @@ module RubyLsp
42
42
  "https://gitlab.com",
43
43
  ].freeze #: Array[String]
44
44
 
45
- #: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, RubyDocument::SorbetLevel sorbet_level) -> void
45
+ #: (ResponseBuilders::Hover response_builder, GlobalState global_state, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
46
46
  def initialize(response_builder, global_state, uri, node_context, dispatcher, sorbet_level) # rubocop:disable Metrics/ParameterLists
47
47
  @response_builder = response_builder
48
48
  @global_state = global_state
@@ -96,7 +96,7 @@ module RubyLsp
96
96
 
97
97
  #: (Prism::ConstantReadNode node) -> void
98
98
  def on_constant_read_node_enter(node)
99
- return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
99
+ return unless @sorbet_level.ignore?
100
100
 
101
101
  name = RubyIndexer::Index.constant_name(node)
102
102
  return if name.nil?
@@ -106,14 +106,14 @@ module RubyLsp
106
106
 
107
107
  #: (Prism::ConstantWriteNode node) -> void
108
108
  def on_constant_write_node_enter(node)
109
- return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
109
+ return unless @sorbet_level.ignore?
110
110
 
111
111
  generate_hover(node.name.to_s, node.name_loc)
112
112
  end
113
113
 
114
114
  #: (Prism::ConstantPathNode node) -> void
115
115
  def on_constant_path_node_enter(node)
116
- return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
116
+ return unless @sorbet_level.ignore?
117
117
 
118
118
  name = RubyIndexer::Index.constant_name(node)
119
119
  return if name.nil?
@@ -128,7 +128,7 @@ module RubyLsp
128
128
  return
129
129
  end
130
130
 
131
- return if sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
131
+ return if @sorbet_level.true_or_higher? && self_receiver?(node)
132
132
 
133
133
  message = node.message
134
134
  return unless message
@@ -283,7 +283,7 @@ module RubyLsp
283
283
  #: -> void
284
284
  def handle_super_node_hover
285
285
  # Sorbet can handle super hover on typed true or higher
286
- return if sorbet_level_true_or_higher?(@sorbet_level)
286
+ return if @sorbet_level.true_or_higher?
287
287
 
288
288
  surrounding_method = @node_context.surrounding_method
289
289
  return unless surrounding_method
@@ -318,7 +318,7 @@ module RubyLsp
318
318
  def handle_instance_variable_hover(name)
319
319
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
320
320
  # to provide all features for them
321
- return if @sorbet_level == RubyDocument::SorbetLevel::Strict
321
+ return if @sorbet_level.strict?
322
322
 
323
323
  type = @type_inferrer.infer_receiver_type(@node_context)
324
324
  return unless type
@@ -366,9 +366,10 @@ module RubyLsp
366
366
  # We should only show hover for private constants if the constant is defined in the same namespace as the
367
367
  # reference
368
368
  first_entry = entries.first #: as !nil
369
- return if first_entry.private? && first_entry.name != "#{@node_context.fully_qualified_name}::#{name}"
369
+ full_name = first_entry.name
370
+ return if first_entry.private? && full_name != "#{@node_context.fully_qualified_name}::#{name}"
370
371
 
371
- categorized_markdown_from_index_entries(name, entries).each do |category, content|
372
+ categorized_markdown_from_index_entries(full_name, entries).each do |category, content|
372
373
  @response_builder.push(content, category: category)
373
374
  end
374
375
  end
@@ -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, RubyDocument::SorbetLevel sorbet_level) -> void
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 sorbet_level_true_or_higher?(@sorbet_level)
22
+ return if @sorbet_level.true_or_higher?
23
23
 
24
24
  message = node.message
25
25
  return unless message
@@ -4,9 +4,7 @@
4
4
  module RubyLsp
5
5
  module Listeners
6
6
  class SpecStyle < TestDiscovery
7
- extend T::Sig
8
-
9
- #: (response_builder: ResponseBuilders::TestCollection, global_state: GlobalState, dispatcher: Prism::Dispatcher, uri: URI::Generic) -> void
7
+ #: (ResponseBuilders::TestCollection, GlobalState, Prism::Dispatcher, URI::Generic) -> void
10
8
  def initialize(response_builder, global_state, dispatcher, uri)
11
9
  super
12
10
 
@@ -22,7 +20,7 @@ module RubyLsp
22
20
  )
23
21
  end
24
22
 
25
- #: (node: Prism::ClassNode) -> void
23
+ #: (Prism::ClassNode) -> void
26
24
  def on_class_node_enter(node)
27
25
  with_test_ancestor_tracking(node) do |_, ancestors|
28
26
  is_spec = ancestors.include?("Minitest::Spec")
@@ -30,14 +28,14 @@ module RubyLsp
30
28
  end
31
29
  end
32
30
 
33
- #: (node: Prism::ClassNode) -> void
31
+ #: (Prism::ClassNode) -> void
34
32
  def on_class_node_leave(node) # rubocop:disable RubyLsp/UseRegisterWithHandlerMethod
35
33
  super
36
34
 
37
35
  @spec_class_stack.pop
38
36
  end
39
37
 
40
- #: (node: Prism::CallNode) -> void
38
+ #: (Prism::CallNode) -> void
41
39
  def on_call_node_enter(node)
42
40
  case node.name
43
41
  when :describe
@@ -47,7 +45,7 @@ module RubyLsp
47
45
  end
48
46
  end
49
47
 
50
- #: (node: Prism::CallNode) -> void
48
+ #: (Prism::CallNode) -> void
51
49
  def on_call_node_leave(node)
52
50
  return unless node.name == :describe && !node.receiver
53
51
 
@@ -56,7 +54,7 @@ module RubyLsp
56
54
 
57
55
  private
58
56
 
59
- #: (node: Prism::CallNode) -> void
57
+ #: (Prism::CallNode) -> void
60
58
  def handle_describe(node)
61
59
  return if node.block.nil?
62
60
 
@@ -74,6 +72,7 @@ module RubyLsp
74
72
  framework: :minitest,
75
73
  )
76
74
  @response_builder.add(test_item)
75
+ @response_builder.add_code_lens(test_item)
77
76
  else
78
77
  add_to_parent_test_group(description, node)
79
78
  end
@@ -81,7 +80,7 @@ module RubyLsp
81
80
  @describe_block_nesting << description
82
81
  end
83
82
 
84
- #: (node: Prism::CallNode) -> void
83
+ #: (Prism::CallNode) -> void
85
84
  def handle_example(node)
86
85
  return unless in_spec_context?
87
86
 
@@ -93,7 +92,7 @@ module RubyLsp
93
92
  add_to_parent_test_group(description, node)
94
93
  end
95
94
 
96
- #: (description: String, node: Prism::CallNode) -> void
95
+ #: (String, Prism::CallNode) -> void
97
96
  def add_to_parent_test_group(description, node)
98
97
  parent_test_group = find_parent_test_group
99
98
  return unless parent_test_group
@@ -106,6 +105,7 @@ module RubyLsp
106
105
  framework: :minitest,
107
106
  )
108
107
  parent_test_group.add(test_item)
108
+ @response_builder.add_code_lens(test_item)
109
109
  end
110
110
 
111
111
  #: -> Requests::Support::TestItem?
@@ -129,7 +129,7 @@ module RubyLsp
129
129
  test_group
130
130
  end
131
131
 
132
- #: (node: Prism::CallNode) -> String?
132
+ #: (Prism::CallNode) -> String?
133
133
  def extract_description(node)
134
134
  first_argument = node.arguments&.arguments&.first
135
135
  return unless first_argument
@@ -143,7 +143,7 @@ module RubyLsp
143
143
  "ruby"
144
144
  end #: String
145
145
 
146
- #: (ResponseBuilders::TestCollection response_builder, GlobalState global_state, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
146
+ #: (ResponseBuilders::TestCollection, GlobalState, Prism::Dispatcher, URI::Generic) -> void
147
147
  def initialize(response_builder, global_state, dispatcher, uri)
148
148
  super
149
149
 
@@ -165,13 +165,16 @@ module RubyLsp
165
165
  @framework = :test_unit if ancestors.include?("Test::Unit::TestCase")
166
166
 
167
167
  if @framework == :test_unit || non_declarative_minitest?(ancestors, name)
168
- @response_builder.add(Requests::Support::TestItem.new(
168
+ test_item = Requests::Support::TestItem.new(
169
169
  name,
170
170
  name,
171
171
  @uri,
172
172
  range_from_node(node),
173
173
  framework: @framework,
174
- ))
174
+ )
175
+
176
+ @response_builder.add(test_item)
177
+ @response_builder.add_code_lens(test_item)
175
178
  end
176
179
  end
177
180
  end
@@ -191,13 +194,15 @@ module RubyLsp
191
194
  test_item = @response_builder[current_group_name]
192
195
  return unless test_item
193
196
 
194
- test_item.add(Requests::Support::TestItem.new(
197
+ example_item = Requests::Support::TestItem.new(
195
198
  "#{current_group_name}##{name}",
196
199
  name,
197
200
  @uri,
198
201
  range_from_node(node),
199
202
  framework: @framework,
200
- ))
203
+ )
204
+ test_item.add(example_item)
205
+ @response_builder.add_code_lens(test_item)
201
206
  end
202
207
 
203
208
  #: (Prism::CallNode node) -> void
@@ -36,9 +36,9 @@ module RubyLsp
36
36
  end
37
37
 
38
38
  # @override
39
- #: -> LanguageId
39
+ #: -> Symbol
40
40
  def language_id
41
- LanguageId::RBS
41
+ :rbs
42
42
  end
43
43
  end
44
44
  end
@@ -13,14 +13,9 @@ module RubyLsp
13
13
  NEW_METHOD_NAME = "new_method"
14
14
 
15
15
  class CodeActionError < StandardError; end
16
-
17
- class Error < ::T::Enum
18
- enums do
19
- EmptySelection = new
20
- InvalidTargetRange = new
21
- UnknownCodeAction = new
22
- end
23
- end
16
+ class EmptySelectionError < CodeActionError; end
17
+ class InvalidTargetRangeError < CodeActionError; end
18
+ class UnknownCodeActionError < CodeActionError; end
24
19
 
25
20
  #: (RubyDocument document, GlobalState global_state, Hash[Symbol, untyped] code_action) -> void
26
21
  def initialize(document, global_state, code_action)
@@ -31,9 +26,9 @@ module RubyLsp
31
26
  end
32
27
 
33
28
  # @override
34
- #: -> (Interface::CodeAction | Error)
29
+ #: -> (Interface::CodeAction)
35
30
  def perform
36
- return Error::EmptySelection if @document.source.empty?
31
+ raise EmptySelectionError, "Invalid selection for refactor" if @document.source.empty?
37
32
 
38
33
  case @code_action[:title]
39
34
  when CodeActions::EXTRACT_TO_VARIABLE_TITLE
@@ -47,26 +42,30 @@ module RubyLsp
47
42
  CodeActions::CREATE_ATTRIBUTE_ACCESSOR
48
43
  create_attribute_accessor
49
44
  else
50
- Error::UnknownCodeAction
45
+ raise UnknownCodeActionError, "Unknown code action: #{@code_action[:title]}"
51
46
  end
52
47
  end
53
48
 
54
49
  private
55
50
 
56
- #: -> (Interface::CodeAction | Error)
51
+ #: -> (Interface::CodeAction)
57
52
  def switch_block_style
58
53
  source_range = @code_action.dig(:data, :range)
59
- return Error::EmptySelection if source_range[:start] == source_range[:end]
54
+ raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
60
55
 
61
56
  target = @document.locate_first_within_range(
62
57
  @code_action.dig(:data, :range),
63
58
  node_types: [Prism::CallNode],
64
59
  )
65
60
 
66
- return Error::InvalidTargetRange unless target.is_a?(Prism::CallNode)
61
+ unless target.is_a?(Prism::CallNode)
62
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
63
+ end
67
64
 
68
65
  node = target.block
69
- return Error::InvalidTargetRange unless node.is_a?(Prism::BlockNode)
66
+ unless node.is_a?(Prism::BlockNode)
67
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
68
+ end
70
69
 
71
70
  indentation = " " * target.location.start_column unless node.opening_loc.slice == "do"
72
71
 
@@ -91,10 +90,10 @@ module RubyLsp
91
90
  )
92
91
  end
93
92
 
94
- #: -> (Interface::CodeAction | Error)
93
+ #: -> (Interface::CodeAction)
95
94
  def refactor_variable
96
95
  source_range = @code_action.dig(:data, :range)
97
- return Error::EmptySelection if source_range[:start] == source_range[:end]
96
+ raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
98
97
 
99
98
  start_index, end_index = @document.find_index_by_position(source_range[:start], source_range[:end])
100
99
  extracted_source = @document.source[start_index...end_index] #: as !nil
@@ -111,7 +110,9 @@ module RubyLsp
111
110
 
112
111
  closest_statements = node_context.node
113
112
  parent_statements = node_context.parent
114
- return Error::InvalidTargetRange if closest_statements.nil? || closest_statements.child_nodes.compact.empty?
113
+ if closest_statements.nil? || closest_statements.child_nodes.compact.empty?
114
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
115
+ end
115
116
 
116
117
  # Find the node with the end line closest to the requested position, so that we can place the refactor
117
118
  # immediately after that closest node
@@ -120,7 +121,9 @@ module RubyLsp
120
121
  distance <= 0 ? Float::INFINITY : distance
121
122
  end #: as !nil
122
123
 
123
- return Error::InvalidTargetRange if closest_node.is_a?(Prism::MissingNode)
124
+ if closest_node.is_a?(Prism::MissingNode)
125
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
126
+ end
124
127
 
125
128
  closest_node_loc = closest_node.location
126
129
  # If the parent expression is a single line block, then we have to extract it inside of the one-line block
@@ -151,7 +154,9 @@ module RubyLsp
151
154
  lines = @document.source.lines
152
155
 
153
156
  indentation_line = lines[indentation_line_number]
154
- return Error::InvalidTargetRange unless indentation_line
157
+ unless indentation_line
158
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
159
+ end
155
160
 
156
161
  indentation = indentation_line[/\A */] #: as !nil
157
162
  .size
@@ -162,7 +167,9 @@ module RubyLsp
162
167
  }
163
168
 
164
169
  line = lines[target_line]
165
- return Error::InvalidTargetRange unless line
170
+ unless line
171
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
172
+ end
166
173
 
167
174
  variable_source = if line.strip.empty?
168
175
  "\n#{" " * indentation}#{NEW_VARIABLE_NAME} = #{extracted_source}"
@@ -190,10 +197,10 @@ module RubyLsp
190
197
  )
191
198
  end
192
199
 
193
- #: -> (Interface::CodeAction | Error)
200
+ #: -> (Interface::CodeAction)
194
201
  def refactor_method
195
202
  source_range = @code_action.dig(:data, :range)
196
- return Error::EmptySelection if source_range[:start] == source_range[:end]
203
+ raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
197
204
 
198
205
  start_index, end_index = @document.find_index_by_position(source_range[:start], source_range[:end])
199
206
  extracted_source = @document.source[start_index...end_index] #: as !nil
@@ -206,11 +213,15 @@ module RubyLsp
206
213
  code_units_cache: @document.code_units_cache,
207
214
  )
208
215
  closest_node = node_context.node
209
- return Error::InvalidTargetRange unless closest_node
216
+ unless closest_node
217
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
218
+ end
210
219
 
211
220
  target_range = if closest_node.is_a?(Prism::DefNode)
212
221
  end_keyword_loc = closest_node.end_keyword_loc
213
- return Error::InvalidTargetRange unless end_keyword_loc
222
+ unless end_keyword_loc
223
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
224
+ end
214
225
 
215
226
  end_line = end_keyword_loc.end_line - 1
216
227
  character = end_keyword_loc.end_column
@@ -331,7 +342,7 @@ module RubyLsp
331
342
  indentation ? body_content.gsub(";", "\n") : "#{body_content.gsub("\n", ";")} "
332
343
  end
333
344
 
334
- #: -> (Interface::CodeAction | Error)
345
+ #: -> (Interface::CodeAction)
335
346
  def create_attribute_accessor
336
347
  source_range = @code_action.dig(:data, :range)
337
348
 
@@ -349,20 +360,12 @@ module RubyLsp
349
360
  )
350
361
  node = node_context.node
351
362
 
352
- return Error::EmptySelection unless CodeActions::INSTANCE_VARIABLE_NODES.include?(node.class)
363
+ unless CodeActions::INSTANCE_VARIABLE_NODES.include?(node.class)
364
+ raise EmptySelectionError, "Invalid selection for refactor"
365
+ end
353
366
  end
354
367
 
355
- node = T.cast(
356
- node,
357
- T.any(
358
- Prism::InstanceVariableAndWriteNode,
359
- Prism::InstanceVariableOperatorWriteNode,
360
- Prism::InstanceVariableOrWriteNode,
361
- Prism::InstanceVariableReadNode,
362
- Prism::InstanceVariableTargetNode,
363
- Prism::InstanceVariableWriteNode,
364
- ),
365
- )
368
+ node = node #: as Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode # rubocop:disable Layout/LineLength
366
369
 
367
370
  node_context = @document.locate_node(
368
371
  {
@@ -376,7 +379,9 @@ module RubyLsp
376
379
  ],
377
380
  )
378
381
  closest_node = node_context.node
379
- return Error::InvalidTargetRange if closest_node.nil?
382
+ if closest_node.nil?
383
+ raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
384
+ end
380
385
 
381
386
  attribute_name = node.name[1..]
382
387
  indentation = " " * (closest_node.location.start_column + 2)
@@ -20,20 +20,32 @@ module RubyLsp
20
20
 
21
21
  #: (GlobalState global_state, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
22
22
  def initialize(global_state, uri, dispatcher)
23
- @response_builder = ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
23
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
24
24
  .new #: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
25
25
  super()
26
- Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
26
+
27
+ @test_builder = ResponseBuilders::TestCollection.new #: ResponseBuilders::TestCollection
28
+
29
+ if global_state.enabled_feature?(:fullTestDiscovery)
30
+ Listeners::TestStyle.new(@test_builder, global_state, dispatcher, uri)
31
+ Listeners::SpecStyle.new(@test_builder, global_state, dispatcher, uri)
32
+ else
33
+ Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
34
+ end
27
35
 
28
36
  Addon.addons.each do |addon|
29
37
  addon.create_code_lens_listener(@response_builder, uri, dispatcher)
38
+
39
+ if global_state.enabled_feature?(:fullTestDiscovery)
40
+ addon.create_discover_tests_listener(@test_builder, dispatcher, uri)
41
+ end
30
42
  end
31
43
  end
32
44
 
33
45
  # @override
34
46
  #: -> Array[Interface::CodeLens]
35
47
  def perform
36
- @response_builder.response
48
+ @response_builder.response + @test_builder.code_lens
37
49
  end
38
50
  end
39
51
  end
@@ -21,7 +21,7 @@ module RubyLsp
21
21
  end
22
22
  end
23
23
 
24
- #: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] params, RubyDocument::SorbetLevel sorbet_level, Prism::Dispatcher dispatcher) -> void
24
+ #: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] params, SorbetLevel sorbet_level, Prism::Dispatcher dispatcher) -> void
25
25
  def initialize(document, global_state, params, sorbet_level, dispatcher)
26
26
  super()
27
27
  @target = nil #: Prism::Node?
@@ -60,7 +60,7 @@ module RubyLsp
60
60
  ],
61
61
  code_units_cache: document.code_units_cache,
62
62
  )
63
- @response_builder = ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem]
63
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
64
64
  .new #: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem]
65
65
 
66
66
  Listeners::Completion.new(
@@ -11,12 +11,11 @@ module RubyLsp
11
11
  class Definition < Request
12
12
  extend T::Generic
13
13
 
14
- #: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] position, Prism::Dispatcher dispatcher, RubyDocument::SorbetLevel sorbet_level) -> void
14
+ #: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] position, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
15
15
  def initialize(document, global_state, position, dispatcher, sorbet_level)
16
16
  super()
17
- @response_builder = ResponseBuilders::CollectionResponseBuilder[
18
- T.any(Interface::Location, Interface::LocationLink)
19
- ].new #: ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)]
17
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
18
+ .new #: ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)]
20
19
  @dispatcher = dispatcher
21
20
 
22
21
  char_position, _ = document.find_index_by_position(position)