ruby-lsp 0.23.11 → 0.26.1
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 +10 -4
- data/exe/ruby-lsp-check +0 -4
- data/exe/ruby-lsp-launcher +45 -22
- data/exe/ruby-lsp-test-exec +6 -0
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -2
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -6
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +82 -116
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +140 -183
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +107 -236
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +166 -281
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +23 -27
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +25 -57
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +58 -68
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +7 -11
- 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 +49 -9
- 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 +185 -135
- data/lib/ruby_indexer/test/instance_variables_test.rb +61 -37
- data/lib/ruby_indexer/test/method_test.rb +166 -123
- data/lib/ruby_indexer/test/prefix_tree_test.rb +21 -21
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +70 -75
- data/lib/ruby_indexer/test/reference_finder_test.rb +79 -14
- data/lib/ruby_indexer/test/test_case.rb +9 -3
- data/lib/ruby_indexer/test/uri_test.rb +15 -2
- data/lib/ruby_lsp/addon.rb +88 -86
- data/lib/ruby_lsp/base_server.rb +59 -54
- data/lib/ruby_lsp/client_capabilities.rb +16 -13
- data/lib/ruby_lsp/document.rb +205 -104
- data/lib/ruby_lsp/erb_document.rb +45 -47
- data/lib/ruby_lsp/global_state.rb +73 -57
- data/lib/ruby_lsp/internal.rb +8 -3
- data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
- data/lib/ruby_lsp/listeners/completion.rb +81 -76
- data/lib/ruby_lsp/listeners/definition.rb +44 -58
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +50 -70
- 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 +107 -115
- data/lib/ruby_lsp/listeners/inlay_hints.rb +8 -13
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
- data/lib/ruby_lsp/listeners/signature_help.rb +12 -27
- data/lib/ruby_lsp/listeners/spec_style.rb +214 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +92 -0
- data/lib/ruby_lsp/listeners/test_style.rb +205 -95
- data/lib/ruby_lsp/node_context.rb +12 -39
- data/lib/ruby_lsp/rbs_document.rb +10 -11
- data/lib/ruby_lsp/requests/code_action_resolve.rb +65 -61
- data/lib/ruby_lsp/requests/code_actions.rb +14 -26
- data/lib/ruby_lsp/requests/code_lens.rb +31 -21
- data/lib/ruby_lsp/requests/completion.rb +8 -21
- data/lib/ruby_lsp/requests/completion_resolve.rb +6 -6
- data/lib/ruby_lsp/requests/definition.rb +8 -20
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/discover_tests.rb +20 -7
- data/lib/ruby_lsp/requests/document_highlight.rb +6 -16
- 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 +85 -0
- data/lib/ruby_lsp/requests/hover.rb +12 -25
- data/lib/ruby_lsp/requests/inlay_hints.rb +8 -19
- data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
- data/lib/ruby_lsp/requests/prepare_rename.rb +5 -10
- 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 +17 -57
- data/lib/ruby_lsp/requests/rename.rb +27 -51
- data/lib/ruby_lsp/requests/request.rb +13 -25
- data/lib/ruby_lsp/requests/selection_ranges.rb +7 -7
- 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 +9 -27
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +16 -58
- data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +13 -16
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +34 -36
- 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 +16 -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 +6 -9
- data/lib/ruby_lsp/response_builders/document_symbol.rb +15 -21
- data/lib/ruby_lsp/response_builders/hover.rb +12 -18
- data/lib/ruby_lsp/response_builders/response_builder.rb +6 -7
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +62 -91
- data/lib/ruby_lsp/response_builders/signature_help.rb +6 -8
- data/lib/ruby_lsp/response_builders/test_collection.rb +35 -13
- data/lib/ruby_lsp/ruby_document.rb +32 -98
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
- data/lib/ruby_lsp/server.rb +303 -196
- data/lib/ruby_lsp/setup_bundler.rb +121 -82
- data/lib/ruby_lsp/static_docs.rb +12 -7
- data/lib/ruby_lsp/store.rb +21 -49
- data/lib/ruby_lsp/test_helper.rb +3 -16
- data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +233 -0
- data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +145 -0
- data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +92 -0
- data/lib/ruby_lsp/type_inferrer.rb +13 -14
- data/lib/ruby_lsp/utils.rb +138 -93
- data/static_docs/break.md +103 -0
- metadata +14 -20
- data/lib/ruby_lsp/load_sorbet.rb +0 -62
@@ -3,93 +3,99 @@
|
|
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
|
-
@
|
62
|
-
|
63
|
-
|
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?
|
59
|
+
@feature_configuration = {
|
60
|
+
inlayHint: RequestConfig.new({
|
61
|
+
enableAll: false,
|
62
|
+
implicitRescue: false,
|
63
|
+
implicitHashValue: false,
|
64
|
+
}),
|
65
|
+
codeLens: RequestConfig.new({
|
66
|
+
enableAll: false,
|
67
|
+
enableTestCodeLens: true,
|
68
|
+
}),
|
69
|
+
} #: Hash[Symbol, RequestConfig]
|
64
70
|
end
|
65
71
|
|
66
|
-
|
72
|
+
#: [T] { -> T } -> T
|
67
73
|
def synchronize(&block)
|
68
74
|
@mutex.synchronize(&block)
|
69
75
|
end
|
70
76
|
|
71
|
-
|
77
|
+
#: (String addon_name) -> Hash[Symbol, untyped]?
|
72
78
|
def settings_for_addon(addon_name)
|
73
79
|
@addon_settings[addon_name]
|
74
80
|
end
|
75
81
|
|
76
|
-
|
82
|
+
#: (String identifier, Requests::Support::Formatter instance) -> void
|
77
83
|
def register_formatter(identifier, instance)
|
78
84
|
@supported_formatters[identifier] = instance
|
79
85
|
end
|
80
86
|
|
81
|
-
|
87
|
+
#: -> Requests::Support::Formatter?
|
82
88
|
def active_formatter
|
83
89
|
@supported_formatters[@formatter]
|
84
90
|
end
|
85
91
|
|
86
|
-
|
92
|
+
#: -> Array[Requests::Support::Formatter]
|
87
93
|
def active_linters
|
88
94
|
@linters.filter_map { |name| @supported_formatters[name] }
|
89
95
|
end
|
90
96
|
|
91
97
|
# Applies the options provided by the editor and returns an array of notifications to send back to the client
|
92
|
-
|
98
|
+
#: (Hash[Symbol, untyped] options) -> Array[Notification]
|
93
99
|
def apply_options(options)
|
94
100
|
notifications = []
|
95
101
|
direct_dependencies = gather_direct_dependencies
|
@@ -180,20 +186,30 @@ module RubyLsp
|
|
180
186
|
@enabled_feature_flags = enabled_flags if enabled_flags
|
181
187
|
|
182
188
|
@telemetry_machine_id = options.dig(:initializationOptions, :telemetryMachineId)
|
189
|
+
|
190
|
+
options.dig(:initializationOptions, :featuresConfiguration)&.each do |feature_name, config|
|
191
|
+
@feature_configuration[feature_name]&.merge!(config)
|
192
|
+
end
|
193
|
+
|
183
194
|
notifications
|
184
195
|
end
|
185
196
|
|
186
|
-
|
197
|
+
#: (Symbol) -> RequestConfig?
|
198
|
+
def feature_configuration(feature_name)
|
199
|
+
@feature_configuration[feature_name]
|
200
|
+
end
|
201
|
+
|
202
|
+
#: (Symbol flag) -> bool?
|
187
203
|
def enabled_feature?(flag)
|
188
204
|
@enabled_feature_flags[:all] || @enabled_feature_flags[flag]
|
189
205
|
end
|
190
206
|
|
191
|
-
|
207
|
+
#: -> String
|
192
208
|
def workspace_path
|
193
|
-
|
209
|
+
@workspace_uri.to_standardized_path #: as !nil
|
194
210
|
end
|
195
211
|
|
196
|
-
|
212
|
+
#: -> String
|
197
213
|
def encoding_name
|
198
214
|
case @encoding
|
199
215
|
when Encoding::UTF_8
|
@@ -205,14 +221,14 @@ module RubyLsp
|
|
205
221
|
end
|
206
222
|
end
|
207
223
|
|
208
|
-
|
224
|
+
#: -> bool
|
209
225
|
def supports_watching_files
|
210
226
|
@client_capabilities.supports_watching_files
|
211
227
|
end
|
212
228
|
|
213
229
|
private
|
214
230
|
|
215
|
-
|
231
|
+
#: (Array[String] direct_dependencies, Array[String] all_dependencies) -> String
|
216
232
|
def detect_formatter(direct_dependencies, all_dependencies)
|
217
233
|
# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.
|
218
234
|
return "rubocop_internal" if direct_dependencies.any?(/^rubocop/)
|
@@ -228,7 +244,7 @@ module RubyLsp
|
|
228
244
|
|
229
245
|
# Try to detect if there are linters in the project's dependencies. For auto-detection, we always only consider a
|
230
246
|
# single linter. To have multiple linters running, the user must configure them manually
|
231
|
-
|
247
|
+
#: (Array[String] dependencies, Array[String] all_dependencies) -> Array[String]
|
232
248
|
def detect_linters(dependencies, all_dependencies)
|
233
249
|
linters = []
|
234
250
|
|
@@ -239,7 +255,7 @@ module RubyLsp
|
|
239
255
|
linters
|
240
256
|
end
|
241
257
|
|
242
|
-
|
258
|
+
#: (Array[String] dependencies) -> String
|
243
259
|
def detect_test_library(dependencies)
|
244
260
|
if dependencies.any?(/^rspec/)
|
245
261
|
"rspec"
|
@@ -259,7 +275,7 @@ module RubyLsp
|
|
259
275
|
end
|
260
276
|
end
|
261
277
|
|
262
|
-
|
278
|
+
#: (Array[String] dependencies) -> bool
|
263
279
|
def detect_typechecker(dependencies)
|
264
280
|
return false if ENV["RUBY_LSP_BYPASS_TYPECHECKER"]
|
265
281
|
|
@@ -268,17 +284,17 @@ module RubyLsp
|
|
268
284
|
false
|
269
285
|
end
|
270
286
|
|
271
|
-
|
287
|
+
#: -> bool
|
272
288
|
def bin_rails_present
|
273
289
|
File.exist?(File.join(workspace_path, "bin/rails"))
|
274
290
|
end
|
275
291
|
|
276
|
-
|
292
|
+
#: -> bool
|
277
293
|
def dot_rubocop_yml_present
|
278
294
|
File.exist?(File.join(workspace_path, ".rubocop.yml"))
|
279
295
|
end
|
280
296
|
|
281
|
-
|
297
|
+
#: -> Array[String]
|
282
298
|
def gather_direct_dependencies
|
283
299
|
Bundler.with_original_env { Bundler.default_gemfile }
|
284
300
|
|
@@ -288,14 +304,14 @@ module RubyLsp
|
|
288
304
|
[]
|
289
305
|
end
|
290
306
|
|
291
|
-
|
307
|
+
#: -> Array[String]
|
292
308
|
def gemspec_dependencies
|
293
309
|
(Bundler.locked_gems&.sources || [])
|
294
310
|
.grep(Bundler::Source::Gemspec)
|
295
311
|
.flat_map { _1.gemspec&.dependencies&.map(&:name) }
|
296
312
|
end
|
297
313
|
|
298
|
-
|
314
|
+
#: -> Array[String]
|
299
315
|
def gather_direct_and_indirect_dependencies
|
300
316
|
Bundler.with_original_env { Bundler.default_gemfile }
|
301
317
|
Bundler.locked_gems&.specs&.map(&:name) || []
|
data/lib/ruby_lsp/internal.rb
CHANGED
@@ -6,15 +6,18 @@
|
|
6
6
|
yarp_require_paths = Gem.loaded_specs["yarp"]&.full_require_paths
|
7
7
|
$LOAD_PATH.delete_if { |path| yarp_require_paths.include?(path) } if yarp_require_paths
|
8
8
|
|
9
|
-
require "sorbet-runtime"
|
10
|
-
|
11
9
|
# Set Bundler's UI level to silent as soon as possible to prevent any prints to STDOUT
|
12
10
|
require "bundler"
|
13
11
|
Bundler.ui.level = :silent
|
14
12
|
|
15
13
|
require "json"
|
16
14
|
require "uri"
|
17
|
-
require "cgi"
|
15
|
+
require "cgi/escape"
|
16
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new("3.5")
|
17
|
+
# Just requiring `cgi/escape` leaves CGI.unescape broken on older rubies
|
18
|
+
# Some background on why this is necessary: https://bugs.ruby-lang.org/issues/21258
|
19
|
+
require "cgi/util"
|
20
|
+
end
|
18
21
|
require "set"
|
19
22
|
require "strscan"
|
20
23
|
require "prism"
|
@@ -25,6 +28,7 @@ require "fileutils"
|
|
25
28
|
require "open3"
|
26
29
|
require "securerandom"
|
27
30
|
require "shellwords"
|
31
|
+
require "set"
|
28
32
|
|
29
33
|
require "ruby-lsp"
|
30
34
|
require "ruby_lsp/base_server"
|
@@ -79,6 +83,7 @@ require "ruby_lsp/requests/document_link"
|
|
79
83
|
require "ruby_lsp/requests/document_symbol"
|
80
84
|
require "ruby_lsp/requests/folding_ranges"
|
81
85
|
require "ruby_lsp/requests/formatting"
|
86
|
+
require "ruby_lsp/requests/go_to_relevant_file"
|
82
87
|
require "ruby_lsp/requests/hover"
|
83
88
|
require "ruby_lsp/requests/inlay_hints"
|
84
89
|
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`.
|