ruby-lsp 0.23.21 → 0.25.0

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 (64) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/exe/ruby-lsp +10 -4
  4. data/exe/ruby-lsp-check +0 -4
  5. data/exe/ruby-lsp-launcher +25 -11
  6. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +0 -1
  7. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +0 -1
  8. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +7 -1
  9. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +1 -4
  10. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +9 -19
  11. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +18 -7
  12. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +2 -2
  13. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +12 -8
  14. data/lib/ruby_indexer/test/configuration_test.rb +1 -1
  15. data/lib/ruby_indexer/test/index_test.rb +24 -0
  16. data/lib/ruby_indexer/test/instance_variables_test.rb +24 -0
  17. data/lib/ruby_indexer/test/method_test.rb +17 -0
  18. data/lib/ruby_indexer/test/rbs_indexer_test.rb +2 -2
  19. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  20. data/lib/ruby_lsp/addon.rb +29 -15
  21. data/lib/ruby_lsp/base_server.rb +14 -12
  22. data/lib/ruby_lsp/document.rb +158 -46
  23. data/lib/ruby_lsp/erb_document.rb +8 -3
  24. data/lib/ruby_lsp/global_state.rb +21 -0
  25. data/lib/ruby_lsp/internal.rb +0 -2
  26. data/lib/ruby_lsp/listeners/completion.rb +9 -1
  27. data/lib/ruby_lsp/listeners/hover.rb +7 -0
  28. data/lib/ruby_lsp/listeners/inlay_hints.rb +5 -3
  29. data/lib/ruby_lsp/listeners/spec_style.rb +63 -20
  30. data/lib/ruby_lsp/listeners/test_discovery.rb +18 -15
  31. data/lib/ruby_lsp/listeners/test_style.rb +21 -10
  32. data/lib/ruby_lsp/requests/code_action_resolve.rb +3 -3
  33. data/lib/ruby_lsp/requests/code_lens.rb +14 -5
  34. data/lib/ruby_lsp/requests/completion.rb +1 -1
  35. data/lib/ruby_lsp/requests/definition.rb +1 -1
  36. data/lib/ruby_lsp/requests/discover_tests.rb +2 -2
  37. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  38. data/lib/ruby_lsp/requests/hover.rb +1 -1
  39. data/lib/ruby_lsp/requests/inlay_hints.rb +3 -3
  40. data/lib/ruby_lsp/requests/on_type_formatting.rb +1 -1
  41. data/lib/ruby_lsp/requests/prepare_rename.rb +1 -1
  42. data/lib/ruby_lsp/requests/references.rb +10 -6
  43. data/lib/ruby_lsp/requests/rename.rb +8 -6
  44. data/lib/ruby_lsp/requests/request.rb +6 -7
  45. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
  46. data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -1
  47. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  48. data/lib/ruby_lsp/requests/support/common.rb +1 -3
  49. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  50. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +2 -2
  51. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +9 -3
  52. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -8
  53. data/lib/ruby_lsp/ruby_document.rb +10 -5
  54. data/lib/ruby_lsp/server.rb +50 -49
  55. data/lib/ruby_lsp/setup_bundler.rb +51 -25
  56. data/lib/ruby_lsp/static_docs.rb +1 -0
  57. data/lib/ruby_lsp/store.rb +0 -10
  58. data/lib/ruby_lsp/test_helper.rb +1 -4
  59. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +13 -5
  60. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +43 -4
  61. data/lib/ruby_lsp/utils.rb +47 -11
  62. data/static_docs/break.md +103 -0
  63. metadata +4 -18
  64. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -19,12 +19,8 @@ module RubyLsp
19
19
  # end
20
20
  # end
21
21
  # ```
22
+ # @abstract
22
23
  class Addon
23
- extend T::Sig
24
- extend T::Helpers
25
-
26
- abstract!
27
-
28
24
  @addons = [] #: Array[Addon]
29
25
  @addon_classes = [] #: Array[singleton(Addon)]
30
26
  # Add-on instances that have declared a handler to accept file watcher events
@@ -60,7 +56,13 @@ module RubyLsp
60
56
  addon_files = Gem.find_files("ruby_lsp/**/addon.rb")
61
57
 
62
58
  if include_project_addons
