ruby-lsp 0.23.11 → 0.26.6
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 +46 -22
- data/exe/ruby-lsp-test-exec +6 -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 +85 -118
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +159 -183
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +10 -14
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +130 -253
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +189 -285
- 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 +31 -59
- 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_lsp/addon.rb +88 -86
- data/lib/ruby_lsp/base_server.rb +79 -65
- data/lib/ruby_lsp/client_capabilities.rb +16 -13
- data/lib/ruby_lsp/document.rb +205 -104
- data/lib/ruby_lsp/erb_document.rb +45 -47
- data/lib/ruby_lsp/global_state.rb +134 -86
- 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 +81 -76
- data/lib/ruby_lsp/listeners/definition.rb +78 -72
- data/lib/ruby_lsp/listeners/document_highlight.rb +149 -151
- data/lib/ruby_lsp/listeners/document_link.rb +93 -86
- 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 +109 -117
- 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 +231 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +107 -0
- data/lib/ruby_lsp/listeners/test_style.rb +207 -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 +92 -66
- data/lib/ruby_lsp/requests/code_actions.rb +34 -31
- 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 +14 -12
- 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 +139 -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 +23 -61
- data/lib/ruby_lsp/requests/support/formatter.rb +16 -15
- data/lib/ruby_lsp/requests/support/package_url.rb +414 -0
- 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 +34 -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 +22 -33
- 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 +24 -16
- 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 +7 -5
- data/lib/ruby_lsp/server.rb +305 -198
- data/lib/ruby_lsp/setup_bundler.rb +160 -97
- 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 +241 -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 +15 -34
- data/lib/ruby_indexer/test/class_variables_test.rb +0 -140
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +0 -745
- data/lib/ruby_indexer/test/configuration_test.rb +0 -239
- data/lib/ruby_indexer/test/constant_test.rb +0 -402
- data/lib/ruby_indexer/test/enhancements_test.rb +0 -325
- data/lib/ruby_indexer/test/global_variable_test.rb +0 -49
- data/lib/ruby_indexer/test/index_test.rb +0 -2186
- data/lib/ruby_indexer/test/instance_variables_test.rb +0 -240
- data/lib/ruby_indexer/test/method_test.rb +0 -947
- data/lib/ruby_indexer/test/prefix_tree_test.rb +0 -150
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +0 -386
- data/lib/ruby_indexer/test/reference_finder_test.rb +0 -330
- data/lib/ruby_indexer/test/test_case.rb +0 -51
- data/lib/ruby_indexer/test/uri_test.rb +0 -72
- data/lib/ruby_lsp/load_sorbet.rb +0 -62
|
@@ -7,23 +7,17 @@ module RubyLsp
|
|
|
7
7
|
# request is used to to resolve the edit field for a given code action, if it is not already provided in the
|
|
8
8
|
# textDocument/codeAction response. We can use it for scenarios that require more computation such as refactoring.
|
|
9
9
|
class CodeActionResolve < Request
|
|
10
|
-
extend T::Sig
|
|
11
10
|
include Support::Common
|
|
12
11
|
|
|
13
12
|
NEW_VARIABLE_NAME = "new_variable"
|
|
14
13
|
NEW_METHOD_NAME = "new_method"
|
|
15
14
|
|
|
16
15
|
class CodeActionError < StandardError; end
|
|
16
|
+
class EmptySelectionError < CodeActionError; end
|
|
17
|
+
class InvalidTargetRangeError < CodeActionError; end
|
|
18
|
+
class UnknownCodeActionError < CodeActionError; end
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
enums do
|
|
20
|
-
EmptySelection = new
|
|
21
|
-
InvalidTargetRange = new
|
|
22
|
-
UnknownCodeAction = new
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
sig { params(document: RubyDocument, global_state: GlobalState, code_action: T::Hash[Symbol, T.untyped]).void }
|
|
20
|
+
#: (RubyDocument document, GlobalState global_state, Hash[Symbol, untyped] code_action) -> void
|
|
27
21
|
def initialize(document, global_state, code_action)
|
|
28
22
|
super()
|
|
29
23
|
@document = document
|
|
@@ -31,9 +25,10 @@ module RubyLsp
|
|
|
31
25
|
@code_action = code_action
|
|
32
26
|
end
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
# @override
|
|
29
|
+
#: -> (Interface::CodeAction)
|
|
35
30
|
def perform
|
|
36
|
-
|
|
31
|
+
raise EmptySelectionError, "Invalid selection for refactor" if @document.source.empty?
|
|
37
32
|
|
|
38
33
|
case @code_action[:title]
|
|
39
34
|
when CodeActions::EXTRACT_TO_VARIABLE_TITLE
|
|
@@ -47,26 +42,52 @@ module RubyLsp
|
|
|
47
42
|
CodeActions::CREATE_ATTRIBUTE_ACCESSOR
|
|
48
43
|
create_attribute_accessor
|
|
49
44
|
else
|
|
50
|
-
|
|
45
|
+
raise UnknownCodeActionError, "Unknown code action: #{@code_action[:title]}"
|
|
51
46
|
end
|
|
52
47
|
end
|
|
53
48
|
|
|
54
49
|
private
|
|
55
50
|
|
|
56
|
-
|
|
51
|
+
#: -> (Interface::CodeAction)
|
|
57
52
|
def switch_block_style
|
|
58
53
|
source_range = @code_action.dig(:data, :range)
|
|
59
|
-
|
|
54
|
+
if source_range[:start] == source_range[:end]
|
|
55
|
+
block_context = @document.locate_node(
|
|
56
|
+
source_range[:start],
|
|
57
|
+
node_types: [Prism::BlockNode],
|
|
58
|
+
)
|
|
59
|
+
node = block_context.node
|
|
60
|
+
unless node.is_a?(Prism::BlockNode)
|
|
61
|
+
raise InvalidTargetRangeError, "Cursor is not inside a block"
|
|
62
|
+
end
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
# Find the call node at the block node's start position.
|
|
65
|
+
# This should be the call node whose block the cursor is inside of.
|
|
66
|
+
call_context = RubyDocument.locate(
|
|
67
|
+
@document.ast,
|
|
68
|
+
node.location.cached_start_code_units_offset(@document.code_units_cache),
|
|
69
|
+
node_types: [Prism::CallNode],
|
|
70
|
+
code_units_cache: @document.code_units_cache,
|
|
71
|
+
)
|
|
72
|
+
target = call_context.node
|
|
73
|
+
unless target.is_a?(Prism::CallNode) && target.block == node
|
|
74
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
75
|
+
end
|
|
76
|
+
else
|
|
77
|
+
target = @document.locate_first_within_range(
|
|
78
|
+
@code_action.dig(:data, :range),
|
|
79
|
+
node_types: [Prism::CallNode],
|
|
80
|
+
)
|
|
65
81
|
|
|
66
|
-
|
|
82
|
+
unless target.is_a?(Prism::CallNode)
|
|
83
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
84
|
+
end
|
|
67
85
|
|
|
68
|
-
|
|
69
|
-
|
|
86
|
+
node = target.block
|
|
87
|
+
unless node.is_a?(Prism::BlockNode)
|
|
88
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
70
91
|
|
|
71
92
|
indentation = " " * target.location.start_column unless node.opening_loc.slice == "do"
|
|
72
93
|
|
|
@@ -91,17 +112,17 @@ module RubyLsp
|
|
|
91
112
|
)
|
|
92
113
|
end
|
|
93
114
|
|
|
94
|
-
|
|
115
|
+
#: -> (Interface::CodeAction)
|
|
95
116
|
def refactor_variable
|
|
96
117
|
source_range = @code_action.dig(:data, :range)
|
|
97
|
-
|
|
118
|
+
raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
|
|
98
119
|
|
|
99
120
|
start_index, end_index = @document.find_index_by_position(source_range[:start], source_range[:end])
|
|
100
|
-
extracted_source =
|
|
121
|
+
extracted_source = @document.source[start_index...end_index] #: as !nil
|
|
101
122
|
|
|
102
123
|
# Find the closest statements node, so that we place the refactor in a valid position
|
|
103
124
|
node_context = RubyDocument
|
|
104
|
-
.locate(@document.
|
|
125
|
+
.locate(@document.ast,
|
|
105
126
|
start_index,
|
|
106
127
|
node_types: [
|
|
107
128
|
Prism::StatementsNode,
|
|
@@ -111,16 +132,20 @@ module RubyLsp
|
|
|
111
132
|
|
|
112
133
|
closest_statements = node_context.node
|
|
113
134
|
parent_statements = node_context.parent
|
|
114
|
-
|
|
135
|
+
if closest_statements.nil? || closest_statements.child_nodes.compact.empty?
|
|
136
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
137
|
+
end
|
|
115
138
|
|
|
116
139
|
# Find the node with the end line closest to the requested position, so that we can place the refactor
|
|
117
140
|
# immediately after that closest node
|
|
118
|
-
closest_node =
|
|
141
|
+
closest_node = closest_statements.child_nodes.compact.min_by do |node|
|
|
119
142
|
distance = source_range.dig(:start, :line) - (node.location.end_line - 1)
|
|
120
143
|
distance <= 0 ? Float::INFINITY : distance
|
|
121
|
-
end
|
|
144
|
+
end #: as !nil
|
|
122
145
|
|
|
123
|
-
|
|
146
|
+
if closest_node.is_a?(Prism::MissingNode)
|
|
147
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
148
|
+
end
|
|
124
149
|
|
|
125
150
|
closest_node_loc = closest_node.location
|
|
126
151
|
# If the parent expression is a single line block, then we have to extract it inside of the one-line block
|
|
@@ -151,9 +176,12 @@ module RubyLsp
|
|
|
151
176
|
lines = @document.source.lines
|
|
152
177
|
|
|
153
178
|
indentation_line = lines[indentation_line_number]
|
|
154
|
-
|
|
179
|
+
unless indentation_line
|
|
180
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
181
|
+
end
|
|
155
182
|
|
|
156
|
-
indentation =
|
|
183
|
+
indentation = indentation_line[/\A */] #: as !nil
|
|
184
|
+
.size
|
|
157
185
|
|
|
158
186
|
target_range = {
|
|
159
187
|
start: { line: target_line, character: indentation },
|
|
@@ -161,7 +189,9 @@ module RubyLsp
|
|
|
161
189
|
}
|
|
162
190
|
|
|
163
191
|
line = lines[target_line]
|
|
164
|
-
|
|
192
|
+
unless line
|
|
193
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
194
|
+
end
|
|
165
195
|
|
|
166
196
|
variable_source = if line.strip.empty?
|
|
167
197
|
"\n#{" " * indentation}#{NEW_VARIABLE_NAME} = #{extracted_source}"
|
|
@@ -189,27 +219,31 @@ module RubyLsp
|
|
|
189
219
|
)
|
|
190
220
|
end
|
|
191
221
|
|
|
192
|
-
|
|
222
|
+
#: -> (Interface::CodeAction)
|
|
193
223
|
def refactor_method
|
|
194
224
|
source_range = @code_action.dig(:data, :range)
|
|
195
|
-
|
|
225
|
+
raise EmptySelectionError, "Invalid selection for refactor" if source_range[:start] == source_range[:end]
|
|
196
226
|
|
|
197
227
|
start_index, end_index = @document.find_index_by_position(source_range[:start], source_range[:end])
|
|
198
|
-
extracted_source =
|
|
228
|
+
extracted_source = @document.source[start_index...end_index] #: as !nil
|
|
199
229
|
|
|
200
230
|
# Find the closest method declaration node, so that we place the refactor in a valid position
|
|
201
231
|
node_context = RubyDocument.locate(
|
|
202
|
-
@document.
|
|
232
|
+
@document.ast,
|
|
203
233
|
start_index,
|
|
204
234
|
node_types: [Prism::DefNode],
|
|
205
235
|
code_units_cache: @document.code_units_cache,
|
|
206
236
|
)
|
|
207
237
|
closest_node = node_context.node
|
|
208
|
-
|
|
238
|
+
unless closest_node
|
|
239
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
240
|
+
end
|
|
209
241
|
|
|
210
242
|
target_range = if closest_node.is_a?(Prism::DefNode)
|
|
211
243
|
end_keyword_loc = closest_node.end_keyword_loc
|
|
212
|
-
|
|
244
|
+
unless end_keyword_loc
|
|
245
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
246
|
+
end
|
|
213
247
|
|
|
214
248
|
end_line = end_keyword_loc.end_line - 1
|
|
215
249
|
character = end_keyword_loc.end_column
|
|
@@ -261,7 +295,7 @@ module RubyLsp
|
|
|
261
295
|
)
|
|
262
296
|
end
|
|
263
297
|
|
|
264
|
-
|
|
298
|
+
#: (Hash[Symbol, untyped] range, String new_text) -> Interface::TextEdit
|
|
265
299
|
def create_text_edit(range, new_text)
|
|
266
300
|
Interface::TextEdit.new(
|
|
267
301
|
range: Interface::Range.new(
|
|
@@ -272,7 +306,7 @@ module RubyLsp
|
|
|
272
306
|
)
|
|
273
307
|
end
|
|
274
308
|
|
|
275
|
-
|
|
309
|
+
#: (Prism::BlockNode node, String? indentation) -> String
|
|
276
310
|
def recursively_switch_nested_block_styles(node, indentation)
|
|
277
311
|
parameters = node.parameters
|
|
278
312
|
body = node.body
|
|
@@ -301,7 +335,7 @@ module RubyLsp
|
|
|
301
335
|
source
|
|
302
336
|
end
|
|
303
337
|
|
|
304
|
-
|
|
338
|
+
#: (Prism::Node body, String? indentation) -> String
|
|
305
339
|
def switch_block_body(body, indentation)
|
|
306
340
|
# Check if there are any nested blocks inside of the current block
|
|
307
341
|
body_loc = body.location
|
|
@@ -330,7 +364,7 @@ module RubyLsp
|
|
|
330
364
|
indentation ? body_content.gsub(";", "\n") : "#{body_content.gsub("\n", ";")} "
|
|
331
365
|
end
|
|
332
366
|
|
|
333
|
-
|
|
367
|
+
#: -> (Interface::CodeAction)
|
|
334
368
|
def create_attribute_accessor
|
|
335
369
|
source_range = @code_action.dig(:data, :range)
|
|
336
370
|
|
|
@@ -348,20 +382,12 @@ module RubyLsp
|
|
|
348
382
|
)
|
|
349
383
|
node = node_context.node
|
|
350
384
|
|
|
351
|
-
|
|
385
|
+
unless CodeActions::INSTANCE_VARIABLE_NODES.include?(node.class)
|
|
386
|
+
raise EmptySelectionError, "Invalid selection for refactor"
|
|
387
|
+
end
|
|
352
388
|
end
|
|
353
389
|
|
|
354
|
-
node =
|
|
355
|
-
node,
|
|
356
|
-
T.any(
|
|
357
|
-
Prism::InstanceVariableAndWriteNode,
|
|
358
|
-
Prism::InstanceVariableOperatorWriteNode,
|
|
359
|
-
Prism::InstanceVariableOrWriteNode,
|
|
360
|
-
Prism::InstanceVariableReadNode,
|
|
361
|
-
Prism::InstanceVariableTargetNode,
|
|
362
|
-
Prism::InstanceVariableWriteNode,
|
|
363
|
-
),
|
|
364
|
-
)
|
|
390
|
+
node = node #: as Prism::InstanceVariableAndWriteNode | Prism::InstanceVariableOperatorWriteNode | Prism::InstanceVariableOrWriteNode | Prism::InstanceVariableReadNode | Prism::InstanceVariableTargetNode | Prism::InstanceVariableWriteNode
|
|
365
391
|
|
|
366
392
|
node_context = @document.locate_node(
|
|
367
393
|
{
|
|
@@ -375,20 +401,20 @@ module RubyLsp
|
|
|
375
401
|
],
|
|
376
402
|
)
|
|
377
403
|
closest_node = node_context.node
|
|
378
|
-
|
|
404
|
+
if closest_node.nil?
|
|
405
|
+
raise InvalidTargetRangeError, "Couldn't find an appropriate location to place extracted refactor"
|
|
406
|
+
end
|
|
379
407
|
|
|
380
408
|
attribute_name = node.name[1..]
|
|
381
409
|
indentation = " " * (closest_node.location.start_column + 2)
|
|
382
|
-
attribute_accessor_source =
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
end,
|
|
391
|
-
)
|
|
410
|
+
attribute_accessor_source = case @code_action[:title]
|
|
411
|
+
when CodeActions::CREATE_ATTRIBUTE_READER
|
|
412
|
+
"#{indentation}attr_reader :#{attribute_name}\n\n"
|
|
413
|
+
when CodeActions::CREATE_ATTRIBUTE_WRITER
|
|
414
|
+
"#{indentation}attr_writer :#{attribute_name}\n\n"
|
|
415
|
+
when CodeActions::CREATE_ATTRIBUTE_ACCESSOR
|
|
416
|
+
"#{indentation}attr_accessor :#{attribute_name}\n\n"
|
|
417
|
+
end #: as !nil
|
|
392
418
|
|
|
393
419
|
target_start_line = closest_node.location.start_line
|
|
394
420
|
target_range = {
|
|
@@ -7,8 +7,6 @@ module RubyLsp
|
|
|
7
7
|
# request informs the editor of RuboCop quick fixes that can be applied. These are accessible by hovering over a
|
|
8
8
|
# specific diagnostic.
|
|
9
9
|
class CodeActions < Request
|
|
10
|
-
extend T::Sig
|
|
11
|
-
|
|
12
10
|
EXTRACT_TO_VARIABLE_TITLE = "Refactor: Extract Variable"
|
|
13
11
|
EXTRACT_TO_METHOD_TITLE = "Refactor: Extract Method"
|
|
14
12
|
TOGGLE_BLOCK_STYLE_TITLE = "Refactor: Toggle block style"
|
|
@@ -16,22 +14,17 @@ module RubyLsp
|
|
|
16
14
|
CREATE_ATTRIBUTE_WRITER = "Create Attribute Writer"
|
|
17
15
|
CREATE_ATTRIBUTE_ACCESSOR = "Create Attribute Accessor"
|
|
18
16
|
|
|
19
|
-
INSTANCE_VARIABLE_NODES =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
],
|
|
28
|
-
T::Array[T.class_of(Prism::Node)],
|
|
29
|
-
)
|
|
17
|
+
INSTANCE_VARIABLE_NODES = [
|
|
18
|
+
Prism::InstanceVariableAndWriteNode,
|
|
19
|
+
Prism::InstanceVariableOperatorWriteNode,
|
|
20
|
+
Prism::InstanceVariableOrWriteNode,
|
|
21
|
+
Prism::InstanceVariableReadNode,
|
|
22
|
+
Prism::InstanceVariableTargetNode,
|
|
23
|
+
Prism::InstanceVariableWriteNode,
|
|
24
|
+
] #: Array[singleton(Prism::Node)]
|
|
30
25
|
|
|
31
26
|
class << self
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
sig { returns(Interface::CodeActionRegistrationOptions) }
|
|
27
|
+
#: -> Interface::CodeActionRegistrationOptions
|
|
35
28
|
def provider
|
|
36
29
|
Interface::CodeActionRegistrationOptions.new(
|
|
37
30
|
document_selector: nil,
|
|
@@ -40,22 +33,17 @@ module RubyLsp
|
|
|
40
33
|
end
|
|
41
34
|
end
|
|
42
35
|
|
|
43
|
-
|
|
44
|
-
params(
|
|
45
|
-
document: T.any(RubyDocument, ERBDocument),
|
|
46
|
-
range: T::Hash[Symbol, T.untyped],
|
|
47
|
-
context: T::Hash[Symbol, T.untyped],
|
|
48
|
-
).void
|
|
49
|
-
end
|
|
36
|
+
#: ((RubyDocument | ERBDocument) document, Hash[Symbol, untyped] range, Hash[Symbol, untyped] context) -> void
|
|
50
37
|
def initialize(document, range, context)
|
|
51
38
|
super()
|
|
52
39
|
@document = document
|
|
53
|
-
@uri =
|
|
40
|
+
@uri = document.uri #: URI::Generic
|
|
54
41
|
@range = range
|
|
55
42
|
@context = context
|
|
56
43
|
end
|
|
57
44
|
|
|
58
|
-
|
|
45
|
+
# @override
|
|
46
|
+
#: -> (Array[Interface::CodeAction] & Object)?
|
|
59
47
|
def perform
|
|
60
48
|
diagnostics = @context[:diagnostics]
|
|
61
49
|
|
|
@@ -75,12 +63,8 @@ module RubyLsp
|
|
|
75
63
|
kind: Constant::CodeActionKind::REFACTOR_EXTRACT,
|
|
76
64
|
data: { range: @range, uri: @uri.to_s },
|
|
77
65
|
)
|
|
78
|
-
code_actions << Interface::CodeAction.new(
|
|
79
|
-
title: TOGGLE_BLOCK_STYLE_TITLE,
|
|
80
|
-
kind: Constant::CodeActionKind::REFACTOR_REWRITE,
|
|
81
|
-
data: { range: @range, uri: @uri.to_s },
|
|
82
|
-
)
|
|
83
66
|
end
|
|
67
|
+
code_actions.concat(toggle_block_style_action)
|
|
84
68
|
code_actions.concat(attribute_actions)
|
|
85
69
|
|
|
86
70
|
code_actions
|
|
@@ -88,7 +72,7 @@ module RubyLsp
|
|
|
88
72
|
|
|
89
73
|
private
|
|
90
74
|
|
|
91
|
-
|
|
75
|
+
#: -> Array[Interface::CodeAction]
|
|
92
76
|
def attribute_actions
|
|
93
77
|
return [] unless @document.is_a?(RubyDocument)
|
|
94
78
|
|
|
@@ -125,6 +109,25 @@ module RubyLsp
|
|
|
125
109
|
),
|
|
126
110
|
]
|
|
127
111
|
end
|
|
112
|
+
|
|
113
|
+
#: -> Array[Interface::CodeAction]
|
|
114
|
+
def toggle_block_style_action
|
|
115
|
+
if @range[:start] == @range[:end]
|
|
116
|
+
block_context = @document.locate_node(
|
|
117
|
+
@range[:start],
|
|
118
|
+
node_types: [Prism::BlockNode],
|
|
119
|
+
)
|
|
120
|
+
return [] unless block_context.node.is_a?(Prism::BlockNode)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
[
|
|
124
|
+
Interface::CodeAction.new(
|
|
125
|
+
title: TOGGLE_BLOCK_STYLE_TITLE,
|
|
126
|
+
kind: Constant::CodeActionKind::REFACTOR_REWRITE,
|
|
127
|
+
data: { range: @range, uri: @uri.to_s },
|
|
128
|
+
),
|
|
129
|
+
]
|
|
130
|
+
end
|
|
128
131
|
end
|
|
129
132
|
end
|
|
130
133
|
end
|
|
@@ -11,40 +11,50 @@ module RubyLsp
|
|
|
11
11
|
# [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
|
|
12
12
|
# request informs the editor of runnable commands such as testing and debugging.
|
|
13
13
|
class CodeLens < Request
|
|
14
|
-
extend T::Sig
|
|
15
|
-
|
|
16
14
|
class << self
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
sig { returns(Interface::CodeLensOptions) }
|
|
15
|
+
#: -> Interface::CodeLensOptions
|
|
20
16
|
def provider
|
|
21
|
-
Interface::CodeLensOptions.new(resolve_provider:
|
|
17
|
+
Interface::CodeLensOptions.new(resolve_provider: true)
|
|
22
18
|
end
|
|
23
19
|
end
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
dispatcher: Prism::Dispatcher,
|
|
30
|
-
).void
|
|
31
|
-
end
|
|
32
|
-
def initialize(global_state, uri, dispatcher)
|
|
33
|
-
@response_builder = T.let(
|
|
34
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens].new,
|
|
35
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
|
36
|
-
)
|
|
21
|
+
#: (GlobalState, RubyDocument | ERBDocument, Prism::Dispatcher) -> void
|
|
22
|
+
def initialize(global_state, document, dispatcher)
|
|
23
|
+
@response_builder = ResponseBuilders::CollectionResponseBuilder
|
|
24
|
+
.new #: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
|
|
37
25
|
super()
|
|
38
|
-
|
|
26
|
+
|
|
27
|
+
@document = document
|
|
28
|
+
@test_builder = ResponseBuilders::TestCollection.new #: ResponseBuilders::TestCollection
|
|
29
|
+
uri = document.uri
|
|
30
|
+
file_path = uri.full_path
|
|
31
|
+
code_lens_config = global_state.feature_configuration(:codeLens)
|
|
32
|
+
test_lenses_enabled = (!code_lens_config || code_lens_config.enabled?(:enableTestCodeLens)) &&
|
|
33
|
+
file_path && File.fnmatch?(TEST_PATH_PATTERN, file_path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
|
34
|
+
|
|
35
|
+
if global_state.enabled_feature?(:fullTestDiscovery)
|
|
36
|
+
if test_lenses_enabled
|
|
37
|
+
Listeners::TestStyle.new(@test_builder, global_state, dispatcher, uri)
|
|
38
|
+
Listeners::SpecStyle.new(@test_builder, global_state, dispatcher, uri)
|
|
39
|
+
end
|
|
40
|
+
else
|
|
41
|
+
Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
|
|
42
|
+
end
|
|
39
43
|
|
|
40
44
|
Addon.addons.each do |addon|
|
|
41
45
|
addon.create_code_lens_listener(@response_builder, uri, dispatcher)
|
|
46
|
+
|
|
47
|
+
if global_state.enabled_feature?(:fullTestDiscovery) && test_lenses_enabled
|
|
48
|
+
addon.create_discover_tests_listener(@test_builder, dispatcher, uri)
|
|
49
|
+
end
|
|
42
50
|
end
|
|
43
51
|
end
|
|
44
52
|
|
|
45
|
-
|
|
53
|
+
# @override
|
|
54
|
+
#: -> Array[Interface::CodeLens]
|
|
46
55
|
def perform
|
|
47
|
-
@
|
|
56
|
+
@document.cache_set("rubyLsp/discoverTests", @test_builder.response)
|
|
57
|
+
@response_builder.response + @test_builder.code_lens
|
|
48
58
|
end
|
|
49
59
|
end
|
|
50
60
|
end
|
|
@@ -8,12 +8,8 @@ module RubyLsp
|
|
|
8
8
|
# The [completion](https://microsoft.github.io/language-server-protocol/specification#textDocument_completion)
|
|
9
9
|
# suggests possible completions according to what the developer is typing.
|
|
10
10
|
class Completion < Request
|
|
11
|
-
extend T::Sig
|
|
12
|
-
|
|
13
11
|
class << self
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
sig { returns(Interface::CompletionOptions) }
|
|
12
|
+
#: -> Interface::CompletionOptions
|
|
17
13
|
def provider
|
|
18
14
|
Interface::CompletionOptions.new(
|
|
19
15
|
resolve_provider: true,
|
|
@@ -25,18 +21,10 @@ module RubyLsp
|
|
|
25
21
|
end
|
|
26
22
|
end
|
|
27
23
|
|
|
28
|
-
|
|
29
|
-
params(
|
|
30
|
-
document: T.any(RubyDocument, ERBDocument),
|
|
31
|
-
global_state: GlobalState,
|
|
32
|
-
params: T::Hash[Symbol, T.untyped],
|
|
33
|
-
sorbet_level: RubyDocument::SorbetLevel,
|
|
34
|
-
dispatcher: Prism::Dispatcher,
|
|
35
|
-
).void
|
|
36
|
-
end
|
|
24
|
+
#: ((RubyDocument | ERBDocument) document, GlobalState global_state, Hash[Symbol, untyped] params, SorbetLevel sorbet_level, Prism::Dispatcher dispatcher) -> void
|
|
37
25
|
def initialize(document, global_state, params, sorbet_level, dispatcher)
|
|
38
26
|
super()
|
|
39
|
-
@target =
|
|
27
|
+
@target = nil #: Prism::Node?
|
|
40
28
|
@dispatcher = dispatcher
|
|
41
29
|
# Completion always receives the position immediately after the character that was just typed. Here we adjust it
|
|
42
30
|
# back by 1, so that we find the right node
|
|
@@ -45,7 +33,7 @@ module RubyLsp
|
|
|
45
33
|
delegate_request_if_needed!(global_state, document, char_position)
|
|
46
34
|
|
|
47
35
|
node_context = RubyDocument.locate(
|
|
48
|
-
document.
|
|
36
|
+
document.ast,
|
|
49
37
|
char_position,
|
|
50
38
|
node_types: [
|
|
51
39
|
Prism::CallNode,
|
|
@@ -72,10 +60,8 @@ module RubyLsp
|
|
|
72
60
|
],
|
|
73
61
|
code_units_cache: document.code_units_cache,
|
|
74
62
|
)
|
|
75
|
-
@response_builder =
|
|
76
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem]
|
|
77
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
|
78
|
-
)
|
|
63
|
+
@response_builder = ResponseBuilders::CollectionResponseBuilder
|
|
64
|
+
.new #: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem]
|
|
79
65
|
|
|
80
66
|
Listeners::Completion.new(
|
|
81
67
|
@response_builder,
|
|
@@ -102,7 +88,8 @@ module RubyLsp
|
|
|
102
88
|
end
|
|
103
89
|
end
|
|
104
90
|
|
|
105
|
-
|
|
91
|
+
# @override
|
|
92
|
+
#: -> Array[Interface::CompletionItem]
|
|
106
93
|
def perform
|
|
107
94
|
return [] unless @target
|
|
108
95
|
|
|
@@ -14,21 +14,21 @@ module RubyLsp
|
|
|
14
14
|
# At most 10 definitions are included, to ensure low latency during request processing and rendering the completion
|
|
15
15
|
# item.
|
|
16
16
|
class CompletionResolve < Request
|
|
17
|
-
extend T::Sig
|
|
18
17
|
include Requests::Support::Common
|
|
19
18
|
|
|
20
19
|
# set a limit on the number of documentation entries returned, to avoid rendering performance issues
|
|
21
20
|
# https://github.com/Shopify/ruby-lsp/pull/1798
|
|
22
21
|
MAX_DOCUMENTATION_ENTRIES = 10
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
#: (GlobalState global_state, Hash[Symbol, untyped] item) -> void
|
|
25
24
|
def initialize(global_state, item)
|
|
26
25
|
super()
|
|
27
|
-
@index =
|
|
26
|
+
@index = global_state.index #: RubyIndexer::Index
|
|
28
27
|
@item = item
|
|
29
28
|
end
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
# @override
|
|
31
|
+
#: -> Hash[Symbol, untyped]
|
|
32
32
|
def perform
|
|
33
33
|
return @item if @item.dig(:data, :skip_resolve)
|
|
34
34
|
|
|
@@ -54,7 +54,7 @@ module RubyLsp
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
first_entry =
|
|
57
|
+
first_entry = entries.first #: as !nil
|
|
58
58
|
|
|
59
59
|
if first_entry.is_a?(RubyIndexer::Entry::Member)
|
|
60
60
|
label = +"#{label}#{first_entry.decorated_parameters}"
|
|
@@ -68,23 +68,25 @@ module RubyLsp
|
|
|
68
68
|
"[Learn more about guessed types](#{GUESSED_TYPES_URL})"
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
@item[:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
unless @item[:kind] == Constant::CompletionItemKind::FILE
|
|
72
|
+
@item[:documentation] = Interface::MarkupContent.new(
|
|
73
|
+
kind: "markdown",
|
|
74
|
+
value: markdown_from_index_entries(label, entries, MAX_DOCUMENTATION_ENTRIES, extra_links: extra_links),
|
|
75
|
+
)
|
|
76
|
+
end
|
|
75
77
|
|
|
76
78
|
@item
|
|
77
79
|
end
|
|
78
80
|
|
|
79
81
|
private
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
#: (Hash[Symbol, untyped] item) -> Hash[Symbol, untyped]
|
|
82
84
|
def keyword_resolve(item)
|
|
83
85
|
keyword = item[:label]
|
|
84
86
|
content = KEYWORD_DOCS[keyword]
|
|
85
87
|
|
|
86
88
|
if content
|
|
87
|
-
|
|
89
|
+
doc_uri = URI::Generic.from_path(path: File.join(STATIC_DOCS_PATH, "#{keyword}.md"))
|
|
88
90
|
|
|
89
91
|
@item[:documentation] = Interface::MarkupContent.new(
|
|
90
92
|
kind: "markdown",
|
|
@@ -93,7 +95,7 @@ module RubyLsp
|
|
|
93
95
|
#{keyword}
|
|
94
96
|
```
|
|
95
97
|
|
|
96
|
-
[Read more](#{
|
|
98
|
+
[Read more](#{doc_uri})
|
|
97
99
|
|
|
98
100
|
#{content}
|
|
99
101
|
MARKDOWN
|