ruby-lsp 0.23.11 → 0.23.12

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 (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp-launcher +12 -11
  5. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
  6. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +52 -77
  7. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +61 -144
  8. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +8 -6
  9. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +73 -182
  10. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +48 -181
  11. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  12. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +12 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +21 -44
  14. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +40 -58
  15. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +9 -16
  16. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
  17. data/lib/ruby_indexer/test/configuration_test.rb +32 -2
  18. data/lib/ruby_indexer/test/method_test.rb +2 -2
  19. data/lib/ruby_lsp/addon.rb +32 -67
  20. data/lib/ruby_lsp/base_server.rb +10 -10
  21. data/lib/ruby_lsp/client_capabilities.rb +4 -6
  22. data/lib/ruby_lsp/document.rb +21 -32
  23. data/lib/ruby_lsp/erb_document.rb +17 -27
  24. data/lib/ruby_lsp/global_state.rb +30 -32
  25. data/lib/ruby_lsp/internal.rb +2 -0
  26. data/lib/ruby_lsp/listeners/code_lens.rb +21 -39
  27. data/lib/ruby_lsp/listeners/completion.rb +34 -53
  28. data/lib/ruby_lsp/listeners/definition.rb +35 -49
  29. data/lib/ruby_lsp/listeners/document_highlight.rb +60 -69
  30. data/lib/ruby_lsp/listeners/document_link.rb +9 -19
  31. data/lib/ruby_lsp/listeners/document_symbol.rb +34 -48
  32. data/lib/ruby_lsp/listeners/folding_ranges.rb +31 -38
  33. data/lib/ruby_lsp/listeners/hover.rb +37 -47
  34. data/lib/ruby_lsp/listeners/inlay_hints.rb +3 -10
  35. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +29 -35
  36. data/lib/ruby_lsp/listeners/signature_help.rb +4 -23
  37. data/lib/ruby_lsp/listeners/spec_style.rb +199 -0
  38. data/lib/ruby_lsp/listeners/test_style.rb +136 -30
  39. data/lib/ruby_lsp/node_context.rb +8 -35
  40. data/lib/ruby_lsp/rbs_document.rb +7 -5
  41. data/lib/ruby_lsp/requests/code_action_resolve.rb +10 -10
  42. data/lib/ruby_lsp/requests/code_actions.rb +5 -14
  43. data/lib/ruby_lsp/requests/code_lens.rb +4 -13
  44. data/lib/ruby_lsp/requests/completion.rb +4 -15
  45. data/lib/ruby_lsp/requests/completion_resolve.rb +4 -4
  46. data/lib/ruby_lsp/requests/definition.rb +4 -12
  47. data/lib/ruby_lsp/requests/diagnostics.rb +6 -9
  48. data/lib/ruby_lsp/requests/discover_tests.rb +15 -3
  49. data/lib/ruby_lsp/requests/document_highlight.rb +3 -11
  50. data/lib/ruby_lsp/requests/document_link.rb +4 -13
  51. data/lib/ruby_lsp/requests/document_symbol.rb +4 -7
  52. data/lib/ruby_lsp/requests/folding_ranges.rb +4 -7
  53. data/lib/ruby_lsp/requests/formatting.rb +4 -7
  54. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +87 -0
  55. data/lib/ruby_lsp/requests/hover.rb +6 -16
  56. data/lib/ruby_lsp/requests/inlay_hints.rb +4 -13
  57. data/lib/ruby_lsp/requests/on_type_formatting.rb +17 -24
  58. data/lib/ruby_lsp/requests/prepare_rename.rb +3 -8
  59. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +4 -13
  60. data/lib/ruby_lsp/requests/range_formatting.rb +3 -4
  61. data/lib/ruby_lsp/requests/references.rb +5 -35
  62. data/lib/ruby_lsp/requests/rename.rb +9 -35
  63. data/lib/ruby_lsp/requests/request.rb +5 -17
  64. data/lib/ruby_lsp/requests/selection_ranges.rb +3 -3
  65. data/lib/ruby_lsp/requests/semantic_highlighting.rb +6 -23
  66. data/lib/ruby_lsp/requests/show_syntax_tree.rb +4 -5
  67. data/lib/ruby_lsp/requests/signature_help.rb +6 -24
  68. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  69. data/lib/ruby_lsp/requests/support/common.rb +12 -49
  70. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -14
  71. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +7 -10
  72. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +9 -15
  73. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  74. data/lib/ruby_lsp/requests/support/sorbet.rb +1 -7
  75. data/lib/ruby_lsp/requests/support/source_uri.rb +5 -16
  76. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +7 -10
  77. data/lib/ruby_lsp/requests/support/test_item.rb +14 -13
  78. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +4 -5
  79. data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -3
  80. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +4 -4
  81. data/lib/ruby_lsp/response_builders/document_symbol.rb +8 -11
  82. data/lib/ruby_lsp/response_builders/hover.rb +5 -5
  83. data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
  84. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +18 -40
  85. data/lib/ruby_lsp/response_builders/signature_help.rb +4 -5
  86. data/lib/ruby_lsp/response_builders/test_collection.rb +5 -9
  87. data/lib/ruby_lsp/ruby_document.rb +15 -40
  88. data/lib/ruby_lsp/ruby_lsp_reporter_plugin.rb +106 -0
  89. data/lib/ruby_lsp/scope.rb +6 -10
  90. data/lib/ruby_lsp/server.rb +125 -74
  91. data/lib/ruby_lsp/setup_bundler.rb +22 -15
  92. data/lib/ruby_lsp/store.rb +12 -28
  93. data/lib/ruby_lsp/test_helper.rb +3 -12
  94. data/lib/ruby_lsp/test_reporter.rb +71 -0
  95. data/lib/ruby_lsp/test_unit_test_runner.rb +96 -0
  96. data/lib/ruby_lsp/type_inferrer.rb +9 -13
  97. data/lib/ruby_lsp/utils.rb +27 -65
  98. metadata +8 -3
@@ -3,13 +3,12 @@
3
3
 
4
4
  module RubyLsp
5
5
  class Server < BaseServer
6
- extend T::Sig
7
-
8
6
  # Only for testing
9
- sig { returns(GlobalState) }
7
+ #: GlobalState
10
8
  attr_reader :global_state
11
9
 
12
- sig { override.params(message: T::Hash[Symbol, T.untyped]).void }
10
+ # @override
11
+ #: (Hash[Symbol, untyped] message) -> void
13
12
  def process_message(message)
14
13
  case message[:method]
15
14
  when "initialize"
@@ -112,6 +111,10 @@ module RubyLsp
112
111
  diagnose_state(message)
113
112
  when "rubyLsp/discoverTests"
114
113
  discover_tests(message)
114
+ when "rubyLsp/resolveTestCommands"
115
+ resolve_test_commands(message)
116
+ when "experimental/goToRelevantFile"
117
+ experimental_go_to_relevant_file(message)
115
118
  when "$/cancelRequest"
116
119
  @global_state.synchronize { @cancelled_requests << message[:params][:id] }
117
120
  when nil
@@ -161,7 +164,7 @@ module RubyLsp
161
164
  end
162
165
 
163
166
  # Process responses to requests that were sent to the client
164
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
167
+ #: (Hash[Symbol, untyped] message) -> void
165
168
  def process_response(message)
166
169
  case message.dig(:result, :method)
167
170
  when "window/showMessageRequest"
@@ -169,7 +172,7 @@ module RubyLsp
169
172
  end
170
173
  end
171
174
 
172
- sig { params(include_project_addons: T::Boolean).void }
175
+ #: (?include_project_addons: bool) -> void
173
176
  def load_addons(include_project_addons: true)
174
177
  # If invoking Bundler.setup failed, then the load path will not be configured properly and trying to load add-ons
175
178
  # with Gem.find_files will find every single version installed of an add-on, leading to requiring several
@@ -209,7 +212,7 @@ module RubyLsp
209
212
 
210
213
  private
211
214
 
212
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
215
+ #: (Hash[Symbol, untyped] message) -> void
213
216
  def run_initialize(message)
214
217
  options = message[:params]
215
218
  global_state_notifications = @global_state.apply_options(options)
@@ -290,6 +293,7 @@ module RubyLsp
290
293
  experimental: {
291
294
  addon_detection: true,
292
295
  compose_bundle: true,
296
+ go_to_relevant_file: true,
293
297
  },
294
298
  ),
