ruby-lsp 0.23.11 → 0.26.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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +45 -22
  7. data/exe/ruby-lsp-test-exec +6 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +107 -236
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +166 -281
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  22. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  23. data/lib/ruby_indexer/test/configuration_test.rb +49 -9
  24. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  25. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  26. data/lib/ruby_indexer/test/index_test.rb +185 -135
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
  28. data/lib/ruby_indexer/test/method_test.rb +166 -123
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  32. data/lib/ruby_indexer/test/test_case.rb +9 -3
  33. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  34. data/lib/ruby_lsp/addon.rb +88 -86
  35. data/lib/ruby_lsp/base_server.rb +59 -54
  36. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  37. data/lib/ruby_lsp/document.rb +205 -104
  38. data/lib/ruby_lsp/erb_document.rb +45 -47
  39. data/lib/ruby_lsp/global_state.rb +73 -57
  40. data/lib/ruby_lsp/internal.rb +8 -3
  41. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  42. data/lib/ruby_lsp/listeners/completion.rb +81 -76
  43. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  44. data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
  45. data/lib/ruby_lsp/listeners/document_link.rb +50 -70
  46. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  47. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  48. data/lib/ruby_lsp/listeners/hover.rb +107 -115
  49. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  50. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  51. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  52. data/lib/ruby_lsp/listeners/spec_style.rb +214 -0
  53. data/lib/ruby_lsp/listeners/test_discovery.rb +92 -0
  54. data/lib/ruby_lsp/listeners/test_style.rb +205 -95
  55. data/lib/ruby_lsp/node_context.rb +12 -39
  56. data/lib/ruby_lsp/rbs_document.rb +10 -11
  57. data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
  58. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  59. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  60. data/lib/ruby_lsp/requests/completion.rb +8 -21
  61. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  62. data/lib/ruby_lsp/requests/definition.rb +8 -20
  63. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  64. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  65. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  66. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  67. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  68. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  69. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  70. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +85 -0
  71. data/lib/ruby_lsp/requests/hover.rb +12 -25
  72. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  73. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  74. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  75. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  76. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  77. data/lib/ruby_lsp/requests/references.rb +17 -57
  78. data/lib/ruby_lsp/requests/rename.rb +27 -51
  79. data/lib/ruby_lsp/requests/request.rb +13 -25
  80. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  81. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  82. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  83. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  84. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  85. data/lib/ruby_lsp/requests/support/common.rb +16 -58
  86. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  87. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  88. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  89. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
  90. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  91. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  92. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  93. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  94. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  95. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  96. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  97. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  98. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  99. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  100. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  101. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  102. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  103. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  104. data/lib/ruby_lsp/ruby_document.rb +32 -98
  105. data/lib/ruby_lsp/scope.rb +7 -11
  106. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  107. data/lib/ruby_lsp/server.rb +303 -196
  108. data/lib/ruby_lsp/setup_bundler.rb +121 -82
  109. data/lib/ruby_lsp/static_docs.rb +12 -7
  110. data/lib/ruby_lsp/store.rb +21 -49
  111. data/lib/ruby_lsp/test_helper.rb +3 -16
  112. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +233 -0
  113. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  114. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  115. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  116. data/lib/ruby_lsp/utils.rb +138 -93
  117. data/static_docs/break.md +103 -0
  118. metadata +14 -20
  119. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -4,7 +4,6 @@
4
4
  module RubyLsp
5
5
  module Listeners
6
6
  class Completion
7
- extend T::Sig
8
7
  include Requests::Support::Common
9
8
 
10
9
  KEYWORDS = [
@@ -51,17 +50,7 @@ module RubyLsp
51
50
  "__LINE__",
52
51
  ].freeze
53
52
 
