ruby-lsp 0.20.1 → 0.22.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp +19 -4
- data/exe/ruby-lsp-launcher +124 -0
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +6 -0
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +233 -59
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +34 -16
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +15 -15
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +4 -4
- 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 +169 -41
- data/lib/ruby_indexer/test/index_test.rb +41 -2
- data/lib/ruby_indexer/test/instance_variables_test.rb +1 -1
- data/lib/ruby_indexer/test/method_test.rb +139 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_lsp/addon.rb +9 -2
- data/lib/ruby_lsp/base_server.rb +14 -5
- data/lib/ruby_lsp/client_capabilities.rb +67 -0
- data/lib/ruby_lsp/document.rb +1 -1
- data/lib/ruby_lsp/global_state.rb +33 -20
- data/lib/ruby_lsp/internal.rb +3 -0
- data/lib/ruby_lsp/listeners/completion.rb +62 -0
- data/lib/ruby_lsp/listeners/definition.rb +48 -13
- data/lib/ruby_lsp/listeners/document_highlight.rb +91 -4
- data/lib/ruby_lsp/listeners/document_symbol.rb +37 -4
- data/lib/ruby_lsp/listeners/hover.rb +52 -0
- data/lib/ruby_lsp/requests/code_action_resolve.rb +1 -1
- data/lib/ruby_lsp/requests/completion.rb +7 -1
- data/lib/ruby_lsp/requests/completion_resolve.rb +1 -1
- data/lib/ruby_lsp/requests/definition.rb +28 -11
- data/lib/ruby_lsp/requests/document_highlight.rb +7 -1
- data/lib/ruby_lsp/requests/document_symbol.rb +2 -1
- data/lib/ruby_lsp/requests/hover.rb +26 -6
- data/lib/ruby_lsp/requests/rename.rb +1 -1
- data/lib/ruby_lsp/requests/request.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +12 -1
- data/lib/ruby_lsp/scripts/compose_bundle.rb +20 -0
- data/lib/ruby_lsp/scripts/compose_bundle_windows.rb +8 -0
- data/lib/ruby_lsp/server.rb +85 -55
- data/lib/ruby_lsp/setup_bundler.rb +154 -47
- data/lib/ruby_lsp/store.rb +0 -4
- data/lib/ruby_lsp/utils.rb +63 -0
- metadata +8 -3
@@ -41,6 +41,9 @@ module RubyLsp
|
|
41
41
|
:on_module_node_enter,
|
42
42
|
:on_module_node_leave,
|
43
43
|
:on_instance_variable_write_node_enter,
|
44
|
+
:on_instance_variable_operator_write_node_enter,
|
45
|
+
:on_instance_variable_or_write_node_enter,
|
46
|
+
:on_instance_variable_and_write_node_enter,
|
44
47
|
:on_class_variable_write_node_enter,
|
45
48
|
:on_singleton_class_node_enter,
|
46
49
|
:on_singleton_class_node_leave,
|
@@ -249,21 +252,51 @@ module RubyLsp
|
|
249
252
|
@response_builder.pop
|
250
253
|
end
|
251
254
|
|
255
|
+
sig { params(node: Prism::ClassVariableWriteNode).void }
|
256
|
+
def on_class_variable_write_node_enter(node)
|
257
|
+
create_document_symbol(
|
258
|
+
name: node.name.to_s,
|
259
|
+
kind: Constant::SymbolKind::VARIABLE,
|
260
|
+
range_location: node.name_loc,
|
261
|
+
selection_range_location: node.name_loc,
|
262
|
+
)
|
263
|
+
end
|
264
|
+
|
252
265
|
sig { params(node: Prism::InstanceVariableWriteNode).void }
|
253
266
|
def on_instance_variable_write_node_enter(node)
|
254
267
|
create_document_symbol(
|
255
268
|
name: node.name.to_s,
|
256
|
-
kind: Constant::SymbolKind::
|
269
|
+
kind: Constant::SymbolKind::FIELD,
|
257
270
|
range_location: node.name_loc,
|
258
271
|
selection_range_location: node.name_loc,
|
259
272
|
)
|
260
273
|
end
|
261
274
|
|
262
|
-
sig { params(node: Prism::
|
263
|
-
def
|
275
|
+
sig { params(node: Prism::InstanceVariableOperatorWriteNode).void }
|
276
|
+
def on_instance_variable_operator_write_node_enter(node)
|
264
277
|
create_document_symbol(
|
265
278
|
name: node.name.to_s,
|
266
|
-
kind: Constant::SymbolKind::
|
279
|
+
kind: Constant::SymbolKind::FIELD,
|
280
|
+
range_location: node.name_loc,
|
281
|
+
selection_range_location: node.name_loc,
|
282
|
+
)
|
283
|
+
end
|
284
|
+
|
285
|
+
sig { params(node: Prism::InstanceVariableOrWriteNode).void }
|
286
|
+
def on_instance_variable_or_write_node_enter(node)
|
287
|
+
create_document_symbol(
|
288
|
+
name: node.name.to_s,
|
289
|
+
kind: Constant::SymbolKind::FIELD,
|
290
|
+
range_location: node.name_loc,
|
291
|
+
selection_range_location: node.name_loc,
|
292
|
+
)
|
293
|
+
end
|
294
|
+
|
295
|
+
sig { params(node: Prism::InstanceVariableAndWriteNode).void }
|
296
|
+
def on_instance_variable_and_write_node_enter(node)
|
297
|
+
create_document_symbol(
|
298
|
+
name: node.name.to_s,
|
299
|
+
kind: Constant::SymbolKind::FIELD,
|
267
300
|
range_location: node.name_loc,
|
268
301
|
selection_range_location: node.name_loc,
|
269
302
|
)
|
@@ -13,6 +13,12 @@ module RubyLsp
|
|
13
13
|
Prism::ConstantReadNode,
|
14
14
|
Prism::ConstantWriteNode,
|
15
15
|
Prism::ConstantPathNode,
|
16
|
+
Prism::GlobalVariableAndWriteNode,
|
17
|
+
Prism::GlobalVariableOperatorWriteNode,
|
18
|
+
Prism::GlobalVariableOrWriteNode,
|
19
|
+
Prism::GlobalVariableReadNode,
|
20
|
+
Prism::GlobalVariableTargetNode,
|
21
|
+
Prism::GlobalVariableWriteNode,
|
16
22
|
Prism::InstanceVariableReadNode,
|
17
23
|
Prism::InstanceVariableAndWriteNode,
|
18
24
|
Prism::InstanceVariableOperatorWriteNode,
|
@@ -62,6 +68,12 @@ module RubyLsp
|
|
62
68
|
:on_constant_write_node_enter,
|
63
69
|
:on_constant_path_node_enter,
|
64
70
|
:on_call_node_enter,
|
71
|
+
:on_global_variable_and_write_node_enter,
|
72
|
+
:on_global_variable_operator_write_node_enter,
|
73
|
+
:on_global_variable_or_write_node_enter,
|
74
|
+
:on_global_variable_read_node_enter,
|
75
|
+
:on_global_variable_target_node_enter,
|
76
|
+
:on_global_variable_write_node_enter,
|
65
77
|
:on_instance_variable_read_node_enter,
|
66
78
|
:on_instance_variable_write_node_enter,
|
67
79
|
:on_instance_variable_and_write_node_enter,
|
@@ -128,6 +140,36 @@ module RubyLsp
|
|
128
140
|
handle_method_hover(message)
|
129
141
|
end
|
130
142
|
|
143
|
+
sig { params(node: Prism::GlobalVariableAndWriteNode).void }
|
144
|
+
def on_global_variable_and_write_node_enter(node)
|
145
|
+
handle_global_variable_hover(node.name.to_s)
|
146
|
+
end
|
147
|
+
|
148
|
+
sig { params(node: Prism::GlobalVariableOperatorWriteNode).void }
|
149
|
+
def on_global_variable_operator_write_node_enter(node)
|
150
|
+
handle_global_variable_hover(node.name.to_s)
|
151
|
+
end
|
152
|
+
|
153
|
+
sig { params(node: Prism::GlobalVariableOrWriteNode).void }
|
154
|
+
def on_global_variable_or_write_node_enter(node)
|
155
|
+
handle_global_variable_hover(node.name.to_s)
|
156
|
+
end
|
157
|
+
|
158
|
+
sig { params(node: Prism::GlobalVariableReadNode).void }
|
159
|
+
def on_global_variable_read_node_enter(node)
|
160
|
+
handle_global_variable_hover(node.name.to_s)
|
161
|
+
end
|
162
|
+
|
163
|
+
sig { params(node: Prism::GlobalVariableTargetNode).void }
|
164
|
+
def on_global_variable_target_node_enter(node)
|
165
|
+
handle_global_variable_hover(node.name.to_s)
|
166
|
+
end
|
167
|
+
|
168
|
+
sig { params(node: Prism::GlobalVariableWriteNode).void }
|
169
|
+
def on_global_variable_write_node_enter(node)
|
170
|
+
handle_global_variable_hover(node.name.to_s)
|
171
|
+
end
|
172
|
+
|
131
173
|
sig { params(node: Prism::InstanceVariableReadNode).void }
|
132
174
|
def on_instance_variable_read_node_enter(node)
|
133
175
|
handle_instance_variable_hover(node.name.to_s)
|
@@ -265,6 +307,16 @@ module RubyLsp
|
|
265
307
|
# If by any chance we haven't indexed the owner, then there's no way to find the right declaration
|
266
308
|
end
|
267
309
|
|
310
|
+
sig { params(name: String).void }
|
311
|
+
def handle_global_variable_hover(name)
|
312
|
+
entries = @index[name]
|
313
|
+
return unless entries
|
314
|
+
|
315
|
+
categorized_markdown_from_index_entries(name, entries).each do |category, content|
|
316
|
+
@response_builder.push(content, category: category)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
268
320
|
sig { params(name: String, location: Prism::Location).void }
|
269
321
|
def generate_hover(name, location)
|
270
322
|
entries = @index.resolve(name, @node_context.nesting)
|
@@ -121,7 +121,7 @@ module RubyLsp
|
|
121
121
|
return Error::InvalidTargetRange if closest_node.is_a?(Prism::MissingNode)
|
122
122
|
|
123
123
|
closest_node_loc = closest_node.location
|
124
|
-
# If the parent expression is a single line block, then we have to extract it inside of the
|
124
|
+
# If the parent expression is a single line block, then we have to extract it inside of the one-line block
|
125
125
|
if parent_statements.is_a?(Prism::BlockNode) &&
|
126
126
|
parent_statements.location.start_line == parent_statements.location.end_line
|
127
127
|
|
@@ -17,7 +17,7 @@ module RubyLsp
|
|
17
17
|
def provider
|
18
18
|
Interface::CompletionOptions.new(
|
19
19
|
resolve_provider: true,
|
20
|
-
trigger_characters: ["/", "\"", "'", ":", "@", ".", "=", "<"],
|
20
|
+
trigger_characters: ["/", "\"", "'", ":", "@", ".", "=", "<", "$"],
|
21
21
|
completion_item: {
|
22
22
|
labelDetailsSupport: true,
|
23
23
|
},
|
@@ -50,6 +50,12 @@ module RubyLsp
|
|
50
50
|
Prism::CallNode,
|
51
51
|
Prism::ConstantReadNode,
|
52
52
|
Prism::ConstantPathNode,
|
53
|
+
Prism::GlobalVariableAndWriteNode,
|
54
|
+
Prism::GlobalVariableOperatorWriteNode,
|
55
|
+
Prism::GlobalVariableOrWriteNode,
|
56
|
+
Prism::GlobalVariableReadNode,
|
57
|
+
Prism::GlobalVariableTargetNode,
|
58
|
+
Prism::GlobalVariableWriteNode,
|
53
59
|
Prism::InstanceVariableReadNode,
|
54
60
|
Prism::InstanceVariableAndWriteNode,
|
55
61
|
Prism::InstanceVariableOperatorWriteNode,
|
@@ -34,7 +34,7 @@ module RubyLsp
|
|
34
34
|
|
35
35
|
# Based on the spec https://microsoft.github.io/language-server-protocol/specification#textDocument_completion,
|
36
36
|
# a completion resolve request must always return the original completion item without modifying ANY fields
|
37
|
-
# other than detail and documentation (NOT labelDetails). If we modify anything, the completion
|
37
|
+
# other than detail and documentation (NOT labelDetails). If we modify anything, the completion behavior might
|
38
38
|
# be broken.
|
39
39
|
#
|
40
40
|
# For example, forgetting to return the `insertText` included in the original item will make the editor use the
|
@@ -12,12 +12,6 @@ module RubyLsp
|
|
12
12
|
extend T::Sig
|
13
13
|
extend T::Generic
|
14
14
|
|
15
|
-
SPECIAL_METHOD_CALLS = [
|
16
|
-
:require,
|
17
|
-
:require_relative,
|
18
|
-
:autoload,
|
19
|
-
].freeze
|
20
|
-
|
21
15
|
sig do
|
22
16
|
params(
|
23
17
|
document: T.any(RubyDocument, ERBDocument),
|
@@ -46,7 +40,12 @@ module RubyLsp
|
|
46
40
|
Prism::ConstantReadNode,
|
47
41
|
Prism::ConstantPathNode,
|
48
42
|
Prism::BlockArgumentNode,
|
43
|
+
Prism::GlobalVariableAndWriteNode,
|
44
|
+
Prism::GlobalVariableOperatorWriteNode,
|
45
|
+
Prism::GlobalVariableOrWriteNode,
|
49
46
|
Prism::GlobalVariableReadNode,
|
47
|
+
Prism::GlobalVariableTargetNode,
|
48
|
+
Prism::GlobalVariableWriteNode,
|
50
49
|
Prism::InstanceVariableReadNode,
|
51
50
|
Prism::InstanceVariableAndWriteNode,
|
52
51
|
Prism::InstanceVariableOperatorWriteNode,
|
@@ -72,11 +71,7 @@ module RubyLsp
|
|
72
71
|
parent,
|
73
72
|
position,
|
74
73
|
)
|
75
|
-
elsif
|
76
|
-
target.message_loc, position
|
77
|
-
)
|
78
|
-
# If the target is a method call, we need to ensure that the requested position is exactly on top of the
|
79
|
-
# method identifier. Otherwise, we risk showing definitions for unrelated things
|
74
|
+
elsif position_outside_target?(position, target)
|
80
75
|
target = nil
|
81
76
|
# For methods with block arguments using symbol-to-proc
|
82
77
|
elsif target.is_a?(Prism::SymbolNode) && parent.is_a?(Prism::BlockArgumentNode)
|
@@ -107,6 +102,28 @@ module RubyLsp
|
|
107
102
|
@dispatcher.dispatch_once(@target) if @target
|
108
103
|
@response_builder.response
|
109
104
|
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
sig { params(position: T::Hash[Symbol, T.untyped], target: T.nilable(Prism::Node)).returns(T::Boolean) }
|
109
|
+
def position_outside_target?(position, target)
|
110
|
+
case target
|
111
|
+
when Prism::GlobalVariableAndWriteNode,
|
112
|
+
Prism::GlobalVariableOperatorWriteNode,
|
113
|
+
Prism::GlobalVariableOrWriteNode,
|
114
|
+
Prism::GlobalVariableWriteNode,
|
115
|
+
Prism::InstanceVariableAndWriteNode,
|
116
|
+
Prism::InstanceVariableOperatorWriteNode,
|
117
|
+
Prism::InstanceVariableOrWriteNode,
|
118
|
+
Prism::InstanceVariableWriteNode
|
119
|
+
|
120
|
+
!covers_position?(target.name_loc, position)
|
121
|
+
when Prism::CallNode
|
122
|
+
!covers_position?(target.message_loc, position)
|
123
|
+
else
|
124
|
+
false
|
125
|
+
end
|
126
|
+
end
|
110
127
|
end
|
111
128
|
end
|
112
129
|
end
|
@@ -38,7 +38,13 @@ module RubyLsp
|
|
38
38
|
ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight].new,
|
39
39
|
ResponseBuilders::CollectionResponseBuilder[Interface::DocumentHighlight],
|
40
40
|
)
|
41
|
-
Listeners::DocumentHighlight.new(
|
41
|
+
Listeners::DocumentHighlight.new(
|
42
|
+
@response_builder,
|
43
|
+
node_context.node,
|
44
|
+
node_context.parent,
|
45
|
+
dispatcher,
|
46
|
+
position,
|
47
|
+
)
|
42
48
|
end
|
43
49
|
|
44
50
|
sig { override.returns(T::Array[Interface::DocumentHighlight]) }
|
@@ -10,7 +10,8 @@ module RubyLsp
|
|
10
10
|
# informs the editor of all the important symbols, such as classes, variables, and methods, defined in a file. With
|
11
11
|
# this information, the editor can populate breadcrumbs, file outline and allow for fuzzy symbol searches.
|
12
12
|
#
|
13
|
-
# In VS Code,
|
13
|
+
# In VS Code, symbol search known as 'Go To Symbol in Editor' and can be accessed with Ctrl/Cmd-Shift-O,
|
14
|
+
# or by opening the command palette and inserting an `@` symbol.
|
14
15
|
class DocumentSymbol < Request
|
15
16
|
extend T::Sig
|
16
17
|
|
@@ -46,17 +46,13 @@ module RubyLsp
|
|
46
46
|
target = node_context.node
|
47
47
|
parent = node_context.parent
|
48
48
|
|
49
|
-
if
|
50
|
-
!Listeners::Hover::ALLOWED_TARGETS.include?(target.class)) ||
|
51
|
-
(parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
|
49
|
+
if should_refine_target?(parent, target)
|
52
50
|
target = determine_target(
|
53
51
|
T.must(target),
|
54
52
|
T.must(parent),
|
55
53
|
position,
|
56
54
|
)
|
57
|
-
elsif
|
58
|
-
!covers_position?(target.message_loc, position)
|
59
|
-
|
55
|
+
elsif position_outside_target?(position, target)
|
60
56
|
target = nil
|
61
57
|
end
|
62
58
|
|
@@ -89,6 +85,30 @@ module RubyLsp
|
|
89
85
|
),
|
90
86
|
)
|
91
87
|
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
sig { params(parent: T.nilable(Prism::Node), target: T.nilable(Prism::Node)).returns(T::Boolean) }
|
92
|
+
def should_refine_target?(parent, target)
|
93
|
+
(Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
|
94
|
+
!Listeners::Hover::ALLOWED_TARGETS.include?(target.class)) ||
|
95
|
+
(parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
|
96
|
+
end
|
97
|
+
|
98
|
+
sig { params(position: T::Hash[Symbol, T.untyped], target: T.nilable(Prism::Node)).returns(T::Boolean) }
|
99
|
+
def position_outside_target?(position, target)
|
100
|
+
case target
|
101
|
+
when Prism::GlobalVariableAndWriteNode,
|
102
|
+
Prism::GlobalVariableOperatorWriteNode,
|
103
|
+
Prism::GlobalVariableOrWriteNode,
|
104
|
+
Prism::GlobalVariableWriteNode
|
105
|
+
!covers_position?(target.name_loc, position)
|
106
|
+
when Prism::CallNode
|
107
|
+
!covers_position?(target.message_loc, position)
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
92
112
|
end
|
93
113
|
end
|
94
114
|
end
|
@@ -72,7 +72,7 @@ module RubyLsp
|
|
72
72
|
|
73
73
|
# If the client doesn't support resource operations, such as renaming files, then we can only return the basic
|
74
74
|
# text changes
|
75
|
-
unless @global_state.
|
75
|
+
unless @global_state.client_capabilities.supports_rename?
|
76
76
|
return Interface::WorkspaceEdit.new(changes: changes)
|
77
77
|
end
|
78
78
|
|
@@ -26,7 +26,7 @@ module RubyLsp
|
|
26
26
|
).void
|
27
27
|
end
|
28
28
|
def delegate_request_if_needed!(global_state, document, char_position)
|
29
|
-
if global_state.supports_request_delegation &&
|
29
|
+
if global_state.client_capabilities.supports_request_delegation &&
|
30
30
|
document.is_a?(ERBDocument) &&
|
31
31
|
document.inside_host_language?(char_position)
|
32
32
|
raise DelegateRequestError
|
@@ -1,16 +1,27 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
# If there's no top level Gemfile, don't load RuboCop from a global installation
|
5
|
+
begin
|
6
|
+
Bundler.with_original_env { Bundler.default_gemfile }
|
7
|
+
rescue Bundler::GemfileNotFound
|
8
|
+
return
|
9
|
+
end
|
10
|
+
|
11
|
+
# Ensure that RuboCop is available
|
4
12
|
begin
|
5
13
|
require "rubocop"
|
6
14
|
rescue LoadError
|
7
15
|
return
|
8
16
|
end
|
9
17
|
|
18
|
+
# Remember to update the version in the documentation (usage/dependency-compatibility section) if you change this
|
19
|
+
# Ensure that RuboCop is at least version 1.4.0
|
10
20
|
begin
|
11
21
|
gem("rubocop", ">= 1.4.0")
|
12
22
|
rescue LoadError
|
13
|
-
|
23
|
+
$stderr.puts "Incompatible RuboCop version. Ruby LSP requires >= 1.4.0"
|
24
|
+
return
|
14
25
|
end
|
15
26
|
|
16
27
|
if RuboCop.const_defined?(:LSP) # This condition will be removed when requiring RuboCop >= 1.61.
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# typed: true
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
def compose(raw_initialize)
|
5
|
+
require_relative "../setup_bundler"
|
6
|
+
require "json"
|
7
|
+
require "uri"
|
8
|
+
require_relative "../../core_ext/uri"
|
9
|
+
|
10
|
+
initialize_request = JSON.parse(raw_initialize, symbolize_names: true)
|
11
|
+
workspace_uri = initialize_request.dig(:params, :workspaceFolders, 0, :uri)
|
12
|
+
workspace_path = workspace_uri && URI(workspace_uri).to_standardized_path
|
13
|
+
workspace_path ||= Dir.pwd
|
14
|
+
|
15
|
+
env = RubyLsp::SetupBundler.new(workspace_path, launcher: true).setup!
|
16
|
+
File.write(
|
17
|
+
File.join(".ruby-lsp", "bundle_env"),
|
18
|
+
env.map { |k, v| "#{k}=#{v}" }.join("\n"),
|
19
|
+
)
|
20
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative "compose_bundle"
|
5
|
+
|
6
|
+
# When this is invoked on Windows, we pass the raw initialize as an argument to this script. On other platforms, we
|
7
|
+
# invoke the compose method from inside a forked process
|
8
|
+
compose(ARGV.first)
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -106,6 +106,8 @@ module RubyLsp
|
|
106
106
|
)
|
107
107
|
when "$/cancelRequest"
|
108
108
|
@mutex.synchronize { @cancelled_requests << message[:params][:id] }
|
109
|
+
when nil
|
110
|
+
process_response(message) if message[:result]
|
109
111
|
end
|
110
112
|
rescue DelegateRequestError
|
111
113
|
send_message(Error.new(id: message[:id], code: DelegateRequestError::CODE, message: "DELEGATE_REQUEST"))
|
@@ -138,8 +140,22 @@ module RubyLsp
|
|
138
140
|
send_log_message("Error processing #{message[:method]}: #{e.full_message}", type: Constant::MessageType::ERROR)
|
139
141
|
end
|
140
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
|
+
|
141
152
|
sig { params(include_project_addons: T::Boolean).void }
|
142
153
|
def load_addons(include_project_addons: true)
|
154
|
+
# If invoking Bundler.setup failed, then the load path will not be configured properly and trying to load add-ons
|
155
|
+
# with Gem.find_files will find every single version installed of an add-on, leading to requiring several
|
156
|
+
# different versions of the same files. We cannot load add-ons if Bundler.setup failed
|
157
|
+
return if @setup_error
|
158
|
+
|
143
159
|
errors = Addon.load_addons(@global_state, @outgoing_queue, include_project_addons: include_project_addons)
|
144
160
|
|
145
161
|
if errors.any?
|
@@ -181,8 +197,6 @@ module RubyLsp
|
|
181
197
|
client_name = options.dig(:clientInfo, :name)
|
182
198
|
@store.client_name = client_name if client_name
|
183
199
|
|
184
|
-
progress = options.dig(:capabilities, :window, :workDoneProgress)
|
185
|
-
@store.supports_progress = progress.nil? ? true : progress
|
186
200
|
configured_features = options.dig(:initializationOptions, :enabledFeatures)
|
187
201
|
|
188
202
|
configured_hints = options.dig(:initializationOptions, :featuresConfiguration, :inlayHint)
|
@@ -202,6 +216,13 @@ module RubyLsp
|
|
202
216
|
Hash.new(true)
|
203
217
|
end
|
204
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
|
+
|
205
226
|
document_symbol_provider = Requests::DocumentSymbol.provider if enabled_features["documentSymbols"]
|
206
227
|
document_link_provider = Requests::DocumentLink.provider if enabled_features["documentLink"]
|
207
228
|
code_lens_provider = Requests::CodeLens.provider if enabled_features["codeLens"]
|
@@ -254,12 +275,14 @@ module RubyLsp
|
|
254
275
|
version: VERSION,
|
255
276
|
},
|
256
277
|
formatter: @global_state.formatter,
|
278
|
+
degraded_mode: !!(@install_error || @setup_error),
|
279
|
+
bundle_env: bundle_env,
|
257
280
|
}
|
258
281
|
|
259
282
|
send_message(Result.new(id: message[:id], response: response))
|
260
283
|
|
261
284
|
# Not every client supports dynamic registration or file watching
|
262
|
-
if global_state.supports_watching_files
|
285
|
+
if @global_state.client_capabilities.supports_watching_files
|
263
286
|
send_message(
|
264
287
|
Request.new(
|
265
288
|
id: @current_request_id,
|
@@ -290,6 +313,24 @@ module RubyLsp
|
|
290
313
|
begin_progress("indexing-progress", "Ruby LSP: indexing files")
|
291
314
|
|
292
315
|
global_state_notifications.each { |notification| send_message(notification) }
|
316
|
+
|
317
|
+
if @setup_error
|
318
|
+
send_message(Notification.telemetry(
|
319
|
+
type: "error",
|
320
|
+
errorMessage: @setup_error.message,
|
321
|
+
errorClass: @setup_error.class,
|
322
|
+
stack: @setup_error.backtrace&.join("\n"),
|
323
|
+
))
|
324
|
+
end
|
325
|
+
|
326
|
+
if @install_error
|
327
|
+
send_message(Notification.telemetry(
|
328
|
+
type: "error",
|
329
|
+
errorMessage: @install_error.message,
|
330
|
+
errorClass: @install_error.class,
|
331
|
+
stack: @install_error.backtrace&.join("\n"),
|
332
|
+
))
|
333
|
+
end
|
293
334
|
end
|
294
335
|
|
295
336
|
sig { void }
|
@@ -297,20 +338,22 @@ module RubyLsp
|
|
297
338
|
load_addons
|
298
339
|
RubyVM::YJIT.enable if defined?(RubyVM::YJIT.enable)
|
299
340
|
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
341
|
+
unless @setup_error
|
342
|
+
if defined?(Requests::Support::RuboCopFormatter)
|
343
|
+
begin
|
344
|
+
@global_state.register_formatter("rubocop", Requests::Support::RuboCopFormatter.new)
|
345
|
+
rescue RuboCop::Error => e
|
346
|
+
# The user may have provided unknown config switches in .rubocop or
|
347
|
+
# is trying to load a non-existent config file.
|
348
|
+
send_message(Notification.window_show_message(
|
349
|
+
"RuboCop configuration error: #{e.message}. Formatting will not be available.",
|
350
|
+
type: Constant::MessageType::ERROR,
|
351
|
+
))
|
352
|
+
end
|
353
|
+
end
|
354
|
+
if defined?(Requests::Support::SyntaxTreeFormatter)
|
355
|
+
@global_state.register_formatter("syntax_tree", Requests::Support::SyntaxTreeFormatter.new)
|
310
356
|
end
|
311
|
-
end
|
312
|
-
if defined?(Requests::Support::SyntaxTreeFormatter)
|
313
|
-
@global_state.register_formatter("syntax_tree", Requests::Support::SyntaxTreeFormatter.new)
|
314
357
|
end
|
315
358
|
|
316
359
|
perform_initial_indexing
|
@@ -569,6 +612,11 @@ module RubyLsp
|
|
569
612
|
# don't want to format it
|
570
613
|
path = uri.to_standardized_path
|
571
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
|
572
620
|
send_empty_response(message[:id])
|
573
621
|
return
|
574
622
|
end
|
@@ -1017,7 +1065,7 @@ module RubyLsp
|
|
1017
1065
|
|
1018
1066
|
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
1019
1067
|
def workspace_dependencies(message)
|
1020
|
-
response =
|
1068
|
+
response = if @global_state.top_level_bundle
|
1021
1069
|
Bundler.with_original_env do
|
1022
1070
|
definition = Bundler.definition
|
1023
1071
|
dep_keys = definition.locked_deps.keys.to_set
|
@@ -1031,7 +1079,7 @@ module RubyLsp
|
|
1031
1079
|
}
|
1032
1080
|
end
|
1033
1081
|
end
|
1034
|
-
|
1082
|
+
else
|
1035
1083
|
[]
|
1036
1084
|
end
|
1037
1085
|
|
@@ -1077,7 +1125,7 @@ module RubyLsp
|
|
1077
1125
|
|
1078
1126
|
sig { params(id: String, title: String, percentage: Integer).void }
|
1079
1127
|
def begin_progress(id, title, percentage: 0)
|
1080
|
-
return unless @
|
1128
|
+
return unless @global_state.client_capabilities.supports_progress
|
1081
1129
|
|
1082
1130
|
send_message(Request.new(
|
1083
1131
|
id: @current_request_id,
|
@@ -1085,52 +1133,21 @@ module RubyLsp
|
|
1085
1133
|
params: Interface::WorkDoneProgressCreateParams.new(token: id),
|
1086
1134
|
))
|
1087
1135
|
|
1088
|
-
send_message(Notification.
|
1089
|
-
method: "$/progress",
|
1090
|
-
params: Interface::ProgressParams.new(
|
1091
|
-
token: id,
|
1092
|
-
value: Interface::WorkDoneProgressBegin.new(
|
1093
|
-
kind: "begin",
|
1094
|
-
title: title,
|
1095
|
-
percentage: percentage,
|
1096
|
-
message: "#{percentage}% completed",
|
1097
|
-
),
|
1098
|
-
),
|
1099
|
-
))
|
1136
|
+
send_message(Notification.progress_begin(id, title, percentage: percentage, message: "#{percentage}% completed"))
|
1100
1137
|
end
|
1101
1138
|
|
1102
1139
|
sig { params(id: String, percentage: Integer).void }
|
1103
1140
|
def progress(id, percentage)
|
1104
|
-
return unless @
|
1141
|
+
return unless @global_state.client_capabilities.supports_progress
|
1105
1142
|
|
1106
|
-
send_message(
|
1107
|
-
Notification.new(
|
1108
|
-
method: "$/progress",
|
1109
|
-
params: Interface::ProgressParams.new(
|
1110
|
-
token: id,
|
1111
|
-
value: Interface::WorkDoneProgressReport.new(
|
1112
|
-
kind: "report",
|
1113
|
-
percentage: percentage,
|
1114
|
-
message: "#{percentage}% completed",
|
1115
|
-
),
|
1116
|
-
),
|
1117
|
-
),
|
1118
|
-
)
|
1143
|
+
send_message(Notification.progress_report(id, percentage: percentage, message: "#{percentage}% completed"))
|
1119
1144
|
end
|
1120
1145
|
|
1121
1146
|
sig { params(id: String).void }
|
1122
1147
|
def end_progress(id)
|
1123
|
-
return unless @
|
1148
|
+
return unless @global_state.client_capabilities.supports_progress
|
1124
1149
|
|
1125
|
-
send_message(
|
1126
|
-
Notification.new(
|
1127
|
-
method: "$/progress",
|
1128
|
-
params: Interface::ProgressParams.new(
|
1129
|
-
token: id,
|
1130
|
-
value: Interface::WorkDoneProgressEnd.new(kind: "end"),
|
1131
|
-
),
|
1132
|
-
),
|
1133
|
-
)
|
1150
|
+
send_message(Notification.progress_end(id))
|
1134
1151
|
rescue ClosedQueueError
|
1135
1152
|
# If the server was killed and the message queue is already closed, there's no way to end the progress
|
1136
1153
|
# notification
|
@@ -1138,6 +1155,7 @@ module RubyLsp
|
|
1138
1155
|
|
1139
1156
|
sig { void }
|
1140
1157
|
def check_formatter_is_available
|
1158
|
+
return if @setup_error
|
1141
1159
|
# Warn of an unavailable `formatter` setting, e.g. `rubocop` on a project which doesn't have RuboCop.
|
1142
1160
|
# Syntax Tree will always be available via Ruby LSP so we don't need to check for it.
|
1143
1161
|
return unless @global_state.formatter == "rubocop"
|
@@ -1194,5 +1212,17 @@ module RubyLsp
|
|
1194
1212
|
# The index expects snake case configurations, but VS Code standardizes on camel case settings
|
1195
1213
|
configuration.apply_config(indexing_options.transform_keys { |key| key.to_s.gsub(/([A-Z])/, "_\\1").downcase })
|
1196
1214
|
end
|
1215
|
+
|
1216
|
+
sig { params(message: T::Hash[Symbol, T.untyped]).void }
|
1217
|
+
def window_show_message_request(message)
|
1218
|
+
result = message[:result]
|
1219
|
+
return unless result
|
1220
|
+
|
1221
|
+
addon_name = result[:addon_name]
|
1222
|
+
addon = Addon.addons.find { |addon| addon.name == addon_name }
|
1223
|
+
return unless addon
|
1224
|
+
|
1225
|
+
addon.handle_window_show_message_response(result[:title])
|
1226
|
+
end
|
1197
1227
|
end
|
1198
1228
|
end
|