ruby-lsp 0.13.2 → 0.13.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +30 -0
- data/VERSION +1 -1
- data/lib/ruby_lsp/check_docs.rb +3 -3
- data/lib/ruby_lsp/document.rb +12 -0
- data/lib/ruby_lsp/executor.rb +77 -266
- data/lib/ruby_lsp/listener.rb +1 -50
- data/lib/ruby_lsp/listeners/code_lens.rb +233 -0
- data/lib/ruby_lsp/listeners/completion.rb +275 -0
- data/lib/ruby_lsp/listeners/definition.rb +158 -0
- data/lib/ruby_lsp/listeners/document_highlight.rb +556 -0
- data/lib/ruby_lsp/listeners/document_link.rb +162 -0
- data/lib/ruby_lsp/listeners/document_symbol.rb +223 -0
- data/lib/ruby_lsp/listeners/folding_ranges.rb +271 -0
- data/lib/ruby_lsp/listeners/hover.rb +152 -0
- data/lib/ruby_lsp/listeners/inlay_hints.rb +80 -0
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +430 -0
- data/lib/ruby_lsp/listeners/signature_help.rb +74 -0
- data/lib/ruby_lsp/requests/code_action_resolve.rb +4 -4
- data/lib/ruby_lsp/requests/code_actions.rb +13 -4
- data/lib/ruby_lsp/requests/code_lens.rb +21 -221
- data/lib/ruby_lsp/requests/completion.rb +64 -244
- data/lib/ruby_lsp/requests/definition.rb +34 -147
- data/lib/ruby_lsp/requests/diagnostics.rb +17 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +12 -536
- data/lib/ruby_lsp/requests/document_link.rb +11 -132
- data/lib/ruby_lsp/requests/document_symbol.rb +23 -210
- data/lib/ruby_lsp/requests/folding_ranges.rb +16 -252
- data/lib/ruby_lsp/requests/formatting.rb +4 -4
- data/lib/ruby_lsp/requests/hover.rb +48 -92
- data/lib/ruby_lsp/requests/inlay_hints.rb +23 -56
- data/lib/ruby_lsp/requests/on_type_formatting.rb +16 -4
- data/lib/ruby_lsp/requests/request.rb +17 -0
- data/lib/ruby_lsp/requests/selection_ranges.rb +4 -3
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +21 -408
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +4 -4
- data/lib/ruby_lsp/requests/signature_help.rb +43 -51
- data/lib/ruby_lsp/requests/support/common.rb +3 -2
- data/lib/ruby_lsp/requests/support/dependency_detector.rb +2 -0
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
- data/lib/ruby_lsp/requests/workspace_symbol.rb +5 -4
- data/lib/ruby_lsp/requests.rb +1 -1
- data/lib/ruby_lsp/utils.rb +8 -0
- metadata +17 -6
- data/lib/ruby_lsp/requests/base_request.rb +0 -24
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/listeners/folding_ranges"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
6
8
|
# ![Folding ranges demo](../../folding_ranges.gif)
|
@@ -15,268 +17,30 @@ module RubyLsp
|
|
15
17
|
# puts "Hello"
|
16
18
|
# end # <-- folding range end
|
17
19
|
# ```
|
18
|
-
class FoldingRanges <
|
20
|
+
class FoldingRanges < Request
|
19
21
|
extend T::Sig
|
20
22
|
extend T::Generic
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
|
25
|
-
def initialize(comments, dispatcher)
|
26
|
-
super(dispatcher)
|
27
|
-
|
28
|
-
@_response = T.let([], ResponseType)
|
29
|
-
@requires = T.let([], T::Array[Prism::CallNode])
|
30
|
-
@finalized_response = T.let(false, T::Boolean)
|
31
|
-
@comments = comments
|
24
|
+
class << self
|
25
|
+
extend T::Sig
|
32
26
|
|
33
|
-
|
34
|
-
|
35
|
-
:
|
36
|
-
:on_in_node_enter,
|
37
|
-
:on_rescue_node_enter,
|
38
|
-
:on_when_node_enter,
|
39
|
-
:on_interpolated_string_node_enter,
|
40
|
-
:on_array_node_enter,
|
41
|
-
:on_block_node_enter,
|
42
|
-
:on_case_node_enter,
|
43
|
-
:on_case_match_node_enter,
|
44
|
-
:on_class_node_enter,
|
45
|
-
:on_module_node_enter,
|
46
|
-
:on_for_node_enter,
|
47
|
-
:on_hash_node_enter,
|
48
|
-
:on_singleton_class_node_enter,
|
49
|
-
:on_unless_node_enter,
|
50
|
-
:on_until_node_enter,
|
51
|
-
:on_while_node_enter,
|
52
|
-
:on_else_node_enter,
|
53
|
-
:on_ensure_node_enter,
|
54
|
-
:on_begin_node_enter,
|
55
|
-
:on_def_node_enter,
|
56
|
-
:on_call_node_enter,
|
57
|
-
:on_lambda_node_enter,
|
58
|
-
)
|
59
|
-
end
|
60
|
-
|
61
|
-
sig { override.returns(ResponseType) }
|
62
|
-
def _response
|
63
|
-
unless @finalized_response
|
64
|
-
push_comment_ranges
|
65
|
-
emit_requires_range
|
66
|
-
@finalized_response = true
|
27
|
+
sig { returns(Interface::FoldingRangeClientCapabilities) }
|
28
|
+
def provider
|
29
|
+
Interface::FoldingRangeClientCapabilities.new(line_folding_only: true)
|
67
30
|
end
|
68
|
-
|
69
|
-
@_response
|
70
|
-
end
|
71
|
-
|
72
|
-
sig { params(node: Prism::IfNode).void }
|
73
|
-
def on_if_node_enter(node)
|
74
|
-
add_statements_range(node)
|
75
|
-
end
|
76
|
-
|
77
|
-
sig { params(node: Prism::InNode).void }
|
78
|
-
def on_in_node_enter(node)
|
79
|
-
add_statements_range(node)
|
80
|
-
end
|
81
|
-
|
82
|
-
sig { params(node: Prism::RescueNode).void }
|
83
|
-
def on_rescue_node_enter(node)
|
84
|
-
add_statements_range(node)
|
85
|
-
end
|
86
|
-
|
87
|
-
sig { params(node: Prism::WhenNode).void }
|
88
|
-
def on_when_node_enter(node)
|
89
|
-
add_statements_range(node)
|
90
|
-
end
|
91
|
-
|
92
|
-
sig { params(node: Prism::InterpolatedStringNode).void }
|
93
|
-
def on_interpolated_string_node_enter(node)
|
94
|
-
opening_loc = node.opening_loc || node.location
|
95
|
-
closing_loc = node.closing_loc || node.parts.last&.location || node.location
|
96
|
-
|
97
|
-
add_lines_range(opening_loc.start_line, closing_loc.start_line - 1)
|
98
31
|
end
|
99
32
|
|
100
|
-
|
101
|
-
def on_array_node_enter(node)
|
102
|
-
add_simple_range(node)
|
103
|
-
end
|
104
|
-
|
105
|
-
sig { params(node: Prism::BlockNode).void }
|
106
|
-
def on_block_node_enter(node)
|
107
|
-
add_simple_range(node)
|
108
|
-
end
|
109
|
-
|
110
|
-
sig { params(node: Prism::CaseNode).void }
|
111
|
-
def on_case_node_enter(node)
|
112
|
-
add_simple_range(node)
|
113
|
-
end
|
114
|
-
|
115
|
-
sig { params(node: Prism::CaseMatchNode).void }
|
116
|
-
def on_case_match_node_enter(node)
|
117
|
-
add_simple_range(node)
|
118
|
-
end
|
119
|
-
|
120
|
-
sig { params(node: Prism::ClassNode).void }
|
121
|
-
def on_class_node_enter(node)
|
122
|
-
add_simple_range(node)
|
123
|
-
end
|
124
|
-
|
125
|
-
sig { params(node: Prism::ModuleNode).void }
|
126
|
-
def on_module_node_enter(node)
|
127
|
-
add_simple_range(node)
|
128
|
-
end
|
129
|
-
|
130
|
-
sig { params(node: Prism::ForNode).void }
|
131
|
-
def on_for_node_enter(node)
|
132
|
-
add_simple_range(node)
|
133
|
-
end
|
134
|
-
|
135
|
-
sig { params(node: Prism::HashNode).void }
|
136
|
-
def on_hash_node_enter(node)
|
137
|
-
add_simple_range(node)
|
138
|
-
end
|
139
|
-
|
140
|
-
sig { params(node: Prism::SingletonClassNode).void }
|
141
|
-
def on_singleton_class_node_enter(node)
|
142
|
-
add_simple_range(node)
|
143
|
-
end
|
144
|
-
|
145
|
-
sig { params(node: Prism::UnlessNode).void }
|
146
|
-
def on_unless_node_enter(node)
|
147
|
-
add_simple_range(node)
|
148
|
-
end
|
149
|
-
|
150
|
-
sig { params(node: Prism::UntilNode).void }
|
151
|
-
def on_until_node_enter(node)
|
152
|
-
add_simple_range(node)
|
153
|
-
end
|
154
|
-
|
155
|
-
sig { params(node: Prism::WhileNode).void }
|
156
|
-
def on_while_node_enter(node)
|
157
|
-
add_simple_range(node)
|
158
|
-
end
|
159
|
-
|
160
|
-
sig { params(node: Prism::ElseNode).void }
|
161
|
-
def on_else_node_enter(node)
|
162
|
-
add_simple_range(node)
|
163
|
-
end
|
164
|
-
|
165
|
-
sig { params(node: Prism::EnsureNode).void }
|
166
|
-
def on_ensure_node_enter(node)
|
167
|
-
add_simple_range(node)
|
168
|
-
end
|
169
|
-
|
170
|
-
sig { params(node: Prism::BeginNode).void }
|
171
|
-
def on_begin_node_enter(node)
|
172
|
-
add_simple_range(node)
|
173
|
-
end
|
174
|
-
|
175
|
-
sig { params(node: Prism::DefNode).void }
|
176
|
-
def on_def_node_enter(node)
|
177
|
-
params = node.parameters
|
178
|
-
parameter_loc = params&.location
|
179
|
-
location = node.location
|
180
|
-
|
181
|
-
if params && parameter_loc.end_line > location.start_line
|
182
|
-
# Multiline parameters
|
183
|
-
add_lines_range(location.start_line, parameter_loc.end_line)
|
184
|
-
add_lines_range(parameter_loc.end_line + 1, location.end_line - 1)
|
185
|
-
else
|
186
|
-
add_lines_range(location.start_line, location.end_line - 1)
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
sig { params(node: Prism::CallNode).void }
|
191
|
-
def on_call_node_enter(node)
|
192
|
-
# If we find a require, don't visit the child nodes (prevent `super`), so that we can keep accumulating into
|
193
|
-
# the `@requires` array and then push the range whenever we find a node that isn't a CallNode
|
194
|
-
if require?(node)
|
195
|
-
@requires << node
|
196
|
-
return
|
197
|
-
end
|
198
|
-
|
199
|
-
location = node.location
|
200
|
-
add_lines_range(location.start_line, location.end_line - 1)
|
201
|
-
end
|
202
|
-
|
203
|
-
sig { params(node: Prism::LambdaNode).void }
|
204
|
-
def on_lambda_node_enter(node)
|
205
|
-
add_simple_range(node)
|
206
|
-
end
|
207
|
-
|
208
|
-
private
|
209
|
-
|
210
|
-
sig { void }
|
211
|
-
def push_comment_ranges
|
212
|
-
# Group comments that are on consecutive lines and then push ranges for each group that has at least 2 comments
|
213
|
-
@comments.chunk_while do |this, other|
|
214
|
-
this.location.end_line + 1 == other.location.start_line
|
215
|
-
end.each do |chunk|
|
216
|
-
next if chunk.length == 1
|
217
|
-
|
218
|
-
@_response << Interface::FoldingRange.new(
|
219
|
-
start_line: T.must(chunk.first).location.start_line - 1,
|
220
|
-
end_line: T.must(chunk.last).location.end_line - 1,
|
221
|
-
kind: "comment",
|
222
|
-
)
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
sig { void }
|
227
|
-
def emit_requires_range
|
228
|
-
if @requires.length > 1
|
229
|
-
@_response << Interface::FoldingRange.new(
|
230
|
-
start_line: T.must(@requires.first).location.start_line - 1,
|
231
|
-
end_line: T.must(@requires.last).location.end_line - 1,
|
232
|
-
kind: "imports",
|
233
|
-
)
|
234
|
-
end
|
235
|
-
|
236
|
-
@requires.clear
|
237
|
-
end
|
238
|
-
|
239
|
-
sig { params(node: Prism::CallNode).returns(T::Boolean) }
|
240
|
-
def require?(node)
|
241
|
-
message = node.message
|
242
|
-
return false unless message == "require" || message == "require_relative"
|
243
|
-
|
244
|
-
receiver = node.receiver
|
245
|
-
return false unless receiver.nil? || receiver.slice == "Kernel"
|
246
|
-
|
247
|
-
arguments = node.arguments&.arguments
|
248
|
-
return false unless arguments
|
249
|
-
|
250
|
-
arguments.length == 1 && arguments.first.is_a?(Prism::StringNode)
|
251
|
-
end
|
252
|
-
|
253
|
-
sig { params(node: T.any(Prism::IfNode, Prism::InNode, Prism::RescueNode, Prism::WhenNode)).void }
|
254
|
-
def add_statements_range(node)
|
255
|
-
statements = node.statements
|
256
|
-
return unless statements
|
257
|
-
|
258
|
-
body = statements.body
|
259
|
-
return if body.empty?
|
260
|
-
|
261
|
-
add_lines_range(node.location.start_line, T.must(body.last).location.end_line)
|
262
|
-
end
|
33
|
+
ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
|
263
34
|
|
264
|
-
sig { params(
|
265
|
-
def
|
266
|
-
|
267
|
-
|
35
|
+
sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
|
36
|
+
def initialize(comments, dispatcher)
|
37
|
+
super()
|
38
|
+
@listener = T.let(Listeners::FoldingRanges.new(comments, dispatcher), Listener[ResponseType])
|
268
39
|
end
|
269
40
|
|
270
|
-
sig {
|
271
|
-
def
|
272
|
-
|
273
|
-
return if start_line >= end_line
|
274
|
-
|
275
|
-
@_response << Interface::FoldingRange.new(
|
276
|
-
start_line: start_line - 1,
|
277
|
-
end_line: end_line - 1,
|
278
|
-
kind: "region",
|
279
|
-
)
|
41
|
+
sig { override.returns(ResponseType) }
|
42
|
+
def perform
|
43
|
+
@listener.response
|
280
44
|
end
|
281
45
|
end
|
282
46
|
end
|
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
# puts "Hello" # --> formatting: fixes the indentation on save
|
26
26
|
# end
|
27
27
|
# ```
|
28
|
-
class Formatting <
|
28
|
+
class Formatting < Request
|
29
29
|
class Error < StandardError; end
|
30
30
|
class InvalidFormatter < StandardError; end
|
31
31
|
|
@@ -55,14 +55,14 @@ module RubyLsp
|
|
55
55
|
|
56
56
|
sig { params(document: Document, formatter: String).void }
|
57
57
|
def initialize(document, formatter: "auto")
|
58
|
-
super(
|
59
|
-
|
58
|
+
super()
|
59
|
+
@document = document
|
60
60
|
@uri = T.let(document.uri, URI::Generic)
|
61
61
|
@formatter = formatter
|
62
62
|
end
|
63
63
|
|
64
64
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
65
|
-
def
|
65
|
+
def perform
|
66
66
|
return if @formatter == "none"
|
67
67
|
return if @document.syntax_error?
|
68
68
|
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/listeners/hover"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
6
8
|
# ![Hover demo](../../hover.gif)
|
@@ -13,123 +15,77 @@ module RubyLsp
|
|
13
15
|
# ```ruby
|
14
16
|
# String # -> Hovering over the class reference will show all declaration locations and the documentation
|
15
17
|
# ```
|
16
|
-
class Hover <
|
18
|
+
class Hover < Request
|
17
19
|
extend T::Sig
|
18
20
|
extend T::Generic
|
19
21
|
|
20
|
-
|
22
|
+
class << self
|
23
|
+
extend T::Sig
|
21
24
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
Prism::ConstantPathNode,
|
28
|
-
],
|
29
|
-
T::Array[T.class_of(Prism::Node)],
|
30
|
-
)
|
25
|
+
sig { returns(Interface::HoverClientCapabilities) }
|
26
|
+
def provider
|
27
|
+
Interface::HoverClientCapabilities.new(dynamic_registration: false)
|
28
|
+
end
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
attr_reader :_response
|
31
|
+
ResponseType = type_member { { fixed: T.nilable(Interface::Hover) } }
|
34
32
|
|
35
33
|
sig do
|
36
34
|
params(
|
35
|
+
document: Document,
|
37
36
|
index: RubyIndexer::Index,
|
38
|
-
|
37
|
+
position: T::Hash[Symbol, T.untyped],
|
39
38
|
dispatcher: Prism::Dispatcher,
|
39
|
+
typechecker_enabled: T::Boolean,
|
40
40
|
).void
|
41
41
|
end
|
42
|
-
def initialize(index,
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
super(dispatcher)
|
48
|
-
dispatcher.register(
|
49
|
-
self,
|
50
|
-
:on_constant_read_node_enter,
|
51
|
-
:on_constant_write_node_enter,
|
52
|
-
:on_constant_path_node_enter,
|
53
|
-
:on_call_node_enter,
|
42
|
+
def initialize(document, index, position, dispatcher, typechecker_enabled)
|
43
|
+
super()
|
44
|
+
target, parent, nesting = document.locate_node(
|
45
|
+
position,
|
46
|
+
node_types: Listeners::Hover::ALLOWED_TARGETS,
|
54
47
|
)
|
55
|
-
end
|
56
48
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
# Merges responses from other hover listeners
|
63
|
-
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
64
|
-
def merge_response!(other)
|
65
|
-
other_response = other.response
|
66
|
-
return self unless other_response
|
67
|
-
|
68
|
-
if @_response.nil?
|
69
|
-
@_response = other.response
|
70
|
-
else
|
71
|
-
@_response.contents.value << "\n\n" << other_response.contents.value
|
49
|
+
if (Listeners::Hover::ALLOWED_TARGETS.include?(parent.class) &&
|
50
|
+
!Listeners::Hover::ALLOWED_TARGETS.include?(target.class)) ||
|
51
|
+
(parent.is_a?(Prism::ConstantPathNode) && target.is_a?(Prism::ConstantReadNode))
|
52
|
+
target = parent
|
72
53
|
end
|
73
54
|
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
sig { params(node: Prism::ConstantReadNode).void }
|
78
|
-
def on_constant_read_node_enter(node)
|
79
|
-
return if DependencyDetector.instance.typechecker
|
80
|
-
|
81
|
-
generate_hover(node.slice, node.location)
|
82
|
-
end
|
55
|
+
@listeners = T.let([], T::Array[Listener[ResponseType]])
|
83
56
|
|
84
|
-
|
85
|
-
|
86
|
-
return if DependencyDetector.instance.typechecker
|
57
|
+
# Don't need to instantiate any listeners if there's no target
|
58
|
+
return unless target
|
87
59
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
60
|
+
uri = document.uri
|
61
|
+
@listeners = T.let(
|
62
|
+
[Listeners::Hover.new(uri, nesting, index, dispatcher, typechecker_enabled)],
|
63
|
+
T::Array[Listener[ResponseType]],
|
64
|
+
)
|
65
|
+
Addon.addons.each do |addon|
|
66
|
+
addon_listener = addon.create_hover_listener(nesting, index, dispatcher)
|
67
|
+
@listeners << addon_listener if addon_listener
|
68
|
+
end
|
94
69
|
|
95
|
-
|
70
|
+
@target = T.let(target, Prism::Node)
|
71
|
+
@dispatcher = dispatcher
|
96
72
|
end
|
97
73
|
|
98
|
-
sig {
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
message = node.message
|
104
|
-
return unless message
|
105
|
-
|
106
|
-
target_method = @index.resolve_method(message, @nesting.join("::"))
|
107
|
-
return unless target_method
|
108
|
-
|
109
|
-
location = target_method.location
|
110
|
-
|
111
|
-
@_response = Interface::Hover.new(
|
112
|
-
range: range_from_location(location),
|
113
|
-
contents: markdown_from_index_entries(message, target_method),
|
114
|
-
)
|
115
|
-
end
|
74
|
+
sig { override.returns(ResponseType) }
|
75
|
+
def perform
|
76
|
+
@dispatcher.dispatch_once(@target)
|
77
|
+
responses = @listeners.map(&:response).compact
|
116
78
|
|
117
|
-
|
79
|
+
first_response, *other_responses = responses
|
118
80
|
|
119
|
-
|
120
|
-
def generate_hover(name, location)
|
121
|
-
entries = @index.resolve(name, @nesting)
|
122
|
-
return unless entries
|
81
|
+
return unless first_response
|
123
82
|
|
124
|
-
#
|
125
|
-
|
126
|
-
|
127
|
-
|
83
|
+
# TODO: other_responses should never be nil. Check Sorbet
|
84
|
+
T.must(other_responses).each do |other_response|
|
85
|
+
first_response.contents.value << "\n\n" << other_response.contents.value
|
86
|
+
end
|
128
87
|
|
129
|
-
|
130
|
-
range: range_from_location(location),
|
131
|
-
contents: markdown_from_index_entries(name, entries),
|
132
|
-
)
|
88
|
+
first_response
|
133
89
|
end
|
134
90
|
end
|
135
91
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require "ruby_lsp/listeners/inlay_hints"
|
5
|
+
|
4
6
|
module RubyLsp
|
5
7
|
module Requests
|
6
8
|
# ![Inlay hint demo](../../inlay_hints.gif)
|
@@ -36,77 +38,42 @@ module RubyLsp
|
|
36
38
|
# a: "hello",
|
37
39
|
# }
|
38
40
|
# ```
|
39
|
-
class InlayHints <
|
41
|
+
class InlayHints < Request
|
40
42
|
extend T::Sig
|
41
43
|
extend T::Generic
|
42
44
|
|
43
|
-
|
45
|
+
class << self
|
46
|
+
extend T::Sig
|
44
47
|
|
45
|
-
|
48
|
+
sig { returns(Interface::InlayHintOptions) }
|
49
|
+
def provider
|
50
|
+
Interface::InlayHintOptions.new(resolve_provider: false)
|
51
|
+
end
|
52
|
+
end
|
46
53
|
|
47
|
-
|
48
|
-
attr_reader :_response
|
54
|
+
ResponseType = type_member { { fixed: T::Array[Interface::InlayHint] } }
|
49
55
|
|
50
56
|
sig do
|
51
57
|
params(
|
52
|
-
|
58
|
+
document: Document,
|
59
|
+
range: T::Hash[Symbol, T.untyped],
|
53
60
|
hints_configuration: RequestConfig,
|
54
61
|
dispatcher: Prism::Dispatcher,
|
55
62
|
).void
|
56
63
|
end
|
57
|
-
def initialize(range, hints_configuration, dispatcher)
|
58
|
-
super(
|
59
|
-
|
60
|
-
|
61
|
-
@
|
62
|
-
|
63
|
-
|
64
|
-
dispatcher.register(self, :on_rescue_node_enter, :on_implicit_node_enter)
|
65
|
-
end
|
66
|
-
|
67
|
-
sig { params(node: Prism::RescueNode).void }
|
68
|
-
def on_rescue_node_enter(node)
|
69
|
-
return unless @hints_configuration.enabled?(:implicitRescue)
|
70
|
-
return unless node.exceptions.empty?
|
71
|
-
|
72
|
-
loc = node.location
|
73
|
-
return unless visible?(node, @range)
|
74
|
-
|
75
|
-
@_response << Interface::InlayHint.new(
|
76
|
-
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
77
|
-
label: "StandardError",
|
78
|
-
padding_left: true,
|
79
|
-
tooltip: "StandardError is implied in a bare rescue",
|
64
|
+
def initialize(document, range, hints_configuration, dispatcher)
|
65
|
+
super()
|
66
|
+
start_line = range.dig(:start, :line)
|
67
|
+
end_line = range.dig(:end, :line)
|
68
|
+
@listener = T.let(
|
69
|
+
Listeners::InlayHints.new(start_line..end_line, hints_configuration, dispatcher),
|
70
|
+
Listener[ResponseType],
|
80
71
|
)
|
81
72
|
end
|
82
73
|
|
83
|
-
sig {
|
84
|
-
def
|
85
|
-
|
86
|
-
return unless visible?(node, @range)
|
87
|
-
|
88
|
-
node_value = node.value
|
89
|
-
loc = node.location
|
90
|
-
tooltip = ""
|
91
|
-
node_name = ""
|
92
|
-
case node_value
|
93
|
-
when Prism::CallNode
|
94
|
-
node_name = node_value.name
|
95
|
-
tooltip = "This is a method call. Method name: #{node_name}"
|
96
|
-
when Prism::ConstantReadNode
|
97
|
-
node_name = node_value.name
|
98
|
-
tooltip = "This is a constant: #{node_name}"
|
99
|
-
when Prism::LocalVariableReadNode
|
100
|
-
node_name = node_value.name
|
101
|
-
tooltip = "This is a local variable: #{node_name}"
|
102
|
-
end
|
103
|
-
|
104
|
-
@_response << Interface::InlayHint.new(
|
105
|
-
position: { line: loc.start_line - 1, character: loc.start_column + node_name.length + 1 },
|
106
|
-
label: node_name,
|
107
|
-
padding_left: true,
|
108
|
-
tooltip: tooltip,
|
109
|
-
)
|
74
|
+
sig { override.returns(ResponseType) }
|
75
|
+
def perform
|
76
|
+
@listener.response
|
110
77
|
end
|
111
78
|
end
|
112
79
|
end
|
@@ -15,9 +15,21 @@ module RubyLsp
|
|
15
15
|
# # <-- cursor ends up here
|
16
16
|
# end # <-- end is automatically added
|
17
17
|
# ```
|
18
|
-
class OnTypeFormatting <
|
18
|
+
class OnTypeFormatting < Request
|
19
19
|
extend T::Sig
|
20
20
|
|
21
|
+
class << self
|
22
|
+
extend T::Sig
|
23
|
+
|
24
|
+
sig { returns(Interface::DocumentOnTypeFormattingOptions) }
|
25
|
+
def provider
|
26
|
+
Interface::DocumentOnTypeFormattingOptions.new(
|
27
|
+
first_trigger_character: "{",
|
28
|
+
more_trigger_character: ["\n", "|", "d"],
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
21
33
|
END_REGEXES = T.let(
|
22
34
|
[
|
23
35
|
/\b(if|unless|for|while|class|module|until|def|case)\b.*/,
|
@@ -28,8 +40,8 @@ module RubyLsp
|
|
28
40
|
|
29
41
|
sig { params(document: Document, position: T::Hash[Symbol, T.untyped], trigger_character: String).void }
|
30
42
|
def initialize(document, position, trigger_character)
|
31
|
-
super(
|
32
|
-
|
43
|
+
super()
|
44
|
+
@document = document
|
33
45
|
@lines = T.let(@document.source.lines, T::Array[String])
|
34
46
|
line = @lines[[position[:line] - 1, 0].max]
|
35
47
|
|
@@ -41,7 +53,7 @@ module RubyLsp
|
|
41
53
|
end
|
42
54
|
|
43
55
|
sig { override.returns(T.all(T::Array[Interface::TextEdit], Object)) }
|
44
|
-
def
|
56
|
+
def perform
|
45
57
|
case @trigger_character
|
46
58
|
when "{"
|
47
59
|
handle_curly_brace if @document.syntax_error?
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# :nodoc:
|
7
|
+
class Request
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Generic
|
10
|
+
|
11
|
+
abstract!
|
12
|
+
|
13
|
+
sig { abstract.returns(T.anything) }
|
14
|
+
def perform; end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -20,18 +20,19 @@ module RubyLsp
|
|
20
20
|
# puts "Hello, world!" # --> Cursor is on this line
|
21
21
|
# end
|
22
22
|
# ```
|
23
|
-
class SelectionRanges
|
23
|
+
class SelectionRanges < Request
|
24
24
|
extend T::Sig
|
25
25
|
include Support::Common
|
26
26
|
sig { params(document: Document).void }
|
27
27
|
def initialize(document)
|
28
|
+
super()
|
28
29
|
@document = document
|
29
30
|
@ranges = T.let([], T::Array[Support::SelectionRange])
|
30
31
|
@stack = T.let([], T::Array[Support::SelectionRange])
|
31
32
|
end
|
32
33
|
|
33
|
-
sig { returns(T.all(T::Array[Support::SelectionRange], Object)) }
|
34
|
-
def
|
34
|
+
sig { override.returns(T.all(T::Array[Support::SelectionRange], Object)) }
|
35
|
+
def perform
|
35
36
|
# [node, parent]
|
36
37
|
queue = [[@document.tree, nil]]
|
37
38
|
|