ruby-lsp 0.23.15 → 0.23.17

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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
  4. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +16 -19
  5. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +0 -3
  6. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +9 -19
  7. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +33 -69
  8. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +1 -10
  9. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +4 -4
  10. data/lib/ruby_indexer/test/index_test.rb +7 -0
  11. data/lib/ruby_indexer/test/method_test.rb +7 -7
  12. data/lib/ruby_indexer/test/rbs_indexer_test.rb +4 -3
  13. data/lib/ruby_indexer/test/test_case.rb +7 -1
  14. data/lib/ruby_lsp/document.rb +7 -10
  15. data/lib/ruby_lsp/erb_document.rb +2 -2
  16. data/lib/ruby_lsp/listeners/completion.rb +8 -8
  17. data/lib/ruby_lsp/listeners/definition.rb +7 -7
  18. data/lib/ruby_lsp/listeners/document_link.rb +7 -10
  19. data/lib/ruby_lsp/listeners/hover.rb +10 -9
  20. data/lib/ruby_lsp/listeners/signature_help.rb +2 -2
  21. data/lib/ruby_lsp/listeners/spec_style.rb +11 -11
  22. data/lib/ruby_lsp/listeners/test_style.rb +15 -10
  23. data/lib/ruby_lsp/rbs_document.rb +2 -2
  24. data/lib/ruby_lsp/requests/code_action_resolve.rb +54 -51
  25. data/lib/ruby_lsp/requests/code_lens.rb +15 -3
  26. data/lib/ruby_lsp/requests/completion.rb +2 -2
  27. data/lib/ruby_lsp/requests/definition.rb +3 -4
  28. data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
  29. data/lib/ruby_lsp/requests/document_link.rb +1 -1
  30. data/lib/ruby_lsp/requests/folding_ranges.rb +1 -1
  31. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +0 -2
  32. data/lib/ruby_lsp/requests/hover.rb +1 -1
  33. data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
  34. data/lib/ruby_lsp/requests/references.rb +1 -16
  35. data/lib/ruby_lsp/requests/rename.rb +1 -4
  36. data/lib/ruby_lsp/requests/request.rb +2 -1
  37. data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
  38. data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
  39. data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -1
  40. data/lib/ruby_lsp/requests/signature_help.rb +1 -1
  41. data/lib/ruby_lsp/requests/support/annotation.rb +1 -1
  42. data/lib/ruby_lsp/requests/support/common.rb +0 -5
  43. data/lib/ruby_lsp/requests/support/source_uri.rb +4 -2
  44. data/lib/ruby_lsp/requests/support/test_item.rb +6 -0
  45. data/lib/ruby_lsp/response_builders/document_symbol.rb +1 -1
  46. data/lib/ruby_lsp/response_builders/test_collection.rb +37 -0
  47. data/lib/ruby_lsp/ruby_document.rb +4 -34
  48. data/lib/ruby_lsp/server.rb +38 -22
  49. data/lib/ruby_lsp/setup_bundler.rb +2 -1
  50. data/lib/ruby_lsp/store.rb +6 -6
  51. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +43 -4
  52. data/lib/ruby_lsp/utils.rb +55 -2
  53. metadata +1 -1
@@ -242,7 +242,9 @@ module RubyLsp
242
242
 
243
243
  bundle_env_path = File.join(".ruby-lsp", "bundle_env")
244
244
  bundle_env = if File.exist?(bundle_env_path)
245
- env = File.readlines(bundle_env_path).to_h { |line| T.cast(line.chomp.split("=", 2), [String, String]) }
245
+ env = File.readlines(bundle_env_path).to_h do |line|
246
+ line.chomp.split("=", 2) #: as [String, String]
247
+ end
246
248
  FileUtils.rm(bundle_env_path)
247
249
  env
248
250
  end
@@ -385,11 +387,11 @@ module RubyLsp
385
387
  text_document = message.dig(:params, :textDocument)
386
388
  language_id = case text_document[:languageId]
387
389
  when "erb", "eruby"
388
- Document::LanguageId::ERB
390
+ :erb
389
391
  when "rbs"
390
- Document::LanguageId::RBS
392
+ :rbs
391
393
  else
392
- Document::LanguageId::Ruby
394
+ :ruby
393
395
  end
394
396
 