54
- sig do
55
- params(
56
- response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
57
- global_state: GlobalState,
58
- node_context: NodeContext,
59
- sorbet_level: RubyDocument::SorbetLevel,
60
- dispatcher: Prism::Dispatcher,
61
- uri: URI::Generic,
62
- trigger_character: T.nilable(String),
63
- ).void
64
- end
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
65
54
  def initialize( # rubocop:disable Metrics/ParameterLists
66
55
  response_builder,
67
56
  global_state,
@@ -73,8 +62,8 @@ module RubyLsp
73
62
  )
74
63
  @response_builder = response_builder
75
64
  @global_state = global_state
76
- @index = T.let(global_state.index, RubyIndexer::Index)
77
- @type_inferrer = T.let(global_state.type_inferrer, TypeInferrer)
65
+ @index = global_state.index #: RubyIndexer::Index
66
+ @type_inferrer = global_state.type_inferrer #: TypeInferrer
78
67
  @node_context = node_context
79
68
  @sorbet_level = sorbet_level
80
69
  @uri = uri
@@ -107,11 +96,11 @@ module RubyLsp
107
96
  end
108
97
 
109
98
  # Handle completion on regular constant references (e.g. `Bar`)
110
- sig { params(node: Prism::ConstantReadNode).void }
99
+ #: (Prism::ConstantReadNode node) -> void
111
100
  def on_constant_read_node_enter(node)
112
101
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
113
102
  # no sigil, Sorbet will still provide completion for constants
114
- return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
103
+ return unless @sorbet_level.ignore?
115
104
 
116
105
  name = RubyIndexer::Index.constant_name(node)
117
106
  return if name.nil?
@@ -119,7 +108,8 @@ module RubyLsp
119
108
  range = range_from_location(node.location)
120
109
  candidates = @index.constant_completion_candidates(name, @node_context.nesting)
121
110
  candidates.each do |entries|
