ruby-lsp 0.22.1 → 0.23.10
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 +12 -11
- data/exe/ruby-lsp-check +5 -5
- data/exe/ruby-lsp-launcher +41 -15
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +191 -100
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +174 -61
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +12 -0
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +82 -61
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +36 -0
- data/lib/ruby_indexer/ruby_indexer.rb +2 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +30 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +143 -44
- data/lib/ruby_indexer/test/instance_variables_test.rb +20 -0
- data/lib/ruby_indexer/test/method_test.rb +86 -8
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +90 -2
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +17 -18
- data/lib/ruby_lsp/client_capabilities.rb +7 -1
- data/lib/ruby_lsp/document.rb +72 -10
- data/lib/ruby_lsp/erb_document.rb +5 -3
- data/lib/ruby_lsp/global_state.rb +42 -3
- data/lib/ruby_lsp/internal.rb +3 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +9 -5
- data/lib/ruby_lsp/listeners/completion.rb +78 -6
- data/lib/ruby_lsp/listeners/definition.rb +80 -19
- data/lib/ruby_lsp/listeners/document_highlight.rb +3 -2
- data/lib/ruby_lsp/listeners/document_link.rb +21 -3
- data/lib/ruby_lsp/listeners/document_symbol.rb +12 -1
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +59 -2
- data/lib/ruby_lsp/load_sorbet.rb +3 -3
- data/lib/ruby_lsp/rbs_document.rb +2 -2
- data/lib/ruby_lsp/requests/code_action_resolve.rb +90 -6
- data/lib/ruby_lsp/requests/code_actions.rb +57 -1
- data/lib/ruby_lsp/requests/completion.rb +8 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +7 -1
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -1
- data/lib/ruby_lsp/requests/folding_ranges.rb +2 -6
- data/lib/ruby_lsp/requests/formatting.rb +2 -6
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +2 -2
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/references.rb +29 -2
- data/lib/ruby_lsp/requests/rename.rb +17 -7
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +1 -4
- data/lib/ruby_lsp/requests/signature_help.rb +1 -1
- data/lib/ruby_lsp/requests/support/common.rb +2 -9
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +3 -3
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +13 -13
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +4 -3
- data/lib/ruby_lsp/ruby_document.rb +80 -6
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +205 -61
- data/lib/ruby_lsp/setup_bundler.rb +50 -43
- data/lib/ruby_lsp/store.rb +7 -7
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +60 -31
- data/lib/ruby_lsp/utils.rb +63 -3
- metadata +8 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -57,6 +57,7 @@ module RubyLsp
|
|
57
57
|
@lockfile_hash_path = T.let(@custom_dir + "main_lockfile_hash", Pathname)
|
58
58
|
@last_updated_path = T.let(@custom_dir + "last_updated", Pathname)
|
59
59
|
@error_path = T.let(@custom_dir + "install_error", Pathname)
|
60
|
+
@already_composed_path = T.let(@custom_dir + "bundle_is_composed", Pathname)
|
60
61
|
|
61
62
|
dependencies, bundler_version = load_dependencies
|
62
63
|
@dependencies = T.let(dependencies, T::Hash[String, T.untyped])
|
@@ -71,6 +72,23 @@ module RubyLsp
|
|
71
72
|
def setup!
|
72
73
|
raise BundleNotLocked if !@launcher && @gemfile&.exist? && !@lockfile&.exist?
|
73
74
|
|
75
|
+
# If the bundle was composed ahead of time using our custom `rubyLsp/composeBundle` request, then we can skip the
|
76
|
+
# entire process and just return the composed environment
|
77
|
+
if @already_composed_path.exist?
|
78
|
+
$stderr.puts("Ruby LSP> Composed bundle was set up ahead of time. Skipping...")
|
79
|
+
@already_composed_path.delete
|
80
|
+
|
81
|
+
env = bundler_settings_as_env
|
82
|
+
env["BUNDLE_GEMFILE"] = @custom_gemfile.exist? ? @custom_gemfile.to_s : @gemfile.to_s
|
83
|
+
|
84
|
+
if env["BUNDLE_PATH"]
|
85
|
+
env["BUNDLE_PATH"] = File.expand_path(env["BUNDLE_PATH"], @project_path)
|
86
|
+
end
|
87
|
+
|
88
|
+
env["BUNDLER_VERSION"] = @bundler_version.to_s if @bundler_version
|
89
|
+
return env
|
90
|
+
end
|
91
|
+
|
74
92
|
# Automatically create and ignore the .ruby-lsp folder for users
|
75
93
|
@custom_dir.mkpath unless @custom_dir.exist?
|
76
94
|
ignore_file = @custom_dir + ".gitignore"
|
@@ -152,7 +170,13 @@ module RubyLsp
|
|
152
170
|
end
|
153
171
|
|
154
172
|
unless @dependencies["debug"]
|
155
|
-
|
173
|
+
# The `mri` platform excludes Windows. We want to install the debug gem only on MRI for any operating system,
|
174
|
+
# but that constraint doesn't yet exist in Bundler. On Windows, we are manually checking if the engine is MRI
|
175
|
+
parts << if Gem.win_platform?
|
176
|
+
'gem "debug", require: false, group: :development, install_if: -> { RUBY_ENGINE == "ruby" }'
|
177
|
+
else
|
178
|
+
'gem "debug", require: false, group: :development, platforms: :mri'
|
179
|
+
end
|
156
180
|
end
|
157
181
|
|
158
182
|
if @rails_app && !@dependencies["ruby-lsp-rails"]
|
@@ -196,15 +220,15 @@ module RubyLsp
|
|
196
220
|
env["BUNDLE_PATH"] = File.expand_path(env["BUNDLE_PATH"], @project_path)
|
197
221
|
end
|
198
222
|
|
199
|
-
|
200
|
-
|
201
|
-
# This same check happens conditionally when running through the command. For invoking the CLI directly, it's
|
202
|
-
# important that we ensure the Bundler version is set to avoid restarts
|
223
|
+
# Set the specific Bundler version used by the main app. This avoids issues with Bundler restarts, which clean the
|
224
|
+
# environment and lead to the `ruby-lsp` executable not being found
|
203
225
|
if @bundler_version
|
204
226
|
env["BUNDLER_VERSION"] = @bundler_version.to_s
|
205
227
|
install_bundler_if_needed
|
206
228
|
end
|
207
229
|
|
230
|
+
return run_bundle_install_through_command(env) unless @launcher
|
231
|
+
|
208
232
|
begin
|
209
233
|
run_bundle_install_directly(env)
|
210
234
|
# If no error occurred, then clear previous errors
|
@@ -217,8 +241,7 @@ module RubyLsp
|
|
217
241
|
|
218
242
|
# If either the Gemfile or the lockfile have been modified during the process of setting up the bundle, retry
|
219
243
|
# composing the bundle from scratch
|
220
|
-
|
221
|
-
if @gemfile && @lockfile
|
244
|
+
if @gemfile&.exist? && @lockfile&.exist?
|
222
245
|
current_gemfile_hash = Digest::SHA256.hexdigest(@gemfile.read)
|
223
246
|
current_lockfile_hash = Digest::SHA256.hexdigest(@lockfile.read)
|
224
247
|
|
@@ -235,12 +258,16 @@ module RubyLsp
|
|
235
258
|
env
|
236
259
|
end
|
237
260
|
|
238
|
-
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }
|
239
|
-
def run_bundle_install_directly(env)
|
261
|
+
sig { params(env: T::Hash[String, String], force_install: T::Boolean).returns(T::Hash[String, String]) }
|
262
|
+
def run_bundle_install_directly(env, force_install: false)
|
240
263
|
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
|
264
|
+
|
265
|
+
# The ENV can only be merged after checking if an update is required because we depend on the original value of
|
266
|
+
# ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
|
267
|
+
should_update = should_bundle_update?
|
241
268
|
T.unsafe(ENV).merge!(env)
|
242
269
|
|
243
|
-
unless
|
270
|
+
unless should_update && !force_install
|
244
271
|
Bundler::CLI::Install.new({}).run
|
245
272
|
correct_relative_remote_paths if @custom_lockfile.exist?
|
246
273
|
return env
|
@@ -255,12 +282,13 @@ module RubyLsp
|
|
255
282
|
correct_relative_remote_paths if @custom_lockfile.exist?
|
256
283
|
@last_updated_path.write(Time.now.iso8601)
|
257
284
|
env
|
285
|
+
rescue Bundler::GemNotFound, Bundler::GitError
|
286
|
+
# If a gem is not installed, skip the upgrade and try to install it with a single retry
|
287
|
+
@retry ? env : run_bundle_install_directly(env, force_install: true)
|
258
288
|
end
|
259
289
|
|
260
290
|
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }
|
261
291
|
def run_bundle_install_through_command(env)
|
262
|
-
base_bundle = base_bundle_command(env)
|
263
|
-
|
264
292
|
# If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
|
265
293
|
# to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just created
|
266
294
|
# and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
|
@@ -269,13 +297,20 @@ module RubyLsp
|
|
269
297
|
|
270
298
|
# When not updating, we run `(bundle check || bundle install)`
|
271
299
|
# When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
|
272
|
-
|
300
|
+
bundler_path = File.join(Gem.default_bindir, "bundle")
|
301
|
+
base_command = (!Gem.win_platform? && File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
|
302
|
+
|
303
|
+
if env["BUNDLER_VERSION"]
|
304
|
+
base_command << " _#{env["BUNDLER_VERSION"]}_"
|
305
|
+
end
|
306
|
+
|
307
|
+
command = +"(#{base_command} check"
|
273
308
|
|
274
309
|
if should_bundle_update?
|
275
310
|
# If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
|
276
311
|
# version
|
277
312
|
command.prepend("(")
|
278
|
-
command << " && #{
|
313
|
+
command << " && #{base_command} update "
|
279
314
|
command << "ruby-lsp " unless @dependencies["ruby-lsp"]
|
280
315
|
command << "debug " unless @dependencies["debug"]
|
281
316
|
command << "ruby-lsp-rails " if @rails_app && !@dependencies["ruby-lsp-rails"]
|
@@ -285,7 +320,7 @@ module RubyLsp
|
|
285
320
|
@last_updated_path.write(Time.now.iso8601)
|
286
321
|
end
|
287
322
|
|
288
|
-
command << " || #{
|
323
|
+
command << " || #{base_command} install) "
|
289
324
|
|
290
325
|
# Redirect stdout to stderr to prevent going into an infinite loop. The extension might confuse stdout output with
|
291
326
|
# responses
|
@@ -395,34 +430,6 @@ module RubyLsp
|
|
395
430
|
/class .* < (::)?Rails::Application/.match?(application_contents)
|
396
431
|
end
|
397
432
|
|
398
|
-
# Returns the base bundle command we should use for this project, which will be:
|
399
|
-
# - `bundle` if there's no locked Bundler version and no `bin/bundle` binstub in the $PATH
|
400
|
-
# - `bundle _<version>_` if there's a locked Bundler version
|
401
|
-
# - `bin/bundle` if there's a `bin/bundle` binstub in the $PATH
|
402
|
-
sig { params(env: T::Hash[String, String]).returns(String) }
|
403
|
-
def base_bundle_command(env)
|
404
|
-
path_parts = if Gem.win_platform?
|
405
|
-
ENV["Path"] || ENV["PATH"] || ENV["path"] || ""
|
406
|
-
else
|
407
|
-
ENV["PATH"] || ""
|
408
|
-
end.split(File::PATH_SEPARATOR)
|
409
|
-
|
410
|
-
bin_dir = File.expand_path("bin", @project_path)
|
411
|
-
bundle_binstub = File.join(@project_path, "bin", "bundle")
|
412
|
-
|
413
|
-
if File.exist?(bundle_binstub) && path_parts.any? { |path| File.expand_path(path, @project_path) == bin_dir }
|
414
|
-
return bundle_binstub
|
415
|
-
end
|
416
|
-
|
417
|
-
if @bundler_version
|
418
|
-
env["BUNDLER_VERSION"] = @bundler_version.to_s
|
419
|
-
install_bundler_if_needed
|
420
|
-
return "bundle _#{@bundler_version}_"
|
421
|
-
end
|
422
|
-
|
423
|
-
"bundle"
|
424
|
-
end
|
425
|
-
|
426
433
|
sig { void }
|
427
434
|
def patch_thor_to_print_progress_to_stderr!
|
428
435
|
return unless defined?(Bundler::Thor::Shell::Basic)
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -13,8 +13,9 @@ module RubyLsp
|
|
13
13
|
sig { returns(String) }
|
14
14
|
attr_accessor :client_name
|
15
15
|
|
16
|
-
sig { void }
|
17
|
-
def initialize
|
16
|
+
sig { params(global_state: GlobalState).void }
|
17
|
+
def initialize(global_state)
|
18
|
+
@global_state = global_state
|
18
19
|
@state = T.let({}, T::Hash[String, Document[T.untyped]])
|
19
20
|
@features_configuration = T.let(
|
20
21
|
{
|
@@ -61,17 +62,16 @@ module RubyLsp
|
|
61
62
|
source: String,
|
62
63
|
version: Integer,
|
63
64
|
language_id: Document::LanguageId,
|
64
|
-
encoding: Encoding,
|
65
65
|
).returns(Document[T.untyped])
|
66
66
|
end
|
67
|
-
def set(uri:, source:, version:, language_id
|
67
|
+
def set(uri:, source:, version:, language_id:)
|
68
68
|
@state[uri.to_s] = case language_id
|
69
69
|
when Document::LanguageId::ERB
|
70
|
-
ERBDocument.new(source: source, version: version, uri: uri,
|
70
|
+
ERBDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
|
71
71
|
when Document::LanguageId::RBS
|
72
|
-
RBSDocument.new(source: source, version: version, uri: uri,
|
72
|
+
RBSDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
|
73
73
|
else
|
74
|
-
RubyDocument.new(source: source, version: version, uri: uri,
|
74
|
+
RubyDocument.new(source: source, version: version, uri: uri, global_state: @global_state)
|
75
75
|
end
|
76
76
|
end
|
77
77
|
|
data/lib/ruby_lsp/test_helper.rb
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: true
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# NOTE: This module is intended to be used by addons for writing their own tests, so keep that in mind if changing.
|
5
5
|
|
6
6
|
module RubyLsp
|
7
7
|
module TestHelper
|
8
|
+
class TestError < StandardError; end
|
9
|
+
|
8
10
|
extend T::Sig
|
11
|
+
extend T::Helpers
|
12
|
+
|
13
|
+
requires_ancestor { Kernel }
|
9
14
|
|
10
15
|
sig do
|
11
16
|
type_parameters(:T)
|
@@ -36,20 +41,49 @@ module RubyLsp
|
|
36
41
|
},
|
37
42
|
},
|
38
43
|
})
|
44
|
+
|
45
|
+
server.global_state.index.index_single(uri, source)
|
39
46
|
end
|
40
47
|
|
41
|
-
server.global_state.index.index_single(
|
42
|
-
RubyIndexer::IndexablePath.new(nil, T.must(uri.to_standardized_path)),
|
43
|
-
source,
|
44
|
-
)
|
45
48
|
server.load_addons(include_project_addons: false) if load_addons
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
49
|
+
|
50
|
+
begin
|
51
|
+
block.call(server, uri)
|
52
|
+
ensure
|
53
|
+
if load_addons
|
54
|
+
RubyLsp::Addon.addons.each(&:deactivate)
|
55
|
+
RubyLsp::Addon.addons.clear
|
56
|
+
end
|
57
|
+
server.run_shutdown
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
sig { params(server: RubyLsp::Server).returns(RubyLsp::Result) }
|
62
|
+
def pop_result(server)
|
63
|
+
result = server.pop_response
|
64
|
+
result = server.pop_response until result.is_a?(RubyLsp::Result) || result.is_a?(RubyLsp::Error)
|
65
|
+
|
66
|
+
if result.is_a?(RubyLsp::Error)
|
67
|
+
raise TestError, "Failed to execute request #{result.message}"
|
68
|
+
else
|
69
|
+
result
|
51
70
|
end
|
52
|
-
|
71
|
+
end
|
72
|
+
|
73
|
+
def pop_log_notification(message_queue, type)
|
74
|
+
log = message_queue.pop
|
75
|
+
return log if log.params.type == type
|
76
|
+
|
77
|
+
log = message_queue.pop until log.params.type == type
|
78
|
+
log
|
79
|
+
end
|
80
|
+
|
81
|
+
def pop_message(outgoing_queue, &block)
|
82
|
+
message = outgoing_queue.pop
|
83
|
+
return message if block.call(message)
|
84
|
+
|
85
|
+
message = outgoing_queue.pop until block.call(message)
|
86
|
+
message
|
53
87
|
end
|
54
88
|
end
|
55
89
|
end
|
@@ -23,6 +23,9 @@ module RubyLsp
|
|
23
23
|
Prism::InstanceVariableOperatorWriteNode, Prism::InstanceVariableOrWriteNode, Prism::InstanceVariableTargetNode,
|
24
24
|
Prism::SuperNode, Prism::ForwardingSuperNode
|
25
25
|
self_receiver_handling(node_context)
|
26
|
+
when Prism::ClassVariableAndWriteNode, Prism::ClassVariableWriteNode, Prism::ClassVariableOperatorWriteNode,
|
27
|
+
Prism::ClassVariableOrWriteNode, Prism::ClassVariableReadNode, Prism::ClassVariableTargetNode
|
28
|
+
infer_receiver_for_class_variables(node_context)
|
26
29
|
end
|
27
30
|
end
|
28
31
|
|
@@ -77,7 +80,7 @@ module RubyLsp
|
|
77
80
|
# When the receiver is a constant reference, we have to try to resolve it to figure out the right
|
78
81
|
# receiver. But since the invocation is directly on the constant, that's the singleton context of that
|
79
82
|
# class/module
|
80
|
-
receiver_name = constant_name(receiver)
|
83
|
+
receiver_name = RubyIndexer::Index.constant_name(receiver)
|
81
84
|
return unless receiver_name
|
82
85
|
|
83
86
|
resolved_receiver = @index.resolve(receiver_name, node_context.nesting)
|
@@ -88,29 +91,45 @@ module RubyLsp
|
|
88
91
|
return Type.new("#{last}::<Class:#{last}>") if parts.empty?
|
89
92
|
|
90
93
|
Type.new("#{parts.join("::")}::#{last}::<Class:#{last}>")
|
91
|
-
|
94
|
+
when Prism::CallNode
|
95
|
+
raw_receiver = receiver.message
|
92
96
|
|
93
|
-
raw_receiver
|
94
|
-
receiver
|
95
|
-
|
96
|
-
receiver
|
97
|
-
|
97
|
+
if raw_receiver == "new"
|
98
|
+
# When invoking `new`, we recursively infer the type of the receiver to get the class type its being invoked
|
99
|
+
# on and then return the attached version of that type, since it's being instantiated.
|
100
|
+
type = infer_receiver_for_call_node(receiver, node_context)
|
101
|
+
|
102
|
+
return unless type
|
103
|
+
|
104
|
+
# If the method `new` was overridden, then we cannot assume that it will return a new instance of the class
|
105
|
+
new_method = @index.resolve_method("new", type.name)&.first
|
106
|
+
return if new_method && new_method.owner&.name != "Class"
|
98
107
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
.delete_prefix("@@")
|
103
|
-
.split("_")
|
104
|
-
.map(&:capitalize)
|
105
|
-
.join
|
106
|
-
|
107
|
-
entries = @index.resolve(guessed_name, node_context.nesting) || @index.first_unqualified_const(guessed_name)
|
108
|
-
name = entries&.first&.name
|
109
|
-
GuessedType.new(name) if name
|
108
|
+
type.attached
|
109
|
+
elsif raw_receiver
|
110
|
+
guess_type(raw_receiver, node_context.nesting)
|
110
111
|
end
|
112
|
+
else
|
113
|
+
guess_type(receiver.slice, node_context.nesting)
|
111
114
|
end
|
112
115
|
end
|
113
116
|
|
117
|
+
sig { params(raw_receiver: String, nesting: T::Array[String]).returns(T.nilable(GuessedType)) }
|
118
|
+
def guess_type(raw_receiver, nesting)
|
119
|
+
guessed_name = raw_receiver
|
120
|
+
.delete_prefix("@")
|
121
|
+
.delete_prefix("@@")
|
122
|
+
.split("_")
|
123
|
+
.map(&:capitalize)
|
124
|
+
.join
|
125
|
+
|
126
|
+
entries = @index.resolve(guessed_name, nesting) || @index.first_unqualified_const(guessed_name)
|
127
|
+
name = entries&.first&.name
|
128
|
+
return unless name
|
129
|
+
|
130
|
+
GuessedType.new(name)
|
131
|
+
end
|
132
|
+
|
114
133
|
sig { params(node_context: NodeContext).returns(Type) }
|
115
134
|
def self_receiver_handling(node_context)
|
116
135
|
nesting = node_context.nesting
|
@@ -128,19 +147,23 @@ module RubyLsp
|
|
128
147
|
Type.new("#{parts.join("::")}::<Class:#{parts.last}>")
|
129
148
|
end
|
130
149
|
|
131
|
-
sig
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
150
|
+
sig { params(node_context: NodeContext).returns(T.nilable(Type)) }
|
151
|
+
def infer_receiver_for_class_variables(node_context)
|
152
|
+
nesting_parts = node_context.nesting.dup
|
153
|
+
|
154
|
+
return Type.new("Object") if nesting_parts.empty?
|
155
|
+
|
156
|
+
nesting_parts.reverse_each do |part|
|
157
|
+
break unless part.include?("<Class:")
|
158
|
+
|
159
|
+
nesting_parts.pop
|
160
|
+
end
|
161
|
+
|
162
|
+
receiver_name = nesting_parts.join("::")
|
163
|
+
resolved_receiver = @index.resolve(receiver_name, node_context.nesting)&.first
|
164
|
+
return unless resolved_receiver&.name
|
165
|
+
|
166
|
+
Type.new(resolved_receiver.name)
|
144
167
|
end
|
145
168
|
|
146
169
|
# A known type
|
@@ -154,6 +177,12 @@ module RubyLsp
|
|
154
177
|
def initialize(name)
|
155
178
|
@name = name
|
156
179
|
end
|
180
|
+
|
181
|
+
# Returns the attached version of this type by removing the `<Class:...>` part from its name
|
182
|
+
sig { returns(Type) }
|
183
|
+
def attached
|
184
|
+
Type.new(T.must(@name.split("::")[..-2]).join("::"))
|
185
|
+
end
|
157
186
|
end
|
158
187
|
|
159
188
|
# A type that was guessed based on the receiver raw name
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
end,
|
26
26
|
String,
|
27
27
|
)
|
28
|
-
GUESSED_TYPES_URL = "https://shopify.github.io/ruby-lsp
|
28
|
+
GUESSED_TYPES_URL = "https://shopify.github.io/ruby-lsp/#guessed-types"
|
29
29
|
|
30
30
|
# Request delegation for embedded languages is not yet standardized into the language server specification. Here we
|
31
31
|
# use this custom error class as a way to return a signal to the client that the request should be delegated to the
|
@@ -37,6 +37,8 @@ module RubyLsp
|
|
37
37
|
CODE = -32900
|
38
38
|
end
|
39
39
|
|
40
|
+
BUNDLE_COMPOSE_FAILED_CODE = -33000
|
41
|
+
|
40
42
|
# A notification to be sent to the client
|
41
43
|
class Message
|
42
44
|
extend T::Sig
|
@@ -142,19 +144,72 @@ module RubyLsp
|
|
142
144
|
),
|
143
145
|
)
|
144
146
|
end
|
147
|
+
|
148
|
+
sig do
|
149
|
+
params(
|
150
|
+
uri: String,
|
151
|
+
diagnostics: T::Array[Interface::Diagnostic],
|
152
|
+
version: T.nilable(Integer),
|
153
|
+
).returns(Notification)
|
154
|
+
end
|
155
|
+
def publish_diagnostics(uri, diagnostics, version: nil)
|
156
|
+
new(
|
157
|
+
method: "textDocument/publishDiagnostics",
|
158
|
+
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: diagnostics, version: version),
|
159
|
+
)
|
160
|
+
end
|
145
161
|
end
|
146
162
|
|
147
163
|
extend T::Sig
|
148
164
|
|
149
165
|
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
150
166
|
def to_hash
|
151
|
-
{ method: @method
|
167
|
+
hash = { method: @method }
|
168
|
+
hash[:params] = T.unsafe(@params).to_hash if @params
|
169
|
+
hash
|
152
170
|
end
|
153
171
|
end
|
154
172
|
|
155
173
|
class Request < Message
|
156
174
|
extend T::Sig
|
157
175
|
|
176
|
+
class << self
|
177
|
+
extend T::Sig
|
178
|
+
|
179
|
+
sig do
|
180
|
+
params(
|
181
|
+
id: Integer,
|
182
|
+
pattern: T.any(Interface::RelativePattern, String),
|
183
|
+
kind: Integer,
|
184
|
+
registration_id: T.nilable(String),
|
185
|
+
).returns(Request)
|
186
|
+
end
|
187
|
+
def register_watched_files(
|
188
|
+
id,
|
189
|
+
pattern,
|
190
|
+
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE,
|
191
|
+
registration_id: nil
|
192
|
+
)
|
193
|
+
new(
|
194
|
+
id: id,
|
195
|
+
method: "client/registerCapability",
|
196
|
+
params: Interface::RegistrationParams.new(
|
197
|
+
registrations: [
|
198
|
+
Interface::Registration.new(
|
199
|
+
id: registration_id || SecureRandom.uuid,
|
200
|
+
method: "workspace/didChangeWatchedFiles",
|
201
|
+
register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
|
202
|
+
watchers: [
|
203
|
+
Interface::FileSystemWatcher.new(glob_pattern: pattern, kind: kind),
|
204
|
+
],
|
205
|
+
),
|
206
|
+
),
|
207
|
+
],
|
208
|
+
),
|
209
|
+
)
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
158
213
|
sig { params(id: T.any(Integer, String), method: String, params: Object).void }
|
159
214
|
def initialize(id:, method:, params:)
|
160
215
|
@id = id
|
@@ -163,7 +218,9 @@ module RubyLsp
|
|
163
218
|
|
164
219
|
sig { override.returns(T::Hash[Symbol, T.untyped]) }
|
165
220
|
def to_hash
|
166
|
-
{ id: @id, method: @method
|
221
|
+
hash = { id: @id, method: @method }
|
222
|
+
hash[:params] = T.unsafe(@params).to_hash if @params
|
223
|
+
hash
|
167
224
|
end
|
168
225
|
end
|
169
226
|
|
@@ -173,6 +230,9 @@ module RubyLsp
|
|
173
230
|
sig { returns(String) }
|
174
231
|
attr_reader :message
|
175
232
|
|
233
|
+
sig { returns(Integer) }
|
234
|
+
attr_reader :code
|
235
|
+
|
176
236
|
sig { params(id: Integer, code: Integer, message: String, data: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
177
237
|
def initialize(id:, code:, message:, data: nil)
|
178
238
|
@id = id
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.23.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
|
-
autorequire:
|
9
8
|
bindir: exe
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 2025-02-10 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: language_server-protocol
|
@@ -94,7 +93,6 @@ files:
|
|
94
93
|
- exe/ruby-lsp
|
95
94
|
- exe/ruby-lsp-check
|
96
95
|
- exe/ruby-lsp-launcher
|
97
|
-
- lib/core_ext/uri.rb
|
98
96
|
- lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb
|
99
97
|
- lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb
|
100
98
|
- lib/ruby-lsp.rb
|
@@ -103,12 +101,14 @@ files:
|
|
103
101
|
- lib/ruby_indexer/lib/ruby_indexer/enhancement.rb
|
104
102
|
- lib/ruby_indexer/lib/ruby_indexer/entry.rb
|
105
103
|
- lib/ruby_indexer/lib/ruby_indexer/index.rb
|
106
|
-
- lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb
|
107
104
|
- lib/ruby_indexer/lib/ruby_indexer/location.rb
|
108
105
|
- lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb
|
109
106
|
- lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb
|
110
107
|
- lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb
|
108
|
+
- lib/ruby_indexer/lib/ruby_indexer/uri.rb
|
109
|
+
- lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb
|
111
110
|
- lib/ruby_indexer/ruby_indexer.rb
|
111
|
+
- lib/ruby_indexer/test/class_variables_test.rb
|
112
112
|
- lib/ruby_indexer/test/classes_and_modules_test.rb
|
113
113
|
- lib/ruby_indexer/test/configuration_test.rb
|
114
114
|
- lib/ruby_indexer/test/constant_test.rb
|
@@ -121,6 +121,7 @@ files:
|
|
121
121
|
- lib/ruby_indexer/test/rbs_indexer_test.rb
|
122
122
|
- lib/ruby_indexer/test/reference_finder_test.rb
|
123
123
|
- lib/ruby_indexer/test/test_case.rb
|
124
|
+
- lib/ruby_indexer/test/uri_test.rb
|
124
125
|
- lib/ruby_lsp/addon.rb
|
125
126
|
- lib/ruby_lsp/base_server.rb
|
126
127
|
- lib/ruby_lsp/client_capabilities.rb
|
@@ -157,6 +158,7 @@ files:
|
|
157
158
|
- lib/ruby_lsp/requests/hover.rb
|
158
159
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
159
160
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
161
|
+
- lib/ruby_lsp/requests/prepare_rename.rb
|
160
162
|
- lib/ruby_lsp/requests/prepare_type_hierarchy.rb
|
161
163
|
- lib/ruby_lsp/requests/range_formatting.rb
|
162
164
|
- lib/ruby_lsp/requests/references.rb
|
@@ -202,7 +204,6 @@ licenses:
|
|
202
204
|
metadata:
|
203
205
|
allowed_push_host: https://rubygems.org
|
204
206
|
documentation_uri: https://shopify.github.io/ruby-lsp/
|
205
|
-
post_install_message:
|
206
207
|
rdoc_options: []
|
207
208
|
require_paths:
|
208
209
|
- lib
|
@@ -217,8 +218,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
218
|
- !ruby/object:Gem::Version
|
218
219
|
version: '0'
|
219
220
|
requirements: []
|
220
|
-
rubygems_version: 3.
|
221
|
-
signing_key:
|
221
|
+
rubygems_version: 3.6.3
|
222
222
|
specification_version: 4
|
223
223
|
summary: An opinionated language server for Ruby
|
224
224
|
test_files: []
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyIndexer
|
5
|
-
class IndexablePath
|
6
|
-
extend T::Sig
|
7
|
-
|
8
|
-
sig { returns(T.nilable(String)) }
|
9
|
-
attr_reader :require_path
|
10
|
-
|
11
|
-
sig { returns(String) }
|
12
|
-
attr_reader :full_path
|
13
|
-
|
14
|
-
# An IndexablePath is instantiated with a load_path_entry and a full_path. The load_path_entry is where the file can
|
15
|
-
# be found in the $LOAD_PATH, which we use to determine the require_path. The load_path_entry may be `nil` if the
|
16
|
-
# indexer is configured to go through files that do not belong in the $LOAD_PATH. For example,
|
17
|
-
# `sorbet/tapioca/require.rb` ends up being a part of the paths to be indexed because it's a Ruby file inside the
|
18
|
-
# project, but the `sorbet` folder is not a part of the $LOAD_PATH. That means that both its load_path_entry and
|
19
|
-
# require_path will be `nil`, since it cannot be required by the project
|
20
|
-
sig { params(load_path_entry: T.nilable(String), full_path: String).void }
|
21
|
-
def initialize(load_path_entry, full_path)
|
22
|
-
@full_path = full_path
|
23
|
-
@require_path = T.let(
|
24
|
-
load_path_entry ? full_path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb") : nil,
|
25
|
-
T.nilable(String),
|
26
|
-
)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|