ruby-lsp 0.23.11 → 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 (112) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp-launcher +20 -11
  5. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -1
  6. data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
  7. data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
  8. data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +134 -183
  9. data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -10
  10. data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +97 -217
  11. data/lib/ruby_indexer/lib/ruby_indexer/index.rb +139 -281
  12. data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
  13. data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +18 -19
  14. data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +23 -55
  15. data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +47 -61
  16. data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
  17. data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
  18. data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
  19. data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
  20. data/lib/ruby_indexer/test/configuration_test.rb +48 -7
  21. data/lib/ruby_indexer/test/constant_test.rb +34 -34
  22. data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
  23. data/lib/ruby_indexer/test/index_test.rb +146 -135
  24. data/lib/ruby_indexer/test/instance_variables_test.rb +37 -37
  25. data/lib/ruby_indexer/test/method_test.rb +149 -123
  26. data/lib/ruby_indexer/test/prefix_tree_test.rb +13 -13
  27. data/lib/ruby_indexer/test/rbs_indexer_test.rb +68 -73
  28. data/lib/ruby_indexer/test/test_case.rb +9 -3
  29. data/lib/ruby_indexer/test/uri_test.rb +15 -2
  30. data/lib/ruby_lsp/addon.rb +44 -71
  31. data/lib/ruby_lsp/base_server.rb +29 -32
  32. data/lib/ruby_lsp/client_capabilities.rb +10 -12
  33. data/lib/ruby_lsp/document.rb +40 -54
  34. data/lib/ruby_lsp/erb_document.rb +37 -41
  35. data/lib/ruby_lsp/global_state.rb +52 -57
  36. data/lib/ruby_lsp/internal.rb +2 -0
  37. data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
  38. data/lib/ruby_lsp/listeners/completion.rb +67 -73
  39. data/lib/ruby_lsp/listeners/definition.rb +44 -58
  40. data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
  41. data/lib/ruby_lsp/listeners/document_link.rb +50 -70
  42. data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
  43. data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
  44. data/lib/ruby_lsp/listeners/hover.rb +92 -110
  45. data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
  46. data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
  47. data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
  48. data/lib/ruby_lsp/listeners/spec_style.rb +155 -0
  49. data/lib/ruby_lsp/listeners/test_discovery.rb +89 -0
  50. data/lib/ruby_lsp/listeners/test_style.rb +167 -90
  51. data/lib/ruby_lsp/node_context.rb +12 -39
  52. data/lib/ruby_lsp/rbs_document.rb +9 -7
  53. data/lib/ruby_lsp/requests/code_action_resolve.rb +63 -59
  54. data/lib/ruby_lsp/requests/code_actions.rb +14 -26
  55. data/lib/ruby_lsp/requests/code_lens.rb +20 -19
  56. data/lib/ruby_lsp/requests/completion.rb +7 -20
  57. data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
  58. data/lib/ruby_lsp/requests/definition.rb +7 -17
  59. data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
  60. data/lib/ruby_lsp/requests/discover_tests.rb +18 -5
  61. data/lib/ruby_lsp/requests/document_highlight.rb +5 -15
  62. data/lib/ruby_lsp/requests/document_link.rb +6 -17
  63. data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
  64. data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
  65. data/lib/ruby_lsp/requests/formatting.rb +6 -9
  66. data/lib/ruby_lsp/requests/go_to_relevant_file.rb +85 -0
  67. data/lib/ruby_lsp/requests/hover.rb +10 -20
  68. data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
  69. data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
  70. data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
  71. data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
  72. data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
  73. data/lib/ruby_lsp/requests/references.rb +9 -53
  74. data/lib/ruby_lsp/requests/rename.rb +20 -46
  75. data/lib/ruby_lsp/requests/request.rb +8 -19
  76. data/lib/ruby_lsp/requests/selection_ranges.rb +6 -6
  77. data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
  78. data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
  79. data/lib/ruby_lsp/requests/signature_help.rb +8 -26
  80. data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
  81. data/lib/ruby_lsp/requests/support/common.rb +15 -55
  82. data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
  83. data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +11 -14
  84. data/lib/ruby_lsp/requests/support/rubocop_runner.rb +22 -34
  85. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
  86. data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
  87. data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
  88. data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
  89. data/lib/ruby_lsp/requests/support/test_item.rb +16 -14
  90. data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
  91. data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
  92. data/lib/ruby_lsp/response_builders/collection_response_builder.rb +5 -5
  93. data/lib/ruby_lsp/response_builders/document_symbol.rb +14 -19
  94. data/lib/ruby_lsp/response_builders/hover.rb +11 -14
  95. data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
  96. data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +60 -88
  97. data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
  98. data/lib/ruby_lsp/response_builders/test_collection.rb +43 -10
  99. data/lib/ruby_lsp/ruby_document.rb +24 -92
  100. data/lib/ruby_lsp/scope.rb +7 -11
  101. data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
  102. data/lib/ruby_lsp/server.rb +182 -99
  103. data/lib/ruby_lsp/setup_bundler.rb +65 -60
  104. data/lib/ruby_lsp/static_docs.rb +11 -7
  105. data/lib/ruby_lsp/store.rb +29 -47
  106. data/lib/ruby_lsp/test_helper.rb +2 -12
  107. data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +191 -0
  108. data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +105 -0
  109. data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +94 -0
  110. data/lib/ruby_lsp/type_inferrer.rb +13 -14
  111. data/lib/ruby_lsp/utils.rb +92 -83
  112. metadata +9 -3
