ruby-lsp 0.21.0 → 0.22.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 +1 -1
- data/exe/ruby-lsp-launcher +0 -3
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +6 -0
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +136 -58
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +31 -28
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +10 -10
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +2 -2
- data/lib/ruby_indexer/test/configuration_test.rb +10 -0
- data/lib/ruby_indexer/test/constant_test.rb +8 -8
- data/lib/ruby_indexer/test/enhancements_test.rb +134 -38
- data/lib/ruby_indexer/test/index_test.rb +39 -0
- data/lib/ruby_indexer/test/method_test.rb +34 -1
- data/lib/ruby_lsp/client_capabilities.rb +8 -1
- data/lib/ruby_lsp/global_state.rb +15 -3
- data/lib/ruby_lsp/internal.rb +1 -0
- data/lib/ruby_lsp/listeners/document_highlight.rb +91 -4
- data/lib/ruby_lsp/requests/definition.rb +2 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +7 -1
- data/lib/ruby_lsp/requests/hover.rb +2 -0
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +1 -0
- data/lib/ruby_lsp/server.rb +35 -43
- data/lib/ruby_lsp/setup_bundler.rb +23 -20
- data/lib/ruby_lsp/store.rb +0 -4
- data/lib/ruby_lsp/utils.rb +55 -0
- metadata +3 -3
data/lib/ruby_lsp/server.rb
CHANGED
@@ -81,8 +81,6 @@ module RubyLsp
|
|
81
81
|
workspace_did_change_watched_files(message)
|
82
82
|
when "workspace/symbol"
|
83
83
|
workspace_symbol(message)
|
84
|
-
when "window/showMessageRequest"
|
85
|
-
window_show_message_request(message)
|
86
84
|
when "rubyLsp/textDocument/showSyntaxTree"
|
87
85
|
text_document_show_syntax_tree(message)
|
88
86
|
when "rubyLsp/workspace/dependencies"
|
@@ -108,6 +106,8 @@ module RubyLsp
|
|
108
106
|
)
|
109
107
|
when "$/cancelRequest"
|
110
108
|
@mutex.synchronize { @cancelled_requests << message[:params][:id] }
|
109
|
+
when nil
|
110
|
+
process_response(message) if message[:result]
|
111
111
|
end
|
112
112
|
rescue DelegateRequestError
|
113
113
|
send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
|
@@ -140,6 +140,15 @@ module RubyLsp
|
|
140
140
|
send_log_message("Error processing #{message[:method]}: #{e.full_message}", type: Constant::MessageType::ERROR)
|
141
141
|
end
|
142
142
|
|
143
|
+
# Process responses to requests that were sent to the client
|
144
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
145
|
+
def process_response(message)
|
146
|
+
case message.dig(:result, :method)
|
147
|
+
when "window/showMessageRequest"
|
148
|
+
window_show_message_request(message)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
143
152
|
sig { params(include_project_addons: T::Boolean).void }
|
144
153
|
def load_addons(include_project_addons: true)
|
145
154
|
# If invoking Bundler.setup failed, then the load path will not be configured properly and trying to load add-ons
|
@@ -188,8 +197,6 @@ module RubyLsp
|
|
188
197
|
client_name = options.dig(:clientInfo, :name)
|
189
198
|
@store.client_name = client_name if client_name
|
190
199
|
|
191
|
-
progress = options.dig(:capabilities, :window, :workDoneProgress)
|
192
|
-
@store.supports_progress = progress.nil? ? true : progress
|
193
200
|
configured_features = options.dig(:initializationOptions, :enabledFeatures)
|
194
201
|
|
195
202
|
configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
|
@@ -209,6 +216,13 @@ module RubyLsp
|
|
209
216
|
Hash.new(true)
|
210
217
|
end
|
211
218
|
|
219
|
+
bundle_env_path = File.join(".ruby-lsp", "bundle_env")
|
220
|
+
bundle_env = if File.exist?(bundle_env_path)
|
221
|
+
env = File.readlines(bundle_env_path).to_h { |line| T.cast(line.chomp.split("=", 2), [String, String]) }
|
222
|
+
FileUtils.rm(bundle_env_path)
|
223
|
+
env
|
224
|
+
end
|
225
|
+
|
212
226
|
document_symbol_provider = Requests::DocumentSymbol.provider if enabled_features["documentSymbols"]
|
213
227
|
document_link_provider = Requests::DocumentLink.provider if enabled_features["documentLink"]
|
214
228
|
code_lens_provider = Requests::CodeLens.provider if enabled_features["codeLens"]
|
@@ -262,6 +276,7 @@ module RubyLsp
|
|
262
276
|
},
|
263
277
|
formatter: @global_state.formatter,
|
264
278
|
degraded_mode: !!(@install_error || @setup_error),
|
279
|
+
bundle_env: bundle_env,
|
265
280
|
}
|
266
281
|
|
267
282
|
send_message(Result.new(id: message[:id], response: response))
|
@@ -597,6 +612,11 @@ module RubyLsp
|
|
597
612
|
# don't want to format it
|
598
613
|
path = uri.to_standardized_path
|
599
614
|
unless path.nil? || path.start_with?(@global_state.workspace_path)
|
615
|
+
send_log_message(<<~MESSAGE)
|
616
|
+
Ignoring formatting request for file outside of the workspace.
|
617
|
+
Workspace path was set by editor as #{@global_state.workspace_path}.
|
618
|
+
File path requested for formatting was #{path}
|
619
|
+
MESSAGE
|
600
620
|
send_empty_response(message[:id])
|
601
621
|
return
|
602
622
|
end
|
@@ -1105,7 +1125,7 @@ module RubyLsp
|
|
1105
1125
|
|
1106
1126
|
sig { params(id: String, title: String, percentage: Integer).void }
|
1107
1127
|
def begin_progress(id, title, percentage: 0)
|
1108
|
-
return unless @
|
1128
|
+
return unless @global_state.client_capabilities.supports_progress
|
1109
1129
|
|
1110
1130
|
send_message(Request.new(
|
1111
1131
|
id: @current_request_id,
|
@@ -1113,52 +1133,21 @@ module RubyLsp
|
|
1113
1133
|
params: Interface::WorkDoneProgressCreateParams.new(token: id),
|
1114
1134
|
))
|
1115
1135
|
|
1116
|
-
send_message(Notification.
|
1117
|
-
method: "$/progress",
|
1118
|
-
params: Interface::ProgressParams.new(
|
1119
|
-
token: id,
|
1120
|
-
value: Interface::WorkDoneProgressBegin.new(
|
1121
|
-
kind: "begin",
|
1122
|
-
title: title,
|
1123
|
-
percentage: percentage,
|
1124
|
-
message: "#{percentage}% completed",
|
1125
|
-
),
|
1126
|
-
),
|
1127
|
-
))
|
1136
|
+
send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
|
1128
1137
|
end
|
1129
1138
|
|
1130
1139
|
sig { params(id: String, percentage: Integer).void }
|
1131
1140
|
def progress(id, percentage)
|
1132
|
-
return unless @
|
1141
|
+
return unless @global_state.client_capabilities.supports_progress
|
1133
1142
|
|
1134
|
-
send_message(
|
1135
|
-
Notification.new(
|
1136
|
-
method: "$/progress",
|
1137
|
-
params: Interface::ProgressParams.new(
|
1138
|
-
token: id,
|
1139
|
-
value: Interface::WorkDoneProgressReport.new(
|
1140
|
-
kind: "report",
|
1141
|
-
percentage: percentage,
|
1142
|
-
message: "#{percentage}% completed",
|
1143
|
-
),
|
1144
|
-
),
|
1145
|
-
),
|
1146
|
-
)
|
1143
|
+
send_message(Notification.progress_report(id, percentage: percentage, message: "#{percentage}% completed"))
|
1147
1144
|
end
|
1148
1145
|
|
1149
1146
|
sig { params(id: String).void }
|
1150
1147
|
def end_progress(id)
|
1151
|
-
return unless @
|
1148
|
+
return unless @global_state.client_capabilities.supports_progress
|
1152
1149
|
|
1153
|
-
send_message(
|
1154
|
-
Notification.new(
|
1155
|
-
method: "$/progress",
|
1156
|
-
params: Interface::ProgressParams.new(
|
1157
|
-
token: id,
|
1158
|
-
value: Interface::WorkDoneProgressEnd.new(kind: "end"),
|
1159
|
-
),
|
1160
|
-
),
|
1161
|
-
)
|
1150
|
+
send_message(Notification.progress_end(id))
|
1162
1151
|
rescue ClosedQueueError
|
1163
1152
|
# If the server was killed and the message queue is already closed, there's no way to end the progress
|
1164
1153
|
# notification
|
@@ -1226,11 +1215,14 @@ module RubyLsp
|
|
1226
1215
|
|
1227
1216
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
1228
1217
|
def window_show_message_request(message)
|
1229
|
-
|
1218
|
+
result = message[:result]
|
1219
|
+
return unless result
|
1220
|
+
|
1221
|
+
addon_name = result[:addon_name]
|
1230
1222
|
addon = Addon.addons.find { |addon| addon.name == addon_name }
|
1231
1223
|
return unless addon
|
1232
1224
|
|
1233
|
-
addon.handle_window_show_message_response(
|
1225
|
+
addon.handle_window_show_message_response(result[:title])
|
1234
1226
|
end
|
1235
1227
|
end
|
1236
1228
|
end
|
@@ -12,7 +12,7 @@ require "digest"
|
|
12
12
|
require "time"
|
13
13
|
require "uri"
|
14
14
|
|
15
|
-
# This file is a script that will configure a
|
15
|
+
# This file is a script that will configure a composed bundle for the Ruby LSP. The composed bundle allows developers to use
|
16
16
|
# the Ruby LSP without including the gem in their application's Gemfile while at the same time giving us access to the
|
17
17
|
# exact locked versions of dependencies.
|
18
18
|
|
@@ -62,7 +62,7 @@ module RubyLsp
|
|
62
62
|
@retry = T.let(false, T::Boolean)
|
63
63
|
end
|
64
64
|
|
65
|
-
# Sets up the
|
65
|
+
# Sets up the composed bundle and returns the `BUNDLE_GEMFILE`, `BUNDLE_PATH` and `BUNDLE_APP_CONFIG` that should be
|
66
66
|
# used for running the server
|
67
67
|
sig { returns(T::Hash[String, String]) }
|
68
68
|
def setup!
|
@@ -73,12 +73,12 @@ module RubyLsp
|
|
73
73
|
ignore_file = @custom_dir + ".gitignore"
|
74
74
|
ignore_file.write("*") unless ignore_file.exist?
|
75
75
|
|
76
|
-
# Do not set up a
|
76
|
+
# Do not set up a composed bundle if LSP dependencies are already in the Gemfile
|
77
77
|
if @dependencies["ruby-lsp"] &&
|
78
78
|
@dependencies["debug"] &&
|
79
79
|
(@rails_app ? @dependencies["ruby-lsp-rails"] : true)
|
80
80
|
$stderr.puts(
|
81
|
-
"Ruby LSP> Skipping
|
81
|
+
"Ruby LSP> Skipping composed bundle setup since LSP dependencies are already in #{@gemfile}",
|
82
82
|
)
|
83
83
|
|
84
84
|
return run_bundle_install
|
@@ -96,7 +96,7 @@ module RubyLsp
|
|
96
96
|
|
97
97
|
if @custom_lockfile.exist? && @lockfile_hash_path.exist? && @lockfile_hash_path.read == current_lockfile_hash
|
98
98
|
$stderr.puts(
|
99
|
-
"Ruby LSP> Skipping
|
99
|
+
"Ruby LSP> Skipping composed bundle setup since #{@custom_lockfile} already exists and is up to date",
|
100
100
|
)
|
101
101
|
return run_bundle_install(@custom_gemfile)
|
102
102
|
end
|
@@ -110,8 +110,8 @@ module RubyLsp
|
|
110
110
|
private
|
111
111
|
|
112
112
|
sig { returns(T::Hash[String, T.untyped]) }
|
113
|
-
def
|
114
|
-
@
|
113
|
+
def composed_bundle_dependencies
|
114
|
+
@composed_bundle_dependencies ||= T.let(
|
115
115
|
begin
|
116
116
|
original_bundle_gemfile = ENV["BUNDLE_GEMFILE"]
|
117
117
|
|
@@ -136,8 +136,8 @@ module RubyLsp
|
|
136
136
|
"",
|
137
137
|
]
|
138
138
|
|
139
|
-
# If there's a top level Gemfile, we want to evaluate from the
|
140
|
-
# Gemfile, so if there isn't one we need to add a default source
|
139
|
+
# If there's a top level Gemfile, we want to evaluate from the composed bundle. We get the source from the top
|
140
|
+
# level Gemfile, so if there isn't one we need to add a default source
|
141
141
|
if @gemfile&.exist? && @lockfile&.exist?
|
142
142
|
parts << "eval_gemfile(File.expand_path(\"../#{@gemfile_name}\", __dir__))"
|
143
143
|
else
|
@@ -187,7 +187,7 @@ module RubyLsp
|
|
187
187
|
env = bundler_settings_as_env
|
188
188
|
env["BUNDLE_GEMFILE"] = bundle_gemfile.to_s
|
189
189
|
|
190
|
-
# If the user has a
|
190
|
+
# If the user has a composed bundle path configured, we need to ensure that we will use the absolute and not
|
191
191
|
# relative version of it when running `bundle install`. This is necessary to avoid installing the gems under the
|
192
192
|
# `.ruby-lsp` folder, which is not the user's intention. For example, if the path is configured as `vendor`, we
|
193
193
|
# want to install it in the top level `vendor` and not `.ruby-lsp/vendor`
|
@@ -244,7 +244,7 @@ module RubyLsp
|
|
244
244
|
base_bundle = base_bundle_command(env)
|
245
245
|
|
246
246
|
# If `ruby-lsp` and `debug` (and potentially `ruby-lsp-rails`) are already in the Gemfile, then we shouldn't try
|
247
|
-
# to upgrade them or else we'll produce undesired source control changes. If the
|
247
|
+
# to upgrade them or else we'll produce undesired source control changes. If the composed bundle was just created
|
248
248
|
# and any of `ruby-lsp`, `ruby-lsp-rails` or `debug` weren't a part of the Gemfile, then we need to run `bundle
|
249
249
|
# install` for the first time to generate the Gemfile.lock with them included or else Bundler will complain that
|
250
250
|
# they're missing. We can only update if the custom `.ruby-lsp/Gemfile.lock` already exists and includes all gems
|
@@ -274,16 +274,16 @@ module RubyLsp
|
|
274
274
|
command << "1>&2"
|
275
275
|
|
276
276
|
# Add bundle update
|
277
|
-
$stderr.puts("Ruby LSP> Running bundle install for the
|
277
|
+
$stderr.puts("Ruby LSP> Running bundle install for the composed bundle. This may take a while...")
|
278
278
|
$stderr.puts("Ruby LSP> Command: #{command}")
|
279
279
|
|
280
|
-
# Try to run the bundle install or update command. If that fails, it normally means that the
|
281
|
-
# a bad state that no longer reflects the top level one. In that case, we can remove the whole directory, try
|
280
|
+
# Try to run the bundle install or update command. If that fails, it normally means that the composed lockfile is
|
281
|
+
# in a bad state that no longer reflects the top level one. In that case, we can remove the whole directory, try
|
282
282
|
# another time and give up if it fails again
|
283
283
|
if !system(env, command) && !@retry && @custom_gemfile.exist?
|
284
284
|
@retry = true
|
285
285
|
@custom_dir.rmtree
|
286
|
-
$stderr.puts("Ruby LSP> Running bundle install failed. Trying to re-generate the
|
286
|
+
$stderr.puts("Ruby LSP> Running bundle install failed. Trying to re-generate the composed bundle from scratch")
|
287
287
|
return setup!
|
288
288
|
end
|
289
289
|
|
@@ -330,14 +330,14 @@ module RubyLsp
|
|
330
330
|
if @rails_app
|
331
331
|
return false if @dependencies.values_at("ruby-lsp", "ruby-lsp-rails", "debug").all?
|
332
332
|
|
333
|
-
# If the
|
334
|
-
# before updating
|
335
|
-
return false if
|
333
|
+
# If the composed lockfile doesn't include `ruby-lsp`, `ruby-lsp-rails` or `debug`, we need to run bundle
|
334
|
+
# install before updating
|
335
|
+
return false if composed_bundle_dependencies.values_at("ruby-lsp", "debug", "ruby-lsp-rails").any?(&:nil?)
|
336
336
|
else
|
337
337
|
return false if @dependencies.values_at("ruby-lsp", "debug").all?
|
338
338
|
|
339
|
-
# If the
|
340
|
-
return false if
|
339
|
+
# If the composed lockfile doesn't include `ruby-lsp` or `debug`, we need to run bundle install before updating
|
340
|
+
return false if composed_bundle_dependencies.values_at("ruby-lsp", "debug").any?(&:nil?)
|
341
341
|
end
|
342
342
|
|
343
343
|
# If the last updated file doesn't exist or was updated more than 4 hours ago, we should update
|
@@ -359,6 +359,9 @@ module RubyLsp
|
|
359
359
|
else
|
360
360
|
match
|
361
361
|
end
|
362
|
+
rescue URI::InvalidURIError, URI::InvalidComponentError
|
363
|
+
# If the path raises an invalid error, it might be a git ssh path, which indeed isn't a URI
|
364
|
+
match
|
362
365
|
end
|
363
366
|
|
364
367
|
@custom_lockfile.write(content)
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -7,9 +7,6 @@ module RubyLsp
|
|
7
7
|
|
8
8
|
class NonExistingDocumentError < StandardError; end
|
9
9
|
|
10
|
-
sig { returns(T::Boolean) }
|
11
|
-
attr_accessor :supports_progress
|
12
|
-
|
13
10
|
sig { returns(T::Hash[Symbol, RequestConfig]) }
|
14
11
|
attr_accessor :features_configuration
|
15
12
|
|
@@ -19,7 +16,6 @@ module RubyLsp
|
|
19
16
|
sig { void }
|
20
17
|
def initialize
|
21
18
|
@state = T.let({}, T::Hash[String, Document[T.untyped]])
|
22
|
-
@supports_progress = T.let(true, T::Boolean)
|
23
19
|
@features_configuration = T.let(
|
24
20
|
{
|
25
21
|
inlayHint: RequestConfig.new({
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -87,6 +87,61 @@ module RubyLsp
|
|
87
87
|
params: data,
|
88
88
|
)
|
89
89
|
end
|
90
|
+
|
91
|
+
sig do
|
92
|
+
params(
|
93
|
+
id: String,
|
94
|
+
title: String,
|
95
|
+
percentage: T.nilable(Integer),
|
96
|
+
message: T.nilable(String),
|
97
|
+
).returns(Notification)
|
98
|
+
end
|
99
|
+
def progress_begin(id, title, percentage: nil, message: nil)
|
100
|
+
new(
|
101
|
+
method: "$/progress",
|
102
|
+
params: Interface::ProgressParams.new(
|
103
|
+
token: id,
|
104
|
+
value: Interface::WorkDoneProgressBegin.new(
|
105
|
+
kind: "begin",
|
106
|
+
title: title,
|
107
|
+
percentage: percentage,
|
108
|
+
message: message,
|
109
|
+
),
|
110
|
+
),
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
sig do
|
115
|
+
params(
|
116
|
+
id: String,
|
117
|
+
percentage: T.nilable(Integer),
|
118
|
+
message: T.nilable(String),
|
119
|
+
).returns(Notification)
|
120
|
+
end
|
121
|
+
def progress_report(id, percentage: nil, message: nil)
|
122
|
+
new(
|
123
|
+
method: "$/progress",
|
124
|
+
params: Interface::ProgressParams.new(
|
125
|
+
token: id,
|
126
|
+
value: Interface::WorkDoneProgressReport.new(
|
127
|
+
kind: "report",
|
128
|
+
percentage: percentage,
|
129
|
+
message: message,
|
130
|
+
),
|
131
|
+
),
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
sig { params(id: String).returns(Notification) }
|
136
|
+
def progress_end(id)
|
137
|
+
Notification.new(
|
138
|
+
method: "$/progress",
|
139
|
+
params: Interface::ProgressParams.new(
|
140
|
+
token: id,
|
141
|
+
value: Interface::WorkDoneProgressEnd.new(kind: "end"),
|
142
|
+
),
|
143
|
+
)
|
144
|
+
end
|
90
145
|
end
|
91
146
|
|
92
147
|
extend T::Sig
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.22.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -217,7 +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.5.
|
220
|
+
rubygems_version: 3.5.23
|
221
221
|
signing_key:
|
222
222
|
specification_version: 4
|
223
223
|
summary: An opinionated language server for Ruby
|