395
397
  document = @store.set(
@@ -489,13 +491,16 @@ module RubyLsp
489
491
  folding_range = Requests::FoldingRanges.new(parse_result.comments, dispatcher)
490
492
  document_symbol = Requests::DocumentSymbol.new(uri, dispatcher)
491
493
  document_link = Requests::DocumentLink.new(uri, parse_result.comments, dispatcher)
492
- code_lens = Requests::CodeLens.new(@global_state, uri, dispatcher)
493
494
  inlay_hint = Requests::InlayHints.new(
494
495
  document,
495
496
  @store.features_configuration.dig(:inlayHint), #: as !nil
496
497
  dispatcher,
497
498
  )
498
499
 
500
+ # The code lens listener requires the index to be populated, so the DeclarationListener must be inserted first in
501
+ # the dispatcher's state
502
+ code_lens = nil #: Requests::CodeLens?
503
+
499
504
  if document.is_a?(RubyDocument) && document.should_index?
500
505
  # Re-index the file as it is modified. This mode of indexing updates entries only. Require path trees are only
501
506
  # updated on save
@@ -505,10 +510,12 @@ module RubyLsp
505
510
  @global_state.index.handle_change(uri) do |index|
506
511
  index.delete(uri, skip_require_paths_tree: true)
507
512
  RubyIndexer::DeclarationListener.new(index, dispatcher, parse_result, uri, collect_comments: true)
513
+ code_lens = Requests::CodeLens.new(@global_state, uri, dispatcher)
508
514
  dispatcher.dispatch(parse_result.value)
509
515
  end
510
516
  end
511
517
  else
518
+ code_lens = Requests::CodeLens.new(@global_state, uri, dispatcher)
512
519
  dispatcher.dispatch(parse_result.value)
513
520
  end
514
521
 
@@ -517,7 +524,11 @@ module RubyLsp
517
524
  document.cache_set("textDocument/foldingRange", folding_range.perform)
518
525
  document.cache_set("textDocument/documentSymbol", document_symbol.perform)
519
526
  document.cache_set("textDocument/documentLink", document_link.perform)
520
- document.cache_set("textDocument/codeLens", code_lens.perform)
527
+ document.cache_set(
528
+ "textDocument/codeLens",
529
+ code_lens #: as !nil
530
+ .perform,
531
+ )
521
532
  document.cache_set("textDocument/inlayHint", inlay_hint.perform)
522
533
 
523
534
  send_message(Result.new(id: message[:id], response: document.cache_get(message[:method])))
@@ -672,6 +683,10 @@ module RubyLsp
672
683
  "Formatting error: #{error.message}",
673
684
  type: Constant::MessageType::ERROR,
674
685
  ))
686
+ send_message(Notification.window_log_message(
687
+ "Formatting failed with\r\n: #{error.full_message}",
688
+ type: Constant::MessageType::ERROR,
689
+ ))
675
690
  send_empty_response(message[:id])
676
691
  end
677
692
 
@@ -795,12 +810,16 @@ module RubyLsp
795
810
  )
796
811
  end
797
812
 
798
- #: (Document[untyped] document) -> RubyDocument::SorbetLevel
813
+ #: (Document[untyped] document) -> SorbetLevel
799
814
  def sorbet_level(document)
800
- return RubyDocument::SorbetLevel::Ignore unless @global_state.has_type_checker
801
- return RubyDocument::SorbetLevel::Ignore unless document.is_a?(RubyDocument)
815
+ return SorbetLevel.ignore unless document.is_a?(RubyDocument)
816
+ return SorbetLevel.ignore unless @global_state.has_type_checker
817
+
818
+ sigil = document.parse_result.magic_comments.find do |comment|
819
+ comment.key == "typed"
820
+ end&.value
802
821
 
803
- document.sorbet_level
822
+ SorbetLevel.new(sigil)
804
823
  end
805
824
 
806
825
  #: (Hash[Symbol, untyped] message) -> void
@@ -871,17 +890,9 @@ module RubyLsp
871
890
  end
872
891
 
873
892
  result = Requests::CodeActionResolve.new(document, @global_state, params).perform