@@ -6,45 +6,32 @@ require "shellwords"
6
6
  module RubyLsp
7
7
  module Listeners
8
8
  class CodeLens
9
- extend T::Sig
10
9
  include Requests::Support::Common
11
10
 
12
- BASE_COMMAND = T.let(
13
- begin
14
- Bundler.with_original_env { Bundler.default_lockfile }
15
- "bundle exec ruby"
16
- rescue Bundler::GemfileNotFound
17
- "ruby"
18
- end,
19
- String,
20
- )
21
- ACCESS_MODIFIERS = T.let([:public, :private, :protected], T::Array[Symbol])
22
- SUPPORTED_TEST_LIBRARIES = T.let(["minitest", "test-unit"], T::Array[String])
23
- DESCRIBE_KEYWORD = T.let(:describe, Symbol)
24
- IT_KEYWORD = T.let(:it, Symbol)
25
- DYNAMIC_REFERENCE_MARKER = T.let("<dynamic_reference>", String)
26
-
27
- sig do
28
- params(
29
- response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
30
- global_state: GlobalState,
31
- uri: URI::Generic,
32
- dispatcher: Prism::Dispatcher,
33
- ).void
34
- end
11
+ BASE_COMMAND = begin
12
+ Bundler.with_original_env { Bundler.default_lockfile }
13
+ "bundle exec ruby"
14
+ rescue Bundler::GemfileNotFound
15
+ "ruby"
16
+ end #: String
17
+ ACCESS_MODIFIERS = [:public, :private, :protected] #: Array[Symbol]
18
+ SUPPORTED_TEST_LIBRARIES = ["minitest", "test-unit"] #: Array[String]
19
+ DYNAMIC_REFERENCE_MARKER = "<dynamic_reference>" #: String
20
+
21
+ #: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, GlobalState global_state, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
35
22
  def initialize(response_builder, global_state, uri, dispatcher)
36
23
  @response_builder = response_builder
37
24
  @global_state = global_state
38
- @uri = T.let(uri, URI::Generic)
39
- @path = T.let(uri.to_standardized_path, T.nilable(String))
25
+ @uri = uri #: URI::Generic
26
+ @path = uri.to_standardized_path #: String?
40
27
  # visibility_stack is a stack of [current_visibility, previous_visibility]
41
- @visibility_stack = T.let([[:public, :public]], T::Array[T::Array[T.nilable(Symbol)]])
42
- @group_stack = T.let([], T::Array[String])
43
- @group_id = T.let(1, Integer)
44
- @group_id_stack = T.let([], T::Array[Integer])
28
+ @visibility_stack = [[:public, :public]] #: Array[Array[Symbol?]]
29
+ @group_stack = [] #: Array[String]
30
+ @group_id = 1 #: Integer
31
+ @group_id_stack = [] #: Array[Integer]
45
32
  # We want to avoid adding code lenses for nested definitions
46
- @def_depth = T.let(0, Integer)
47
- @spec_id = T.let(0, Integer)
33
+ @def_depth = 0 #: Integer
34
+ @spec_id = 0 #: Integer
48
35
 
49
36
  dispatcher.register(
50
37
  self,
@@ -59,7 +46,7 @@ module RubyLsp
59
46
  )
60
47
  end
61
48
 
62
- sig { params(node: Prism::ClassNode).void }
49
+ #: (Prism::ClassNode node) -> void
63
50
  def on_class_node_enter(node)
64
51
  @visibility_stack.push([:public, :public])
65
52
  class_name = node.constant_path.slice
@@ -79,7 +66,7 @@ module RubyLsp
79
66
  end
80
67
  end
81
68
 
82
- sig { params(node: Prism::ClassNode).void }
69
+ #: (Prism::ClassNode node) -> void
83
70
  def on_class_node_leave(node)