295
299
  serverInfo: {
@@ -346,7 +350,7 @@ module RubyLsp
346
350
  end
347
351
  end
348
352
 
349
- sig { void }
353
+ #: -> void
350
354
  def run_initialized
351
355
  load_addons
352
356
  RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
@@ -373,7 +377,7 @@ module RubyLsp
373
377
  check_formatter_is_available
374
378
  end
375
379
 
376
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
380
+ #: (Hash[Symbol, untyped] message) -> void
377
381
  def text_document_did_open(message)
378
382
  @global_state.synchronize do
379
383
  text_document = message.dig(:params, :textDocument)
@@ -412,7 +416,7 @@ module RubyLsp
412
416
  end
413
417
  end
414
418
 
415
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
419
+ #: (Hash[Symbol, untyped] message) -> void
416
420
  def text_document_did_close(message)
417
421
  @global_state.synchronize do
418
422
  uri = message.dig(:params, :textDocument, :uri)
@@ -423,7 +427,7 @@ module RubyLsp
423
427
  end
424
428
  end
425
429
 
426
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
430
+ #: (Hash[Symbol, untyped] message) -> void
427
431
  def text_document_did_change(message)
428
432
  params = message[:params]
429
433
  text_document = params[:textDocument]
@@ -433,7 +437,7 @@ module RubyLsp
433
437
  end
434
438
  end
435
439
 
436
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
440
+ #: (Hash[Symbol, untyped] message) -> void
437
441
  def text_document_selection_range(message)
438
442
  uri = message.dig(:params, :textDocument, :uri)
439
443
  ranges = @store.cache_fetch(uri, "textDocument/selectionRange") do |document|
@@ -459,7 +463,7 @@ module RubyLsp
459
463
  send_message(Result.new(id: message[:id], response: response))
460
464
  end
461
465
 
462
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
466
+ #: (Hash[Symbol, untyped] message) -> void
463
467
  def run_combined_requests(message)
464
468
  uri = URI(message.dig(:params, :textDocument, :uri))
465
469
  document = @store.get(uri)
@@ -518,7 +522,7 @@ module RubyLsp
518
522
  alias_method :text_document_code_lens, :run_combined_requests
519
523
  alias_method :text_document_folding_range, :run_combined_requests
520
524
 
521
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
525
+ #: (Hash[Symbol, untyped] message) -> void
522
526
  def text_document_semantic_tokens_full(message)
523
527
  document = @store.get(message.dig(:params, :textDocument, :uri))
524
528
 
@@ -539,7 +543,7 @@ module RubyLsp
539
543
  send_message(Result.new(id: message[:id], response: semantic_highlighting.perform))
540
544
  end
541
545
 
542
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
546
+ #: (Hash[Symbol, untyped] message) -> void
543
547
  def text_document_semantic_tokens_delta(message)
544
548
  document = @store.get(message.dig(:params, :textDocument, :uri))
545
549
 
@@ -564,7 +568,7 @@ module RubyLsp
564
568
  send_message(Result.new(id: message[:id], response: request.perform))
565
569
  end
566
570
 
567
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
571
+ #: (Hash[Symbol, untyped] message) -> void
568
572
  def text_document_semantic_tokens_range(message)
569
573
  params = message[:params]
570
574
  range = params[:range]
@@ -593,7 +597,7 @@ module RubyLsp
593
597
  send_message(Result.new(id: message[:id], response: request.perform))
594
598
  end
595
599
 
596
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
600
+ #: (Hash[Symbol, untyped] message) -> void
597
601
  def text_document_range_formatting(message)
598
602
  # If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
599
603
  if @global_state.formatter == "none"
@@ -621,7 +625,7 @@ module RubyLsp
621
625
  send_message(Result.new(id: message[:id], response: response))
622
626
  end
623
627
 
624
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
628
+ #: (Hash[Symbol, untyped] message) -> void
625
629
  def text_document_formatting(message)
626
630
  # If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
627
631
  if @global_state.formatter == "none"
@@ -665,7 +669,7 @@ module RubyLsp
665
669
  send_empty_response(message[:id])
666
670
  end
667
671
 
668
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
672
+ #: (Hash[Symbol, untyped] message) -> void
669
673
  def text_document_document_highlight(message)
670
674
  params = message[:params]
671
675
  dispatcher = Prism::Dispatcher.new
@@ -681,7 +685,7 @@ module RubyLsp
681
685
  send_message(Result.new(id: message[:id], response: request.perform))
682
686
  end
683
687
 
684
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
688
+ #: (Hash[Symbol, untyped] message) -> void
685
689
  def text_document_on_type_formatting(message)
686
690
  params = message[:params]
687
691
  document = @store.get(params.dig(:textDocument, :uri))
@@ -704,7 +708,7 @@ module RubyLsp
704
708
  )
