ruby-lsp 0.23.11 → 0.26.4

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 (120) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -4
  5. data/exe/ruby-lsp-check +0 -4
  6. data/exe/ruby-lsp-launcher +45 -22
  7. data/exe/ruby-lsp-test-exec +6 -0
  8. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
  9. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
  10. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  11. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
  12. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
  13. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +107 -236
  14. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +188 -285
  15. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  16. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
  17. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
  18. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
  19. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  20. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  21. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  22. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  23. data/lib/ruby_indexer/test/configuration_test.rb +49 -9
  24. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  25. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  26. data/lib/ruby_indexer/test/index_test.rb +225 -135
  27. data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
  28. data/lib/ruby_indexer/test/method_test.rb +166 -123
  29. data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
  30. data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
  31. data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
  32. data/lib/ruby_indexer/test/test_case.rb +9 -3
  33. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  34. data/lib/ruby_lsp/addon.rb +88 -86
  35. data/lib/ruby_lsp/base_server.rb +79 -65
  36. data/lib/ruby_lsp/client_capabilities.rb +16 -13
  37. data/lib/ruby_lsp/document.rb +205 -104
  38. data/lib/ruby_lsp/erb_document.rb +45 -47
  39. data/lib/ruby_lsp/global_state.rb +73 -57
  40. data/lib/ruby_lsp/internal.rb +8 -3
  41. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  42. data/lib/ruby_lsp/listeners/completion.rb +81 -76
  43. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  44. data/lib/ruby_lsp/listeners/document_highlight.rb +149 -151
  45. data/lib/ruby_lsp/listeners/document_link.rb +94 -82
  46. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  47. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  48. data/lib/ruby_lsp/listeners/hover.rb +107 -115
  49. data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
  50. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  51. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  52. data/lib/ruby_lsp/listeners/spec_style.rb +231 -0
  53. data/lib/ruby_lsp/listeners/test_discovery.rb +107 -0
  54. data/lib/ruby_lsp/listeners/test_style.rb +207 -95
  55. data/lib/ruby_lsp/node_context.rb +12 -39
  56. data/lib/ruby_lsp/rbs_document.rb +10 -11
  57. data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
  58. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  59. data/lib/ruby_lsp/requests/code_lens.rb +31 -21
  60. data/lib/ruby_lsp/requests/completion.rb +8 -21
  61. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  62. data/lib/ruby_lsp/requests/definition.rb +8 -20
  63. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  64. data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
  65. data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
  66. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  67. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  68. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  69. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  70. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +139 -0
  71. data/lib/ruby_lsp/requests/hover.rb +12 -25
  72. data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
  73. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  74. data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
  75. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  76. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  77. data/lib/ruby_lsp/requests/references.rb +17 -57
  78. data/lib/ruby_lsp/requests/rename.rb +27 -51
  79. data/lib/ruby_lsp/requests/request.rb +13 -25
  80. data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
  81. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  82. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  83. data/lib/ruby_lsp/requests/signature_help.rb +9 -27
  84. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  85. data/lib/ruby_lsp/requests/support/common.rb +23 -61
  86. data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
  87. data/lib/ruby_lsp/requests/support/package_url.rb +414 -0
  88. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  89. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
  90. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
  91. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  92. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  93. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  94. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  95. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  96. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  97. data/lib/ruby_lsp/requests/workspace_symbol.rb +24 -16
  98. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +6 -9
  99. data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
  100. data/lib/ruby_lsp/response_builders/hover.rb +12 -18
  101. data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
  102. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
  103. data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
  104. data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
  105. data/lib/ruby_lsp/ruby_document.rb +32 -98
  106. data/lib/ruby_lsp/scope.rb +7 -11
  107. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  108. data/lib/ruby_lsp/server.rb +305 -198
  109. data/lib/ruby_lsp/setup_bundler.rb +131 -82
  110. data/lib/ruby_lsp/static_docs.rb +12 -7
  111. data/lib/ruby_lsp/store.rb +21 -49
  112. data/lib/ruby_lsp/test_helper.rb +3 -16
  113. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +241 -0
  114. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
  115. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
  116. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  117. data/lib/ruby_lsp/utils.rb +138 -93
  118. data/static_docs/break.md +103 -0
  119. metadata +15 -20
  120. data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -1,27 +1,29 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "ruby_lsp/listeners/test_discovery"