84
71
  @visibility_stack.pop
85
72
  @group_stack.pop
@@ -91,7 +78,7 @@ module RubyLsp
91
78
  end
92
79
  end
93
80
 
94
- sig { params(node: Prism::DefNode).void }
81
+ #: (Prism::DefNode node) -> void
95
82
  def on_def_node_enter(node)
96
83
  @def_depth += 1
97
84
  return if @def_depth > 1
@@ -114,12 +101,12 @@ module RubyLsp
114
101
  end
115
102
  end
116
103
 
117
- sig { params(node: Prism::DefNode).void }
104
+ #: (Prism::DefNode node) -> void
118
105
  def on_def_node_leave(node)
119
106
  @def_depth -= 1
120
107
  end
121
108
 
122
- sig { params(node: Prism::ModuleNode).void }
109
+ #: (Prism::ModuleNode node) -> void
123
110
  def on_module_node_enter(node)
124
111
  if (path = namespace_constant_name(node))
125
112
  @group_stack.push(path)
@@ -128,12 +115,12 @@ module RubyLsp
128
115
  end
129
116
  end
130
117
 
131
- sig { params(node: Prism::ModuleNode).void }
118
+ #: (Prism::ModuleNode node) -> void
132
119
  def on_module_node_leave(node)
133
120
  @group_stack.pop
134
121
  end
135
122
 
136
- sig { params(node: Prism::CallNode).void }
123
+ #: (Prism::CallNode node) -> void
137
124
  def on_call_node_enter(node)
138
125
  name = node.name
139
126
  arguments = node.arguments
@@ -151,23 +138,21 @@ module RubyLsp
151
138
  return
152
139
  end
153
140
 
154
- if [DESCRIBE_KEYWORD, IT_KEYWORD].include?(name)
155
- case name
156
- when DESCRIBE_KEYWORD
157
- add_spec_code_lens(node, kind: :group)
158
- @group_id_stack.push(@group_id)
159
- @group_id += 1
160
- when IT_KEYWORD
161
- add_spec_code_lens(node, kind: :example)
162
- end
141
+ case name
142
+ when :describe
143
+ add_spec_code_lens(node, kind: :group)
144
+ @group_id_stack.push(@group_id)
145
+ @group_id += 1
146
+ when :it, :specify # `specify` is an alias for `it`
147
+ add_spec_code_lens(node, kind: :example)
163
148
  end
164
149
  end
165
150
 
166
- sig { params(node: Prism::CallNode).void }
151
+ #: (Prism::CallNode node) -> void
167
152
  def on_call_node_leave(node)
168
153
  _, prev_visibility = @visibility_stack.pop
169
154
  @visibility_stack.push([prev_visibility, prev_visibility])
170
- if node.name == DESCRIBE_KEYWORD
155
+ if node.name == :describe
171
156
  @group_id_stack.pop
172
157
  @group_stack.pop
173
158
  end
@@ -175,7 +160,7 @@ module RubyLsp
175
160
 
176
161
  private
177
162
 
178
- sig { params(node: Prism::Node, name: String, command: String, kind: Symbol, id: String).void }
163
+ #: (Prism::Node node, name: String, command: String, kind: Symbol, ?id: String) -> void
179
164
  def add_test_code_lens(node, name:, command:, kind:, id: name)
180
165
  # don't add code lenses if the test library is not supported or unknown
181
166
  return unless SUPPORTED_TEST_LIBRARIES.include?(@global_state.test_library) && @path
@@ -221,15 +206,9 @@ module RubyLsp
221
206
  )
222
207
  end
223
208
 
224
- sig do
225
- params(
226
- group_stack: T::Array[String],
227
- spec_name: T.nilable(String),
228
- method_name: T.nilable(String),
229
- ).returns(String)
230
- end
209
+ #: (?group_stack: Array[String], ?spec_name: String?, ?method_name: String?) -> String
231
210
  def generate_test_command(group_stack: [], spec_name: nil, method_name: nil)
232
- path = T.must(@path)
211
+ path = @path #: as !nil
233
212
  command = BASE_COMMAND
234
213
  command += " -Itest" if File.fnmatch?("**/test/**/*", path, File::FNM_PATHNAME)
235
214
  command += " -Ispec" if File.fnmatch?("**/spec/**/*", path, File::FNM_PATHNAME)
@@ -237,44 +216,58 @@ module RubyLsp
237
216
 
238
217
  case @global_state.test_library
239
218
  when "minitest"