705
709
  end
706
710
 
707
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
711
+ #: (Hash[Symbol, untyped] message) -> void
708
712
  def text_document_hover(message)
709
713
  params = message[:params]
710
714
  dispatcher = Prism::Dispatcher.new
@@ -729,7 +733,7 @@ module RubyLsp
729
733
  )
730
734
  end
731
735
 
732
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
736
+ #: (Hash[Symbol, untyped] message) -> void
733
737
  def text_document_rename(message)
734
738
  params = message[:params]
735
739
  document = @store.get(params.dig(:textDocument, :uri))
@@ -749,7 +753,7 @@ module RubyLsp
749
753
  send_message(Error.new(id: message[:id], code: Constant::ErrorCodes::REQUEST_FAILED, message: e.message))
750
754
  end
751
755
 
752
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
756
+ #: (Hash[Symbol, untyped] message) -> void
753
757
  def text_document_prepare_rename(message)
754
758
  params = message[:params]
755
759
  document = @store.get(params.dig(:textDocument, :uri))
@@ -767,7 +771,7 @@ module RubyLsp
767
771
  )
768
772
  end
769
773
 
770
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
774
+ #: (Hash[Symbol, untyped] message) -> void
771
775
  def text_document_references(message)
772
776
  params = message[:params]
773
777
  document = @store.get(params.dig(:textDocument, :uri))