4
5
  require "ruby_lsp/listeners/test_style"
6
+ require "ruby_lsp/listeners/spec_style"
5
7
 
6
8
  module RubyLsp
7
9
  module Requests
8
10
  # This is a custom request to ask the server to parse a test file and discover all available examples in it. Add-ons
9
11
  # can augment the behavior through listeners, allowing them to handle discovery for different frameworks
10
12
  class DiscoverTests < Request
11
- extend T::Sig
12
13
  include Support::Common
13
14
 
14
- sig { params(global_state: GlobalState, document: RubyDocument, dispatcher: Prism::Dispatcher).void }
15
+ #: (GlobalState global_state, RubyDocument document, Prism::Dispatcher dispatcher) -> void
15
16
  def initialize(global_state, document, dispatcher)
16
17
  super()
17
18
  @global_state = global_state
18
19
  @document = document
19
20
  @dispatcher = dispatcher
20
- @response_builder = T.let(ResponseBuilders::TestCollection.new, ResponseBuilders::TestCollection)
21
- @index = T.let(global_state.index, RubyIndexer::Index)
21
+ @response_builder = ResponseBuilders::TestCollection.new #: ResponseBuilders::TestCollection
22
+ @index = global_state.index #: RubyIndexer::Index
22
23
  end
23
24
 
24
- sig { override.returns(T::Array[Support::TestItem]) }
25
+ # @override
26
+ #: -> Array[Support::TestItem]
25
27
  def perform
26
28
  uri = @document.uri
27
29
 
@@ -35,7 +37,13 @@ module RubyLsp
35
37
  # in the index first and then discover the tests, all in the same traversal.
36
38
  if @index.entries_for(uri.to_s)
37
39
  Listeners::TestStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
38
- @dispatcher.visit(@document.parse_result.value)
40
+ Listeners::SpecStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
41
+
42
+ Addon.addons.each do |addon|
43
+ addon.create_discover_tests_listener(@response_builder, @dispatcher, @document.uri)
44
+ end
45
+
46
+ @dispatcher.visit(@document.ast)
39
47
  else
40
48
  @global_state.synchronize do
41
49
  RubyIndexer::DeclarationListener.new(
@@ -47,11 +55,16 @@ module RubyLsp
47
55
  )
48
56
 
49
57
  Listeners::TestStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
58
+ Listeners::SpecStyle.new(@response_builder, @global_state, @dispatcher, @document.uri)
59
+
60
+ Addon.addons.each do |addon|
61
+ addon.create_discover_tests_listener(@response_builder, @dispatcher, @document.uri)
62
+ end
50
63
 
51
64
  # Dispatch the events both for indexing the test file and discovering the tests. The order here is
52
65
  # important because we need the index to be aware of the existing classes/modules/methods before the test
53
66
  # listeners can do their work
54
- @dispatcher.visit(@document.parse_result.value)
67
+ @dispatcher.visit(@document.ast)
55
68
  end
56
69
  end
57
70
 
@@ -13,31 +13,20 @@ module RubyLsp
13
13
  # For writable elements like constants or variables, their read/write occurrences should be highlighted differently.
14
14
  # This is achieved by sending different "kind" attributes to the editor (2 for read and 3 for write).
15
15
  class DocumentHighlight < Request