122
- complete_name = T.must(entries.first).name
111
+ complete_name = entries.first #: as !nil
112
+ .name
123
113
  @response_builder << build_entry_completion(
124
114
  complete_name,
125
115
  name,
@@ -131,11 +121,11 @@ module RubyLsp
131
121
  end
132
122
 
133
123
  # Handle completion on namespaced constant references (e.g. `Foo::Bar`)
134
- sig { params(node: Prism::ConstantPathNode).void }
124
+ #: (Prism::ConstantPathNode node) -> void
135
125
  def on_constant_path_node_enter(node)
136
126
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
137
127
  # no sigil, Sorbet will still provide completion for constants
138
- return if @sorbet_level != RubyDocument::SorbetLevel::Ignore
128
+ return unless @sorbet_level.ignore?
139
129
 
140
130
  name = begin
141
131
  node.full_name
@@ -149,11 +139,11 @@ module RubyLsp
149
139
  constant_path_completion(name, range_from_location(node.location))
150
140
  end
151
141
 
152
- sig { params(node: Prism::CallNode).void }
142
+ #: (Prism::CallNode node) -> void
153
143
  def on_call_node_enter(node)
154
144
  # The only scenario where Sorbet doesn't provide constant completion is on ignored files. Even if the file has
155
145
  # no sigil, Sorbet will still provide completion for constants
156
- if @sorbet_level == RubyDocument::SorbetLevel::Ignore
146
+ if @sorbet_level.ignore?
157
147
  receiver = node.receiver
158
148
 
159
149
  # When writing `Foo::`, the AST assigns a method call node (because you can use that syntax to invoke
@@ -166,7 +156,7 @@ module RubyLsp
166
156
 
167
157
  if name
168
158
  start_loc = node.location
169
- end_loc = T.must(node.call_operator_loc)
159
+ end_loc = node.call_operator_loc #: as !nil
170
160
 
171
161
  constant_path_completion(
172
162
  "#{name}::",
@@ -193,99 +183,99 @@ module RubyLsp
193
183
  end
194
184
  end
195
185
 
196
- sig { params(node: Prism::GlobalVariableAndWriteNode).void }
186
+ #: (Prism::GlobalVariableAndWriteNode node) -> void
197
187
  def on_global_variable_and_write_node_enter(node)
198
188
  handle_global_variable_completion(node.name.to_s, node.name_loc)
199
189
  end
200
190
 
201
- sig { params(node: Prism::GlobalVariableOperatorWriteNode).void }
191
+ #: (Prism::GlobalVariableOperatorWriteNode node) -> void
202
192
  def on_global_variable_operator_write_node_enter(node)
203
193
  handle_global_variable_completion(node.name.to_s, node.name_loc)
204
194
  end
205
195
 
206
- sig { params(node: Prism::GlobalVariableOrWriteNode).void }
196
+ #: (Prism::GlobalVariableOrWriteNode node) -> void
207
197
  def on_global_variable_or_write_node_enter(node)
208
198
  handle_global_variable_completion(node.name.to_s, node.name_loc)
209
199
  end
210
200
 
211
- sig { params(node: Prism::GlobalVariableReadNode).void }
201
+ #: (Prism::GlobalVariableReadNode node) -> void
212
202
  def on_global_variable_read_node_enter(node)
213
203
  handle_global_variable_completion(node.name.to_s, node.location)
214
204
  end
215
205
 
216
- sig { params(node: Prism::GlobalVariableTargetNode).void }
206
+ #: (Prism::GlobalVariableTargetNode node) -> void
217
207
  def on_global_variable_target_node_enter(node)
218
208
  handle_global_variable_completion(node.name.to_s, node.location)
219
209
  end
220
210
 
221
- sig { params(node: Prism::GlobalVariableWriteNode).void }
211
+ #: (Prism::GlobalVariableWriteNode node) -> void
222
212
  def on_global_variable_write_node_enter(node)
223
213
  handle_global_variable_completion(node.name.to_s, node.name_loc)
224
214
  end
225
215
 
226
- sig { params(node: Prism::InstanceVariableReadNode).void }
216
+ #: (Prism::InstanceVariableReadNode node) -> void
227
217
  def on_instance_variable_read_node_enter(node)
228
218
  handle_instance_variable_completion(node.name.to_s, node.location)
229
219
  end
230
220
 
231
- sig { params(node: Prism::InstanceVariableWriteNode).void }
221
+ #: (Prism::InstanceVariableWriteNode node) -> void
232
222
  def on_instance_variable_write_node_enter(node)
233
223
  handle_instance_variable_completion(node.name.to_s, node.name_loc)
234
224
  end
235
225
 
236
- sig { params(node: Prism::InstanceVariableAndWriteNode).void }
226
+ #: (Prism::InstanceVariableAndWriteNode node) -> void
237
227
  def on_instance_variable_and_write_node_enter(node)
238
228
  handle_instance_variable_completion(node.name.to_s, node.name_loc)
239
229
  end
240
230
 
241
- sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
231
+ #: (Prism::InstanceVariableOperatorWriteNode node) -> void
242
232
  def on_instance_variable_operator_write_node_enter(node)
243
233
  handle_instance_variable_completion(node.name.to_s, node.name_loc)
244
234
  end
245
235
 
246
- sig { params(node: Prism::InstanceVariableOrWriteNode).void }
236
+ #: (Prism::InstanceVariableOrWriteNode node) -> void
247
237
  def on_instance_variable_or_write_node_enter(node)
248
238
  handle_instance_variable_completion(node.name.to_s, node.name_loc)
249
239
  end
250
240
 
251
- sig { params(node: Prism::InstanceVariableTargetNode).void }
241
+ #: (Prism::InstanceVariableTargetNode node) -> void
252
242
  def on_instance_variable_target_node_enter(node)
253
243
  handle_instance_variable_completion(node.name.to_s, node.location)
254
244
  end
255
245
 
256
- sig { params(node: Prism::ClassVariableAndWriteNode).void }
246
+ #: (Prism::ClassVariableAndWriteNode node) -> void
257
247
  def on_class_variable_and_write_node_enter(node)
258
248
  handle_class_variable_completion(node.name.to_s, node.name_loc)
259
249
  end
260
250
 
261
- sig { params(node: Prism::ClassVariableOperatorWriteNode).void }
251
+ #: (Prism::ClassVariableOperatorWriteNode node) -> void
262
252
  def on_class_variable_operator_write_node_enter(node)
263
253
  handle_class_variable_completion(node.name.to_s, node.name_loc)
264
254
  end
265
255
 
266
- sig { params(node: Prism::ClassVariableOrWriteNode).void }
256
+ #: (Prism::ClassVariableOrWriteNode node) -> void
267
257
  def on_class_variable_or_write_node_enter(node)
268
258
  handle_class_variable_completion(node.name.to_s, node.name_loc)
269
259
  end
270
260
 
271
- sig { params(node: Prism::ClassVariableTargetNode).void }
261
+ #: (Prism::ClassVariableTargetNode node) -> void
272
262
  def on_class_variable_target_node_enter(node)
273
263
  handle_class_variable_completion(node.name.to_s, node.location)
274
264
  end
275
265
 
276
- sig { params(node: Prism::ClassVariableReadNode).void }
266
+ #: (Prism::ClassVariableReadNode node) -> void
277
267
  def on_class_variable_read_node_enter(node)
278
268
  handle_class_variable_completion(node.name.to_s, node.location)
279
269
  end
280
270
 
281
- sig { params(node: Prism::ClassVariableWriteNode).void }
271
+ #: (Prism::ClassVariableWriteNode node) -> void
282
272
  def on_class_variable_write_node_enter(node)
283
273
  handle_class_variable_completion(node.name.to_s, node.name_loc)
284
274
  end
285
275
 
286
276
  private
287
277
 
288
- sig { params(name: String, range: Interface::Range).void }
278
+ #: (String name, Interface::Range range) -> void
289
279
  def constant_path_completion(name, range)
290
280
  top_level_reference = if name.start_with?("::")
291
281
  name = name.delete_prefix("::")
@@ -307,7 +297,9 @@ module RubyLsp
307
297
  namespace_entries = @index.resolve(aliased_namespace, nesting)
308
298
  return unless namespace_entries
309
299
 
310
- real_namespace = @index.follow_aliased_namespace(T.must(namespace_entries.first).name)
300
+ namespace_name = namespace_entries.first #: as !nil
301
+ .name
302
+ real_namespace = @index.follow_aliased_namespace(namespace_name)
311
303
 
312
304
  candidates = @index.constant_completion_candidates(
313
305
  "#{real_namespace}::#{incomplete_name}",
@@ -316,7 +308,7 @@ module RubyLsp
316
308
  candidates.each do |entries|
317
309
  # The only time we may have a private constant reference from outside of the namespace is if we're dealing
318
310
  # with ConstantPath and the entry name doesn't start with the current nesting
319
- first_entry = T.must(entries.first)
311
+ first_entry = entries.first #: as !nil
320
312
  next if first_entry.private? && !first_entry.name.start_with?("#{nesting}::")
321
313
 
322
314
  entry_name = first_entry.name
@@ -335,12 +327,12 @@ module RubyLsp
335
327
  name,
336
328
  range,
337
329
  entries,
338
- top_level_reference || top_level?(T.must(entries.first).name),
330
+ top_level_reference || top_level?(first_entry.name),
339
331
  )
340
332
  end
341
333
  end
342
334
 
343
- sig { params(name: String, location: Prism::Location).void }
335
+ #: (String name, Prism::Location location) -> void
344
336
  def handle_global_variable_completion(name, location)
345
337
  candidates = @index.prefix_search(name)
346
338
 
@@ -363,7 +355,7 @@ module RubyLsp
363
355
  end
364
356
  end
365
357
 
366
- sig { params(name: String, location: Prism::Location).void }
358
+ #: (String name, Prism::Location location) -> void
367
359
  def handle_class_variable_completion(name, location)
368
360
  type = @type_inferrer.infer_receiver_type(@node_context)
369
361
  return unless type
@@ -394,11 +386,11 @@ module RubyLsp
394
386
  # If by any chance we haven't indexed the owner, then there's no way to find the right declaration
395
387
  end
396
388
 
397
- sig { params(name: String, location: Prism::Location).void }
389
+ #: (String name, Prism::Location location) -> void
398
390
  def handle_instance_variable_completion(name, location)
399
391
  # Sorbet enforces that all instance variables be declared on typed strict or higher, which means it will be able
400
392
  # to provide all features for them
401
- return if @sorbet_level == RubyDocument::SorbetLevel::Strict
393
+ return if @sorbet_level.strict?
402
394
 
403
395
  type = @type_inferrer.infer_receiver_type(@node_context)
404
396
  return unless type
@@ -428,7 +420,7 @@ module RubyLsp
428
420
  # If by any chance we haven't indexed the owner, then there's no way to find the right declaration
429
421
  end
430
422
 
431
- sig { params(node: Prism::CallNode).void }
423
+ #: (Prism::CallNode node) -> void
432
424
  def complete_require(node)
433
425
  arguments_node = node.arguments
434
426
  return unless arguments_node
@@ -440,21 +432,27 @@ module RubyLsp
440
432
  matched_uris = @index.search_require_paths(path_node_to_complete.content)
441
433
 
442
434
  matched_uris.map!(&:require_path).sort!.each do |path|
443
- @response_builder << build_completion(T.must(path), path_node_to_complete)
435
+ @response_builder << build_completion(
436
+ path, #: as !nil
437
+ path_node_to_complete,
438
+ )
444
439
  end
445
440
  end
446
441
 
447
- sig { params(node: Prism::CallNode).void }
442
+ #: (Prism::CallNode node) -> void
448
443
  def complete_require_relative(node)
449
444
  arguments_node = node.arguments
450
445
  return unless arguments_node
451
446
 
452
447
  path_node_to_complete = arguments_node.arguments.first
453
-
454
448
  return unless path_node_to_complete.is_a?(Prism::StringNode)
455
449
 
456
- origin_dir = Pathname.new(@uri.to_standardized_path).dirname
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
457
454
 
455
+ origin_dir = Pathname.new(full_path).dirname
458
456
  content = path_node_to_complete.content
459
457
  # if the path is not a directory, glob all possible next characters
460
458
  # for example ../somethi| (where | is the cursor position)
@@ -476,17 +474,17 @@ module RubyLsp
476
474
  # might fail with EPERM
477
475
  end
478
476
 
479
- sig { params(node: Prism::CallNode, name: String).void }
477
+ #: (Prism::CallNode node, String name) -> void
480
478
  def complete_methods(node, name)
481
479
  # If the node has a receiver, then we don't need to provide local nor keyword completions. Sorbet can provide
482
480
  # local and keyword completion for any file with a Sorbet level of true or higher
483
- if !sorbet_level_true_or_higher?(@sorbet_level) && !node.receiver
481
+ if !@sorbet_level.true_or_higher? && !node.receiver
484
482
  add_local_completions(node, name)
485
483
  add_keyword_completions(node, name)
486
484
  end
487
485
 
488
486
  # Sorbet can provide completion for methods invoked on self on typed true or higher files
489
- return if sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
487
+ return if @sorbet_level.true_or_higher? && self_receiver?(node)
490
488
 
491
489
  type = @type_inferrer.infer_receiver_type(@node_context)
492
490
  return unless type
@@ -497,7 +495,9 @@ module RubyLsp
497
495
  method_name = @trigger_character == "." ? nil : name
498
496
 
499
497
  range = if method_name
500
- range_from_location(T.must(node.message_loc))
498
+ range_from_location(
499
+ node.message_loc, #: as !nil
500
+ )
501
501
  else
502
502
  loc = node.call_operator_loc
503
503
 
@@ -515,10 +515,18 @@ module RubyLsp
515
515
  external_references = @node_context.fully_qualified_name != type.name
516
516
 
517
517
  @index.method_completion_candidates(method_name, type.name).each do |entry|
518
- next if entry.visibility != RubyIndexer::Entry::Visibility::PUBLIC && external_references
518
+ next if entry.visibility != :public && external_references
519
519
 
520
520
  entry_name = entry.name
521
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
522
530
 
523
531
  label_details = Interface::CompletionItemLabelDetails.new(
524
532
  description: entry.file_name,
@@ -528,7 +536,7 @@ module RubyLsp
528
536
  label: entry_name,
529
537
  filter_text: entry_name,
530
538
  label_details: label_details,
531
- text_edit: Interface::TextEdit.new(range: range, new_text: entry_name),
539
+ text_edit: Interface::TextEdit.new(range: range, new_text: new_text),
532
540
  kind: Constant::CompletionItemKind::METHOD,
533
541
  data: {
534
542
  owner_name: owner_name,
@@ -540,9 +548,11 @@ module RubyLsp
540
548
  # We have not indexed this namespace, so we can't provide any completions
541
549
  end
542
550
 
543
- sig { params(node: Prism::CallNode, name: String).void }
551
+ #: (Prism::CallNode node, String name) -> void
544
552
  def add_local_completions(node, name)
545
- range = range_from_location(T.must(node.message_loc))
553
+ range = range_from_location(
554
+ node.message_loc, #: as !nil
555
+ )
546
556
 
547
557
  @node_context.locals_for_scope.each do |local|
548
558
  local_name = local.to_s
@@ -560,9 +570,11 @@ module RubyLsp
560
570
  end
561
571
  end
562
572
 
563
- sig { params(node: Prism::CallNode, name: String).void }
573
+ #: (Prism::CallNode node, String name) -> void
564
574
  def add_keyword_completions(node, name)
565
- range = range_from_location(T.must(node.message_loc))
575
+ range = range_from_location(
576
+ node.message_loc, #: as !nil
577
+ )
566
578
 
567
579
  KEYWORDS.each do |keyword|
568
580
  next unless keyword.start_with?(name)
@@ -578,7 +590,7 @@ module RubyLsp
578
590
  end
579
591
  end
580
592
 
581
- sig { params(label: String, node: Prism::StringNode).returns(Interface::CompletionItem) }
593
+ #: (String label, Prism::StringNode node) -> Interface::CompletionItem
582
594
  def build_completion(label, node)
583
595
  # We should use the content location as we only replace the content and not the delimiters of the string
584
596
  loc = node.content_loc
@@ -593,17 +605,9 @@ module RubyLsp
593
605
  )
594
606
  end
595
607
 
596
- sig do
597
- params(
598
- real_name: String,
599
- incomplete_name: String,
600
- range: Interface::Range,
601
- entries: T::Array[RubyIndexer::Entry],
602
- top_level: T::Boolean,
603
- ).returns(Interface::CompletionItem)
604
- end
608
+ #: (String real_name, String incomplete_name, Interface::Range range, Array[RubyIndexer::Entry] entries, bool top_level) -> Interface::CompletionItem
605
609
  def build_entry_completion(real_name, incomplete_name, range, entries, top_level)
606
- first_entry = T.must(entries.first)
610
+ first_entry = entries.first #: as !nil
607
611
  kind = case first_entry
608
612
  when RubyIndexer::Entry::Class
609
613
  Constant::CompletionItemKind::CLASS
@@ -690,11 +694,12 @@ module RubyLsp
690
694
  # B
691
695
  # end
692
696
  # ```
693
- sig { params(entry_name: String).returns(T::Boolean) }
697
+ #: (String entry_name) -> bool
694
698
  def top_level?(entry_name)
695
699
  nesting = @node_context.nesting
696
700
  nesting.length.downto(0) do |i|
697
- prefix = T.must(nesting[0...i]).join("::")
701
+ prefix = nesting[0...i] #: as !nil
702
+ .join("::")
698
703
  full_name = prefix.empty? ? entry_name : "#{prefix}::#{entry_name}"
699
704
  next if full_name == entry_name
700
705