@@ -785,7 +789,7 @@ module RubyLsp
785
789
  )
786
790
  end
787
791
 
788
- sig { params(document: Document[T.untyped]).returns(RubyDocument::SorbetLevel) }
792
+ #: (Document[untyped] document) -> RubyDocument::SorbetLevel
789
793
  def sorbet_level(document)
790
794
  return RubyDocument::SorbetLevel::Ignore unless @global_state.has_type_checker
791
795
  return RubyDocument::SorbetLevel::Ignore unless document.is_a?(RubyDocument)
@@ -793,7 +797,7 @@ module RubyLsp
793
797
  document.sorbet_level
794
798
  end
795
799
 
796
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
800
+ #: (Hash[Symbol, untyped] message) -> void
797
801
  def text_document_inlay_hint(message)
798
802
  params = message[:params]
799
803
  document = @store.get(params.dig(:textDocument, :uri))
@@ -827,7 +831,7 @@ module RubyLsp
827
831
  send_message(Result.new(id: message[:id], response: result.select { |hint| range.cover?(hint.position[:line]) }))
828
832
  end
829
833
 
830
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
834
+ #: (Hash[Symbol, untyped] message) -> void
831
835
  def text_document_code_action(message)
832
836
  params = message[:params]
833
837
  document = @store.get(params.dig(:textDocument, :uri))