16
- extend T::Sig
17
-
18
- sig do
19
- params(
20
- global_state: GlobalState,
21
- document: T.any(RubyDocument, ERBDocument),
22
- position: T::Hash[Symbol, T.untyped],
23
- dispatcher: Prism::Dispatcher,
24
- ).void
25
- end
16
+ #: (GlobalState global_state, (RubyDocument | ERBDocument) document, Hash[Symbol, untyped] position, Prism::Dispatcher dispatcher) -> void
26
17
  def initialize(global_state, document, position, dispatcher)
27
18
  super()
28
19
  char_position, _ = document.find_index_by_position(position)
29
20
  delegate_request_if_needed!(global_state, document, char_position)
30
21
 
31
22
  node_context = RubyDocument.locate(
32
- document.parse_result.value,
23
+ document.ast,
33
24
  char_position,
34
25
  code_units_cache: document.code_units_cache,
35
26
  )
36
27
 
37
- @response_builder = T.let(
38
- ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight].new,
39
- ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight],
40
- )
28
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
29
+ .new #: ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight]
41
30
  Listeners::DocumentHighlight.new(
42
31
  @response_builder,
43
32
  node_context.node,
@@ -47,7 +36,8 @@ module RubyLsp
47
36
  )
48
37
  end
49
38
 
50
- sig { override.returns(T::Array[Interface::DocumentHighlight]) }
39
+ # @override
40
+ #: -> Array[Interface::DocumentHighlight]
51
41
  def perform
52
42
  @response_builder.response
53
43
  end
@@ -9,34 +9,23 @@ module RubyLsp
9
9
  # makes `# source://PATH_TO_FILE#line` comments in a Ruby/RBI file clickable if the file exists.
10
10
  # When the user clicks the link, it'll open that location.
11
11
  class DocumentLink < Request
12
- extend T::Sig
13
-
14
12
  class << self
15
- extend T::Sig
16
-
17
- sig { returns(Interface::DocumentLinkOptions) }
13
+ #: -> Interface::DocumentLinkOptions
18
14
  def provider
19
15
  Interface::DocumentLinkOptions.new(resolve_provider: false)
20
16
  end
21
17
  end
22
18
 
23
- sig do
24
- params(
25
- uri: URI::Generic,
26
- comments: T::Array[Prism::Comment],
27
- dispatcher: Prism::Dispatcher,
28
- ).void
29
- end
19
+ #: (URI::Generic uri, Array[Prism::Comment] comments, Prism::Dispatcher dispatcher) -> void
30
20
  def initialize(uri, comments, dispatcher)
31
21
  super()
32
- @response_builder = T.let(
33
- ResponseBuilders::CollectionResponseBuilder[Interface::DocumentLink].new,
34
- ResponseBuilders::CollectionResponseBuilder[Interface::DocumentLink],
35
- )
22
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
23
+ .new #: ResponseBuilders::CollectionResponseBuilder[Interface::DocumentLink]
36
24
  Listeners::DocumentLink.new(@response_builder, uri, comments, dispatcher)
37
25
  end
38
26
 
39
- sig { override.returns(T::Array[Interface::DocumentLink]) }
27
+ # @override
28
+ #: -> Array[Interface::DocumentLink]
40
29
  def perform
41
30
  @response_builder.response
42
31
  end
@@ -13,21 +13,17 @@ module RubyLsp
13
13
  # In VS Code, symbol search known as 'Go To Symbol in Editor' and can be accessed with Ctrl/Cmd-Shift-O,
14
14
  # or by opening the command palette and inserting an `@` symbol.
15
15
  class DocumentSymbol < Request
16
- extend T::Sig
17
-
18
16
  class << self
19
- extend T::Sig
20
-
21
- sig { returns(Interface::DocumentSymbolOptions) }
17
+ #: -> Interface::DocumentSymbolOptions
22
18
  def provider
23
19
  Interface::DocumentSymbolOptions.new
24
20
  end
25
21
  end
26
22
 
