ruby-lsp 0.23.11 → 0.25.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/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 +18 -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 +106 -236
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +155 -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 -8
- 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 +170 -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 +73 -86
- data/lib/ruby_lsp/base_server.rb +41 -42
- data/lib/ruby_lsp/client_capabilities.rb +16 -13
- data/lib/ruby_lsp/document.rb +201 -98
- 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 +76 -74
- 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 +203 -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 +30 -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 +266 -143
- data/lib/ruby_lsp/setup_bundler.rb +113 -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 +236 -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
data/lib/ruby_lsp/server.rb
CHANGED
|
@@ -3,13 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
module RubyLsp
|
|
5
5
|
class Server < BaseServer
|
|
6
|
-
extend T::Sig
|
|
7
|
-
|
|
8
6
|
# Only for testing
|
|
9
|
-
|
|
7
|
+
#: GlobalState
|
|
10
8
|
attr_reader :global_state
|
|
11
9
|
|
|
12
|
-
|
|
10
|
+
# @override
|
|
11
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
13
12
|
def process_message(message)
|
|
14
13
|
case message[:method]
|
|
15
14
|
when "initialize"
|
|
@@ -33,6 +32,8 @@ module RubyLsp
|
|
|
33
32
|
text_document_document_link(message)
|
|
34
33
|
when "textDocument/codeLens"
|
|
35
34
|
text_document_code_lens(message)
|
|
35
|
+
when "codeLens/resolve"
|
|
36
|
+
code_lens_resolve(message)
|
|
36
37
|
when "textDocument/semanticTokens/full"
|
|
37
38
|
text_document_semantic_tokens_full(message)
|
|
38
39
|
when "textDocument/semanticTokens/full/delta"
|
|
@@ -93,13 +94,10 @@ module RubyLsp
|
|
|
93
94
|
id: message[:id],
|
|
94
95
|
response:
|
|
95
96
|
Addon.addons.map do |addon|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
# Therefore, we only call the method if it's defined by the add-on itself
|
|
101
|
-
if version_method.owner != Addon
|
|
102
|
-
version = addon.version
|
|
97
|
+
version = begin
|
|
98
|
+
addon.version
|
|
99
|
+
rescue AbstractMethodInvokedError
|
|
100
|
+
nil
|
|
103
101
|
end
|
|
104
102
|
|
|
105
103
|
{ name: addon.name, version: version, errored: addon.error? }
|
|
@@ -112,6 +110,10 @@ module RubyLsp
|
|
|
112
110
|
diagnose_state(message)
|
|
113
111
|
when "rubyLsp/discoverTests"
|
|
114
112
|
discover_tests(message)
|
|
113
|
+
when "rubyLsp/resolveTestCommands"
|
|
114
|
+
resolve_test_commands(message)
|
|
115
|
+
when "experimental/goToRelevantFile"
|
|
116
|
+
experimental_go_to_relevant_file(message)
|
|
115
117
|
when "$/cancelRequest"
|
|
116
118
|
@global_state.synchronize { @cancelled_requests << message[:params][:id] }
|
|
117
119
|
when nil
|
|
@@ -119,30 +121,18 @@ module RubyLsp
|
|
|
119
121
|
end
|
|
120
122
|
rescue DelegateRequestError
|
|
121
123
|
send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
|
|
122
|
-
rescue StandardError, LoadError => e
|
|
124
|
+
rescue StandardError, LoadError, SystemExit => e
|
|
123
125
|
# If an error occurred in a request, we have to return an error response or else the editor will hang
|
|
124
126
|
if message[:id]
|
|
125
127
|
# If a document is deleted before we are able to process all of its enqueued requests, we will try to read it
|
|
126
128
|
# from disk and it raise this error. This is expected, so we don't include the `data` attribute to avoid
|
|
127
129
|
# reporting these to our telemetry
|
|
128
|
-
|
|
129
|
-
when Store::NonExistingDocumentError
|
|
130
|
+
if e.is_a?(Store::NonExistingDocumentError)
|
|
130
131
|
send_message(Error.new(
|
|
131
132
|
id: message[:id],
|
|
132
133
|
code: Constant::ErrorCodes::INVALID_PARAMS,
|
|
133
134
|
message: e.full_message,
|
|
134
135
|
))
|
|
135
|
-
when Document::LocationNotFoundError
|
|
136
|
-
send_message(Error.new(
|
|
137
|
-
id: message[:id],
|
|
138
|
-
code: Constant::ErrorCodes::REQUEST_FAILED,
|
|
139
|
-
message: <<~MESSAGE,
|
|
140
|
-
Request #{message[:method]} failed to find the target position.
|
|
141
|
-
The file might have been modified while the server was in the middle of searching for the target.
|
|
142
|
-
If you experience this regularly, please report any findings and extra information on
|
|
143
|
-
https://github.com/Shopify/ruby-lsp/issues/2446
|
|
144
|
-
MESSAGE
|
|
145
|
-
))
|
|
146
136
|
else
|
|
147
137
|
send_message(Error.new(
|
|
148
138
|
id: message[:id],
|
|
@@ -161,7 +151,7 @@ module RubyLsp
|
|
|
161
151
|
end
|
|
162
152
|
|
|
163
153
|
# Process responses to requests that were sent to the client
|
|
164
|
-
|
|
154
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
165
155
|
def process_response(message)
|
|
166
156
|
case message.dig(:result, :method)
|
|
167
157
|
when "window/showMessageRequest"
|
|
@@ -169,7 +159,7 @@ module RubyLsp
|
|
|
169
159
|
end
|
|
170
160
|
end
|
|
171
161
|
|
|
172
|
-
|
|
162
|
+
#: (?include_project_addons: bool) -> void
|
|
173
163
|
def load_addons(include_project_addons: true)
|
|
174
164
|
# If invoking Bundler.setup failed, then the load path will not be configured properly and trying to load add-ons
|
|
175
165
|
# with Gem.find_files will find every single version installed of an add-on, leading to requiring several
|
|
@@ -209,7 +199,7 @@ module RubyLsp
|
|
|
209
199
|
|
|
210
200
|
private
|
|
211
201
|
|
|
212
|
-
|
|
202
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
213
203
|
def run_initialize(message)
|
|
214
204
|
options = message[:params]
|
|
215
205
|
global_state_notifications = @global_state.apply_options(options)
|
|
@@ -219,9 +209,6 @@ module RubyLsp
|
|
|
219
209
|
|
|
220
210
|
configured_features = options.dig(:initializationOptions, :enabledFeatures)
|
|
221
211
|
|
|
222
|
-
configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
|
|
223
|
-
T.must(@store.features_configuration.dig(:inlayHint)).configuration.merge!(configured_hints) if configured_hints
|
|
224
|
-
|
|
225
212
|
enabled_features = case configured_features
|
|
226
213
|
when Array
|
|
227
214
|
# If the configuration is using an array, then absent features are disabled and present ones are enabled. That's
|
|
@@ -238,7 +225,9 @@ module RubyLsp
|
|
|
238
225
|
|
|
239
226
|
bundle_env_path = File.join(".ruby-lsp", "bundle_env")
|
|
240
227
|
bundle_env = if File.exist?(bundle_env_path)
|
|
241
|
-
env = File.readlines(bundle_env_path).to_h
|
|
228
|
+
env = File.readlines(bundle_env_path).to_h do |line|
|
|
229
|
+
line.chomp.split("=", 2) #: as [String, String]
|
|
230
|
+
end
|
|
242
231
|
FileUtils.rm(bundle_env_path)
|
|
243
232
|
env
|
|
244
233
|
end
|
|
@@ -290,6 +279,8 @@ module RubyLsp
|
|
|
290
279
|
experimental: {
|
|
291
280
|
addon_detection: true,
|
|
292
281
|
compose_bundle: true,
|
|
282
|
+
go_to_relevant_file: true,
|
|
283
|
+
full_test_discovery: true,
|
|
293
284
|
},
|
|
294
285
|
),
|
|
295
286
|
serverInfo: {
|
|
@@ -346,7 +337,7 @@ module RubyLsp
|
|
|
346
337
|
end
|
|
347
338
|
end
|
|
348
339
|
|
|
349
|
-
|
|
340
|
+
#: -> void
|
|
350
341
|
def run_initialized
|
|
351
342
|
load_addons
|
|
352
343
|
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
|
|
@@ -371,19 +362,20 @@ module RubyLsp
|
|
|
371
362
|
|
|
372
363
|
perform_initial_indexing
|
|
373
364
|
check_formatter_is_available
|
|
365
|
+
update_server if @global_state.enabled_feature?(:launcher)
|
|
374
366
|
end
|
|
375
367
|
|
|
376
|
-
|
|
368
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
377
369
|
def text_document_did_open(message)
|
|
378
370
|
@global_state.synchronize do
|
|
379
371
|
text_document = message.dig(:params, :textDocument)
|
|
380
372
|
language_id = case text_document[:languageId]
|
|
381
373
|
when "erb", "eruby"
|
|
382
|
-
|
|
374
|
+
:erb
|
|
383
375
|
when "rbs"
|
|
384
|
-
|
|
376
|
+
:rbs
|
|
385
377
|
else
|
|
386
|
-
|
|
378
|
+
:ruby
|
|
387
379
|
end
|
|
388
380
|
|
|
389
381
|
document = @store.set(
|
|
@@ -412,7 +404,7 @@ module RubyLsp
|
|
|
412
404
|
end
|
|
413
405
|
end
|
|
414
406
|
|
|
415
|
-
|
|
407
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
416
408
|
def text_document_did_close(message)
|
|
417
409
|
@global_state.synchronize do
|
|
418
410
|
uri = message.dig(:params, :textDocument, :uri)
|
|
@@ -423,7 +415,7 @@ module RubyLsp
|
|
|
423
415
|
end
|
|
424
416
|
end
|
|
425
417
|
|
|
426
|
-
|
|
418
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
427
419
|
def text_document_did_change(message)
|
|
428
420
|
params = message[:params]
|
|
429
421
|
text_document = params[:textDocument]
|
|
@@ -433,7 +425,7 @@ module RubyLsp
|
|
|
433
425
|
end
|
|
434
426
|
end
|
|
435
427
|
|
|
436
|
-
|
|
428
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
437
429
|
def text_document_selection_range(message)
|
|
438
430
|
uri = message.dig(:params, :textDocument, :uri)
|
|
439
431
|
ranges = @store.cache_fetch(uri, "textDocument/selectionRange") do |document|
|
|
@@ -459,7 +451,7 @@ module RubyLsp
|
|
|
459
451
|
send_message(Result.new(id: message[:id], response: response))
|
|
460
452
|
end
|
|
461
453
|
|
|
462
|
-
|
|
454
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
463
455
|
def run_combined_requests(message)
|
|
464
456
|
uri = URI(message.dig(:params, :textDocument, :uri))
|
|
465
457
|
document = @store.get(uri)
|
|
@@ -483,8 +475,15 @@ module RubyLsp
|
|
|
483
475
|
folding_range = Requests::FoldingRanges.new(parse_result.comments, dispatcher)
|
|
484
476
|
document_symbol = Requests::DocumentSymbol.new(uri, dispatcher)
|
|
485
477
|
document_link = Requests::DocumentLink.new(uri, parse_result.comments, dispatcher)
|
|
486
|
-
|
|
487
|
-
|
|
478
|
+
inlay_hint = Requests::InlayHints.new(
|
|
479
|
+
@global_state,
|
|
480
|
+
document,
|
|
481
|
+
dispatcher,
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
# The code lens listener requires the index to be populated, so the DeclarationListener must be inserted first in
|
|
485
|
+
# the dispatcher's state
|
|
486
|
+
code_lens = nil #: Requests::CodeLens?
|
|
488
487
|
|
|
489
488
|
if document.is_a?(RubyDocument) && document.should_index?
|
|
490
489
|
# Re-index the file as it is modified. This mode of indexing updates entries only. Require path trees are only
|
|
@@ -495,11 +494,13 @@ module RubyLsp
|
|
|
495
494
|
@global_state.index.handle_change(uri) do |index|
|
|
496
495
|
index.delete(uri, skip_require_paths_tree: true)
|
|
497
496
|
RubyIndexer::DeclarationListener.new(index, dispatcher, parse_result, uri, collect_comments: true)
|
|
498
|
-
|
|
497
|
+
code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
|
|
498
|
+
dispatcher.dispatch(document.ast)
|
|
499
499
|
end
|
|
500
500
|
end
|
|
501
501
|
else
|
|
502
|
-
|
|
502
|
+
code_lens = Requests::CodeLens.new(@global_state, document, dispatcher)
|
|
503
|
+
dispatcher.dispatch(document.ast)
|
|
503
504
|
end
|
|
504
505
|
|
|
505
506
|
# Store all responses retrieve in this round of visits in the cache and then return the response for the request
|
|
@@ -507,7 +508,11 @@ module RubyLsp
|
|
|
507
508
|
document.cache_set("textDocument/foldingRange", folding_range.perform)
|
|
508
509
|
document.cache_set("textDocument/documentSymbol", document_symbol.perform)
|
|
509
510
|
document.cache_set("textDocument/documentLink", document_link.perform)
|
|
510
|
-
document.cache_set(
|
|
511
|
+
document.cache_set(
|
|
512
|
+
"textDocument/codeLens",
|
|
513
|
+
code_lens #: as !nil
|
|
514
|
+
.perform,
|
|
515
|
+
)
|
|
511
516
|
document.cache_set("textDocument/inlayHint", inlay_hint.perform)
|
|
512
517
|
|
|
513
518
|
send_message(Result.new(id: message[:id], response: document.cache_get(message[:method])))
|
|
@@ -518,7 +523,7 @@ module RubyLsp
|
|
|
518
523
|
alias_method :text_document_code_lens, :run_combined_requests
|
|
519
524
|
alias_method :text_document_folding_range, :run_combined_requests
|
|
520
525
|
|
|
521
|
-
|
|
526
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
522
527
|
def text_document_semantic_tokens_full(message)
|
|
523
528
|
document = @store.get(message.dig(:params, :textDocument, :uri))
|
|
524
529
|
|
|
@@ -534,12 +539,12 @@ module RubyLsp
|
|
|
534
539
|
|
|
535
540
|
dispatcher = Prism::Dispatcher.new
|
|
536
541
|
semantic_highlighting = Requests::SemanticHighlighting.new(@global_state, dispatcher, document, nil)
|
|
537
|
-
dispatcher.visit(document.
|
|
542
|
+
dispatcher.visit(document.ast)
|
|
538
543
|
|
|
539
544
|
send_message(Result.new(id: message[:id], response: semantic_highlighting.perform))
|
|
540
545
|
end
|
|
541
546
|
|
|
542
|
-
|
|
547
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
543
548
|
def text_document_semantic_tokens_delta(message)
|
|
544
549
|
document = @store.get(message.dig(:params, :textDocument, :uri))
|
|
545
550
|
|
|
@@ -560,11 +565,11 @@ module RubyLsp
|
|
|
560
565
|
document,
|
|
561
566
|
message.dig(:params, :previousResultId),
|
|
562
567
|
)
|
|
563
|
-
dispatcher.visit(document.
|
|
568
|
+
dispatcher.visit(document.ast)
|
|
564
569
|
send_message(Result.new(id: message[:id], response: request.perform))
|
|
565
570
|
end
|
|
566
571
|
|
|
567
|
-
|
|
572
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
568
573
|
def text_document_semantic_tokens_range(message)
|
|
569
574
|
params = message[:params]
|
|
570
575
|
range = params[:range]
|
|
@@ -589,11 +594,11 @@ module RubyLsp
|
|
|
589
594
|
nil,
|
|
590
595
|
range: range.dig(:start, :line)..range.dig(:end, :line),
|
|
591
596
|
)
|
|
592
|
-
dispatcher.visit(document.
|
|
597
|
+
dispatcher.visit(document.ast)
|
|
593
598
|
send_message(Result.new(id: message[:id], response: request.perform))
|
|
594
599
|
end
|
|
595
600
|
|
|
596
|
-
|
|
601
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
597
602
|
def text_document_range_formatting(message)
|
|
598
603
|
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
|
599
604
|
if @global_state.formatter == "none"
|
|
@@ -621,7 +626,7 @@ module RubyLsp
|
|
|
621
626
|
send_message(Result.new(id: message[:id], response: response))
|
|
622
627
|
end
|
|
623
628
|
|
|
624
|
-
|
|
629
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
625
630
|
def text_document_formatting(message)
|
|
626
631
|
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
|
627
632
|
if @global_state.formatter == "none"
|
|
@@ -662,10 +667,14 @@ module RubyLsp
|
|
|
662
667
|
"Formatting error: #{error.message}",
|
|
663
668
|
type: Constant::MessageType::ERROR,
|
|
664
669
|
))
|
|
670
|
+
send_message(Notification.window_log_message(
|
|
671
|
+
"Formatting failed with\r\n: #{error.full_message}",
|
|
672
|
+
type: Constant::MessageType::ERROR,
|
|
673
|
+
))
|
|
665
674
|
send_empty_response(message[:id])
|
|
666
675
|
end
|
|
667
676
|
|
|
668
|
-
|
|
677
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
669
678
|
def text_document_document_highlight(message)
|
|
670
679
|
params = message[:params]
|
|
671
680
|
dispatcher = Prism::Dispatcher.new
|
|
@@ -677,11 +686,11 @@ module RubyLsp
|
|
|
677
686
|
end
|
|
678
687
|
|
|
679
688
|
request = Requests::DocumentHighlight.new(@global_state, document, params[:position], dispatcher)
|
|
680
|
-
dispatcher.dispatch(document.
|
|
689
|
+
dispatcher.dispatch(document.ast)
|
|
681
690
|
send_message(Result.new(id: message[:id], response: request.perform))
|
|
682
691
|
end
|
|
683
692
|
|
|
684
|
-
|
|
693
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
685
694
|
def text_document_on_type_formatting(message)
|
|
686
695
|
params = message[:params]
|
|
687
696
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -704,7 +713,7 @@ module RubyLsp
|
|
|
704
713
|
)
|
|
705
714
|
end
|
|
706
715
|
|
|
707
|
-
|
|
716
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
708
717
|
def text_document_hover(message)
|
|
709
718
|
params = message[:params]
|
|
710
719
|
dispatcher = Prism::Dispatcher.new
|
|
@@ -729,7 +738,7 @@ module RubyLsp
|
|
|
729
738
|
)
|
|
730
739
|
end
|
|
731
740
|
|
|
732
|
-
|
|
741
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
733
742
|
def text_document_rename(message)
|
|
734
743
|
params = message[:params]
|
|
735
744
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -749,7 +758,7 @@ module RubyLsp
|
|
|
749
758
|
send_message(Error.new(id: message[:id], code: Constant::ErrorCodes::REQUEST_FAILED, message: e.message))
|
|
750
759
|
end
|
|
751
760
|
|
|
752
|
-
|
|
761
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
753
762
|
def text_document_prepare_rename(message)
|
|
754
763
|
params = message[:params]
|
|
755
764
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -767,7 +776,7 @@ module RubyLsp
|
|
|
767
776
|
)
|
|
768
777
|
end
|
|
769
778
|
|
|
770
|
-
|
|
779
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
771
780
|
def text_document_references(message)
|
|
772
781
|
params = message[:params]
|
|
773
782
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -785,15 +794,19 @@ module RubyLsp
|
|
|
785
794
|
)
|
|
786
795
|
end
|
|
787
796
|
|
|
788
|
-
|
|
797
|
+
#: (Document[untyped] document) -> SorbetLevel
|
|
789
798
|
def sorbet_level(document)
|
|
790
|
-
return
|
|
791
|
-
return
|
|
799
|
+
return SorbetLevel.ignore unless document.is_a?(RubyDocument)
|
|
800
|
+
return SorbetLevel.ignore unless @global_state.has_type_checker
|
|
801
|
+
|
|
802
|
+
sigil = document.parse_result.magic_comments.find do |comment|
|
|
803
|
+
comment.key == "typed"
|
|
804
|
+
end&.value
|
|
792
805
|
|
|
793
|
-
|
|
806
|
+
SorbetLevel.new(sigil)
|
|
794
807
|
end
|
|
795
808
|
|
|
796
|
-
|
|
809
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
797
810
|
def text_document_inlay_hint(message)
|
|
798
811
|
params = message[:params]
|
|
799
812
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -811,7 +824,6 @@ module RubyLsp
|
|
|
811
824
|
return
|
|
812
825
|
end
|
|
813
826
|
|
|
814
|
-
hints_configurations = T.must(@store.features_configuration.dig(:inlayHint))
|
|
815
827
|
dispatcher = Prism::Dispatcher.new
|
|
816
828
|
|
|
817
829
|
unless document.is_a?(RubyDocument) || document.is_a?(ERBDocument)
|
|
@@ -819,15 +831,15 @@ module RubyLsp
|
|
|
819
831
|
return
|
|
820
832
|
end
|
|
821
833
|
|
|
822
|
-
request = Requests::InlayHints.new(
|
|
823
|
-
dispatcher.visit(document.
|
|
834
|
+
request = Requests::InlayHints.new(@global_state, document, dispatcher)
|
|
835
|
+
dispatcher.visit(document.ast)
|
|
824
836
|
result = request.perform
|
|
825
837
|
document.cache_set("textDocument/inlayHint", result)
|
|
826
838
|
|
|
827
839
|
send_message(Result.new(id: message[:id], response: result.select { |hint| range.cover?(hint.position[:line]) }))
|
|
828
840
|
end
|
|
829
841
|
|
|
830
|
-
|
|
842
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
831
843
|
def text_document_code_action(message)
|
|
832
844
|
params = message[:params]
|
|
833
845
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -849,7 +861,7 @@ module RubyLsp
|
|
|
849
861
|
)
|
|
850
862
|
end
|
|
851
863
|
|
|
852
|
-
|
|
864
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
853
865
|
def code_action_resolve(message)
|
|
854
866
|
params = message[:params]
|
|
855
867
|
uri = URI(params.dig(:data, :uri))
|
|
@@ -861,20 +873,12 @@ module RubyLsp
|
|
|
861
873
|
end
|
|
862
874
|
|
|
863
875
|
result = Requests::CodeActionResolve.new(document, @global_state, params).perform
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
fail_request_and_notify(message[:id], "Invalid selection for extract variable refactor")
|
|
868
|
-
when Requests::CodeActionResolve::Error::InvalidTargetRange
|
|
869
|
-
fail_request_and_notify(message[:id], "Couldn't find an appropriate location to place extracted refactor")
|
|
870
|
-
when Requests::CodeActionResolve::Error::UnknownCodeAction
|
|
871
|
-
fail_request_and_notify(message[:id], "Unknown code action")
|
|
872
|
-
else
|
|
873
|
-
send_message(Result.new(id: message[:id], response: result))
|
|
874
|
-
end
|
|
876
|
+
send_message(Result.new(id: message[:id], response: result))
|
|
877
|
+
rescue Requests::CodeActionResolve::CodeActionError => e
|
|
878
|
+
fail_request_and_notify(message[:id], e.message)
|
|
875
879
|
end
|
|
876
880
|
|
|
877
|
-
|
|
881
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
878
882
|
def text_document_diagnostic(message)
|
|
879
883
|
# Do not compute diagnostics for files outside of the workspace. For example, if someone is looking at a gem's
|
|
880
884
|
# source code, we don't want to show diagnostics for it
|
|
@@ -911,10 +915,14 @@ module RubyLsp
|
|
|
911
915
|
"Error running diagnostics: #{error.message}",
|
|
912
916
|
type: Constant::MessageType::ERROR,
|
|
913
917
|
))
|
|
918
|
+
send_message(Notification.window_log_message(
|
|
919
|
+
"Diagnostics failed with\r\n: #{error.full_message}",
|
|
920
|
+
type: Constant::MessageType::ERROR,
|
|
921
|
+
))
|
|
914
922
|
send_empty_response(message[:id])
|
|
915
923
|
end
|
|
916
924
|
|
|
917
|
-
|
|
925
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
918
926
|
def text_document_completion(message)
|
|
919
927
|
params = message[:params]
|
|
920
928
|
dispatcher = Prism::Dispatcher.new
|
|
@@ -939,7 +947,7 @@ module RubyLsp
|
|
|
939
947
|
)
|
|
940
948
|
end
|
|
941
949
|
|
|
942
|
-
|
|
950
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
943
951
|
def text_document_completion_item_resolve(message)
|
|
944
952
|
# When responding to a delegated completion request, it means we're handling a completion item that isn't related
|
|
945
953
|
# to Ruby (probably related to an ERB host language like HTML). We need to return the original completion item
|
|
@@ -958,7 +966,7 @@ module RubyLsp
|
|
|
958
966
|
))
|
|
959
967
|
end
|
|
960
968
|
|
|
961
|
-
|
|
969
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
962
970
|
def text_document_signature_help(message)
|
|
963
971
|
params = message[:params]
|
|
964
972
|
dispatcher = Prism::Dispatcher.new
|
|
@@ -984,7 +992,7 @@ module RubyLsp
|
|
|
984
992
|
)
|
|
985
993
|
end
|
|
986
994
|
|
|
987
|
-
|
|
995
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
988
996
|
def text_document_definition(message)
|
|
989
997
|
params = message[:params]
|
|
990
998
|
dispatcher = Prism::Dispatcher.new
|
|
@@ -1009,8 +1017,23 @@ module RubyLsp
|
|
|
1009
1017
|
)
|
|
1010
1018
|
end
|
|
1011
1019
|
|
|
1012
|
-
|
|
1020
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1013
1021
|
def workspace_did_change_watched_files(message)
|
|
1022
|
+
# If indexing is not complete yet, delay processing did change watched file notifications. We need initial
|
|
1023
|
+
# indexing to be in place so that we can handle file changes appropriately without risking duplicates. We also
|
|
1024
|
+
# have to sleep before re-inserting the notification in the queue otherwise the worker can get stuck in its own
|
|
1025
|
+
# loop of pushing and popping the same notification
|
|
1026
|
+
unless @global_state.index.initial_indexing_completed
|
|
1027
|
+
Thread.new do
|
|
1028
|
+
sleep(2)
|
|
1029
|
+
# We have to ensure that the queue is not closed yet, since nothing stops the user from saving a file and then
|
|
1030
|
+
# immediately telling the LSP to shutdown
|
|
1031
|
+
@incoming_queue << message unless @incoming_queue.closed?
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
return
|
|
1035
|
+
end
|
|
1036
|
+
|
|
1014
1037
|
changes = message.dig(:params, :changes)
|
|
1015
1038
|
# We allow add-ons to register for watching files and we have no restrictions for what they register for. If the
|
|
1016
1039
|
# same pattern is registered more than once, the LSP will receive duplicate change notifications. Receiving them
|
|
@@ -1037,7 +1060,8 @@ module RubyLsp
|
|
|
1037
1060
|
end
|
|
1038
1061
|
|
|
1039
1062
|
Addon.file_watcher_addons.each do |addon|
|
|
1040
|
-
|
|
1063
|
+
addon #: as untyped
|
|
1064
|
+
.workspace_did_change_watched_files(changes)
|
|
1041
1065
|
rescue => e
|
|
1042
1066
|
send_log_message(
|
|
1043
1067
|
"Error in #{addon.name} add-on while processing watched file notifications: #{e.full_message}",
|
|
@@ -1046,32 +1070,34 @@ module RubyLsp
|
|
|
1046
1070
|
end
|
|
1047
1071
|
end
|
|
1048
1072
|
|
|
1049
|
-
|
|
1073
|
+
#: (RubyIndexer::Index index, String file_path, Integer change_type) -> void
|
|
1050
1074
|
def handle_ruby_file_change(index, file_path, change_type)
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1075
|
+
@global_state.synchronize do
|
|
1076
|
+
load_path_entry = $LOAD_PATH.find { |load_path| file_path.start_with?(load_path) }
|
|
1077
|
+
uri = URI::Generic.from_path(load_path_entry: load_path_entry, path: file_path)
|
|
1078
|
+
|
|
1079
|
+
case change_type
|
|
1080
|
+
when Constant::FileChangeType::CREATED
|
|
1081
|
+
content = File.read(file_path)
|
|
1082
|
+
# If we receive a late created notification for a file that has already been claimed by the client, we want to
|
|
1083
|
+
# handle change for that URI so that the require path tree is updated
|
|
1084
|
+
@store.key?(uri) ? index.handle_change(uri, content) : index.index_single(uri, content)
|
|
1085
|
+
when Constant::FileChangeType::CHANGED
|
|
1086
|
+
content = File.read(file_path)
|
|
1087
|
+
# We only handle changes on file watched notifications if the client is not the one managing this URI.
|
|
1088
|
+
# Otherwise, these changes are handled when running the combined requests
|
|
1089
|
+
index.handle_change(uri, content) unless @store.key?(uri)
|
|
1090
|
+
when Constant::FileChangeType::DELETED
|
|
1091
|
+
index.delete(uri)
|
|
1092
|
+
end
|
|
1093
|
+
rescue Errno::ENOENT
|
|
1094
|
+
# If a file is created and then delete immediately afterwards, we will process the created notification before
|
|
1095
|
+
# we receive the deleted one, but the file no longer exists. This may happen when running a test suite that
|
|
1096
|
+
# creates and deletes files automatically.
|
|
1097
|
+
end
|
|
1072
1098
|
end
|
|
1073
1099
|
|
|
1074
|
-
|
|
1100
|
+
#: (URI::Generic uri) -> void
|
|
1075
1101
|
def handle_rubocop_config_change(uri)
|
|
1076
1102
|
return unless defined?(Requests::Support::RuboCopFormatter)
|
|
1077
1103
|
|
|
@@ -1081,7 +1107,7 @@ module RubyLsp
|
|
|
1081
1107
|
# Clear all document caches for pull diagnostics
|
|
1082
1108
|
@global_state.synchronize do
|
|
1083
1109
|
@store.each do |_uri, document|
|
|
1084
|
-
document.
|
|
1110
|
+
document.clear_cache("textDocument/diagnostic")
|
|
1085
1111
|
end
|
|
1086
1112
|
end
|
|
1087
1113
|
|
|
@@ -1091,7 +1117,7 @@ module RubyLsp
|
|
|
1091
1117
|
end
|
|
1092
1118
|
end
|
|
1093
1119
|
|
|
1094
|
-
|
|
1120
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1095
1121
|
def workspace_symbol(message)
|
|
1096
1122
|
send_message(
|
|
1097
1123
|
Result.new(
|
|
@@ -1104,7 +1130,7 @@ module RubyLsp
|
|
|
1104
1130
|
)
|
|
1105
1131
|
end
|
|
1106
1132
|
|
|
1107
|
-
|
|
1133
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1108
1134
|
def text_document_show_syntax_tree(message)
|
|
1109
1135
|
params = message[:params]
|
|
1110
1136
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -1123,7 +1149,26 @@ module RubyLsp
|
|
|
1123
1149
|
send_message(Result.new(id: message[:id], response: response))
|
|
1124
1150
|
end
|
|
1125
1151
|
|
|
1126
|
-
|
|
1152
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1153
|
+
def experimental_go_to_relevant_file(message)
|
|
1154
|
+
path = message.dig(:params, :textDocument, :uri).to_standardized_path
|
|
1155
|
+
unless path.nil? || path.start_with?(@global_state.workspace_path)
|
|
1156
|
+
send_empty_response(message[:id])
|
|
1157
|
+
return
|
|
1158
|
+
end
|
|
1159
|
+
|
|
1160
|
+
unless path
|
|
1161
|
+
send_empty_response(message[:id])
|
|
1162
|
+
return
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
response = {
|
|
1166
|
+
locations: Requests::GoToRelevantFile.new(path, @global_state.workspace_path).perform,
|
|
1167
|
+
}
|
|
1168
|
+
send_message(Result.new(id: message[:id], response: response))
|
|
1169
|
+
end
|
|
1170
|
+
|
|
1171
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1127
1172
|
def text_document_prepare_type_hierarchy(message)
|
|
1128
1173
|
params = message[:params]
|
|
1129
1174
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
@@ -1142,7 +1187,7 @@ module RubyLsp
|
|
|
1142
1187
|
send_message(Result.new(id: message[:id], response: response))
|
|
1143
1188
|
end
|
|
1144
1189
|
|
|
1145
|
-
|
|
1190
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1146
1191
|
def type_hierarchy_supertypes(message)
|
|
1147
1192
|
response = Requests::TypeHierarchySupertypes.new(
|
|
1148
1193
|
@global_state.index,
|
|
@@ -1151,14 +1196,14 @@ module RubyLsp
|
|
|
1151
1196
|
send_message(Result.new(id: message[:id], response: response))
|
|
1152
1197
|
end
|
|
1153
1198
|
|
|
1154
|
-
|
|
1199
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1155
1200
|
def type_hierarchy_subtypes(message)
|
|
1156
1201
|
# TODO: implement subtypes
|
|
1157
1202
|
# The current index representation doesn't allow us to find the children of an entry.
|
|
1158
1203
|
send_message(Result.new(id: message[:id], response: nil))
|
|
1159
1204
|
end
|
|
1160
1205
|
|
|
1161
|
-
|
|
1206
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1162
1207
|
def workspace_dependencies(message)
|
|
1163
1208
|
unless @global_state.top_level_bundle
|
|
1164
1209
|
send_message(Result.new(id: message[:id], response: []))
|
|
@@ -1186,12 +1231,13 @@ module RubyLsp
|
|
|
1186
1231
|
send_message(Result.new(id: message[:id], response: response))
|
|
1187
1232
|
end
|
|
1188
1233
|
|
|
1189
|
-
|
|
1234
|
+
# @override
|
|
1235
|
+
#: -> void
|
|
1190
1236
|
def shutdown
|
|
1191
1237
|
Addon.unload_addons
|
|
1192
1238
|
end
|
|
1193
1239
|
|
|
1194
|
-
|
|
1240
|
+
#: -> void
|
|
1195
1241
|
def perform_initial_indexing
|
|
1196
1242
|
# The begin progress invocation happens during `initialize`, so that the notification is sent before we are
|
|
1197
1243
|
# stuck indexing files
|
|
@@ -1217,13 +1263,29 @@ module RubyLsp
|
|
|
1217
1263
|
# allocations and garbage collections are faster
|
|
1218
1264
|
GC.compact unless @test_mode
|
|
1219
1265
|
|
|
1266
|
+
@global_state.synchronize do
|
|
1267
|
+
# If we linearize ancestors while the index is not fully populated, we may end up caching incorrect results
|
|
1268
|
+
# that were missing namespaces. After indexing is complete, we need to clear the ancestors cache and start
|
|
1269
|
+
# again
|
|
1270
|
+
@global_state.index.clear_ancestors
|
|
1271
|
+
|
|
1272
|
+
# The results for code lens depend on ancestor linearization, so we need to clear any previously computed
|
|
1273
|
+
# responses
|
|
1274
|
+
@store.each { |_uri, document| document.clear_cache("textDocument/codeLens") }
|
|
1275
|
+
end
|
|
1276
|
+
|
|
1220
1277
|
# Always end the progress notification even if indexing failed or else it never goes away and the user has no
|
|
1221
1278
|
# way of dismissing it
|
|
1222
1279
|
end_progress("indexing-progress")
|
|
1280
|
+
|
|
1281
|
+
# Request a code lens refresh if we populated them before all test parent classes were indexed
|
|
1282
|
+
if @global_state.client_capabilities.supports_code_lens_refresh
|
|
1283
|
+
send_message(Request.new(id: @current_request_id, method: "workspace/codeLens/refresh", params: nil))
|
|
1284
|
+
end
|
|
1223
1285
|
end
|
|
1224
1286
|
end
|
|
1225
1287
|
|
|
1226
|
-
|
|
1288
|
+
#: (String id, String title, ?percentage: Integer) -> void
|
|
1227
1289
|
def begin_progress(id, title, percentage: 0)
|
|
1228
1290
|
return unless @global_state.client_capabilities.supports_progress
|
|
1229
1291
|
|
|
@@ -1236,14 +1298,14 @@ module RubyLsp
|
|
|
1236
1298
|
send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
|
|
1237
1299
|
end
|
|
1238
1300
|
|
|
1239
|
-
|
|
1301
|
+
#: (String id, Integer percentage) -> void
|
|
1240
1302
|
def progress(id, percentage)
|
|
1241
1303
|
return unless @global_state.client_capabilities.supports_progress
|
|
1242
1304
|
|
|
1243
1305
|
send_message(Notification.progress_report(id, percentage: percentage, message: "#{percentage}% completed"))
|
|
1244
1306
|
end
|
|
1245
1307
|
|
|
1246
|
-
|
|
1308
|
+
#: (String id) -> void
|
|
1247
1309
|
def end_progress(id)
|
|
1248
1310
|
return unless @global_state.client_capabilities.supports_progress
|
|
1249
1311
|
|
|
@@ -1253,7 +1315,7 @@ module RubyLsp
|
|
|
1253
1315
|
# notification
|
|
1254
1316
|
end
|
|
1255
1317
|
|
|
1256
|
-
|
|
1318
|
+
#: -> void
|
|
1257
1319
|
def check_formatter_is_available
|
|
1258
1320
|
return if @setup_error
|
|
1259
1321
|
# Warn of an unavailable `formatter` setting, e.g. `rubocop_internal` on a project which doesn't have RuboCop.
|
|
@@ -1271,7 +1333,7 @@ module RubyLsp
|
|
|
1271
1333
|
end
|
|
1272
1334
|
end
|
|
1273
1335
|
|
|
1274
|
-
|
|
1336
|
+
#: (Hash[Symbol, untyped]? indexing_options) -> void
|
|
1275
1337
|
def process_indexing_configuration(indexing_options)
|
|
1276
1338
|
# Need to use the workspace URI, otherwise, this will fail for people working on a project that is a symlink.
|
|
1277
1339
|
index_path = File.join(@global_state.workspace_path, ".index.yml")
|
|
@@ -1312,7 +1374,7 @@ module RubyLsp
|
|
|
1312
1374
|
configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
|
|
1313
1375
|
end
|
|
1314
1376
|
|
|
1315
|
-
|
|
1377
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1316
1378
|
def window_show_message_request(message)
|
|
1317
1379
|
result = message[:result]
|
|
1318
1380
|
return unless result
|
|
@@ -1327,7 +1389,7 @@ module RubyLsp
|
|
|
1327
1389
|
# NOTE: all servers methods are void because they can produce several messages for the client. The only reason this
|
|
1328
1390
|
# method returns the created thread is to that we can join it in tests and avoid flakiness. The implementation is
|
|
1329
1391
|
# not supposed to rely on the return of this method
|
|
1330
|
-
|
|
1392
|
+
#: (Hash[Symbol, untyped] message) -> Thread?
|
|
1331
1393
|
def compose_bundle(message)
|
|
1332
1394
|
already_composed_path = File.join(@global_state.workspace_path, ".ruby-lsp", "bundle_is_composed")
|
|
1333
1395
|
id = message[:id]
|
|
@@ -1345,36 +1407,58 @@ module RubyLsp
|
|
|
1345
1407
|
|
|
1346
1408
|
# We compose the bundle in a thread so that the LSP continues to work while we're checking for its validity. Once
|
|
1347
1409
|
# we return the response back to the editor, then the restart is triggered
|
|
1410
|
+
launch_bundle_compose("Recomposing the bundle ahead of restart") do |stderr, status|
|
|
1411
|
+
if status&.exitstatus == 0
|
|
1412
|
+
# Create a signal for the restart that it can skip composing the bundle and launch directly
|
|
1413
|
+
FileUtils.touch(already_composed_path)
|
|
1414
|
+
send_message(Result.new(id: id, response: { success: true }))
|
|
1415
|
+
else
|
|
1416
|
+
# This special error code makes the extension avoid restarting in case we already know that the composed
|
|
1417
|
+
# bundle is not valid
|
|
1418
|
+
send_message(
|
|
1419
|
+
Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: "Failed to compose bundle\n#{stderr}"),
|
|
1420
|
+
)
|
|
1421
|
+
end
|
|
1422
|
+
end
|
|
1423
|
+
end
|
|
1424
|
+
|
|
1425
|
+
#: -> void
|
|
1426
|
+
def update_server
|
|
1427
|
+
return unless File.exist?(File.join(@global_state.workspace_path, ".ruby-lsp", "needs_update"))
|
|
1428
|
+
|
|
1429
|
+
launch_bundle_compose("Trying to update server") do |stderr, status|
|
|
1430
|
+
if status&.exitstatus == 0
|
|
1431
|
+
send_log_message("Successfully updated the server")
|
|
1432
|
+
else
|
|
1433
|
+
send_log_message("Failed to update server\n#{stderr}", type: Constant::MessageType::ERROR)
|
|
1434
|
+
end
|
|
1435
|
+
end
|
|
1436
|
+
end
|
|
1437
|
+
|
|
1438
|
+
#: (String) { (IO, Process::Status?) -> void } -> Thread
|
|
1439
|
+
def launch_bundle_compose(log, &block)
|
|
1348
1440
|
Thread.new do
|
|
1349
|
-
send_log_message(
|
|
1441
|
+
send_log_message(log)
|
|
1350
1442
|
|
|
1351
1443
|
_stdout, stderr, status = Bundler.with_unbundled_env do
|
|
1352
1444
|
Open3.capture3(
|
|
1353
1445
|
Gem.ruby,
|
|
1354
1446
|
"-I",
|
|
1355
|
-
File.dirname(
|
|
1447
|
+
File.dirname(
|
|
1448
|
+
__dir__, #: as !nil
|
|
1449
|
+
),
|
|
1356
1450
|
File.expand_path("../../exe/ruby-lsp-launcher", __dir__),
|
|
1357
1451
|
@global_state.workspace_uri.to_s,
|
|
1358
1452
|
chdir: @global_state.workspace_path,
|
|
1359
1453
|
)
|
|
1360
1454
|
end
|
|
1361
1455
|
|
|
1362
|
-
|
|
1363
|
-
# Create a signal for the restart that it can skip composing the bundle and launch directly
|
|
1364
|
-
FileUtils.touch(already_composed_path)
|
|
1365
|
-
send_message(Result.new(id: id, response: { success: true }))
|
|
1366
|
-
else
|
|
1367
|
-
# This special error code makes the extension avoid restarting in case we already know that the composed
|
|
1368
|
-
# bundle is not valid
|
|
1369
|
-
send_message(
|
|
1370
|
-
Error.new(id: id, code: BUNDLE_COMPOSE_FAILED_CODE, message: "Failed to compose bundle\n#{stderr}"),
|
|
1371
|
-
)
|
|
1372
|
-
end
|
|
1456
|
+
block.call(stderr, status)
|
|
1373
1457
|
end
|
|
1374
1458
|
end
|
|
1375
1459
|
|
|
1376
1460
|
# Returns internal state information for debugging purposes
|
|
1377
|
-
|
|
1461
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1378
1462
|
def diagnose_state(message)
|
|
1379
1463
|
documents = {}
|
|
1380
1464
|
@store.each { |uri, document| documents[uri] = document.source }
|
|
@@ -1394,7 +1478,7 @@ module RubyLsp
|
|
|
1394
1478
|
|
|
1395
1479
|
# Discovers all available test groups and examples in a given file taking into consideration the merged response of
|
|
1396
1480
|
# all add-ons
|
|
1397
|
-
|
|
1481
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1398
1482
|
def discover_tests(message)
|
|
1399
1483
|
document = @store.get(message.dig(:params, :textDocument, :uri))
|
|
1400
1484
|
|
|
@@ -1414,5 +1498,44 @@ module RubyLsp
|
|
|
1414
1498
|
|
|
1415
1499
|
send_message(Result.new(id: message[:id], response: items.map(&:to_hash)))
|
|
1416
1500
|
end
|
|
1501
|
+
|
|
1502
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1503
|
+
def resolve_test_commands(message)
|
|
1504
|
+
items = message.dig(:params, :items)
|
|
1505
|
+
commands = Listeners::TestStyle.resolve_test_commands(items)
|
|
1506
|
+
|
|
1507
|
+
Addon.addons.each do |addon|
|
|
1508
|
+
commands.concat(addon.resolve_test_commands(items))
|
|
1509
|
+
end
|
|
1510
|
+
|
|
1511
|
+
send_message(Result.new(
|
|
1512
|
+
id: message[:id],
|
|
1513
|
+
response: {
|
|
1514
|
+
commands: commands,
|
|
1515
|
+
reporterPaths: [Listeners::TestStyle::MINITEST_REPORTER_PATH, Listeners::TestStyle::TEST_UNIT_REPORTER_PATH],
|
|
1516
|
+
},
|
|
1517
|
+
))
|
|
1518
|
+
end
|
|
1519
|
+
|
|
1520
|
+
#: (Hash[Symbol, untyped] message) -> void
|
|
1521
|
+
def code_lens_resolve(message)
|
|
1522
|
+
code_lens = message[:params]
|
|
1523
|
+
args = code_lens.dig(:data, :arguments)
|
|
1524
|
+
|
|
1525
|
+
case code_lens.dig(:data, :kind)
|
|
1526
|
+
when "run_test"
|
|
1527
|
+
code_lens[:command] = Interface::Command.new(title: "▶ Run", command: "rubyLsp.runTest", arguments: args)
|
|
1528
|
+
when "run_test_in_terminal"
|
|
1529
|
+
code_lens[:command] =
|
|
1530
|
+
Interface::Command.new(title: "▶ Run in terminal", command: "rubyLsp.runTestInTerminal", arguments: args)
|
|
1531
|
+
when "debug_test"
|
|
1532
|
+
code_lens[:command] = Interface::Command.new(title: "⚙ Debug", command: "rubyLsp.debugTest", arguments: args)
|
|
1533
|
+
end
|
|
1534
|
+
|
|
1535
|
+
send_message(Result.new(
|
|
1536
|
+
id: message[:id],
|
|
1537
|
+
response: code_lens,
|
|
1538
|
+
))
|
|
1539
|
+
end
|
|
1417
1540
|
end
|
|
1418
1541
|
end
|