@@ -849,7 +853,7 @@ module RubyLsp
849
853
  )
850
854
  end
851
855
 
852
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
856
+ #: (Hash[Symbol, untyped] message) -> void
853
857
  def code_action_resolve(message)
854
858
  params = message[:params]
855
859
  uri = URI(params.dig(:data, :uri))
@@ -874,7 +878,7 @@ module RubyLsp
874
878
  end
875
879
  end
876
880
 
877
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
881
+ #: (Hash[Symbol, untyped] message) -> void
878
882
  def text_document_diagnostic(message)
879
883
  # Do not compute diagnostics for files outside of the workspace. For example, if someone is looking at a gem's
880
884
  # source code, we don't want to show diagnostics for it
@@ -914,7 +918,7 @@ module RubyLsp
914
918
  send_empty_response(message[:id])
915
919
  end
916
920
 
917
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
921
+ #: (Hash[Symbol, untyped] message) -> void
918
922
  def text_document_completion(message)
919
923
  params = message[:params]
920
924
  dispatcher = Prism::Dispatcher.new
@@ -939,7 +943,7 @@ module RubyLsp
939
943
  )
940
944
  end
941
945
 
942
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
946
+ #: (Hash[Symbol, untyped] message) -> void
943
947
  def text_document_completion_item_resolve(message)
944
948
  # When responding to a delegated completion request, it means we're handling a completion item that isn't related
945
949
  # to Ruby (probably related to an ERB host language like HTML). We need to return the original completion item
@@ -958,7 +962,7 @@ module RubyLsp
958
962
  ))
959
963
  end
960
964
 
961
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
965
+ #: (Hash[Symbol, untyped] message) -> void
962
966
  def text_document_signature_help(message)
963
967
  params = message[:params]
964
968
  dispatcher = Prism::Dispatcher.new
@@ -984,7 +988,7 @@ module RubyLsp
984
988
  )
985
989
  end
986
990
 
987
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
991
+ #: (Hash[Symbol, untyped] message) -> void
988
992
  def text_document_definition(message)
989
993
  params = message[:params]
990
994
  dispatcher = Prism::Dispatcher.new
@@ -1009,8 +1013,23 @@ module RubyLsp
1009
1013
  )
1010
1014
  end
1011
1015
 
1012
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1016
+ #: (Hash[Symbol, untyped] message) -> void
1013
1017
  def workspace_did_change_watched_files(message)
1018
+ # If indexing is not complete yet, delay processing did change watched file notifications. We need initial
1019
+ # indexing to be in place so that we can handle file changes appropriately without risking duplicates. We also
1020
+ # have to sleep before re-inserting the notification in the queue otherwise the worker can get stuck in its own
1021
+ # loop of pushing and popping the same notification
1022
+ unless @global_state.index.initial_indexing_completed
1023
+ Thread.new do
1024
+ sleep(2)
1025
+ # We have to ensure that the queue is not closed yet, since nothing stops the user from saving a file and then
1026
+ # immediately telling the LSP to shutdown
1027
+ @incoming_queue << message unless @incoming_queue.closed?
1028
+ end
1029
+
1030
+ return
1031
+ end
1032
+
1014
1033
  changes = message.dig(:params, :changes)
1015
1034
  # We allow add-ons to register for watching files and we have no restrictions for what they register for. If the
