ruby-lsp 0.10.1 → 0.11.1

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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp-check +1 -1
  5. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +40 -5
  6. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +141 -5
  7. data/lib/ruby_indexer/lib/ruby_indexer/visitor.rb +66 -18
  8. data/lib/ruby_indexer/test/classes_and_modules_test.rb +23 -0
  9. data/lib/ruby_indexer/test/configuration_test.rb +2 -0
  10. data/lib/ruby_indexer/test/constant_test.rb +202 -0
  11. data/lib/ruby_indexer/test/index_test.rb +20 -0
  12. data/lib/ruby_lsp/{extension.rb → addon.rb} +27 -25
  13. data/lib/ruby_lsp/check_docs.rb +7 -8
  14. data/lib/ruby_lsp/document.rb +35 -38
  15. data/lib/ruby_lsp/event_emitter.rb +239 -77
  16. data/lib/ruby_lsp/executor.rb +45 -55
  17. data/lib/ruby_lsp/internal.rb +2 -3
  18. data/lib/ruby_lsp/listener.rb +8 -7
  19. data/lib/ruby_lsp/parameter_scope.rb +33 -0
  20. data/lib/ruby_lsp/requests/base_request.rb +3 -3
  21. data/lib/ruby_lsp/requests/code_action_resolve.rb +14 -14
  22. data/lib/ruby_lsp/requests/code_lens.rb +39 -63
  23. data/lib/ruby_lsp/requests/completion.rb +54 -32
  24. data/lib/ruby_lsp/requests/definition.rb +30 -27
  25. data/lib/ruby_lsp/requests/diagnostics.rb +26 -3
  26. data/lib/ruby_lsp/requests/document_highlight.rb +18 -19
  27. data/lib/ruby_lsp/requests/document_link.rb +50 -9
  28. data/lib/ruby_lsp/requests/document_symbol.rb +82 -75
  29. data/lib/ruby_lsp/requests/folding_ranges.rb +199 -222
  30. data/lib/ruby_lsp/requests/formatting.rb +5 -6
  31. data/lib/ruby_lsp/requests/hover.rb +33 -22
  32. data/lib/ruby_lsp/requests/inlay_hints.rb +2 -3
  33. data/lib/ruby_lsp/requests/selection_ranges.rb +65 -40
  34. data/lib/ruby_lsp/requests/semantic_highlighting.rb +187 -145
  35. data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -4
  36. data/lib/ruby_lsp/requests/support/annotation.rb +18 -17
  37. data/lib/ruby_lsp/requests/support/common.rb +17 -26
  38. data/lib/ruby_lsp/requests/support/dependency_detector.rb +67 -42
  39. data/lib/ruby_lsp/requests/support/highlight_target.rb +64 -45
  40. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +9 -4
  41. data/lib/ruby_lsp/requests/support/selection_range.rb +5 -4
  42. data/lib/ruby_lsp/requests/support/sorbet.rb +2 -57
  43. data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +7 -1
  44. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -1
  45. data/lib/ruby_lsp/server.rb +6 -44
  46. data/lib/ruby_lsp/utils.rb +2 -12
  47. metadata +11 -30
@@ -25,41 +25,37 @@ module RubyLsp
25
25
 