63
- addon_files.concat(Dir.glob(File.join(global_state.workspace_path, "**", "ruby_lsp/**/addon.rb")))
59
+ project_addons = Dir.glob("#{global_state.workspace_path}/**/ruby_lsp/**/addon.rb")
60
+
61
+ # Ignore add-ons from dependencies if the bundle is stored inside the project. We already found those with
62
+ # `Gem.find_files`
63
+ bundle_path = Bundler.bundle_path.to_s
64
+ project_addons.reject! { |path| path.start_with?(bundle_path) }
65
+ addon_files.concat(project_addons)
64
66
  end
65
67
 
66
68
  errors = addon_files.filter_map do |addon_path|
@@ -178,22 +180,34 @@ module RubyLsp
178
180
 
179
181
  # Each add-on should implement `MyAddon#activate` and use to perform any sort of initialization, such as
180
182
  # reading information into memory or even spawning a separate process
181
- sig { abstract.params(global_state: GlobalState, outgoing_queue: Thread::Queue).void }
182
- def activate(global_state, outgoing_queue); end
183
+ # @abstract
184
+ #: (GlobalState, Thread::Queue) -> void
185
+ def activate(global_state, outgoing_queue)
186
+ raise AbstractMethodInvokedError
187
+ end
183
188
 
184
- # Each add-on should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
189
+ # Each add-on must implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
185
190
  # child process
186
- sig { abstract.void }
187
- def deactivate; end
191
+ # @abstract
192
+ #: -> void
193
+ def deactivate
194
+ raise AbstractMethodInvokedError
195
+ end
188
196
 
189
197
  # Add-ons should override the `name` method to return the add-on name
190
- sig { abstract.returns(String) }
191
- def name; end
198
+ # @abstract
199
+ #: -> String
200
+ def name
201
+ raise AbstractMethodInvokedError
202
+ end
192
203
 
193
204
  # Add-ons should override the `version` method to return a semantic version string representing the add-on's
194
205
  # version. This is used for compatibility checks
195
- sig { abstract.returns(String) }
196
- def version; end
206
+ # @abstract
207
+ #: -> String
208
+ def version
209
+ raise AbstractMethodInvokedError
210
+ end
197
211
 
198
212
  # Handle a response from a window/showMessageRequest request. Add-ons must include the addon_name as part of the
199
213
  # original request so that the response is delegated to the correct add-on and must override this method to handle
@@ -2,19 +2,15 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
+ # @abstract
5
6
  class BaseServer
6
- extend T::Sig
7
- extend T::Helpers
8
-
9
- abstract!
10
-
11
7
  #: (**untyped options) -> void
12
8
  def initialize(**options)
9
+ @reader = MessageReader.new(options[:reader] || $stdin) #: MessageReader
10
+ @writer = MessageWriter.new(options[:writer] || $stdout) #: MessageWriter
13
11
  @test_mode = options[:test_mode] #: bool?
14
12
  @setup_error = options[:setup_error] #: StandardError?
15
13
  @install_error = options[:install_error] #: StandardError?
16
- @writer = Transport::Stdio::Writer.new #: Transport::Stdio::Writer
17
- @reader = Transport::Stdio::Reader.new #: Transport::Stdio::Reader
18
14
  @incoming_queue = Thread::Queue.new #: Thread::Queue
19
15
  @outgoing_queue = Thread::Queue.new #: Thread::Queue
20
16
  @cancelled_requests = [] #: Array[Integer]
@@ -40,7 +36,7 @@ module RubyLsp
40
36
 
41
37
  #: -> void
42
38
  def start
43
- @reader.read do |message|
39
+ @reader.each_message do |message|
44
40
  method = message[:method]
45
41
 
46
42
  # We must parse the document under a mutex lock or else we might switch threads and accept text edits in the
@@ -130,11 +126,17 @@ module RubyLsp
130
126
  @incoming_queue << message
131
127
  end
132
128
 
133
- sig { abstract.params(message: T::Hash[Symbol, T.untyped]).void }
134
- def process_message(message); end
129
+ # @abstract
130
+ #: (Hash[Symbol, untyped] message) -> void
131
+ def process_message(message)
132
+ raise AbstractMethodInvokedError
133
+ end
135
134
 
136
- sig { abstract.void }
137
- def shutdown; end
135
+ # @abstract
136
+ #: -> void
137
+ def shutdown
138
+ raise AbstractMethodInvokedError
139
+ end
138
140
 