1016
1035
  # same pattern is registered more than once, the LSP will receive duplicate change notifications. Receiving them
@@ -1046,32 +1065,34 @@ module RubyLsp
1046
1065
  end
1047
1066
  end
1048
1067
 
1049
- sig { params(index: RubyIndexer::Index, file_path: String, change_type: Integer).void }
1068
+ #: (RubyIndexer::Index index, String file_path, Integer change_type) -> void
1050
1069
  def handle_ruby_file_change(index, file_path, change_type)
1051
- load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
1052
- uri = URI::Generic.from_path(load_path_entry: load_path_entry, path: file_path)
1053
-
1054
- content = File.read(file_path)
1055
-
1056
- case change_type
1057
- when Constant::FileChangeType::CREATED
1058
- # If we receive a late created notification for a file that has already been claimed by the client, we want to
1059
- # handle change for that URI so that the require path tree is updated
1060
- @store.key?(uri) ? index.handle_change(uri, content) : index.index_single(uri, content)
1061
- when Constant::FileChangeType::CHANGED
1062
- # We only handle changes on file watched notifications if the client is not the one managing this URI.
1063
- # Otherwise, these changes are handled when running the combined requests
1064
- index.handle_change(uri, content) unless @store.key?(uri)
1065
- when Constant::FileChangeType::DELETED
1066
- index.delete(uri)
1067
- end
1068
- rescue Errno::ENOENT
1069
- # If a file is created and then delete immediately afterwards, we will process the created notification before we
1070
- # receive the deleted one, but the file no longer exists. This may happen when running a test suite that creates
1071
- # and deletes files automatically.
1070
+ @global_state.synchronize do
1071
+ load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
1072
+ uri = URI::Generic.from_path(load_path_entry: load_path_entry, path: file_path)
1073
+
1074
+ case change_type
1075
+ when Constant::FileChangeType::CREATED
1076
+ content = File.read(file_path)
1077
+ # If we receive a late created notification for a file that has already been claimed by the client, we want to
1078
+ # handle change for that URI so that the require path tree is updated
1079
+ @store.key?(uri) ? index.handle_change(uri, content) : index.index_single(uri, content)
1080
+ when Constant::FileChangeType::CHANGED
1081
+ content = File.read(file_path)
1082
+ # We only handle changes on file watched notifications if the client is not the one managing this URI.
1083
+ # Otherwise, these changes are handled when running the combined requests
1084
+ index.handle_change(uri, content) unless @store.key?(uri)
1085
+ when Constant::FileChangeType::DELETED
1086
+ index.delete(uri)
1087
+ end
1088
+ rescue Errno::ENOENT
1089
+ # If a file is created and then delete immediately afterwards, we will process the created notification before
1090
+ # we receive the deleted one, but the file no longer exists. This may happen when running a test suite that
1091
+ # creates and deletes files automatically.
1092
+ end
1072
1093
  end
1073
1094
 
1074
- sig { params(uri: URI::Generic).void }
1095
+ #: (URI::Generic uri) -> void
1075
1096
  def handle_rubocop_config_change(uri)
1076
1097
  return unless defined?(Requests::Support::RuboCopFormatter)
1077
1098
 
@@ -1091,7 +1112,7 @@ module RubyLsp
1091
1112
  end
1092
1113
  end
1093
1114
 
1094
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1115
+ #: (Hash[Symbol, untyped] message) -> void
1095
1116
  def workspace_symbol(message)