874
-
875
- case result
876
- when Requests::CodeActionResolve::Error::EmptySelection
877
- fail_request_and_notify(message[:id], "Invalid selection for extract variable refactor")
878
- when Requests::CodeActionResolve::Error::InvalidTargetRange
879
- fail_request_and_notify(message[:id], "Couldn't find an appropriate location to place extracted refactor")
880
- when Requests::CodeActionResolve::Error::UnknownCodeAction
881
- fail_request_and_notify(message[:id], "Unknown code action")
882
- else
883
- send_message(Result.new(id: message[:id], response: result))
884
- end
893
+ send_message(Result.new(id: message[:id], response: result))
894
+ rescue Requests::CodeActionResolve::CodeActionError => e
895
+ fail_request_and_notify(message[:id], e.message)
885
896
  end
886
897
 
887
898
  #: (Hash[Symbol, untyped] message) -> void
@@ -921,6 +932,10 @@ module RubyLsp
921
932
  "Error running diagnostics: #{error.message}",
922
933
  type: Constant::MessageType::ERROR,
923
934
  ))
935
+ send_message(Notification.window_log_message(
936
+ "Diagnostics failed with\r\n: #{error.full_message}",
937
+ type: Constant::MessageType::ERROR,
938
+ ))
924
939
  send_empty_response(message[:id])
925
940
  end
926
941
 
@@ -1062,7 +1077,8 @@ module RubyLsp
1062
1077
  end
1063
1078
 
1064
1079
  Addon.file_watcher_addons.each do |addon|
1065
- T.unsafe(addon).workspace_did_change_watched_files(changes)
1080
+ addon #: as untyped
1081
+ .workspace_did_change_watched_files(changes)
1066
1082
  rescue => e