139
141
  #: (Integer id, String message, ?type: Integer) -> void
140
142
  def fail_request_and_notify(id, message, type: Constant::MessageType::INFO)
@@ -2,21 +2,16 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
+ # @abstract
5
6
  #: [ParseResultType]
6
7
  class Document
7
- extend T::Sig
8
- extend T::Helpers
9
- extend T::Generic
10
-
11
- class LocationNotFoundError < StandardError; end
8
+ class InvalidLocationError < StandardError; end
12
9
 
13
10
  # This maximum number of characters for providing expensive features, like semantic highlighting and diagnostics.
14
11
  # This is the same number used by the TypeScript extension in VS Code
15
12
  MAXIMUM_CHARACTERS_FOR_EXPENSIVE_FEATURES = 100_000
16
13
  EMPTY_CACHE = Object.new.freeze #: Object
17
14
 
18
- abstract!
19
-
20
15
  #: ParseResultType
21
16
  attr_reader :parse_result
22
17
 
@@ -63,8 +58,11 @@ module RubyLsp
63
58
  self.class == other.class && uri == other.uri && @source == other.source
64
59
  end
65
60
 
66
- sig { abstract.returns(Symbol) }
67
- def language_id; end
61
+ # @abstract
62
+ #: -> Symbol
63
+ def language_id
64
+ raise AbstractMethodInvokedError
65
+ end
68
66
 
69
67
  #: [T] (String request_name) { (Document[ParseResultType] document) -> T } -> T
70
68
  def cache_fetch(request_name, &block)
@@ -122,11 +120,17 @@ module RubyLsp
122
120
  end
123
121
 
124
122
  # Returns `true` if the document was parsed and `false` if nothing needed parsing
125
- sig { abstract.returns(T::Boolean) }
126
- def parse!; end
123
+ # @abstract
124
+ #: -> bool
125
+ def parse!
126
+ raise AbstractMethodInvokedError
127
+ end
127
128
 
128
- sig { abstract.returns(T::Boolean) }
129
- def syntax_error?; end
129
+ # @abstract
130
+ #: -> bool
131
+ def syntax_error?
132
+ raise AbstractMethodInvokedError
133
+ end
130
134
 
131
135
  #: -> bool
132
136
  def past_expensive_limit?
@@ -147,15 +151,18 @@ module RubyLsp
147
151
 
148
152
  #: -> Scanner
149
153
  def create_scanner
150
- Scanner.new(@source, @encoding)
154
+ case @encoding
155
+ when Encoding::UTF_8
156
+ Utf8Scanner.new(@source)
157
+ when Encoding::UTF_16LE
158
+ Utf16Scanner.new(@source)
159
+ else
160
+ Utf32Scanner.new(@source)
161
+ end
151
162
  end
152
163
 
164
+ # @abstract
153
165
  class Edit
154
- extend T::Sig
155
- extend T::Helpers
156
-
157
- abstract!
158
-
159
166
  #: Hash[Symbol, untyped]
160
167
  attr_reader :range
161
168
 
@@ -169,33 +176,114 @@ module RubyLsp
169
176
  class Replace < Edit; end
170
177
  class Delete < Edit; end
171
178
 
179
+ # Parent class for all position scanners. Scanners are used to translate a position given by the editor into a
180
+ # string index that we can use to find the right place in the document source. The logic for finding the correct
181
+ # index depends on the encoding negotiated with the editor, so we have different subclasses for each encoding.
182
+ # See https://microsoft.github.io/language-server-protocol/specification/#positionEncodingKind for more information
183
+ # @abstract
172
184
  class Scanner
173
- extend T::Sig
174
-
175
185
  LINE_BREAK = 0x0A #: Integer
176
186
  # After character 0xFFFF, UTF-16 considers characters to have length 2 and we have to account for that
177
187
  SURROGATE_PAIR_START = 0xFFFF #: Integer
178
188
 
179
- #: (String source, Encoding encoding) -> void
180
- def initialize(source, encoding)
189
+ #: -> void
190
+ def initialize
181
191
  @current_line = 0 #: Integer
182
192
  @pos = 0 #: Integer
183
- @source = source.codepoints #: Array[Integer]
184
- @encoding = encoding
185
193
  end
186
194
 
