ruby-lsp 0.23.23 → 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 (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/exe/ruby-lsp-test-exec +3 -15
  7. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +0 -1
  8. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +0 -1
  9. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +7 -1
  10. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +1 -4
  11. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +10 -19
  12. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +29 -7
  13. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +12 -8
  14. data/lib/ruby_indexer/test/configuration_test.rb +1 -2
  15. data/lib/ruby_indexer/test/index_test.rb +39 -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 +44 -15
  21. data/lib/ruby_lsp/base_server.rb +34 -26
  22. data/lib/ruby_lsp/document.rb +162 -52
  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 +14 -3
  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 +7 -8
  30. data/lib/ruby_lsp/listeners/test_discovery.rb +18 -15
  31. data/lib/ruby_lsp/listeners/test_style.rb +14 -13
  32. data/lib/ruby_lsp/requests/code_action_resolve.rb +3 -3
  33. data/lib/ruby_lsp/requests/code_lens.rb +9 -3
  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 +13 -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 +93 -108
  55. data/lib/ruby_lsp/setup_bundler.rb +59 -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 -8
  60. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +17 -4
  61. data/lib/ruby_lsp/utils.rb +47 -11
  62. data/static_docs/break.md +103 -0
  63. metadata +2 -16
  64. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -4,13 +4,11 @@
4
4
  module RubyLsp
5
5
  module Requests
6
6
  module Support
7
+ # @requires_ancestor: Kernel
7
8
  module Common
8
9
  # WARNING: Methods in this class may be used by Ruby LSP add-ons such as
9
10
  # https://github.com/Shopify/ruby-lsp-rails, or add-ons by created by developers outside of Shopify, so be
10
11
  # cautious of changing anything.
11
- extend T::Helpers
12
-
13
- requires_ancestor { Kernel }
14
12
 
15
13
  #: (Prism::Node node) -> Interface::Range
16
14
  def range_from_node(node)
@@ -4,25 +4,26 @@
4
4
  module RubyLsp
5
5
  module Requests
6
6
  module Support
7
+ # Empty module to avoid the runtime component. This is an interface defined in sorbet/rbi/shims/ruby_lsp.rbi
8
+ # @interface
7
9
  module Formatter
8
- extend T::Sig
9
- extend T::Helpers
10
-
11
- interface!
12
-
13
- sig { abstract.params(uri: URI::Generic, document: RubyDocument).returns(T.nilable(String)) }
14
- def run_formatting(uri, document); end
10
+ # @abstract
11
+ #: (URI::Generic, RubyLsp::RubyDocument) -> String?
12
+ def run_formatting(uri, document)
13
+ raise AbstractMethodInvokedError
14
+ end
15
15
 
16
- sig { abstract.params(uri: URI::Generic, source: String, base_indentation: Integer).returns(T.nilable(String)) }
17
- def run_range_formatting(uri, source, base_indentation); end
16
+ # @abstract
17
+ #: (URI::Generic, String, Integer) -> String?
18
+ def run_range_formatting(uri, source, base_indentation)
19
+ raise AbstractMethodInvokedError
20
+ end
18
21
 
19
- sig do
20
- abstract.params(
21
- uri: URI::Generic,
22
- document: RubyDocument,
23
- ).returns(T.nilable(T::Array[Interface::Diagnostic]))
22
+ # @abstract
23
+ #: (URI::Generic, RubyLsp::RubyDocument) -> Array[Interface::Diagnostic]?
24
+ def run_diagnostic(uri, document)
25
+ raise AbstractMethodInvokedError
24
26
  end
25
- def run_diagnostic(uri, document); end
26
27
  end
27
28
  end
28
29
  end
@@ -24,7 +24,7 @@ module RubyLsp
24
24
  filename = uri.to_standardized_path || uri.opaque #: as !nil
25
25
 
26
26
  # Invoke RuboCop with just this file in `paths`
27
- @format_runner.run(filename, document.source)
27
+ @format_runner.run(filename, document.source, document.parse_result)
28
28
  @format_runner.formatted_source
29
29
  end
30
30
 
@@ -40,7 +40,7 @@ module RubyLsp
40
40
  def run_diagnostic(uri, document)
41
41
  filename = uri.to_standardized_path || uri.opaque #: as !nil
42
42
  # Invoke RuboCop with just this file in `paths`
43
- @diagnostic_runner.run(filename, document.source)
43
+ @diagnostic_runner.run(filename, document.source, document.parse_result)
44
44
 
45
45
  @diagnostic_runner.offenses.map do |offense|
46
46
  Support::RuboCopDiagnostic.new(
@@ -81,6 +81,7 @@ module RubyLsp
81
81
  @offenses = [] #: Array[::RuboCop::Cop::Offense]
82
82
  @errors = [] #: Array[String]
83
83
  @warnings = [] #: Array[String]
84
+ # @prism_result = nil #: Prism::ParseLexResult?
84
85
 
85
86
  args += DEFAULT_ARGS
86
87
  rubocop_options = ::RuboCop::Options.new.parse(args).first
@@ -92,8 +93,8 @@ module RubyLsp
92
93
  super(rubocop_options, config_store)
93
94
  end
94
95
 
95
- #: (String path, String contents) -> void
96
- def run(path, contents)
96
+ #: (String, String, Prism::ParseLexResult) -> void
97
+ def run(path, contents, prism_result)
97
98
  # Clear Runner state between runs since we get a single instance of this class
98
99
  # on every use site.
99
100
  @errors = []
@@ -101,6 +102,11 @@ module RubyLsp
101
102
  @offenses = []
102
103
  @options[:stdin] = contents
103
104
 
105
+ # Setting the Prism result before running the RuboCop runner makes it reuse the existing AST and avoids
106
+ # double-parsing. Unfortunately, this leads to a bunch of cops failing to execute properly under LSP mode.
107
+ # Uncomment this once reusing the Prism result is more stable
108
+ # @prism_result = prism_result
109
+
104
110
  super([path])
105
111
 
106
112
  # RuboCop rescues interrupts and then sets the `@aborting` variable to true. We don't want them to be rescued,
@@ -111,7 +117,11 @@ module RubyLsp
111
117
  rescue ::RuboCop::ValidationError => error
112
118
  raise ConfigurationError, error.message
113
119
  rescue StandardError => error
114
- raise InternalRuboCopError, error
120
+ # Maintain the original backtrace so that debugging cops that are breaking is easier, but re-raise as a
121
+ # different error class
122
+ internal_error = InternalRuboCopError.new(error)
123
+ internal_error.set_backtrace(error.backtrace)
124
+ raise internal_error
115
125
  end
116
126
 
117
127
  #: -> String
@@ -3,15 +3,13 @@
3
3
 
4
4
  module RubyLsp
5
5
  module ResponseBuilders
6
+ # @abstract
6
7
  class ResponseBuilder
7
- extend T::Sig
8
- extend T::Helpers
9
- extend T::Generic
10
-
11
- abstract!
12
-
13
- sig { abstract.returns(T.anything) }
14
- def response; end
8
+ # @abstract
9
+ #: -> top
10
+ def response
11
+ raise AbstractMethodInvokedError
12
+ end
15
13
  end
16
14
  end
17
15
  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 RubyDocument < Document
7
7
  METHODS_THAT_CHANGE_DECLARATIONS = [
8
8
  :private_constant,
@@ -26,7 +26,7 @@ module RubyLsp
26
26
  queue = node.child_nodes.compact #: Array[Prism::Node?]
27
27
  closest = node
28
28
  parent = nil #: Prism::Node?
29
- nesting_nodes = [] #: Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)] # rubocop:disable Layout/LineLength
29
+ nesting_nodes = [] #: Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)]
30
30
 
31
31
  nesting_nodes << node if node.is_a?(Prism::ProgramNode)
32
32
  call_node = nil #: Prism::CallNode?
@@ -129,11 +129,16 @@ module RubyLsp
129
129
  return false unless @needs_parsing
130
130
 
131
131
  @needs_parsing = false
132
- @parse_result = Prism.parse(@source)
132
+ @parse_result = Prism.parse_lex(@source)
133
133
  @code_units_cache = @parse_result.code_units_cache(@encoding)
134
134
  true
135
135
  end
136
136
 
137
+ #: -> Prism::ProgramNode
138
+ def ast
139
+ @parse_result.value.first
140
+ end
141
+
137
142
  # @override
138
143
  #: -> bool
139
144
  def syntax_error?
@@ -151,7 +156,7 @@ module RubyLsp
151
156
  start_position, end_position = find_index_by_position(range[:start], range[:end])
152
157
 
153
158
  desired_range = (start_position...end_position)
154
- queue = @parse_result.value.child_nodes.compact #: Array[Prism::Node?]
159
+ queue = ast.child_nodes.compact #: Array[Prism::Node?]
155
160
 
156
161
  until queue.empty?
157
162
  candidate = queue.shift
@@ -179,7 +184,7 @@ module RubyLsp
179
184
  char_position, _ = find_index_by_position(position)
180
185
 
181
186
  RubyDocument.locate(
182
- @parse_result.value,
187
+ ast,
183
188
  char_position,
184
189
  code_units_cache: @code_units_cache,
185
190
  node_types: node_types,
@@ -94,13 +94,10 @@ module RubyLsp
94
94
  id: message[:id],
95
95
  response:
96
96
  Addon.addons.map do |addon|
97
- version_method = addon.method(:version)
98
-
99
- # If the add-on doesn't define a `version` method, we'd be calling the abstract method defined by
100
- # Sorbet, which would raise an error.
101
- # Therefore, we only call the method if it's defined by the add-on itself
102
- if version_method.owner != Addon
103
- version = addon.version
97
+ version = begin
98
+ addon.version
99
+ rescue AbstractMethodInvokedError
100
+ nil
104
101
  end
105
102
 
106
103
  { name: addon.name, version: version, errored: addon.error? }
@@ -124,30 +121,22 @@ module RubyLsp
124
121
  end
125
122
  rescue DelegateRequestError
126
123
  send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
127
- rescue StandardError, LoadError => e
124
+ rescue StandardError, LoadError, SystemExit => e
128
125
  # If an error occurred in a request, we have to return an error response or else the editor will hang
129
126
  if message[:id]
130
127
  # If a document is deleted before we are able to process all of its enqueued requests, we will try to read it
131
128
  # from disk and it raise this error. This is expected, so we don't include the `data` attribute to avoid
132
- # reporting these to our telemetry
129
+ # reporting these to our telemetry.
130
+ #
131
+ # Similarly, if we receive a location for an invalid position in the
132
+ # document, we don't report it to telemetry
133
133
  case e
134
- when Store::NonExistingDocumentError
134
+ when Store::NonExistingDocumentError, Document::InvalidLocationError
135
135
  send_message(Error.new(
136
136
  id: message[:id],
137
137
  code: Constant::ErrorCodes::INVALID_PARAMS,
138
138
  message: e.full_message,
139
139
  ))
140
- when Document::LocationNotFoundError
141
- send_message(Error.new(
142
- id: message[:id],
143
- code: Constant::ErrorCodes::REQUEST_FAILED,
144
- message: <<~MESSAGE,
145
- Request #{message[:method]} failed to find the target position.
146
- The file might have been modified while the server was in the middle of searching for the target.
147
- If you experience this regularly, please report any findings and extra information on
148
- https://github.com/Shopify/ruby-lsp/issues/2446
149
- MESSAGE
150
- ))
151
140
  else
152
141
  send_message(Error.new(
153
142
  id: message[:id],
@@ -182,6 +171,7 @@ module RubyLsp
182
171
  return if @setup_error
183
172
 
184
173
  errors = Addon.load_addons(@global_state, @outgoing_queue, include_project_addons: include_project_addons)
174
+ return if test_mode?
185
175
 
186
176
  if errors.any?
187
177
  send_log_message(
@@ -194,21 +184,13 @@ module RubyLsp
194
184
 
195
185
  if errored_addons.any?
196
186
  send_message(
197
- Notification.new(
198
- method: "window/showMessage",
199
- params: Interface::ShowMessageParams.new(
200
- type: Constant::MessageType::WARNING,
201
- message: "Error loading add-ons:\n\n#{errored_addons.map(&:formatted_errors).join("\n\n")}",
202
- ),
187
+ Notification.window_show_message(
188
+ "Error loading add-ons:\n\n#{errored_addons.map(&:formatted_errors).join("\n\n")}",
189
+ type: Constant::MessageType::WARNING,
203
190
  ),
204
191
  )
205
192
 
206
- unless @test_mode
207
- send_log_message(
208
- errored_addons.map(&:errors_details).join("\n\n"),
209
- type: Constant::MessageType::WARNING,
210
- )
211
- end
193
+ send_log_message(errored_addons.map(&:errors_details).join("\n\n"), type: Constant::MessageType::WARNING)
212
194
  end
213
195
  end
214
196
 
@@ -224,10 +206,6 @@ module RubyLsp
224
206
 
225
207
  configured_features = options.dig(:initializationOptions, :enabledFeatures)
226
208
 
227
- configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
228
- @store.features_configuration.dig(:inlayHint) #: as !nil
229
- .configuration.merge!(configured_hints) if configured_hints
230
-
231
209
  enabled_features = case configured_features
232
210
  when Array
233
211
  # If the configuration is using an array, then absent features are disabled and present ones are enabled. That's
@@ -381,56 +359,53 @@ module RubyLsp
381
359
 
382
360
  perform_initial_indexing
383
361
  check_formatter_is_available
362
+ update_server if @global_state.enabled_feature?(:launcher)
384
363
  end
385
364
 
386
365
  #: (Hash[Symbol, untyped] message) -> void
387
366
  def text_document_did_open(message)
388
- @global_state.synchronize do
389
- text_document = message.dig(:params, :textDocument)
390
- language_id = case text_document[:languageId]
391
- when "erb", "eruby"
392
- :erb
393
- when "rbs"
394
- :rbs
395
- else
396
- :ruby
397
- end
367
+ text_document = message.dig(:params, :textDocument)
368
+ language_id = case text_document[:languageId]
369
+ when "erb", "eruby"
370
+ :erb
371
+ when "rbs"
372
+ :rbs
373
+ else
374
+ :ruby
375
+ end
398
376
 
399
- document = @store.set(
400
- uri: text_document[:uri],
401
- source: text_document[:text],
402
- version: text_document[:version],
403
- language_id: language_id,
404
- )
377
+ document = @store.set(
378
+ uri: text_document[:uri],
379
+ source: text_document[:text],
380
+ version: text_document[:version],
381
+ language_id: language_id,
382
+ )
405
383
 
406
- if document.past_expensive_limit? && text_document[:uri].scheme == "file"
407
- log_message = <<~MESSAGE
408
- The file #{text_document[:uri].path} is too long. For performance reasons, semantic highlighting and
409
- diagnostics will be disabled.
410
- MESSAGE
384
+ if document.past_expensive_limit? && text_document[:uri].scheme == "file"
385
+ log_message = <<~MESSAGE
386
+ The file #{text_document[:uri].path} is too long. For performance reasons, semantic highlighting and
387
+ diagnostics will be disabled.
388
+ MESSAGE
411
389
 
412
- send_message(
413
- Notification.new(
414
- method: "window/logMessage",
415
- params: Interface::LogMessageParams.new(
416
- type: Constant::MessageType::WARNING,
417
- message: log_message,
418
- ),
390
+ send_message(
391
+ Notification.new(
392
+ method: "window/logMessage",
393
+ params: Interface::LogMessageParams.new(
394
+ type: Constant::MessageType::WARNING,
395
+ message: log_message,
419
396
  ),
420
- )
421
- end
397
+ ),
398
+ )
422
399
  end
423
400
  end
424
401
 
425
402
  #: (Hash[Symbol, untyped] message) -> void
426
403
  def text_document_did_close(message)
427
- @global_state.synchronize do
428
- uri = message.dig(:params, :textDocument, :uri)
429
- @store.delete(uri)
404
+ uri = message.dig(:params, :textDocument, :uri)
405
+ @store.delete(uri)
430
406
 
431
- # Clear diagnostics for the closed file, so that they no longer appear in the problems tab
432
- send_message(Notification.publish_diagnostics(uri.to_s, []))
433
- end
407
+ # Clear diagnostics for the closed file, so that they no longer appear in the problems tab
408
+ send_message(Notification.publish_diagnostics(uri.to_s, []))
434
409
  end
435
410
 
436
411
  #: (Hash[Symbol, untyped] message) -> void
@@ -438,9 +413,7 @@ module RubyLsp
438
413
  params = message[:params]
439
414
  text_document = params[:textDocument]
440
415
 
441
- @global_state.synchronize do
442
- @store.push_edits(uri: text_document[:uri], edits: params[:contentChanges], version: text_document[:version])
443
- end
416
+ @store.push_edits(uri: text_document[:uri], edits: params[:contentChanges], version: text_document[:version])
444
417
  end
445
418
 
446
419
  #: (Hash[Symbol, untyped] message) -> void
@@ -494,8 +467,8 @@ module RubyLsp
494
467
  document_symbol = Requests::DocumentSymbol.new(uri, dispatcher)
495
468
  document_link = Requests::DocumentLink.new(uri, parse_result.comments, dispatcher)
496
469
  inlay_hint = Requests::InlayHints.new(
470
+ @global_state,
497
471
  document,
498
- @store.features_configuration.dig(:inlayHint), #: as !nil
499
472
  dispatcher,
500
473
  )
501
474
 
@@ -513,12 +486,12 @@ module RubyLsp
513
486
  index.delete(uri, skip_require_paths_tree: true)
514
487
  RubyIndexer::DeclarationListener.new(index, dispatcher, parse_result, uri, collect_comments: true)
515
488
  code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
516
- dispatcher.dispatch(parse_result.value)
489
+ dispatcher.dispatch(document.ast)
517
490
  end
518
491
  end
519
492
  else
520
493
  code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
521
- dispatcher.dispatch(parse_result.value)
494
+ dispatcher.dispatch(document.ast)
522
495
  end
523
496
 
524
497
  # Store all responses retrieve in this round of visits in the cache and then return the response for the request
@@ -557,7 +530,7 @@ module RubyLsp
557
530
 
558
531
  dispatcher = Prism::Dispatcher.new
559
532
  semantic_highlighting = Requests::SemanticHighlighting.new(@global_state, dispatcher, document, nil)
560
- dispatcher.visit(document.parse_result.value)
533
+ dispatcher.visit(document.ast)
561
534
 
562
535
  send_message(Result.new(id: message[:id], response: semantic_highlighting.perform))
563
536
  end
@@ -583,7 +556,7 @@ module RubyLsp
583
556
  document,
584
557
  message.dig(:params, :previousResultId),
585
558
  )
586
- dispatcher.visit(document.parse_result.value)
559
+ dispatcher.visit(document.ast)
587
560
  send_message(Result.new(id: message[:id], response: request.perform))
588
561
  end
589
562
 
@@ -612,7 +585,7 @@ module RubyLsp
612
585
  nil,
613
586
  range: range.dig(:start, :line)..range.dig(:end, :line),
614
587
  )
615
- dispatcher.visit(document.parse_result.value)
588
+ dispatcher.visit(document.ast)
616
589
  send_message(Result.new(id: message[:id], response: request.perform))
617
590
  end
618
591
 
@@ -704,7 +677,7 @@ module RubyLsp
704
677
  end
705
678
 
706
679
  request = Requests::DocumentHighlight.new(@global_state, document, params[:position], dispatcher)
707
- dispatcher.dispatch(document.parse_result.value)
680
+ dispatcher.dispatch(document.ast)
708
681
  send_message(Result.new(id: message[:id], response: request.perform))
709
682
  end
710
683
 
@@ -842,7 +815,6 @@ module RubyLsp
842
815
  return
843
816
  end
844
817
 
845
- hints_configurations = @store.features_configuration.dig(:inlayHint) #: as !nil
846
818
  dispatcher = Prism::Dispatcher.new
847
819
 
848
820
  unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
@@ -850,8 +822,8 @@ module RubyLsp
850
822
  return
851
823
  end
852
824
 
853
- request = Requests::InlayHints.new(document, hints_configurations, dispatcher)
854
- dispatcher.visit(document.parse_result.value)
825
+ request = Requests::InlayHints.new(@global_state, document, dispatcher)
826
+ dispatcher.visit(document.ast)
855
827
  result = request.perform
856
828
  document.cache_set("textDocument/inlayHint", result)
857
829
 
@@ -1124,11 +1096,7 @@ module RubyLsp
1124
1096
  @global_state.register_formatter("rubocop_internal", Requests::Support::RuboCopFormatter.new)
1125
1097
 
1126
1098
  # Clear all document caches for pull diagnostics
1127
- @global_state.synchronize do
1128
- @store.each do |_uri, document|
1129
- document.clear_cache("textDocument/diagnostic")
1130
- end
1131
- end
1099
+ @store.each { |_uri, document| document.clear_cache("textDocument/diagnostic") }
1132
1100
 
1133
1101
  # Request a pull diagnostic refresh from the editor
1134
1102
  if @global_state.client_capabilities.supports_diagnostic_refresh
@@ -1243,7 +1211,7 @@ module RubyLsp
1243
1211
  }
1244
1212
  end
1245
1213
  end
1246
- rescue Bundler::GemNotFound
1214
+ rescue Bundler::GemNotFound, Bundler::GemfileNotFound
1247
1215
  []
1248
1216
  end
1249
1217
 
@@ -1426,8 +1394,38 @@ module RubyLsp
1426
1394
 
1427
1395
  # We compose the bundle in a thread so that the LSP continues to work while we're checking for its validity. Once
1428
1396
  # we return the response back to the editor, then the restart is triggered
1397
+ launch_bundle_compose("Recomposing the bundle ahead of restart") do |stderr, status|
1398
+ if status&.exitstatus == 0
1399
+ # Create a signal for the restart that it can skip composing the bundle and launch directly
1400
+ FileUtils.touch(already_composed_path)
1401
+ send_message(Result.new(id: id, response: { success: true }))
1402
+ else
1403
+ # This special error code makes the extension avoid restarting in case we already know that the composed
1404
+ # bundle is not valid
1405
+ send_message(
1406
+ Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: "Failed to compose bundle\n#{stderr}"),
1407
+ )
1408
+ end
1409
+ end
1410
+ end
1411
+
1412
+ #: -> void
1413
+ def update_server
1414
+ return unless File.exist?(File.join(@global_state.workspace_path, ".ruby-lsp", "needs_update"))
1415
+
1416
+ launch_bundle_compose("Trying to update server") do |stderr, status|
1417
+ if status&.exitstatus == 0
1418
+ send_log_message("Successfully updated the server")
1419
+ else
1420
+ send_log_message("Failed to update server\n#{stderr}", type: Constant::MessageType::ERROR)
1421
+ end
1422
+ end
1423
+ end
1424
+
1425
+ #: (String) { (IO, Process::Status?) -> void } -> Thread
1426
+ def launch_bundle_compose(log, &block)
1429
1427
  Thread.new do
1430
- send_log_message("Recomposing the bundle ahead of restart")
1428
+ send_log_message(log)
1431
1429
 
1432
1430
  _stdout, stderr, status = Bundler.with_unbundled_env do
1433
1431
  Open3.capture3(
@@ -1442,17 +1440,7 @@ module RubyLsp
1442
1440
  )
1443
1441
  end
1444
1442
 
1445
- if status&.exitstatus == 0
1446
- # Create a signal for the restart that it can skip composing the bundle and launch directly
1447
- FileUtils.touch(already_composed_path)
1448
- send_message(Result.new(id: id, response: { success: true }))
1449
- else
1450
- # This special error code makes the extension avoid restarting in case we already know that the composed
1451
- # bundle is not valid
1452
- send_message(
1453
- Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: "Failed to compose bundle\n#{stderr}"),
1454
- )
1455
- end
1443
+ block.call(stderr, status)
1456
1444
  end
1457
1445
  end
1458
1446
 
@@ -1509,10 +1497,7 @@ module RubyLsp
1509
1497
 
1510
1498
  send_message(Result.new(
1511
1499
  id: message[:id],
1512
- response: {
1513
- commands: commands,
1514
- reporterPaths: [Listeners::TestStyle::MINITEST_REPORTER_PATH, Listeners::TestStyle::TEST_UNIT_REPORTER_PATH],
1515
- },
1500
+ response: { commands: commands },
1516
1501
  ))
1517
1502
  end
1518
1503