27
- sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
23
+ #: (URI::Generic uri, Prism::Dispatcher dispatcher) -> void
28
24
  def initialize(uri, dispatcher)
29
25
  super()
30
- @response_builder = T.let(ResponseBuilders::DocumentSymbol.new, ResponseBuilders::DocumentSymbol)
26
+ @response_builder = ResponseBuilders::DocumentSymbol.new #: ResponseBuilders::DocumentSymbol
31
27
  Listeners::DocumentSymbol.new(@response_builder, uri, dispatcher)
32
28
 
33
29
  Addon.addons.each do |addon|
@@ -35,7 +31,8 @@ module RubyLsp
35
31
  end
36
32
  end
37
33
 
38
- sig { override.returns(T::Array[Interface::DocumentSymbol]) }
34
+ # @override
35
+ #: -> Array[Interface::DocumentSymbol]
39
36
  def perform
40
37
  @response_builder.response
41
38
  end
@@ -8,31 +8,23 @@ module RubyLsp
8
8
  # The [folding ranges](https://microsoft.github.io/language-server-protocol/specification#textDocument_foldingRange)
9
9
  # request informs the editor of the ranges where and how code can be folded.
10
10
  class FoldingRanges < Request
11
- extend T::Sig
12
-
13
11
  class << self
14
- extend T::Sig
15
-
16
- sig { returns(TrueClass) }
12
+ #: -> TrueClass
17
13
  def provider
18
14
  true
19
15
  end
20
16
  end
21
17
 
22
- sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
18
+ #: (Array[Prism::Comment] comments, Prism::Dispatcher dispatcher) -> void
23
19
  def initialize(comments, dispatcher)
24
20
  super()
25
- @response_builder = T.let(
26
- ResponseBuilders::CollectionResponseBuilder[Interface::FoldingRange].new,
27
- ResponseBuilders::CollectionResponseBuilder[Interface::FoldingRange],
28
- )
29
- @listener = T.let(
30
- Listeners::FoldingRanges.new(@response_builder, comments, dispatcher),
31
- Listeners::FoldingRanges,
32
- )
21
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
22
+ .new #: ResponseBuilders::CollectionResponseBuilder[Interface::FoldingRange]
23
+ @listener = Listeners::FoldingRanges.new(@response_builder, comments, dispatcher) #: Listeners::FoldingRanges
33
24
  end
34
25
 
35
- sig { override.returns(T::Array[Interface::FoldingRange]) }
26
+ # @override
27
+ #: -> Array[Interface::FoldingRange]
36
28
  def perform
37
29
  @listener.finalize_response!
38
30
  @response_builder.response
@@ -7,28 +7,25 @@ module RubyLsp
7
7
  # request uses RuboCop to fix auto-correctable offenses in the document. This requires enabling format on save and
8
8
  # registering the ruby-lsp as the Ruby formatter.
9
9
  class Formatting < Request
10
- extend T::Sig
11
-
12
10
  class Error < StandardError; end
13
11
 
14
12
  class << self
15
- extend T::Sig
16
-
17
- sig { returns(TrueClass) }
13
+ #: -> TrueClass
18
14
  def provider
19
15
  true
20
16
  end
21
17
  end
22
18
 
23
- sig { params(global_state: GlobalState, document: RubyDocument).void }
19
+ #: (GlobalState global_state, RubyDocument document) -> void
24
20
  def initialize(global_state, document)
25
21
  super()
26
22
  @document = document
27
- @active_formatter = T.let(global_state.active_formatter, T.nilable(Support::Formatter))
28
- @uri = T.let(document.uri, URI::Generic)
23
+ @active_formatter = global_state.active_formatter #: Support::Formatter?
24
+ @uri = document.uri #: URI::Generic
29
25
  end
30
26
 
31
- sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
27
+ # @override
28
+ #: -> (Array[Interface::TextEdit] & Object)?
32
29
  def perform
33
30
  return unless @active_formatter
