ruby-lsp 0.23.11 → 0.23.16
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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp-launcher +20 -11
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -1
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +123 -169
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +92 -202
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +116 -222
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +18 -19
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +22 -45
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +47 -61
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
- data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
- data/lib/ruby_indexer/test/configuration_test.rb +48 -7
- data/lib/ruby_indexer/test/constant_test.rb +34 -34
- data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
- data/lib/ruby_indexer/test/index_test.rb +139 -135
- data/lib/ruby_indexer/test/instance_variables_test.rb +37 -37
- data/lib/ruby_indexer/test/method_test.rb +143 -117
- data/lib/ruby_indexer/test/prefix_tree_test.rb +13 -13
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +65 -71
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +15 -2
- data/lib/ruby_lsp/addon.rb +44 -71
- data/lib/ruby_lsp/base_server.rb +29 -32
- data/lib/ruby_lsp/client_capabilities.rb +10 -12
- data/lib/ruby_lsp/document.rb +39 -45
- data/lib/ruby_lsp/erb_document.rb +36 -40
- data/lib/ruby_lsp/global_state.rb +52 -57
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
- data/lib/ruby_lsp/listeners/completion.rb +60 -66
- data/lib/ruby_lsp/listeners/definition.rb +38 -52
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +46 -63
- data/lib/ruby_lsp/listeners/document_symbol.rb +38 -52
- data/lib/ruby_lsp/listeners/folding_ranges.rb +40 -43
- data/lib/ruby_lsp/listeners/hover.rb +83 -102
- data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
- data/lib/ruby_lsp/listeners/signature_help.rb +11 -26
- data/lib/ruby_lsp/listeners/spec_style.rb +155 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +89 -0
- data/lib/ruby_lsp/listeners/test_style.rb +160 -88
- data/lib/ruby_lsp/node_context.rb +12 -39
- data/lib/ruby_lsp/rbs_document.rb +8 -6
- data/lib/ruby_lsp/requests/code_action_resolve.rb +24 -25
- data/lib/ruby_lsp/requests/code_actions.rb +14 -26
- data/lib/ruby_lsp/requests/code_lens.rb +6 -17
- data/lib/ruby_lsp/requests/completion.rb +7 -20
- data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
- data/lib/ruby_lsp/requests/definition.rb +8 -17
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/discover_tests.rb +18 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -15
- data/lib/ruby_lsp/requests/document_link.rb +6 -17
- data/lib/ruby_lsp/requests/document_symbol.rb +5 -8
- data/lib/ruby_lsp/requests/folding_ranges.rb +7 -15
- data/lib/ruby_lsp/requests/formatting.rb +6 -9
- data/lib/ruby_lsp/requests/go_to_relevant_file.rb +87 -0
- data/lib/ruby_lsp/requests/hover.rb +10 -20
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
- data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
- data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +5 -15
- data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
- data/lib/ruby_lsp/requests/references.rb +8 -37
- data/lib/ruby_lsp/requests/rename.rb +19 -42
- data/lib/ruby_lsp/requests/request.rb +7 -19
- data/lib/ruby_lsp/requests/selection_ranges.rb +6 -6
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +16 -35
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +7 -8
- data/lib/ruby_lsp/requests/signature_help.rb +8 -26
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +16 -51
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +11 -14
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +22 -34
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
- data/lib/ruby_lsp/requests/support/sorbet.rb +29 -38
- data/lib/ruby_lsp/requests/support/source_uri.rb +20 -32
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
- data/lib/ruby_lsp/requests/support/test_item.rb +10 -14
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +5 -6
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -4
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +5 -5
- data/lib/ruby_lsp/response_builders/document_symbol.rb +13 -18
- data/lib/ruby_lsp/response_builders/hover.rb +11 -14
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +60 -88
- data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
- data/lib/ruby_lsp/response_builders/test_collection.rb +6 -10
- data/lib/ruby_lsp/ruby_document.rb +24 -62
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
- data/lib/ruby_lsp/server.rb +147 -79
- data/lib/ruby_lsp/setup_bundler.rb +65 -60
- data/lib/ruby_lsp/static_docs.rb +11 -7
- data/lib/ruby_lsp/store.rb +24 -42
- data/lib/ruby_lsp/test_helper.rb +2 -12
- data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +164 -0
- data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +105 -0
- data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +94 -0
- data/lib/ruby_lsp/type_inferrer.rb +13 -14
- data/lib/ruby_lsp/utils.rb +49 -83
- metadata +9 -3
@@ -3,93 +3,88 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
class GlobalState
|
6
|
-
|
7
|
-
|
8
|
-
sig { returns(String) }
|
6
|
+
#: String
|
9
7
|
attr_reader :test_library
|
10
8
|
|
11
|
-
|
9
|
+
#: String
|
12
10
|
attr_accessor :formatter
|
13
11
|
|
14
|
-
|
12
|
+
#: bool
|
15
13
|
attr_reader :has_type_checker
|
16
14
|
|
17
|
-
|
15
|
+
#: RubyIndexer::Index
|
18
16
|
attr_reader :index
|
19
17
|
|
20
|
-
|
18
|
+
#: Encoding
|
21
19
|
attr_reader :encoding
|
22
20
|
|
23
|
-
|
21
|
+
#: bool
|
24
22
|
attr_reader :top_level_bundle
|
25
23
|
|
26
|
-
|
24
|
+
#: TypeInferrer
|
27
25
|
attr_reader :type_inferrer
|
28
26
|
|
29
|
-
|
27
|
+
#: ClientCapabilities
|
30
28
|
attr_reader :client_capabilities
|
31
29
|
|
32
|
-
|
30
|
+
#: URI::Generic
|
33
31
|
attr_reader :workspace_uri
|
34
32
|
|
35
|
-
|
33
|
+
#: String?
|
36
34
|
attr_reader :telemetry_machine_id
|
37
35
|
|
38
|
-
|
36
|
+
#: -> void
|
39
37
|
def initialize
|
40
|
-
@workspace_uri =
|
41
|
-
@encoding =
|
42
|
-
|
43
|
-
@formatter =
|
44
|
-
@linters =
|
45
|
-
@test_library =
|
46
|
-
@has_type_checker =
|
47
|
-
@index =
|
48
|
-
@supported_formatters =
|
49
|
-
@type_inferrer =
|
50
|
-
@addon_settings =
|
51
|
-
@top_level_bundle =
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
@
|
61
|
-
@enabled_feature_flags = T.let({}, T::Hash[Symbol, T::Boolean])
|
62
|
-
@mutex = T.let(Mutex.new, Mutex)
|
63
|
-
@telemetry_machine_id = T.let(nil, T.nilable(String))
|
38
|
+
@workspace_uri = URI::Generic.from_path(path: Dir.pwd) #: URI::Generic
|
39
|
+
@encoding = Encoding::UTF_8 #: Encoding
|
40
|
+
|
41
|
+
@formatter = "auto" #: String
|
42
|
+
@linters = [] #: Array[String]
|
43
|
+
@test_library = "minitest" #: String
|
44
|
+
@has_type_checker = true #: bool
|
45
|
+
@index = RubyIndexer::Index.new #: RubyIndexer::Index
|
46
|
+
@supported_formatters = {} #: Hash[String, Requests::Support::Formatter]
|
47
|
+
@type_inferrer = TypeInferrer.new(@index) #: TypeInferrer
|
48
|
+
@addon_settings = {} #: Hash[String, untyped]
|
49
|
+
@top_level_bundle = begin
|
50
|
+
Bundler.with_original_env { Bundler.default_gemfile }
|
51
|
+
true
|
52
|
+
rescue Bundler::GemfileNotFound, Bundler::GitError
|
53
|
+
false
|
54
|
+
end #: bool
|
55
|
+
@client_capabilities = ClientCapabilities.new #: ClientCapabilities
|
56
|
+
@enabled_feature_flags = {} #: Hash[Symbol, bool]
|
57
|
+
@mutex = Mutex.new #: Mutex
|
58
|
+
@telemetry_machine_id = nil #: String?
|
64
59
|
end
|
65
60
|
|
66
|
-
|
61
|
+
#: [T] { -> T } -> T
|
67
62
|
def synchronize(&block)
|
68
63
|
@mutex.synchronize(&block)
|
69
64
|
end
|
70
65
|
|
71
|
-
|
66
|
+
#: (String addon_name) -> Hash[Symbol, untyped]?
|
72
67
|
def settings_for_addon(addon_name)
|
73
68
|
@addon_settings[addon_name]
|
74
69
|
end
|
75
70
|
|
76
|
-
|
71
|
+
#: (String identifier, Requests::Support::Formatter instance) -> void
|
77
72
|
def register_formatter(identifier, instance)
|
78
73
|
@supported_formatters[identifier] = instance
|
79
74
|
end
|
80
75
|
|
81
|
-
|
76
|
+
#: -> Requests::Support::Formatter?
|
82
77
|
def active_formatter
|
83
78
|
@supported_formatters[@formatter]
|
84
79
|
end
|
85
80
|
|
86
|
-
|
81
|
+
#: -> Array[Requests::Support::Formatter]
|
87
82
|
def active_linters
|
88
83
|
@linters.filter_map { |name| @supported_formatters[name] }
|
89
84
|
end
|
90
85
|
|
91
86
|
# Applies the options provided by the editor and returns an array of notifications to send back to the client
|
92
|
-
|
87
|
+
#: (Hash[Symbol, untyped] options) -> Array[Notification]
|
93
88
|
def apply_options(options)
|
94
89
|
notifications = []
|
95
90
|
direct_dependencies = gather_direct_dependencies
|
@@ -183,17 +178,17 @@ module RubyLsp
|
|
183
178
|
notifications
|
184
179
|
end
|
185
180
|
|
186
|
-
|
181
|
+
#: (Symbol flag) -> bool?
|
187
182
|
def enabled_feature?(flag)
|
188
183
|
@enabled_feature_flags[:all] || @enabled_feature_flags[flag]
|
189
184
|
end
|
190
185
|
|
191
|
-
|
186
|
+
#: -> String
|
192
187
|
def workspace_path
|
193
|
-
|
188
|
+
@workspace_uri.to_standardized_path #: as !nil
|
194
189
|
end
|
195
190
|
|
196
|
-
|
191
|
+
#: -> String
|
197
192
|
def encoding_name
|
198
193
|
case @encoding
|
199
194
|
when Encoding::UTF_8
|
@@ -205,14 +200,14 @@ module RubyLsp
|
|
205
200
|
end
|
206
201
|
end
|
207
202
|
|
208
|
-
|
203
|
+
#: -> bool
|
209
204
|
def supports_watching_files
|
210
205
|
@client_capabilities.supports_watching_files
|
211
206
|
end
|
212
207
|
|
213
208
|
private
|
214
209
|
|
215
|
-
|
210
|
+
#: (Array[String] direct_dependencies, Array[String] all_dependencies) -> String
|
216
211
|
def detect_formatter(direct_dependencies, all_dependencies)
|
217
212
|
# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.
|
218
213
|
return "rubocop_internal" if direct_dependencies.any?(/^rubocop/)
|
@@ -228,7 +223,7 @@ module RubyLsp
|
|
228
223
|
|
229
224
|
# Try to detect if there are linters in the project's dependencies. For auto-detection, we always only consider a
|
230
225
|
# single linter. To have multiple linters running, the user must configure them manually
|
231
|
-
|
226
|
+
#: (Array[String] dependencies, Array[String] all_dependencies) -> Array[String]
|
232
227
|
def detect_linters(dependencies, all_dependencies)
|
233
228
|
linters = []
|
234
229
|
|
@@ -239,7 +234,7 @@ module RubyLsp
|
|
239
234
|
linters
|
240
235
|
end
|
241
236
|
|
242
|
-
|
237
|
+
#: (Array[String] dependencies) -> String
|
243
238
|
def detect_test_library(dependencies)
|
244
239
|
if dependencies.any?(/^rspec/)
|
245
240
|
"rspec"
|
@@ -259,7 +254,7 @@ module RubyLsp
|
|
259
254
|
end
|
260
255
|
end
|
261
256
|
|
262
|
-
|
257
|
+
#: (Array[String] dependencies) -> bool
|
263
258
|
def detect_typechecker(dependencies)
|
264
259
|
return false if ENV["RUBY_LSP_BYPASS_TYPECHECKER"]
|
265
260
|
|
@@ -268,17 +263,17 @@ module RubyLsp
|
|
268
263
|
false
|
269
264
|
end
|
270
265
|
|
271
|
-
|
266
|
+
#: -> bool
|
272
267
|
def bin_rails_present
|
273
268
|
File.exist?(File.join(workspace_path, "bin/rails"))
|
274
269
|
end
|
275
270
|
|
276
|
-
|
271
|
+
#: -> bool
|
277
272
|
def dot_rubocop_yml_present
|
278
273
|
File.exist?(File.join(workspace_path, ".rubocop.yml"))
|
279
274
|
end
|
280
275
|
|
281
|
-
|
276
|
+
#: -> Array[String]
|
282
277
|
def gather_direct_dependencies
|
283
278
|
Bundler.with_original_env { Bundler.default_gemfile }
|
284
279
|
|
@@ -288,14 +283,14 @@ module RubyLsp
|
|
288
283
|
[]
|
289
284
|
end
|
290
285
|
|
291
|
-
|
286
|
+
#: -> Array[String]
|
292
287
|
def gemspec_dependencies
|
293
288
|
(Bundler.locked_gems&.sources || [])
|
294
289
|
.grep(Bundler::Source::Gemspec)
|
295
290
|
.flat_map { _1.gemspec&.dependencies&.map(&:name) }
|
296
291
|
end
|
297
292
|
|
298
|
-
|
293
|
+
#: -> Array[String]
|
299
294
|
def gather_direct_and_indirect_dependencies
|
300
295
|
Bundler.with_original_env { Bundler.default_gemfile }
|
301
296
|
Bundler.locked_gems&.specs&.map(&:name) || []
|
data/lib/ruby_lsp/internal.rb
CHANGED
@@ -25,6 +25,7 @@ require "fileutils"
|
|
25
25
|
require "open3"
|
26
26
|
require "securerandom"
|
27
27
|
require "shellwords"
|
28
|
+
require "set"
|
28
29
|
|
29
30
|
require "ruby-lsp"
|
30
31
|
require "ruby_lsp/base_server"
|
@@ -79,6 +80,7 @@ require "ruby_lsp/requests/document_link"
|
|
79
80
|
require "ruby_lsp/requests/document_symbol"
|
80
81
|
require "ruby_lsp/requests/folding_ranges"
|
81
82
|
require "ruby_lsp/requests/formatting"
|
83
|
+
require "ruby_lsp/requests/go_to_relevant_file"
|
82
84
|
require "ruby_lsp/requests/hover"
|
83
85
|
require "ruby_lsp/requests/inlay_hints"
|
84
86
|
require "ruby_lsp/requests/on_type_formatting"
|
@@ -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 =
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
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 =
|
39
|
-
@path =
|
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 =
|
42
|
-
@group_stack =
|
43
|
-
@group_id =
|
44
|
-
@group_id_stack =
|
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 =
|
47
|
-
@spec_id =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
104
|
+
#: (Prism::DefNode node) -> void
|
118
105
|
def on_def_node_leave(node)
|
119
106
|
@def_depth -= 1
|
120
107
|
end
|
121
108
|
|
122
|
-
|
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
|
-
|
118
|
+
#: (Prism::ModuleNode node) -> void
|
132
119
|
def on_module_node_leave(node)
|
133
120
|
@group_stack.pop
|
134
121
|
end
|
135
122
|
|
136
|
-
|
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
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
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 ==
|
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
|
-
|
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
|
-
|
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 =
|
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
|
-
|
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
|
-
|
267
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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`.
|