1096
1117
  send_message(
1097
1118
  Result.new(
@@ -1104,7 +1125,7 @@ module RubyLsp
1104
1125
  )
1105
1126
  end
1106
1127
 
1107
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1128
+ #: (Hash[Symbol, untyped] message) -> void
1108
1129
  def text_document_show_syntax_tree(message)
1109
1130
  params = message[:params]
1110
1131
  document = @store.get(params.dig(:textDocument, :uri))
@@ -1123,7 +1144,26 @@ module RubyLsp
1123
1144
  send_message(Result.new(id: message[:id], response: response))
1124
1145
  end
1125
1146
 
1126
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1147
+ #: (Hash[Symbol, untyped] message) -> void
1148
+ def experimental_go_to_relevant_file(message)
1149
+ path = message.dig(:params, :textDocument, :uri).to_standardized_path
1150
+ unless path.nil? || path.start_with?(@global_state.workspace_path)
1151
+ send_empty_response(message[:id])
1152
+ return
1153
+ end
1154
+
1155
+ unless path
1156
+ send_empty_response(message[:id])
1157
+ return
1158
+ end
1159
+
1160
+ response = {
1161
+ locations: Requests::GoToRelevantFile.new(path, @global_state.workspace_path).perform,
1162
+ }
1163
+ send_message(Result.new(id: message[:id], response: response))
1164
+ end
1165
+
1166
+ #: (Hash[Symbol, untyped] message) -> void
1127
1167
  def text_document_prepare_type_hierarchy(message)
1128
1168
  params = message[:params]
1129
1169
  document = @store.get(params.dig(:textDocument, :uri))
@@ -1142,7 +1182,7 @@ module RubyLsp
1142
1182
  send_message(Result.new(id: message[:id], response: response))
1143
1183
  end
1144
1184
 
1145
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1185
+ #: (Hash[Symbol, untyped] message) -> void
1146
1186
  def type_hierarchy_supertypes(message)
1147
1187
  response = Requests::TypeHierarchySupertypes.new(
1148
1188
  @global_state.index,
@@ -1151,14 +1191,14 @@ module RubyLsp
1151
1191
  send_message(Result.new(id: message[:id], response: response))
1152
1192
  end
1153
1193
 
1154
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1194
+ #: (Hash[Symbol, untyped] message) -> void
1155
1195
  def type_hierarchy_subtypes(message)
1156
1196
  # TODO: implement subtypes
1157
1197
  # The current index representation doesn't allow us to find the children of an entry.
1158
1198
  send_message(Result.new(id: message[:id], response: nil))
1159
1199
  end
1160
1200
 
1161
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1201
+ #: (Hash[Symbol, untyped] message) -> void
1162
1202
  def workspace_dependencies(message)
1163
1203
  unless @global_state.top_level_bundle
1164
1204
  send_message(Result.new(id: message[:id], response: []))
@@ -1186,12 +1226,13 @@ module RubyLsp
1186
1226
  send_message(Result.new(id: message[:id], response: response))
1187
1227
  end
1188
1228
 
1189
- sig { override.void }
1229
+ # @override
1230
+ #: -> void
1190
1231
  def shutdown
1191
1232
  Addon.unload_addons
1192
1233
  end
1193
1234
 
1194
- sig { void }
1235
+ #: -> void
1195
1236
  def perform_initial_indexing
1196
1237
  # The begin progress invocation happens during `initialize`, so that the notification is sent before we are
1197
1238
  # stuck indexing files
@@ -1223,7 +1264,7 @@ module RubyLsp
1223
1264
  end
1224
1265
  end
1225
1266
 
1226
- sig { params(id: String, title: String, percentage: Integer).void }
1267
+ #: (String id, String title, ?percentage: Integer) -> void
1227
1268
  def begin_progress(id, title, percentage: 0)
1228
1269
  return unless @global_state.client_capabilities.supports_progress
1229
1270
 
@@ -1236,14 +1277,14 @@ module RubyLsp
1236
1277
  send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
1237
1278
  end
1238
1279
 
1239
- sig { params(id: String, percentage: Integer).void }
1280
+ #: (String id, Integer percentage) -> void
1240
1281
  def progress(id, percentage)
1241
1282
  return unless @global_state.client_capabilities.supports_progress
1242
1283
 
1243
1284
  send_message(Notification.progress_report(id, percentage: percentage, message: "#{percentage}% completed"))
1244
1285
  end
1245
1286
 
1246
- sig { params(id: String).void }
1287
+ #: (String id) -> void
1247
1288
  def end_progress(id)
1248
1289
  return unless @global_state.client_capabilities.supports_progress
1249
1290
 
@@ -1253,7 +1294,7 @@ module RubyLsp
1253
1294
  # notification
1254
1295
  end
1255
1296
 
1256
- sig { void }
1297
+ #: -> void
1257
1298
  def check_formatter_is_available
1258
1299
  return if @setup_error
1259
1300
  # Warn of an unavailable `formatter` setting, e.g. `rubocop_internal` on a project which doesn't have RuboCop.
@@ -1271,7 +1312,7 @@ module RubyLsp
1271
1312
  end
1272
1313
  end
1273
1314
 
1274
- sig { params(indexing_options: T.nilable(T::Hash[Symbol, T.untyped])).void }
1315
+ #: (Hash[Symbol, untyped]? indexing_options) -> void
1275
1316
  def process_indexing_configuration(indexing_options)
1276
1317
  # Need to use the workspace URI, otherwise, this will fail for people working on a project that is a symlink.
1277
1318
  index_path = File.join(@global_state.workspace_path, ".index.yml")
@@ -1312,7 +1353,7 @@ module RubyLsp
1312
1353
  configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
1313
1354
  end
1314
1355
 
1315
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1356
+ #: (Hash[Symbol, untyped] message) -> void
1316
1357
  def window_show_message_request(message)
1317
1358
  result = message[:result]
1318
1359
  return unless result
@@ -1327,7 +1368,7 @@ module RubyLsp
1327
1368
  # NOTE: all servers methods are void because they can produce several messages for the client. The only reason this
1328
1369
  # method returns the created thread is to that we can join it in tests and avoid flakiness. The implementation is
1329
1370
  # not supposed to rely on the return of this method
1330
- sig { params(message: T::Hash[Symbol, T.untyped]).returns(T.nilable(Thread)) }
1371
+ #: (Hash[Symbol, untyped] message) -> Thread?
1331
1372
  def compose_bundle(message)
1332
1373
  already_composed_path = File.join(@global_state.workspace_path, ".ruby-lsp", "bundle_is_composed")
1333
1374
  id = message[:id]
@@ -1374,7 +1415,7 @@ module RubyLsp
1374
1415
  end
1375
1416
 
1376
1417
  # Returns internal state information for debugging purposes
1377
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1418
+ #: (Hash[Symbol, untyped] message) -> void
1378
1419
  def diagnose_state(message)
1379
1420
  documents = {}
1380
1421
  @store.each { |uri, document| documents[uri] = document.source }
@@ -1394,7 +1435,7 @@ module RubyLsp
1394
1435
 
1395
1436
  # Discovers all available test groups and examples in a given file taking into consideration the merged response of
1396
1437
  # all add-ons
1397
- sig { params(message: T::Hash[Symbol, T.untyped]).void }
1438
+ #: (Hash[Symbol, untyped] message) -> void
1398
1439
  def discover_tests(message)
1399
1440
  document = @store.get(message.dig(:params, :textDocument, :uri))
1400
1441
 
@@ -1414,5 +1455,15 @@ module RubyLsp
1414
1455
 
1415
1456
  send_message(Result.new(id: message[:id], response: items.map(&:to_hash)))
1416
1457
  end
1458
+
1459
+ #: (Hash[Symbol, untyped] message) -> void
1460
+ def resolve_test_commands(message)
1461
+ items = message.dig(:params, :items)
1462
+
1463
+ send_message(Result.new(
1464
+ id: message[:id],
1465
+ response: { commands: Listeners::TestStyle.resolve_test_commands(items) },
1466
+ ))
1467
+ end
1417
1468
  end
1418
1469
  end