1067
1083
  send_log_message(
1068
1084
  "Error in #{addon.name} add-on while processing watched file notifications: #{e.full_message}",
@@ -260,7 +260,8 @@ module RubyLsp
260
260
  # The ENV can only be merged after checking if an update is required because we depend on the original value of
261
261
  # ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
262
262
  should_update = should_bundle_update?
263
- T.unsafe(ENV).merge!(env)
263
+ ENV #: as untyped
264
+ .merge!(env)
264
265
 
265
266
  unless should_update && !force_install
266
267
  Bundler::CLI::Install.new({ "no-cache" => true }).run
@@ -38,11 +38,11 @@ module RubyLsp
38
38
  ext = File.extname(path)
39
39
  language_id = case ext
40
40
  when ".erb", ".rhtml"
41
- Document::LanguageId::ERB
41
+ :erb
42
42
  when ".rbs"
43
- Document::LanguageId::RBS
43
+ :rbs
44
44
  else
45
- Document::LanguageId::Ruby
45
+ :ruby
46
46
  end
47
47
 
48
48
  set(uri: uri, source: File.binread(path), version: 0, language_id: language_id)
@@ -51,12 +51,12 @@ module RubyLsp
51
51
  raise NonExistingDocumentError, uri.to_s
52
52
  end
53
53
 
54
- #: (uri: URI::Generic, source: String, version: Integer, language_id: Document::LanguageId) -> Document[untyped]
54
+ #: (uri: URI::Generic, source: String, version: Integer, language_id: Symbol) -> Document[untyped]
55
55
  def set(uri:, source:, version:, language_id:)
56
56
  @state[uri.to_s] = case language_id
57
- when Document::LanguageId::ERB
57
+ when :erb
58
58
  ERBDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
59
- when Document::LanguageId::RBS
59
+ when :rbs
60
60
  RBSDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
61
61
  else
62
62
  RubyDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
@@ -4,25 +4,57 @@
4
4
  require "json"
5
5
  require "socket"
6
6
  require "singleton"
7
+ require "tmpdir"
7
8
 
8
9
  module RubyLsp
9
10
  class LspReporter
10
11
  include Singleton
11
12
 
13
+ #: bool
14
+ attr_reader :invoked_shutdown
15
+
12
16
  #: -> void
13
17
  def initialize
18
+ dir_path = File.join(Dir.tmpdir, "ruby-lsp")
19
+ FileUtils.mkdir_p(dir_path)
20
+
21
+ port_path = File.join(dir_path, "test_reporter_port")
14
22
  port = ENV["RUBY_LSP_REPORTER_PORT"]
15
- @io = if port
16
- TCPSocket.new("localhost", port)
17
- else
18
- # For tests that don't spawn the TCP server
23
+
24
+ @io = begin
25
+ # The environment variable is only used for tests. The extension always writes to the temporary file
26
+ if port
27
+ TCPSocket.new("localhost", port)
28
+ elsif File.exist?(port_path)
29
+ TCPSocket.new("localhost", File.read(port_path))
30
+ else
31
+ # For tests that don't spawn the TCP server
32
+ require "stringio"
33
+ StringIO.new
34
+ end
35
+ rescue
19
36
  require "stringio"
20
37
  StringIO.new
21
38
  end #: IO | StringIO
39
+
40
+ @invoked_shutdown = false #: bool
22
41
  end
23
42
 
24
43
  #: -> void
25
44
  def shutdown
45
+ # When running in coverage mode, we don't want to inform the extension that we finished immediately after running
46
+ # tests. We only do it after we finish processing coverage results, by invoking `internal_shutdown`
47
+ return if ENV["RUBY_LSP_TEST_RUNNER"] == "coverage"
48
+
49
+ internal_shutdown
50
+ end
51
+
52
+ # This method is intended to be used by the RubyLsp::LspReporter class itself only. If you're writing a custom test
53
+ # reporter, use `shutdown` instead
54
+ #: -> void
55
+ def internal_shutdown
56
+ @invoked_shutdown = true
57
+
26
58
  send_message("finish")
27
59
  @io.close
28
60
  end
@@ -148,5 +180,12 @@ if ENV["RUBY_LSP_TEST_RUNNER"] == "coverage"
148
180
  at_exit do
149
181
  coverage_results = RubyLsp::LspReporter.instance.gather_coverage_results
150
182
  File.write(File.join(".ruby-lsp", "coverage_result.json"), coverage_results.to_json)
183
+ RubyLsp::LspReporter.instance.internal_shutdown
184
+ end
185
+ elsif ENV["RUBY_LSP_TEST_RUNNER"] && ENV["RUBY_LSP_ENV"] != "test"
186
+ at_exit do
187
+ # If the test process crashed immediately without finishing the tests, we still need to tell the extension that the
188
+ # execution ended so that it can clean up
189
+ RubyLsp::LspReporter.instance.internal_shutdown unless RubyLsp::LspReporter.instance.invoked_shutdown
151
190
  end
152
191
  end
@@ -137,7 +137,12 @@ module RubyLsp
137
137
  #: -> Hash[Symbol, untyped]
138
138
  def to_hash
139
139
  hash = { method: @method }
140
- hash[:params] = T.unsafe(@params).to_hash if @params
140
+
141
+ if @params
142
+ hash[:params] = @params #: as untyped
143
+ .to_hash
144
+ end
145
+
141
146
  hash
142
147
  end
143
148
  end
@@ -181,7 +186,12 @@ module RubyLsp
181
186
  #: -> Hash[Symbol, untyped]
182
187
  def to_hash
183
188
  hash = { id: @id, method: @method }
184
- hash[:params] = T.unsafe(@params).to_hash if @params
189
+
190
+ if @params
191
+ hash[:params] = @params #: as untyped
192
+ .to_hash
193
+ end
194
+
185
195
  hash
186
196
  end
187
197
  end
@@ -249,4 +259,47 @@ module RubyLsp
249
259
  @configuration[:enableAll] || @configuration[feature]
250
260
  end
251
261
  end
262
+
263
+ class SorbetLevel
264
+ class << self
265
+ #: -> SorbetLevel
266
+ def ignore
267
+ new("ignore")
268
+ end
269
+ end
270
+
271
+ #: (String?) -> void
272
+ def initialize(sigil)
273
+ @level = case sigil
274
+ when "ignore"
275
+ :ignore
276
+ when "false"
277
+ :false
278
+ when "true"
279
+ :true
280
+ when "strict", "strong"
281
+ :strict
282
+ else
283
+ :none
284
+ end #: Symbol
285
+ end
286
+
287
+ #: -> bool
288
+ def ignore? = @level == :ignore
289
+
290
+ #: -> bool
291
+ def false? = @level == :false
292
+
293
+ #: -> bool
294
+ def true? = @level == :true
295
+
296
+ #: -> bool
297
+ def strict? = @level == :strict
298
+
299
+ #: -> bool
300
+ def none? = @level == :none
301
+
302
+ #: -> bool
303
+ def true_or_higher? = @level == :true || @level == :strict
304
+ end
252
305
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.15
4
+ version: 0.23.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify