ruby-lsp 0.10.1 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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 +35 -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