187
- # Finds the character index inside the source string for a given line and column
195
+ # Finds the character index inside the source string for a given line and column. This method always returns the
196
+ # character index regardless of whether we are searching positions based on bytes, code units, or codepoints.
197
+ # @abstract
198
+ #: (Hash[Symbol, untyped] position) -> Integer
199
+ def find_char_position(position)
200
+ raise AbstractMethodInvokedError
201
+ end
202
+ end
203
+
204
+ # For the UTF-8 encoding, positions correspond to bytes
205
+ class Utf8Scanner < Scanner
206
+ #: (String source) -> void
207
+ def initialize(source)
208
+ super()
209
+ @bytes = source.bytes #: Array[Integer]
210
+ @character_length = 0 #: Integer
211
+ end
212
+
213
+ # @override
214
+ #: (Hash[Symbol, untyped] position) -> Integer
215
+ def find_char_position(position)
216
+ # Each group of bytes is a character. We advance based on the number of bytes to count how many full characters
217
+ # we have in the requested offset
218
+ until @current_line == position[:line]
219
+ byte = @bytes[@pos] #: Integer?
220
+ raise InvalidLocationError unless byte
221
+
222
+ until LINE_BREAK == byte
223
+ @pos += character_byte_length(byte)
224
+ @character_length += 1
225
+ byte = @bytes[@pos]
226
+ raise InvalidLocationError unless byte
227
+ end
228
+
229
+ @pos += 1
230
+ @character_length += 1
231
+ @current_line += 1
232
+ end
233
+
234
+ # @character_length has the number of characters until the beginning of the line. We don't accumulate on it for
235
+ # the character part because locating the same position twice must return the same value
236
+ line_byte_offset = 0
237
+ line_characters = 0
238
+
239
+ while line_byte_offset < position[:character]
240
+ byte = @bytes[@pos + line_byte_offset] #: Integer?
241
+ raise InvalidLocationError unless byte
242
+
243
+ line_byte_offset += character_byte_length(byte)
244
+ line_characters += 1
245
+ end
246
+
247
+ @character_length + line_characters
248
+ end
249
+
250
+ private
251
+
252
+ #: (Integer) -> Integer
253
+ def character_byte_length(byte)
254
+ if byte < 0x80 # 1-byte character
255
+ 1
256
+ elsif byte < 0xE0 # 2-byte character
257
+ 2
258
+ elsif byte < 0xF0 # 3-byte character
259
+ 3
260
+ else # 4-byte character
261
+ 4
262
+ end
263
+ end
264
+ end
265
+
266
+ # For the UTF-16 encoding, positions correspond to UTF-16 code units, which count characters beyond the surrogate
267
+ # pair as length 2
268
+ class Utf16Scanner < Scanner
269
+ #: (String) -> void
270
+ def initialize(source)
271
+ super()
272
+ @codepoints = source.codepoints #: Array[Integer]
273
+ end
274
+
275
+ # @override
188
276
  #: (Hash[Symbol, untyped] position) -> Integer
189
277
  def find_char_position(position)
190
278
  # Find the character index for the beginning of the requested line
191
279
  until @current_line == position[:line]
192
- until LINE_BREAK == @source[@pos]
193
- @pos += 1
280
+ codepoint = @codepoints[@pos] #: Integer?
281
+ raise InvalidLocationError unless codepoint
194
282
 
195
- if @pos >= @source.length
196
- # Pack the code points back into the original string to provide context in the error message
197
- raise LocationNotFoundError, "Requested position: #{position}\nSource:\n\n#{@source.pack("U*")}"
198
- end
283
+ until LINE_BREAK == @codepoints[@pos]
284
+ @pos += 1
285
+ codepoint = @codepoints[@pos] #: Integer?
286
+ raise InvalidLocationError unless codepoint
199
287
  end
200
288
 
201
289
  @pos += 1
@@ -204,29 +292,53 @@ module RubyLsp
204
292
 
205
293
  # The final position is the beginning of the line plus the requested column. If the encoding is UTF-16, we also
206
294
  # need to adjust for surrogate pairs
207
- requested_position = @pos + position[:character]
295
+ line_characters = 0
296
+ line_code_units = 0
208
297
 