26
26
  NODES_THAT_CAN_BE_PARENTS = T.let(
27
27
  [
28
- SyntaxTree::Assign,
29
- SyntaxTree::ArrayLiteral,
30
- SyntaxTree::Begin,
31
- SyntaxTree::BlockNode,
32
- SyntaxTree::CallNode,
33
- SyntaxTree::Case,
34
- SyntaxTree::ClassDeclaration,
35
- SyntaxTree::Command,
36
- SyntaxTree::DefNode,
37
- SyntaxTree::Elsif,
38
- SyntaxTree::Else,
39
- SyntaxTree::EmbDoc,
40
- SyntaxTree::Ensure,
41
- SyntaxTree::For,
42
- SyntaxTree::HashLiteral,
43
- SyntaxTree::Heredoc,
44
- SyntaxTree::HeredocBeg,
45
- SyntaxTree::HshPtn,
46
- SyntaxTree::IfNode,
47
- SyntaxTree::In,
48
- SyntaxTree::Lambda,
49
- SyntaxTree::MethodAddBlock,
50
- SyntaxTree::ModuleDeclaration,
51
- SyntaxTree::Params,
52
- SyntaxTree::Rescue,
53
- SyntaxTree::RescueEx,
54
- SyntaxTree::StringConcat,
55
- SyntaxTree::StringLiteral,
56
- SyntaxTree::UnlessNode,
57
- SyntaxTree::UntilNode,
58
- SyntaxTree::VCall,
59
- SyntaxTree::When,
60
- SyntaxTree::WhileNode,
28
+ YARP::ArgumentsNode,
29
+ YARP::ArrayNode,
30
+ YARP::AssocNode,
31
+ YARP::BeginNode,
32
+ YARP::BlockNode,
33
+ YARP::CallNode,
34
+ YARP::CaseNode,
35
+ YARP::ClassNode,
36
+ YARP::DefNode,
37
+ YARP::ElseNode,
38
+ YARP::EnsureNode,
39
+ YARP::ForNode,
40
+ YARP::HashNode,
41
+ YARP::HashPatternNode,
42
+ YARP::IfNode,
43
+ YARP::InNode,
44
+ YARP::InterpolatedStringNode,
45
+ YARP::KeywordHashNode,
46
+ YARP::LambdaNode,
47
+ YARP::LocalVariableWriteNode,
48
+ YARP::ModuleNode,
49
+ YARP::ParametersNode,
50
+ YARP::RescueNode,
51
+ YARP::StringConcatNode,
52
+ YARP::StringNode,
53
+ YARP::UnlessNode,
54
+ YARP::UntilNode,
55
+ YARP::WhenNode,
56
+ YARP::WhileNode,
61
57
  ].freeze,
62
- T::Array[T.class_of(SyntaxTree::Node)],
58
+ T::Array[T.class_of(YARP::Node)],
63
59
  )
64
60
 
65
61
  sig { params(document: Document).void }
@@ -72,19 +68,23 @@ module RubyLsp
72
68
 
73
69
  sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
74
70
  def run
75
- visit(@document.tree) if @document.parsed?
71
+ visit(@document.tree)
76
72
  @ranges.reverse!
77
73
  end
78
74
 
79
75
  private
80
76
 
81
- sig { override.params(node: T.nilable(SyntaxTree::Node)).void }
77
+ sig { override.params(node: T.nilable(YARP::Node)).void }
82
78
  def visit(node)
83
79
  return if node.nil?
84
80
 
85
- range = create_selection_range(node.location, @stack.last)
86
-
81
+ range = if node.is_a?(YARP::InterpolatedStringNode)
82
+ create_heredoc_selection_range(node, @stack.last)
83
+ else
84
+ create_selection_range(node.location, @stack.last)
85
+ end
87
86
  @ranges << range
87
+
88
88
  return if node.child_nodes.empty?
89
89
 
90
90
  @stack << range if NODES_THAT_CAN_BE_PARENTS.include?(node.class)
@@ -94,11 +94,36 @@ module RubyLsp
94
94
 
95
95
  sig do
96
96
  params(
97
- location: SyntaxTree::Location,
97
+ node: YARP::InterpolatedStringNode,
98
+ parent: T.nilable(Support::SelectionRange),
99
+ ).returns(Support::SelectionRange)
100
+ end
101
+ def create_heredoc_selection_range(node, parent)
102
+ opening_loc = node.opening_loc || node.location
103
+ closing_loc = node.closing_loc || node.location
104
+
105
+ RubyLsp::Requests::Support::SelectionRange.new(
106
+ range: Interface::Range.new(
107
+ start: Interface::Position.new(
108
+ line: opening_loc.start_line - 1,
109
+ character: opening_loc.start_column,
110
+ ),
111
+ end: Interface::Position.new(
112
+ line: closing_loc.end_line - 1,
113
+ character: closing_loc.end_column,
114
+ ),
115
+ ),
116
+ parent: parent,
117
+ )
118
+ end
119
+
120
+ sig do
121
+ params(
122
+ location: YARP::Location,
98
123
  parent: T.nilable(Support::SelectionRange),
99
124
  ).returns(Support::SelectionRange)
100
125
  end