34
31
  return if @document.syntax_error?
@@ -0,0 +1,139 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # GoTo Relevant File is a custom [LSP
7
+ # request](https://microsoft.github.io/language-server-protocol/specification#requestMessage)
8
+ # that navigates to the relevant file for the current document.
9
+ # Currently, it supports source code file <> test file navigation.
10
+ class GoToRelevantFile < Request
11
+ TEST_KEYWORDS = ["test", "spec", "integration_test"]
12
+
13
+ TEST_PREFIX_PATTERN = /^(#{TEST_KEYWORDS.join("_|")}_)/
14
+ TEST_SUFFIX_PATTERN = /(_#{TEST_KEYWORDS.join("|_")})$/
15
+ TEST_PATTERN = /#{TEST_PREFIX_PATTERN}|#{TEST_SUFFIX_PATTERN}/
16
+
17
+ TEST_PREFIX_GLOB = "#{TEST_KEYWORDS.join("_,")}_" #: String
18
+ TEST_SUFFIX_GLOB = "_#{TEST_KEYWORDS.join(",_")}" #: String
19
+
20
+ #: (String path, String workspace_path) -> void
21
+ def initialize(path, workspace_path)
22
+ super()
23
+
24
+ @workspace_path = workspace_path
25
+ @path = path.delete_prefix(workspace_path) #: String
26
+ end
27
+
28
+ # @override
29
+ #: -> Array[String]
30
+ def perform
31
+ find_relevant_paths
32
+ end
33
+
34
+ private
35
+
36
+ #: -> Array[String]
37
+ def find_relevant_paths
38
+ patterns = relevant_filename_patterns
39
+
40
+ candidate_paths = patterns.flat_map do |pattern|
41
+ Dir.glob(File.join(search_root, "**", pattern))
42
+ end
43
+
44
+ return [] if candidate_paths.empty?
45
+
46
+ find_most_similar_with_jaccard(candidate_paths).map { |path| File.expand_path(path, @workspace_path) }
47
+ end
48
+
49
+ # Determine the search roots based on the closest test directories.
50
+ # This scopes the search to reduce the number of files that need to be checked.
51
+ #: -> String
52
+ def search_root
53
+ current_path = File.join(".", @path)
54
+ current_dir = File.dirname(current_path)
55
+ while current_dir != "."
56
+ dir_basename = File.basename(current_dir)
57
+
58
+ # If current directory is a test directory, return its parent as search root
59
+ if TEST_KEYWORDS.include?(dir_basename)
60
+ return File.dirname(current_dir)
61
+ end
62
+
63
+ # Search the test directories by walking up the directory tree
64
+ begin
65
+ contains_test_dir = Dir
66
+ .entries(current_dir)
67
+ .filter { |entry| TEST_KEYWORDS.include?(entry) }
68
+ .any? { |entry| File.directory?(File.join(current_dir, entry)) }
69
+
70
+ return current_dir if contains_test_dir
71
+ rescue Errno::EACCES, Errno::ENOENT
72
+ # Skip directories we can't read
73
+ end
74
+
75
+ # Move up one level
76
+ parent_dir = File.dirname(current_dir)
77
+ current_dir = parent_dir
78
+ end
79
+
80
+ "."
81
+ end
82
+
83
+ #: -> Array[String]
84
+ def relevant_filename_patterns
85
+ extension = File.extname(@path)
86
+ input_basename = File.basename(@path, extension)
87
+
88
+ if input_basename.match?(TEST_PATTERN)
89
+ # Test file -> find implementation
90
+ base = input_basename.gsub(TEST_PATTERN, "")
91
+ parent_dir = File.basename(File.dirname(@path))
92
+
93
+ # If test file is in a directory matching the implementation name
94
+ # (e.g., go_to_relevant_file/test_go_to_relevant_file_a.rb)
95
+ # return patterns for both the base file name and the parent directory name
96
+ if base.include?(parent_dir) && base != parent_dir
97
+ ["#{base}#{extension}", "#{parent_dir}#{extension}"]
98
+ else
99
+ ["#{base}#{extension}"]
100
+ end
101
+ else
102
+ # Implementation file -> find tests (including in matching directory)
103
+ [
104
+ "{#{TEST_PREFIX_GLOB}}#{input_basename}#{extension}",
105
+ "#{input_basename}{#{TEST_SUFFIX_GLOB}}#{extension}",
106
+ "#{input_basename}/{#{TEST_PREFIX_GLOB}}*#{extension}",
107
+ "#{input_basename}/*{#{TEST_SUFFIX_GLOB}}#{extension}",
108
+ ]
109
+ end
110
+ end
111
+
112
+ # Using the Jaccard algorithm to determine the similarity between the
113
+ # input path and the candidate relevant file paths.
114
+ # Ref: https://en.wikipedia.org/wiki/Jaccard_index
115
+ # The main idea of this algorithm is to take the size of interaction and divide
116
+ # it by the size of union between two sets (in our case the elements in each set
117
+ # would be the parts of the path separated by path divider.)
118
+ #: (Array[String] candidates) -> Array[String]
119
+ def find_most_similar_with_jaccard(candidates)
120
+ dirs = get_dir_parts(@path)
121
+
122
+ _, results = candidates
123
+ .group_by do |other_path|
124
+ other_dirs = get_dir_parts(other_path)
125
+ # Similarity score between the two directories
126
+ (dirs & other_dirs).size.to_f / (dirs | other_dirs).size
127
+ end
128
+ .max_by(&:first)
129
+
130
+ results || []
131
+ end
132
+
133
+ #: (String path) -> Set[String]
134
+ def get_dir_parts(path)
135
+ Set.new(File.dirname(path).split(File::SEPARATOR))
136
+ end
137
+ end
138
+ end
139
+ end
@@ -7,30 +7,16 @@ module RubyLsp
7
7
  module Requests
8
8
  # The [hover request](https://microsoft.github.io/language-server-protocol/specification#textDocument_hover)
9
9
  # displays the documentation for the symbol currently under the cursor.
10
+ #: [ResponseType = Interface::Hover?]
10
11
  class Hover < Request
11
- extend T::Sig
12
- extend T::Generic
13
-
14
12
  class << self
15
- extend T::Sig
16
-
17
- sig { returns(Interface::HoverOptions) }
13
+ #: -> Interface::HoverOptions
18
14
  def provider
19
15
  Interface::HoverOptions.new
20
16
  end
21
17
  end
22
18
 
23
- ResponseType = type_member { { fixed: T.nilable(Interface::Hover) } }
24
-
25
- sig do
26
- params(
27
- document: T.any(RubyDocument, ERBDocument),
28
- global_state: GlobalState,
29
- position: T::Hash[Symbol, T.untyped],
30
- dispatcher: Prism::Dispatcher,
31
- sorbet_level: RubyDocument::SorbetLevel,
32
- ).void
33
- end
19
+ #: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] position, Prism::Dispatcher dispatcher, SorbetLevel sorbet_level) -> void
34
20
  def initialize(document, global_state, position, dispatcher, sorbet_level)
35
21
  super()
36
22
 
@@ -38,7 +24,7 @@ module RubyLsp
38
24
  delegate_request_if_needed!(global_state, document, char_position)
39
25
 
40
26
  node_context = RubyDocument.locate(
41
- document.parse_result.value,
27
+ document.ast,
42
28
  char_position,
43
29
  node_types: Listeners::Hover::ALLOWED_TARGETS,
44
30
  code_units_cache: document.code_units_cache,
@@ -48,8 +34,8 @@ module RubyLsp
48
34
 
49
35
  if should_refine_target?(parent, target)
50
36
  target = determine_target(
51
- T.must(target),
52
- T.must(parent),
37
+ target, #: as !nil
38
+ parent, #: as !nil
53
39
  position,
54
40
  )
55
41
  elsif position_outside_target?(position, target)
@@ -59,9 +45,9 @@ module RubyLsp
59
45
  # Don't need to instantiate any listeners if there's no target
60
46
  return unless target
61
47
 
62
- @target = T.let(target, T.nilable(Prism::Node))
48
+ @target = target #: Prism::Node?
63
49
  uri = document.uri
64
- @response_builder = T.let(ResponseBuilders::Hover.new, ResponseBuilders::Hover)
50
+ @response_builder = ResponseBuilders::Hover.new #: ResponseBuilders::Hover
65
51
  Listeners::Hover.new(@response_builder, global_state, uri, node_context, dispatcher, sorbet_level)
66
52
  Addon.addons.each do |addon|
67
53
  addon.create_hover_listener(@response_builder, node_context, dispatcher)
@@ -70,7 +56,8 @@ module RubyLsp
70
56
  @dispatcher = dispatcher
71
57
  end
72
58
 
73
- sig { override.returns(ResponseType) }
59
+ # @override
60
+ #: -> ResponseType
74
61
  def perform
75
62
  return unless @target
76
63
 
@@ -88,14 +75,14 @@ module RubyLsp
88
75
 
89
76
  private
90
77
 
91
- sig { params(parent: T.nilable(Prism::Node), target: T.nilable(Prism::Node)).returns(T::Boolean) }
78
+ #: (Prism::Node? parent, Prism::Node? target) -> bool
92
79
  def should_refine_target?(parent, target)
93
80
  (Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
94
81
  !Listeners::Hover::ALLOWED_TARGETS.include?(target.class)) ||
95
82
  (parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
96
83
  end
97
84
 
98
- sig { params(position: T::Hash[Symbol, T.untyped], target: T.nilable(Prism::Node)).returns(T::Boolean) }
85
+ #: (Hash[Symbol, untyped] position, Prism::Node? target) -> bool
99
86
  def position_outside_target?(position, target)
100
87
  case target
101
88
  when Prism::GlobalVariableAndWriteNode,
@@ -9,35 +9,24 @@ module RubyLsp
9
9
  # are labels added directly in the code that explicitly show the user something that might
10
10
  # otherwise just be implied.
11
11
  class InlayHints < Request
12
- extend T::Sig
13
-
14
12
  class << self
15
- extend T::Sig
16
-
17
- sig { returns(Interface::InlayHintOptions) }
13
+ #: -> Interface::InlayHintOptions
18
14
  def provider
19
15
  Interface::InlayHintOptions.new(resolve_provider: false)
20
16
  end
21
17
  end
22
18
 
23
- sig do
24
- params(
25
- document: T.any(RubyDocument, ERBDocument),
26
- hints_configuration: RequestConfig,
27
- dispatcher: Prism::Dispatcher,
28
- ).void
29
- end
30
- def initialize(document, hints_configuration, dispatcher)
19
+ #: (GlobalState, (RubyDocument | ERBDocument), Prism::Dispatcher) -> void
20
+ def initialize(global_state, document, dispatcher)
31
21
  super()
32
22
 
33
- @response_builder = T.let(
34
- ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint].new,
35
- ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint],
36
- )
37
- Listeners::InlayHints.new(@response_builder, hints_configuration, dispatcher)
23
+ @response_builder = ResponseBuilders::CollectionResponseBuilder
24
+ .new #: ResponseBuilders::CollectionResponseBuilder[Interface::InlayHint]
25
+ Listeners::InlayHints.new(global_state, @response_builder, dispatcher)
38
26
  end
39
27
 
40
- sig { override.returns(T::Array[Interface::InlayHint]) }
28
+ # @override
29
+ #: -> Array[Interface::InlayHint]
41
30
  def perform
42
31
  @response_builder.response
43
32
  end