240
- last_dynamic_reference_index = group_stack.rindex(DYNAMIC_REFERENCE_MARKER)
241
- command += if last_dynamic_reference_index
242
- # In cases where the test path looks like `foo::Bar`
243
- # the best we can do is match everything to the right of it.
244
- # Tests are classes, dynamic references are only a thing for modules,
245
- # so there must be something to the left of the available path.
246
- group_stack = T.must(group_stack[last_dynamic_reference_index + 1..])
247
- if method_name
248
- " --name " + "/::#{Shellwords.escape(group_stack.join("::")) + "#" + Shellwords.escape(method_name)}$/"
249
- else
250
- # When clicking on a CodeLens for `Test`, `(#|::)` will match all tests
251
- # that are registered on the class itself (matches after `#`) and all tests
252
- # that are nested inside of that class in other modules/classes (matches after `::`)
253
- " --name " + "\"/::#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
254
- end
255
- elsif method_name
256
- # We know the entire path, do an exact match
257
- " --name " + Shellwords.escape(group_stack.join("::")) + "#" + Shellwords.escape(method_name)
258
- elsif spec_name
259
- " --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}##{Shellwords.escape(spec_name)}$/\""
260
- else
261
- # Execute all tests of the selected class and tests in
262
- # modules/classes nested inside of that class
263
- " --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
264
- end
219
+ command += generate_minitest_command(group_stack, method_name, spec_name)
265
220
  when "test-unit"
266
- group_name = T.must(group_stack.last)
267
- command += " --testcase " + "/#{Shellwords.escape(group_name)}/"
221
+ command += generate_test_unit_command(group_stack, method_name)
222
+ end
223
+
224
+ command
225
+ end
226
+
227
+ #: (Array[String] group_stack, String? method_name, String? spec_name) -> String
228
+ def generate_minitest_command(group_stack, method_name, spec_name)
229
+ last_dynamic_reference_index = group_stack.rindex(DYNAMIC_REFERENCE_MARKER)
230
+
231
+ if last_dynamic_reference_index
232
+ # In cases where the test path looks like `foo::Bar`
233
+ # the best we can do is match everything to the right of it.
234
+ # Tests are classes, dynamic references are only a thing for modules,
235
+ # so there must be something to the left of the available path.
236
+ dynamic_stack = group_stack[last_dynamic_reference_index + 1..] #: as !nil
268
237
 
269
238
  if method_name
270
- command += " --name " + Shellwords.escape(method_name)
239
+ " --name " + "/::#{Shellwords.escape(dynamic_stack.join("::")) + "#" + Shellwords.escape(method_name)}$/"
240
+ else
241
+ # When clicking on a CodeLens for `Test`, `(#|::)` will match all tests
242
+ # that are registered on the class itself (matches after `#`) and all tests
243
+ # that are nested inside of that class in other modules/classes (matches after `::`)
244
+ " --name " + "\"/::#{Shellwords.escape(dynamic_stack.join("::"))}(#|::)/\""
271
245
  end
246
+ elsif method_name
247
+ # We know the entire path, do an exact match
248
+ " --name " + Shellwords.escape(group_stack.join("::")) + "#" + Shellwords.escape(method_name)
249
+ elsif spec_name
250
+ " --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}##{Shellwords.escape(spec_name)}$/\""
251
+ else
252
+ # Execute all tests of the selected class and tests in
253
+ # modules/classes nested inside of that class
254
+ " --name " + "\"/^#{Shellwords.escape(group_stack.join("::"))}(#|::)/\""
255
+ end
256
+ end
257
+
258
+ #: (Array[String] group_stack, String? method_name) -> String
259
+ def generate_test_unit_command(group_stack, method_name)
260
+ group_name = group_stack.last #: as !nil
261
+ command = " --testcase " + "/#{Shellwords.escape(group_name)}/"
262
+
263
+ if method_name
264
+ command += " --name " + Shellwords.escape(method_name)
272
265
  end
273
266
 
274
267
  command
275
268
  end
276
269
 
277
- sig { params(node: Prism::CallNode, kind: Symbol).void }
270
+ #: (Prism::CallNode node, kind: Symbol) -> void
278
271
  def add_spec_code_lens(node, kind:)
279
272
  arguments = node.arguments
280
273
  return unless arguments
@@ -312,7 +305,7 @@ module RubyLsp
312
305
  end
313
306
  end
314
307
 
315
- sig { params(group_stack: T::Array[String], method_name: T.nilable(String)).returns(String) }
308
+ #: (group_stack: Array[String], ?method_name: String?) -> String
316
309
  def generate_fully_qualified_id(group_stack:, method_name: nil)
317
310
  if method_name
318
311
  # For tests, this will be the test class and method name: `Foo::BarTest#test_baz`.