209
- if @encoding == Encoding::UTF_16LE
210
- requested_position -= utf_16_character_position_correction(@pos, requested_position)
298
+ while line_code_units < position[:character]
299
+ code_point = @codepoints[@pos + line_characters]
300
+ raise InvalidLocationError unless code_point
301
+
302
+ line_code_units += if code_point > SURROGATE_PAIR_START
303
+ 2 # Surrogate pair, so we skip the next code unit
304
+ else
305
+ 1 # Single code unit character
306
+ end
307
+
308
+ line_characters += 1
211
309
  end
212
310
 
213
- requested_position
311
+ @pos + line_characters
214
312
  end
313
+ end
215
314
 
216
- # Subtract 1 for each character after 0xFFFF in the current line from the column position, so that we hit the
217
- # right character in the UTF-8 representation
218
- #: (Integer current_position, Integer requested_position) -> Integer
219
- def utf_16_character_position_correction(current_position, requested_position)
220
- utf16_unicode_correction = 0
315
+ # For the UTF-32 encoding, positions correspond directly to codepoints
316
+ class Utf32Scanner < Scanner
317
+ #: (String) -> void
318
+ def initialize(source)
319
+ super()
320
+ @codepoints = source.codepoints #: Array[Integer]
321
+ end
322
+
323
+ # @override
324
+ #: (Hash[Symbol, untyped] position) -> Integer
325
+ def find_char_position(position)
326
+ # Find the character index for the beginning of the requested line
327
+ until @current_line == position[:line]
328
+ codepoint = @codepoints[@pos] #: Integer?
329
+ raise InvalidLocationError unless codepoint
221
330
 
222
- until current_position == requested_position
223
- codepoint = @source[current_position]
224
- utf16_unicode_correction += 1 if codepoint && codepoint > SURROGATE_PAIR_START
331
+ until LINE_BREAK == @codepoints[@pos]
332
+ @pos += 1
333
+ codepoint = @codepoints[@pos] #: Integer?
334
+ raise InvalidLocationError unless codepoint
335
+ end
225
336
 
226
- current_position += 1
337
+ @pos += 1
338
+ @current_line += 1
227
339
  end
228
340
 
229
- utf16_unicode_correction
341
+ @pos + position[:character]
230
342
  end
231
343
  end
232
344
  end
@@ -2,7 +2,7 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module RubyLsp
5
- #: [ParseResultType = Prism::ParseResult]
5
+ #: [ParseResultType = Prism::ParseLexResult]
6
6
  class ERBDocument < Document
7
7
  #: String
8
8
  attr_reader :host_language_source
@@ -31,11 +31,16 @@ module RubyLsp
31
31
  @host_language_source = scanner.host_language
32
32
  # Use partial script to avoid syntax errors in ERB files where keywords may be used without the full context in
33
33
  # which they will be evaluated
34
- @parse_result = Prism.parse(scanner.ruby, partial_script: true)
34
+ @parse_result = Prism.parse_lex(scanner.ruby, partial_script: true)
35
35
  @code_units_cache = @parse_result.code_units_cache(@encoding)
36
36
  true
37
37
  end
38
38
 
39
+ #: -> Prism::ProgramNode
40
+ def ast
41
+ @parse_result.value.first
42
+ end
43
+
39
44
  # @override
40
45
  #: -> bool
41
46
  def syntax_error?
@@ -53,7 +58,7 @@ module RubyLsp
53
58
  char_position, _ = find_index_by_position(position)
54
59
 