101
- def create_selection_range(location, parent = nil)
126
+ def create_selection_range(location, parent)
102
127
  RubyLsp::Requests::Support::SelectionRange.new(
103
128
  range: Interface::Range.new(
104
129
  start: Interface::Position.new(
@@ -83,7 +83,7 @@ module RubyLsp
83
83
  class SemanticToken
84
84
  extend T::Sig
85
85
 
86
- sig { returns(SyntaxTree::Location) }
86
+ sig { returns(YARP::Location) }
87
87
  attr_reader :location
88
88
 
89
89
  sig { returns(Integer) }
@@ -95,7 +95,7 @@ module RubyLsp
95
95
  sig { returns(T::Array[Integer]) }
96
96
  attr_reader :modifier
97
97
 
98
- sig { params(location: SyntaxTree::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
98
+ sig { params(location: YARP::Location, length: Integer, type: Integer, modifier: T::Array[Integer]).void }
99
99
  def initialize(location:, length:, type:, modifier:)
100
100
  @location = location
101
101
  @length = length
@@ -120,56 +120,60 @@ module RubyLsp
120
120
  @_response = T.let([], ResponseType)
121
121
  @range = range
122
122
  @special_methods = T.let(nil, T.nilable(T::Array[String]))
123
+ @current_scope = T.let(ParameterScope.new, ParameterScope)
123
124
 
124
125
  emitter.register(
125
126
  self,
126
- :after_binary,
127
- :on_block_var,
128
127
  :on_call,
129
128
  :on_class,
130
- :on_command,
131
- :on_command_call,
132
- :on_const,
133
129
  :on_def,
134
- :on_field,
135
- :on_kw,
136
- :on_lambda_var,
130
+ :after_def,
131
+ :on_block,
132
+ :after_block,
133
+ :on_self,
137
134
  :on_module,
138
- :on_params,
139
- :on_var_field,
140
- :on_var_ref,
141
- :on_vcall,
135
+ :on_local_variable_write,
136
+ :on_local_variable_read,
137
+ :on_block_parameter,
138
+ :on_keyword_parameter,
139
+ :on_keyword_rest_parameter,
140
+ :on_optional_parameter,
141
+ :on_required_parameter,
142
+ :on_rest_parameter,
143
+ :on_constant_read,
144
+ :on_constant_write,
145
+ :on_constant_and_write,
146
+ :on_constant_operator_write,
147
+ :on_constant_or_write,
148
+ :on_constant_target,
149
+ :on_local_variable_and_write,
150
+ :on_local_variable_operator_write,
151
+ :on_local_variable_or_write,
152
+ :on_local_variable_target,
153
+ :on_block_local_variable,
142
154
  )
143
155
  end
144
156
 
145
- sig { params(node: SyntaxTree::CallNode).void }
157
+ sig { params(node: YARP::CallNode).void }
146
158
  def on_call(node)
147
159
  return unless visible?(node, @range)
148
160
 
149
161
  message = node.message
150
- if !message.is_a?(Symbol) && !special_method?(message.value)
151
- type = Support::Sorbet.annotation?(node) ? :type : :method
152
- add_token(message.location, type)
153
- end
154
- end
155
-
156
- sig { params(node: SyntaxTree::Command).void }
157
- def on_command(node)
158
- return unless visible?(node, @range)
162
+ return unless message
159
163
 
160
- add_token(node.message.location, :method) unless special_method?(node.message.value)
161
- end
164
+ # We can't push a semantic token for [] and []= because the argument inside the brackets is a part of
165
+ # the message_loc
166
+ return if message.start_with?("[") && (message.end_with?("]") || message.end_with?("]="))
162
167
 
163
- sig { params(node: SyntaxTree::CommandCall).void }
164
- def on_command_call(node)
165
- return unless visible?(node, @range)
168
+ return process_regexp_locals(node) if message == "=~"
169
+ return if special_method?(message)
166
170
 
167
- message = node.message
168
- add_token(message.location, :method) unless message.is_a?(Symbol)
171
+ type = Support::Sorbet.annotation?(node) ? :type : :method
172
+ add_token(T.must(node.message_loc), type)
169
173
  end
170
174
 
171
- sig { params(node: SyntaxTree::Const).void }
172
- def on_const(node)
175
+ sig { params(node: YARP::ConstantReadNode).void }
176
+ def on_constant_read(node)
173
177
  return unless visible?(node, @range)
174
178
  # When finding a module or class definition, we will have already pushed a token related to this constant. We
175
179
  # need to look at the previous two tokens and if they match this locatione exactly, avoid pushing another token
@@ -179,153 +183,199 @@ module RubyLsp
179
183
  add_token(node.location, :namespace)
180
184
  end
181
185
 
182
- sig { params(node: SyntaxTree::DefNode).void }
183
- def on_def(node)
186
+ sig { params(node: YARP::ConstantWriteNode).void }
187
+ def on_constant_write(node)
184
188
  return unless visible?(node, @range)
185
189
 
186
- add_token(node.name.location, :method, [:declaration])
190
+ add_token(node.name_loc, :namespace)
187
191
  end
188
192
 
189
- sig { params(node: SyntaxTree::Kw).void }
190
- def on_kw(node)
193
+ sig { params(node: YARP::ConstantAndWriteNode).void }
194
+ def on_constant_and_write(node)
191
195
  return unless visible?(node, @range)
192
196
 
193
- case node.value
194
- when "self"
195
- add_token(node.location, :variable, [:default_library])
196
- end
197
+ add_token(node.name_loc, :namespace)
197
198
  end
198
199
 
199
- sig { params(node: SyntaxTree::Params).void }
200
- def on_params(node)
200
+ sig { params(node: YARP::ConstantOperatorWriteNode).void }
201
+ def on_constant_operator_write(node)
201
202
  return unless visible?(node, @range)
202
203
 
203
- node.keywords.each do |keyword, *|
204
- location = keyword.location
205
- add_token(location_without_colon(location), :parameter)
206
- end
204
+ add_token(node.name_loc, :namespace)
205
+ end
207
206
 
208
- node.requireds.each do |required|
209
- add_token(required.location, :parameter)
210
- end
207
+ sig { params(node: YARP::ConstantOrWriteNode).void }
208
+ def on_constant_or_write(node)
209
+ return unless visible?(node, @range)
211
210
 
212
- rest = node.keyword_rest
213
- if rest && !rest.is_a?(SyntaxTree::ArgsForward) && !rest.is_a?(Symbol)
214
- name = rest.name
215
- add_token(name.location, :parameter) if name
216
- end
211
+ add_token(node.name_loc, :namespace)
212
+ end
213
+
214
+ sig { params(node: YARP::ConstantTargetNode).void }
215
+ def on_constant_target(node)
216
+ return unless visible?(node, @range)
217
+
218
+ add_token(node.location, :namespace)
217
219
  end
218
220
 
219
- sig { params(node: SyntaxTree::Field).void }
220
- def on_field(node)
221
+ sig { params(node: YARP::DefNode).void }
222
+ def on_def(node)
223
+ @current_scope = ParameterScope.new(@current_scope)
221
224
  return unless visible?(node, @range)
222
225
 
223
- add_token(node.name.location, :method)
226
+ add_token(node.name_loc, :method, [:declaration])
227
+ end
228
+
229
+ sig { params(node: YARP::DefNode).void }
230
+ def after_def(node)
231
+ @current_scope = T.must(@current_scope.parent)
232
+ end
233
+
234
+ sig { params(node: YARP::BlockNode).void }
235
+ def on_block(node)
236
+ @current_scope = ParameterScope.new(@current_scope)
224
237
  end
225
238
 
226
- sig { params(node: SyntaxTree::VarField).void }
227
- def on_var_field(node)
239
+ sig { params(node: YARP::BlockNode).void }
240
+ def after_block(node)
241
+ @current_scope = T.must(@current_scope.parent)
242
+ end
243
+
244
+ sig { params(node: YARP::BlockLocalVariableNode).void }
245
+ def on_block_local_variable(node)
246
+ add_token(node.location, :variable)
247
+ end
248
+
249
+ sig { params(node: YARP::BlockParameterNode).void }
250
+ def on_block_parameter(node)
251
+ name = node.name
252
+ @current_scope << name.to_sym if name
253
+ end
254
+
255
+ sig { params(node: YARP::KeywordParameterNode).void }
256
+ def on_keyword_parameter(node)
257
+ name = node.name
258
+ @current_scope << name.to_s.delete_suffix(":").to_sym if name
259
+
228
260
  return unless visible?(node, @range)
229
261
 
230
- value = node.value
262
+ location = node.name_loc
263
+ add_token(location.copy(length: location.length - 1), :parameter)
264
+ end
231
265
 
232
- case value
233
- when SyntaxTree::Ident
234
- type = type_for_local(value)
235
- add_token(value.location, type)
266
+ sig { params(node: YARP::KeywordRestParameterNode).void }
267
+ def on_keyword_rest_parameter(node)
268
+ name = node.name
269
+
270
+ if name
271
+ @current_scope << name.to_sym
272
+
273
+ add_token(T.must(node.name_loc), :parameter) if visible?(node, @range)
236
274
  end
237
275
  end
238
276
 
239
- sig { params(node: SyntaxTree::VarRef).void }
240
- def on_var_ref(node)
277
+ sig { params(node: YARP::OptionalParameterNode).void }
278
+ def on_optional_parameter(node)
279
+ @current_scope << node.name
280
+ return unless visible?(node, @range)
281
+
282
+ add_token(node.name_loc, :parameter)
283
+ end
284
+
285
+ sig { params(node: YARP::RequiredParameterNode).void }
286
+ def on_required_parameter(node)
287
+ @current_scope << node.name
241
288
  return unless visible?(node, @range)
242
289
 
243
- value = node.value
290
+ add_token(node.location, :parameter)
291
+ end
292
+
293
+ sig { params(node: YARP::RestParameterNode).void }
294
+ def on_rest_parameter(node)
295
+ name = node.name
244
296
 
245
- case value
246
- when SyntaxTree::Ident
247
- type = type_for_local(value)
248
- add_token(value.location, type)
297
+ if name
298
+ @current_scope << name.to_sym
299
+
300
+ add_token(T.must(node.name_loc), :parameter) if visible?(node, @range)
249
301
  end
250
302
  end
251
303
 
252
- # All block locals are variables. E.g.: [].each do |x; block_local|
253
- sig { params(node: SyntaxTree::BlockVar).void }
254
- def on_block_var(node)
255
- node.locals.each { |local| add_token(local.location, :variable) }
304
+ sig { params(node: YARP::SelfNode).void }
305
+ def on_self(node)
306
+ return unless visible?(node, @range)
307
+
308
+ add_token(node.location, :variable, [:default_library])
256
309
  end
257
310
 
258
- # All lambda locals are variables. E.g.: ->(x; lambda_local) {}
259
- sig { params(node: SyntaxTree::LambdaVar).void }
260
- def on_lambda_var(node)
261
- node.locals.each { |local| add_token(local.location, :variable) }
311
+ sig { params(node: YARP::LocalVariableWriteNode).void }
312
+ def on_local_variable_write(node)
313
+ return unless visible?(node, @range)
314
+
315
+ add_token(node.name_loc, @current_scope.type_for(node.name))
262
316
  end
263
317
 
264
- sig { params(node: SyntaxTree::VCall).void }
265
- def on_vcall(node)
318
+ sig { params(node: YARP::LocalVariableReadNode).void }
319
+ def on_local_variable_read(node)
266
320
  return unless visible?(node, @range)
267
321
 
268
- # A VCall may exist as a local in the current_scope. This happens when used named capture groups in a regexp
269
- ident = node.value
270
- value = ident.value
271
- local = @emitter.current_scope.find_local(value)
272
- return if local.nil? && special_method?(value)
273
-
274
- type = if local
275
- :variable
276
- elsif Support::Sorbet.annotation?(node)
277
- :type
278
- else
279
- :method
322
+ # Numbered parameters
323
+ if /_\d+/.match?(node.name)
324
+ add_token(node.location, :parameter)
325
+ return
280
326
  end
281
327
 
282
- add_token(node.value.location, type)
328
+ add_token(node.location, @current_scope.type_for(node.name))
283
329
  end
284
330
 
285
- sig { params(node: SyntaxTree::Binary).void }
286
- def after_binary(node)
287
- # You can only capture local variables with regexp by using the =~ operator
288
- return unless node.operator == :=~
331
+ sig { params(node: YARP::LocalVariableAndWriteNode).void }
332
+ def on_local_variable_and_write(node)
333
+ return unless visible?(node, @range)
289
334
 
290
- left = node.left
291
- # The regexp needs to be on the left hand side of the =~ for local variable capture
292
- return unless left.is_a?(SyntaxTree::RegexpLiteral)
335
+ add_token(node.name_loc, @current_scope.type_for(node.name))
336
+ end
293
337
 
294
- parts = left.parts
295
- return unless parts.one?
338
+ sig { params(node: YARP::LocalVariableOperatorWriteNode).void }
339
+ def on_local_variable_operator_write(node)
340
+ return unless visible?(node, @range)
296
341
 
297
- content = parts.first
298
- return unless content.is_a?(SyntaxTree::TStringContent)
342
+ add_token(node.name_loc, @current_scope.type_for(node.name))
343
+ end
299
344
 
300
- # For each capture name we find in the regexp, look for a local in the current_scope
301
- Regexp.new(content.value, Regexp::FIXEDENCODING).names.each do |name|
302
- local = @emitter.current_scope.find_local(name)
303
- next unless local
345
+ sig { params(node: YARP::LocalVariableOrWriteNode).void }
346
+ def on_local_variable_or_write(node)
347
+ return unless visible?(node, @range)
304
348
 
305
- local.definitions.each { |definition| add_token(definition, :variable) }
306
- end
349
+ add_token(node.name_loc, @current_scope.type_for(node.name))
350
+ end
351
+
352
+ sig { params(node: YARP::LocalVariableTargetNode).void }
353
+ def on_local_variable_target(node)
354
+ return unless visible?(node, @range)
355
+
356
+ add_token(node.location, @current_scope.type_for(node.name))
307
357
  end
308
358
 
309
- sig { params(node: SyntaxTree::ClassDeclaration).void }
359
+ sig { params(node: YARP::ClassNode).void }
310
360
  def on_class(node)
311
361
  return unless visible?(node, @range)
312
362
 
313
- add_token(node.constant.location, :class, [:declaration])
363
+ add_token(node.constant_path.location, :class, [:declaration])
314
364
 
315
365
  superclass = node.superclass
316
366
  add_token(superclass.location, :class) if superclass
317
367
  end
318
368
 
319
- sig { params(node: SyntaxTree::ModuleDeclaration).void }
369
+ sig { params(node: YARP::ModuleNode).void }
320
370
  def on_module(node)
321
371
  return unless visible?(node, @range)
322
372
 
323
- add_token(node.constant.location, :namespace, [:declaration])
373
+ add_token(node.constant_path.location, :namespace, [:declaration])
324
374
  end
325
375
 
326
- sig { params(location: SyntaxTree::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
376
+ sig { params(location: YARP::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
327
377
  def add_token(location, type, modifiers = [])
328
- length = location.end_char - location.start_char
378
+ length = location.end_offset - location.start_offset
329
379
  modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
330
380
  @_response.push(
331
381
  SemanticToken.new(
@@ -339,38 +389,30 @@ module RubyLsp
339
389
 
340
390
  private
341
391
 
342
- # Exclude the ":" symbol at the end of a location
343
- # We use it on keyword parameters to be consistent
344
- # with the rest of the parameters
345
- sig { params(location: T.untyped).returns(SyntaxTree::Location) }
346
- def location_without_colon(location)
347
- SyntaxTree::Location.new(
348
- start_line: location.start_line,
349
- start_column: location.start_column,
350
- start_char: location.start_char,
351
- end_char: location.end_char - 1,
352
- end_column: location.end_column - 1,
353
- end_line: location.end_line,
354
- )
355
- end
356
-
357
- # Textmate provides highlighting for a subset
358
- # of these special Ruby-specific methods.
359
- # We want to utilize that highlighting, so we
360
- # avoid making a semantic token for it.
392
+ # Textmate provides highlighting for a subset of these special Ruby-specific methods. We want to utilize that
393
+ # highlighting, so we avoid making a semantic token for it.
361
394
  sig { params(method_name: String).returns(T::Boolean) }
362
395
  def special_method?(method_name)
363
396
  SPECIAL_RUBY_METHODS.include?(method_name)
364
397
  end
365
398
 
366
- sig { params(value: SyntaxTree::Ident).returns(Symbol) }
367
- def type_for_local(value)
368
- local = @emitter.current_scope.find_local(value.value)
399
+ sig { params(node: YARP::CallNode).void }
400
+ def process_regexp_locals(node)
401
+ receiver = node.receiver
402
+
403
+ # The regexp needs to be the receiver of =~ for local variable capture
404
+ return unless receiver.is_a?(YARP::RegularExpressionNode)
405
+
406
+ content = receiver.content
407
+ loc = receiver.content_loc
408
+
409
+ # For each capture name we find in the regexp, look for a local in the current_scope
410
+ Regexp.new(content, Regexp::FIXEDENCODING).names.each do |name|
411
+ # The +3 is to compensate for the "(?<" part of the capture name
412
+ capture_name_offset = T.must(content.index("(?<#{name}>")) + 3
413
+ local_var_loc = loc.copy(start_offset: loc.start_offset + capture_name_offset, length: name.length)
369
414
 
370
- if local.nil? || local.type == :variable
371
- :variable
372
- else
373
- :parameter
415
+ add_token(local_var_loc, @current_scope.type_for(name))
374
416
  end
375
417
  end
376
418
  end
@@ -29,7 +29,6 @@ module RubyLsp
29
29
 
30
30
  sig { override.returns(String) }
31
31
  def run
32
- return "Document contains syntax error" if @document.syntax_error?
33
32
  return ast_for_range if @range
34
33
 
35
34
  output_string = +""
@@ -47,7 +46,7 @@ module RubyLsp
47
46
  start_char = scanner.find_char_position(range[:start])
48
47
  end_char = scanner.find_char_position(range[:end])
49
48
 
50
- queue = T.cast(@document.tree, SyntaxTree::Program).statements.body.dup
49
+ queue = @document.tree.statements.body.dup
51
50
  found_nodes = []
52
51
 
53
52
  until queue.empty?
@@ -58,10 +57,10 @@ module RubyLsp
58
57
 
59
58
  # If the node is fully covered by the selection, then we found one of the nodes to be displayed and don't want
60
59
  # to continue descending into its children
61
- if (start_char..end_char).cover?(loc.start_char..loc.end_char)
60
+ if (start_char..end_char).cover?(loc.start_offset..loc.end_offset)
62
61
  found_nodes << node
63
62
  else
64
- queue.unshift(*node.child_nodes)
63
+ T.unsafe(queue).unshift(*node.child_nodes)
65
64
  end
66
65
  end
67
66
 
@@ -17,28 +17,29 @@ module RubyLsp
17
17
  @receiver = receiver
18
18
  end
19
19
 
20
- sig { returns(T.any(Integer, T::Range[Integer])) }
21
- attr_reader :arity
20
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
21
+ def match?(node)
22
+ receiver_matches?(node) && arity_matches?(node)
23
+ end
22
24
 
23
- sig { returns(T::Boolean) }
24
- attr_reader :receiver
25
+ private
25
26
 
26
- sig { params(arity: T.any(T::Range[Integer], Integer)).returns(T::Boolean) }
27
- def supports_arity?(arity)
28
- if @arity.is_a?(Integer)
29
- @arity == arity
30
- elsif @arity.is_a?(Range)
31
- @arity.cover?(arity)
32
- else
33
- T.absurd(@arity)
34
- end
27
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
28
+ def receiver_matches?(node)
29
+ node_receiver = node.receiver
30
+ (node_receiver && @receiver && node_receiver.location.slice == "T") || (!node_receiver && !@receiver)
35
31
  end
36
32
 
37
- sig { params(receiver: T.nilable(String)).returns(T::Boolean) }
38
- def supports_receiver?(receiver)
39
- return receiver.nil? || receiver.empty? if @receiver == false
33
+ sig { params(node: YARP::CallNode).returns(T::Boolean) }
34
+ def arity_matches?(node)
35
+ node_arity = node.arguments&.arguments&.size || 0
40
36
 
41
- receiver == "T"
37
+ case @arity
38
+ when Integer
39
+ node_arity == @arity
40
+ when Range
41
+ @arity.cover?(node_arity)
42
+ end
42
43
  end
43
44
  end
44
45
  end