ruby-lsp 0.22.1 → 0.23.0
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/VERSION +1 -1
- data/exe/ruby-lsp +10 -9
- data/exe/ruby-lsp-check +5 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +88 -22
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -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 +72 -43
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
- 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 +15 -6
- data/lib/ruby_lsp/document.rb +10 -1
- data/lib/ruby_lsp/internal.rb +1 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
- data/lib/ruby_lsp/listeners/completion.rb +73 -4
- data/lib/ruby_lsp/listeners/definition.rb +73 -17
- 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 +57 -0
- data/lib/ruby_lsp/requests/completion.rb +6 -0
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +6 -0
- 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/rename.rb +14 -4
- data/lib/ruby_lsp/requests/support/common.rb +1 -5
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +42 -7
- data/lib/ruby_lsp/setup_bundler.rb +31 -41
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +22 -0
- data/lib/ruby_lsp/utils.rb +3 -0
- metadata +7 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -0,0 +1,51 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# The
|
7
|
+
# [prepare_rename](https://microsoft.github.io/language-server-protocol/specification#textDocument_prepareRename)
|
8
|
+
# # request checks the validity of a rename operation at a given location.
|
9
|
+
class PrepareRename < Request
|
10
|
+
extend T::Sig
|
11
|
+
include Support::Common
|
12
|
+
|
13
|
+
sig do
|
14
|
+
params(
|
15
|
+
document: RubyDocument,
|
16
|
+
position: T::Hash[Symbol, T.untyped],
|
17
|
+
).void
|
18
|
+
end
|
19
|
+
def initialize(document, position)
|
20
|
+
super()
|
21
|
+
@document = document
|
22
|
+
@position = T.let(position, T::Hash[Symbol, Integer])
|
23
|
+
end
|
24
|
+
|
25
|
+
sig { override.returns(T.nilable(Interface::Range)) }
|
26
|
+
def perform
|
27
|
+
char_position = @document.create_scanner.find_char_position(@position)
|
28
|
+
|
29
|
+
node_context = RubyDocument.locate(
|
30
|
+
@document.parse_result.value,
|
31
|
+
char_position,
|
32
|
+
node_types: [Prism::ConstantReadNode, Prism::ConstantPathNode, Prism::ConstantPathTargetNode],
|
33
|
+
code_units_cache: @document.code_units_cache,
|
34
|
+
)
|
35
|
+
target = node_context.node
|
36
|
+
parent = node_context.parent
|
37
|
+
return if !target || target.is_a?(Prism::ProgramNode)
|
38
|
+
|
39
|
+
if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
|
40
|
+
target = determine_target(
|
41
|
+
target,
|
42
|
+
parent,
|
43
|
+
@position,
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
range_from_location(target.location)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -66,7 +66,7 @@ module RubyLsp
|
|
66
66
|
Interface::TypeHierarchyItem.new(
|
67
67
|
name: first_entry.name,
|
68
68
|
kind: kind_for_entry(first_entry),
|
69
|
-
uri:
|
69
|
+
uri: first_entry.uri.to_s,
|
70
70
|
range: range,
|
71
71
|
selection_range: range,
|
72
72
|
),
|
@@ -12,6 +12,15 @@ module RubyLsp
|
|
12
12
|
|
13
13
|
class InvalidNameError < StandardError; end
|
14
14
|
|
15
|
+
class << self
|
16
|
+
extend T::Sig
|
17
|
+
|
18
|
+
sig { returns(Interface::RenameOptions) }
|
19
|
+
def provider
|
20
|
+
Interface::RenameOptions.new(prepare_provider: true)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
15
24
|
sig do
|
16
25
|
params(
|
17
26
|
global_state: GlobalState,
|
@@ -106,7 +115,9 @@ module RubyLsp
|
|
106
115
|
|
107
116
|
T.must(@global_state.index[fully_qualified_name]).each do |entry|
|
108
117
|
# Do not rename files that are not part of the workspace
|
109
|
-
|
118
|
+
uri = entry.uri
|
119
|
+
file_path = T.must(uri.full_path)
|
120
|
+
next unless file_path.start_with?(@global_state.workspace_path)
|
110
121
|
|
111
122
|
case entry
|
112
123
|
when RubyIndexer::Entry::Class, RubyIndexer::Entry::Module, RubyIndexer::Entry::Constant,
|
@@ -117,13 +128,12 @@ module RubyLsp
|
|
117
128
|
if "#{file_name}.rb" == entry.file_name
|
118
129
|
new_file_name = file_from_constant_name(T.must(@new_name.split("::").last))
|
119
130
|
|
120
|
-
old_uri = URI::Generic.from_path(path: entry.file_path).to_s
|
121
131
|
new_uri = URI::Generic.from_path(path: File.join(
|
122
|
-
File.dirname(
|
132
|
+
File.dirname(file_path),
|
123
133
|
"#{new_file_name}.rb",
|
124
134
|
)).to_s
|
125
135
|
|
126
|
-
document_changes << Interface::RenameFile.new(kind: "rename", old_uri:
|
136
|
+
document_changes << Interface::RenameFile.new(kind: "rename", old_uri: uri.to_s, new_uri: new_uri)
|
127
137
|
end
|
128
138
|
end
|
129
139
|
end
|
@@ -93,11 +93,7 @@ module RubyLsp
|
|
93
93
|
# based, which is why instead of the usual subtraction of 1 to line numbers, we are actually adding 1 to
|
94
94
|
# columns. The format for VS Code file URIs is
|
95
95
|
# `file:///path/to/file.rb#Lstart_line,start_column-end_line,end_column`
|
96
|
-
uri =
|
97
|
-
path: entry.file_path,
|
98
|
-
fragment: "L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}",
|
99
|
-
)
|
100
|
-
|
96
|
+
uri = "#{entry.uri}#L#{loc.start_line},#{loc.start_column + 1}-#{loc.end_line},#{loc.end_column + 1}"
|
101
97
|
definitions << "[#{entry.file_name}](#{uri})"
|
102
98
|
content << "\n\n#{entry.comments}" unless entry.comments.empty?
|
103
99
|
end
|
@@ -65,7 +65,7 @@ module RubyLsp
|
|
65
65
|
Interface::TypeHierarchyItem.new(
|
66
66
|
name: entry.name,
|
67
67
|
kind: kind_for_entry(entry),
|
68
|
-
uri:
|
68
|
+
uri: entry.uri.to_s,
|
69
69
|
range: range_from_location(entry.location),
|
70
70
|
selection_range: range_from_location(entry.name_location),
|
71
71
|
detail: entry.file_name,
|
@@ -21,7 +21,8 @@ module RubyLsp
|
|
21
21
|
sig { override.returns(T::Array[Interface::WorkspaceSymbol]) }
|
22
22
|
def perform
|
23
23
|
@index.fuzzy_search(@query).filter_map do |entry|
|
24
|
-
|
24
|
+
uri = entry.uri
|
25
|
+
file_path = T.must(uri.full_path)
|
25
26
|
|
26
27
|
# We only show symbols declared in the workspace
|
27
28
|
in_dependencies = !not_in_dependencies?(file_path)
|
@@ -43,7 +44,7 @@ module RubyLsp
|
|
43
44
|
container_name: container.join("::"),
|
44
45
|
kind: kind,
|
45
46
|
location: Interface::Location.new(
|
46
|
-
uri:
|
47
|
+
uri: uri.to_s,
|
47
48
|
range: Interface::Range.new(
|
48
49
|
start: Interface::Position.new(line: loc.start_line - 1, character: loc.start_column),
|
49
50
|
end: Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
@@ -5,7 +5,7 @@ def compose(raw_initialize)
|
|
5
5
|
require_relative "../setup_bundler"
|
6
6
|
require "json"
|
7
7
|
require "uri"
|
8
|
-
|
8
|
+
require "ruby_indexer/lib/ruby_indexer/uri"
|
9
9
|
|
10
10
|
initialize_request = JSON.parse(raw_initialize, symbolize_names: true)
|
11
11
|
workspace_uri = initialize_request.dig(:params, :workspaceFolders, 0, :uri)
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -71,6 +71,8 @@ module RubyLsp
|
|
71
71
|
text_document_prepare_type_hierarchy(message)
|
72
72
|
when "textDocument/rename"
|
73
73
|
text_document_rename(message)
|
74
|
+
when "textDocument/prepareRename"
|
75
|
+
text_document_prepare_rename(message)
|
74
76
|
when "textDocument/references"
|
75
77
|
text_document_references(message)
|
76
78
|
when "typeHierarchy/supertypes"
|
@@ -117,12 +119,24 @@ module RubyLsp
|
|
117
119
|
# If a document is deleted before we are able to process all of its enqueued requests, we will try to read it
|
118
120
|
# from disk and it raise this error. This is expected, so we don't include the `data` attribute to avoid
|
119
121
|
# reporting these to our telemetry
|
120
|
-
|
122
|
+
case e
|
123
|
+
when Store::NonExistingDocumentError
|
121
124
|
send_message(Error.new(
|
122
125
|
id: message[:id],
|
123
126
|
code: Constant::ErrorCodes::INVALID_PARAMS,
|
124
127
|
message: e.full_message,
|
125
128
|
))
|
129
|
+
when Document::LocationNotFoundError
|
130
|
+
send_message(Error.new(
|
131
|
+
id: message[:id],
|
132
|
+
code: Constant::ErrorCodes::REQUEST_FAILED,
|
133
|
+
message: <<~MESSAGE,
|
134
|
+
Request #{message[:method]} failed to find the target position.
|
135
|
+
The file might have been modified while the server was in the middle of searching for the target.
|
136
|
+
If you experience this regularly, please report any findings and extra information on
|
137
|
+
https://github.com/Shopify/ruby-lsp/issues/2446
|
138
|
+
MESSAGE
|
139
|
+
))
|
126
140
|
else
|
127
141
|
send_message(Error.new(
|
128
142
|
id: message[:id],
|
@@ -237,6 +251,7 @@ module RubyLsp
|
|
237
251
|
completion_provider = Requests::Completion.provider if enabled_features["completion"]
|
238
252
|
signature_help_provider = Requests::SignatureHelp.provider if enabled_features["signatureHelp"]
|
239
253
|
type_hierarchy_provider = Requests::PrepareTypeHierarchy.provider if enabled_features["typeHierarchy"]
|
254
|
+
rename_provider = Requests::Rename.provider unless @global_state.has_type_checker
|
240
255
|
|
241
256
|
response = {
|
242
257
|
capabilities: Interface::ServerCapabilities.new(
|
@@ -263,7 +278,7 @@ module RubyLsp
|
|
263
278
|
workspace_symbol_provider: enabled_features["workspaceSymbol"] && !@global_state.has_type_checker,
|
264
279
|
signature_help_provider: signature_help_provider,
|
265
280
|
type_hierarchy_provider: type_hierarchy_provider,
|
266
|
-
rename_provider:
|
281
|
+
rename_provider: rename_provider,
|
267
282
|
references_provider: !@global_state.has_type_checker,
|
268
283
|
document_range_formatting_provider: true,
|
269
284
|
experimental: {
|
@@ -727,6 +742,24 @@ module RubyLsp
|
|
727
742
|
send_message(Error.new(id: message[:id], code: Constant::ErrorCodes::REQUEST_FAILED, message: e.message))
|
728
743
|
end
|
729
744
|
|
745
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
746
|
+
def text_document_prepare_rename(message)
|
747
|
+
params = message[:params]
|
748
|
+
document = @store.get(params.dig(:textDocument, :uri))
|
749
|
+
|
750
|
+
unless document.is_a?(RubyDocument)
|
751
|
+
send_empty_response(message[:id])
|
752
|
+
return
|
753
|
+
end
|
754
|
+
|
755
|
+
send_message(
|
756
|
+
Result.new(
|
757
|
+
id: message[:id],
|
758
|
+
response: Requests::PrepareRename.new(document, params[:position]).perform,
|
759
|
+
),
|
760
|
+
)
|
761
|
+
end
|
762
|
+
|
730
763
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
731
764
|
def text_document_references(message)
|
732
765
|
params = message[:params]
|
@@ -981,15 +1014,17 @@ module RubyLsp
|
|
981
1014
|
next unless file_path.end_with?(".rb")
|
982
1015
|
|
983
1016
|
load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
|
984
|
-
|
1017
|
+
uri.add_require_path_from_load_entry(load_path_entry) if load_path_entry
|
1018
|
+
|
1019
|
+
content = File.read(file_path)
|
985
1020
|
|
986
1021
|
case change[:type]
|
987
1022
|
when Constant::FileChangeType::CREATED
|
988
|
-
index.index_single(
|
1023
|
+
index.index_single(uri, content)
|
989
1024
|
when Constant::FileChangeType::CHANGED
|
990
|
-
index.handle_change(
|
1025
|
+
index.handle_change(uri, content)
|
991
1026
|
when Constant::FileChangeType::DELETED
|
992
|
-
index.delete(
|
1027
|
+
index.delete(uri)
|
993
1028
|
end
|
994
1029
|
end
|
995
1030
|
|
@@ -1088,7 +1123,7 @@ module RubyLsp
|
|
1088
1123
|
|
1089
1124
|
sig { override.void }
|
1090
1125
|
def shutdown
|
1091
|
-
Addon.
|
1126
|
+
Addon.unload_addons
|
1092
1127
|
end
|
1093
1128
|
|
1094
1129
|
sig { void }
|
@@ -152,7 +152,13 @@ module RubyLsp
|
|
152
152
|
end
|
153
153
|
|
154
154
|
unless @dependencies["debug"]
|
155
|
-
|
155
|
+
# The `mri` platform excludes Windows. We want to install the debug gem only on MRI for any operating system,
|
156
|
+
# but that constraint doesn't yet exist in Bundler. On Windows, we are manually checking if the engine is MRI
|
157
|
+
parts << if Gem.win_platform?
|
158
|
+
'gem "debug", require: false, group: :development, install_if: -> { RUBY_ENGINE == "ruby" }'
|
159
|
+
else
|
160
|
+
'gem "debug", require: false, group: :development, platforms: :mri'
|
161
|
+
end
|
156
162
|
end
|
157
163
|
|
158
164
|
if @rails_app && !@dependencies["ruby-lsp-rails"]
|
@@ -196,15 +202,15 @@ module RubyLsp
|
|
196
202
|
env["BUNDLE_PATH"] = File.expand_path(env["BUNDLE_PATH"], @project_path)
|
197
203
|
end
|
198
204
|
|
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
|
205
|
+
# Set the specific Bundler version used by the main app. This avoids issues with Bundler restarts, which clean the
|
206
|
+
# environment and lead to the `ruby-lsp` executable not being found
|
203
207
|
if @bundler_version
|
204
208
|
env["BUNDLER_VERSION"] = @bundler_version.to_s
|
205
209
|
install_bundler_if_needed
|
206
210
|
end
|
207
211
|
|
212
|
+
return run_bundle_install_through_command(env) unless @launcher
|
213
|
+
|
208
214
|
begin
|
209
215
|
run_bundle_install_directly(env)
|
210
216
|
# If no error occurred, then clear previous errors
|
@@ -235,12 +241,16 @@ module RubyLsp
|
|
235
241
|
env
|
236
242
|
end
|
237
243
|
|
238
|
-
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }
|
239
|
-
def run_bundle_install_directly(env)
|
244
|
+
sig { params(env: T::Hash[String, String], force_install: T::Boolean).returns(T::Hash[String, String]) }
|
245
|
+
def run_bundle_install_directly(env, force_install: false)
|
240
246
|
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
|
247
|
+
|
248
|
+
# The ENV can only be merged after checking if an update is required because we depend on the original value of
|
249
|
+
# ENV["BUNDLE_GEMFILE"], which gets overridden after the merge
|
250
|
+
should_update = should_bundle_update?
|
241
251
|
T.unsafe(ENV).merge!(env)
|
242
252
|
|
243
|
-
unless
|
253
|
+
unless should_update && !force_install
|
244
254
|
Bundler::CLI::Install.new({}).run
|
245
255
|
correct_relative_remote_paths if @custom_lockfile.exist?
|
246
256
|
return env
|
@@ -255,12 +265,13 @@ module RubyLsp
|
|
255
265
|
correct_relative_remote_paths if @custom_lockfile.exist?
|
256
266
|
@last_updated_path.write(Time.now.iso8601)
|
257
267
|
env
|
268
|
+
rescue Bundler::GemNotFound, Bundler::GitError
|
269
|
+
# If a gem is not installed, skip the upgrade and try to install it with a single retry
|
270
|
+
@retry ? env : run_bundle_install_directly(env, force_install: true)
|
258
271
|
end
|
259
272
|
|
260
273
|
sig { params(env: T::Hash[String, String]).returns(T::Hash[String, String]) }
|
261
274
|
def run_bundle_install_through_command(env)
|
262
|
-
base_bundle = base_bundle_command(env)
|
263
|
-
|
264
275
|
# If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
|
265
276
|
# to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just created
|
266
277
|
# 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 +280,20 @@ module RubyLsp
|
|
269
280
|
|
270
281
|
# When not updating, we run `(bundle check || bundle install)`
|
271
282
|
# When updating, we run `((bundle check && bundle update ruby-lsp debug) || bundle install)`
|
272
|
-
|
283
|
+
bundler_path = File.join(Gem.default_bindir, "bundle")
|
284
|
+
base_command = (File.exist?(bundler_path) ? "#{Gem.ruby} #{bundler_path}" : "bundle").dup
|
285
|
+
|
286
|
+
if env["BUNDLER_VERSION"]
|
287
|
+
base_command << " _#{env["BUNDLER_VERSION"]}_"
|
288
|
+
end
|
289
|
+
|
290
|
+
command = +"(#{base_command} check"
|
273
291
|
|
274
292
|
if should_bundle_update?
|
275
293
|
# If any of `ruby-lsp`, `ruby-lsp-rails` or `debug` are not in the Gemfile, try to update them to the latest
|
276
294
|
# version
|
277
295
|
command.prepend("(")
|
278
|
-
command << " && #{
|
296
|
+
command << " && #{base_command} update "
|
279
297
|
command << "ruby-lsp " unless @dependencies["ruby-lsp"]
|
280
298
|
command << "debug " unless @dependencies["debug"]
|
281
299
|
command << "ruby-lsp-rails " if @rails_app && !@dependencies["ruby-lsp-rails"]
|
@@ -285,7 +303,7 @@ module RubyLsp
|
|
285
303
|
@last_updated_path.write(Time.now.iso8601)
|
286
304
|
end
|
287
305
|
|
288
|
-
command << " || #{
|
306
|
+
command << " || #{base_command} install) "
|
289
307
|
|
290
308
|
# Redirect stdout to stderr to prevent going into an infinite loop. The extension might confuse stdout output with
|
291
309
|
# responses
|
@@ -395,34 +413,6 @@ module RubyLsp
|
|
395
413
|
/class .* < (::)?Rails::Application/.match?(application_contents)
|
396
414
|
end
|
397
415
|
|
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
416
|
sig { void }
|
427
417
|
def patch_thor_to_print_progress_to_stderr!
|
428
418
|
return unless defined?(Bundler::Thor::Shell::Basic)
|
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
|
|
@@ -143,6 +146,25 @@ module RubyLsp
|
|
143
146
|
nil
|
144
147
|
end
|
145
148
|
|
149
|
+
sig { params(node_context: NodeContext).returns(T.nilable(Type)) }
|
150
|
+
def infer_receiver_for_class_variables(node_context)
|
151
|
+
nesting_parts = node_context.nesting.dup
|
152
|
+
|
153
|
+
return Type.new("Object") if nesting_parts.empty?
|
154
|
+
|
155
|
+
nesting_parts.reverse_each do |part|
|
156
|
+
break unless part.include?("<Class:")
|
157
|
+
|
158
|
+
nesting_parts.pop
|
159
|
+
end
|
160
|
+
|
161
|
+
receiver_name = nesting_parts.join("::")
|
162
|
+
resolved_receiver = @index.resolve(receiver_name, node_context.nesting)&.first
|
163
|
+
return unless resolved_receiver&.name
|
164
|
+
|
165
|
+
Type.new(resolved_receiver.name)
|
166
|
+
end
|
167
|
+
|
146
168
|
# A known type
|
147
169
|
class Type
|
148
170
|
extend T::Sig
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -173,6 +173,9 @@ module RubyLsp
|
|
173
173
|
sig { returns(String) }
|
174
174
|
attr_reader :message
|
175
175
|
|
176
|
+
sig { returns(Integer) }
|
177
|
+
attr_reader :code
|
178
|
+
|
176
179
|
sig { params(id: Integer, code: Integer, message: String, data: T.nilable(T::Hash[Symbol, T.untyped])).void }
|
177
180
|
def initialize(id:, code:, message:, data: nil)
|
178
181
|
@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.0
|
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-01-06 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,13 @@ 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
|
111
109
|
- lib/ruby_indexer/ruby_indexer.rb
|
110
|
+
- lib/ruby_indexer/test/class_variables_test.rb
|
112
111
|
- lib/ruby_indexer/test/classes_and_modules_test.rb
|
113
112
|
- lib/ruby_indexer/test/configuration_test.rb
|
114
113
|
- lib/ruby_indexer/test/constant_test.rb
|
@@ -121,6 +120,7 @@ files:
|
|
121
120
|
- lib/ruby_indexer/test/rbs_indexer_test.rb
|
122
121
|
- lib/ruby_indexer/test/reference_finder_test.rb
|
123
122
|
- lib/ruby_indexer/test/test_case.rb
|
123
|
+
- lib/ruby_indexer/test/uri_test.rb
|
124
124
|
- lib/ruby_lsp/addon.rb
|
125
125
|
- lib/ruby_lsp/base_server.rb
|
126
126
|
- lib/ruby_lsp/client_capabilities.rb
|
@@ -157,6 +157,7 @@ files:
|
|
157
157
|
- lib/ruby_lsp/requests/hover.rb
|
158
158
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
159
159
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
160
|
+
- lib/ruby_lsp/requests/prepare_rename.rb
|
160
161
|
- lib/ruby_lsp/requests/prepare_type_hierarchy.rb
|
161
162
|
- lib/ruby_lsp/requests/range_formatting.rb
|
162
163
|
- lib/ruby_lsp/requests/references.rb
|
@@ -202,7 +203,6 @@ licenses:
|
|
202
203
|
metadata:
|
203
204
|
allowed_push_host: https://rubygems.org
|
204
205
|
documentation_uri: https://shopify.github.io/ruby-lsp/
|
205
|
-
post_install_message:
|
206
206
|
rdoc_options: []
|
207
207
|
require_paths:
|
208
208
|
- lib
|
@@ -217,8 +217,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
217
217
|
- !ruby/object:Gem::Version
|
218
218
|
version: '0'
|
219
219
|
requirements: []
|
220
|
-
rubygems_version: 3.
|
221
|
-
signing_key:
|
220
|
+
rubygems_version: 3.6.2
|
222
221
|
specification_version: 4
|
223
222
|
summary: An opinionated language server for Ruby
|
224
223
|
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
|