55
60
  RubyDocument.locate(
56
- @parse_result.value,
61
+ ast,
57
62
  char_position,
58
63
  code_units_cache: @code_units_cache,
59
64
  node_types: node_types,
@@ -56,6 +56,17 @@ module RubyLsp
56
56
  @enabled_feature_flags = {} #: Hash[Symbol, bool]
57
57
  @mutex = Mutex.new #: Mutex
58
58
  @telemetry_machine_id = nil #: String?
59
+ @feature_configuration = {
60
+ inlayHint: RequestConfig.new({
61
+ enableAll: false,
62
+ implicitRescue: false,
63
+ implicitHashValue: false,
64
+ }),
65
+ codeLens: RequestConfig.new({
66
+ enableAll: false,
67
+ enableTestCodeLens: true,
68
+ }),
69
+ } #: Hash[Symbol, RequestConfig]
59
70
  end
60
71
 
61
72
  #: [T] { -> T } -> T
@@ -175,9 +186,19 @@ module RubyLsp
175
186
  @enabled_feature_flags = enabled_flags if enabled_flags
176
187
 
177
188
  @telemetry_machine_id = options.dig(:initializationOptions, :telemetryMachineId)
189
+
190
+ options.dig(:initializationOptions, :featuresConfiguration)&.each do |feature_name, config|
191
+ @feature_configuration[feature_name]&.merge!(config)
192
+ end
193
+
178
194
  notifications
179
195
  end
180
196
 
197
+ #: (Symbol) -> RequestConfig?
198
+ def feature_configuration(feature_name)
199
+ @feature_configuration[feature_name]
200
+ end
201
+
181
202
  #: (Symbol flag) -> bool?
182
203
  def enabled_feature?(flag)
183
204
  @enabled_feature_flags[:all] || @enabled_feature_flags[flag]
@@ -6,8 +6,6 @@
6
6
  yarp_require_paths = Gem.loaded_specs["yarp"]&.full_require_paths
7
7
  $LOAD_PATH.delete_if { |path| yarp_require_paths.include?(path) } if yarp_require_paths
8
8
 
9
- require "sorbet-runtime"
10
-
11
9
  # Set Bundler's UI level to silent as soon as possible to prevent any prints to STDOUT
12
10
  require "bundler"
13
11
  Bundler.ui.level = :silent
@@ -516,6 +516,14 @@ module RubyLsp
516
516
 
517
517
  entry_name = entry.name
518
518
  owner_name = entry.owner&.name
519
+ new_text = entry_name
520
+
521
+ if entry_name.end_with?("=")
522
+ method_name = entry_name.delete_suffix("=")
523
+
524
+ # For writer methods, format as assignment and prefix "self." when no receiver is specified
525
+ new_text = node.receiver.nil? ? "self.#{method_name} = " : "#{method_name} = "
526
+ end
519
527
 
520
528
  label_details = Interface::CompletionItemLabelDetails.new(
521
529
  description: entry.file_name,
@@ -525,7 +533,7 @@ module RubyLsp
525
533
  label: entry_name,
526
534
  filter_text: entry_name,
527
535
  label_details: label_details,
528
- text_edit: Interface::TextEdit.new(range: range, new_text: entry_name),
536
+ text_edit: Interface::TextEdit.new(range: range, new_text: new_text),
529
537
  kind: Constant::CompletionItemKind::METHOD,
530
538
  data: {
531
539
  owner_name: owner_name,
@@ -7,6 +7,7 @@ module RubyLsp
7
7
  include Requests::Support::Common
8
8
 
9
9
  ALLOWED_TARGETS = [
10
+ Prism::BreakNode,
10
11
  Prism::CallNode,
11
12
  Prism::ConstantReadNode,
12
13
  Prism::ConstantWriteNode,
@@ -54,6 +55,7 @@ module RubyLsp
54
55
 
55
56
  dispatcher.register(
56
57
  self,
58
+ :on_break_node_enter,
57
59
  :on_constant_read_node_enter,
58
60
  :on_constant_write_node_enter,
59
61
  :on_constant_path_node_enter,
@@ -84,6 +86,11 @@ module RubyLsp
84
86
  )
85
87
  end
86
88
 
89
+ #: (Prism::BreakNode node) -> void
90
+ def on_break_node_enter(node)
91
+ handle_keyword_documentation(node.keyword)
92
+ end
93
+
87
94
  #: (Prism::StringNode node) -> void
88
95
  def on_string_node_enter(node)
89
96
  if @path && File.basename(@path) == GEMFILE_NAME
@@ -8,10 +8,12 @@ module RubyLsp
8
8
 
9
9
  RESCUE_STRING_LENGTH = "rescue".length #: Integer
10
10
 
11
- #: (ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint] response_builder, RequestConfig hints_configuration, Prism::Dispatcher dispatcher) -> void
12
- def initialize(response_builder, hints_configuration, dispatcher)
11
+ #: (GlobalState, ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint], Prism::Dispatcher) -> void
12
+ def initialize(global_state, response_builder, dispatcher)
13
13
  @response_builder = response_builder
14
- @hints_configuration = hints_configuration
14
+ @hints_configuration = ( # rubocop:disable Style/RedundantParentheses
15
+ global_state.feature_configuration(:inlayHint) #: as !nil
16
+ ) #: RequestConfig
15
17
 
16
18
  dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
17
19
  end