ruby-lsp 0.23.10 → 0.23.13
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-launcher +12 -11
- data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +1 -1
- data/lib/rubocop/cop/ruby_lsp/use_register_with_handler_method.rb +3 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +81 -115
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +117 -166
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +89 -201
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +63 -192
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +14 -16
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +22 -45
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +42 -60
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +9 -16
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +75 -0
- data/lib/ruby_indexer/test/configuration_test.rb +42 -3
- data/lib/ruby_indexer/test/index_test.rb +21 -0
- data/lib/ruby_indexer/test/method_test.rb +28 -2
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_lsp/addon.rb +44 -71
- data/lib/ruby_lsp/base_server.rb +31 -33
- data/lib/ruby_lsp/client_capabilities.rb +10 -12
- data/lib/ruby_lsp/document.rb +34 -45
- data/lib/ruby_lsp/erb_document.rb +24 -36
- data/lib/ruby_lsp/global_state.rb +51 -56
- data/lib/ruby_lsp/internal.rb +6 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +81 -88
- data/lib/ruby_lsp/listeners/completion.rb +36 -55
- data/lib/ruby_lsp/listeners/definition.rb +37 -51
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +43 -62
- data/lib/ruby_lsp/listeners/document_symbol.rb +35 -49
- data/lib/ruby_lsp/listeners/folding_ranges.rb +32 -39
- data/lib/ruby_lsp/listeners/hover.rb +81 -100
- data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +42 -51
- data/lib/ruby_lsp/listeners/signature_help.rb +6 -25
- data/lib/ruby_lsp/listeners/spec_style.rb +155 -0
- data/lib/ruby_lsp/listeners/test_discovery.rb +89 -0
- data/lib/ruby_lsp/listeners/test_style.rb +236 -0
- data/lib/ruby_lsp/node_context.rb +12 -39
- data/lib/ruby_lsp/rbs_document.rb +8 -6
- data/lib/ruby_lsp/requests/code_action_resolve.rb +10 -10
- data/lib/ruby_lsp/requests/code_actions.rb +14 -26
- data/lib/ruby_lsp/requests/code_lens.rb +6 -17
- data/lib/ruby_lsp/requests/completion.rb +7 -20
- data/lib/ruby_lsp/requests/completion_resolve.rb +5 -5
- data/lib/ruby_lsp/requests/definition.rb +8 -17
- data/lib/ruby_lsp/requests/diagnostics.rb +8 -11
- data/lib/ruby_lsp/requests/discover_tests.rb +75 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +5 -15
- 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 +87 -0
- data/lib/ruby_lsp/requests/hover.rb +8 -18
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
- data/lib/ruby_lsp/requests/on_type_formatting.rb +28 -38
- data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +4 -13
- data/lib/ruby_lsp/requests/range_formatting.rb +5 -6
- data/lib/ruby_lsp/requests/references.rb +6 -36
- data/lib/ruby_lsp/requests/rename.rb +11 -37
- data/lib/ruby_lsp/requests/request.rb +7 -19
- data/lib/ruby_lsp/requests/selection_ranges.rb +5 -5
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +12 -31
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +5 -6
- data/lib/ruby_lsp/requests/signature_help.rb +8 -26
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +13 -48
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +9 -12
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +22 -34
- 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 +16 -30
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
- data/lib/ruby_lsp/requests/support/test_item.rb +55 -0
- 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 +5 -5
- data/lib/ruby_lsp/response_builders/document_symbol.rb +10 -16
- data/lib/ruby_lsp/response_builders/hover.rb +10 -13
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +59 -87
- data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
- data/lib/ruby_lsp/response_builders/test_collection.rb +34 -0
- data/lib/ruby_lsp/ruby_document.rb +22 -60
- data/lib/ruby_lsp/ruby_lsp_reporter_plugin.rb +109 -0
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/server.rb +177 -72
- data/lib/ruby_lsp/setup_bundler.rb +61 -59
- data/lib/ruby_lsp/static_docs.rb +4 -7
- data/lib/ruby_lsp/store.rb +21 -40
- data/lib/ruby_lsp/test_helper.rb +3 -12
- data/lib/ruby_lsp/test_reporter.rb +207 -0
- data/lib/ruby_lsp/test_unit_test_runner.rb +98 -0
- data/lib/ruby_lsp/type_inferrer.rb +9 -13
- data/lib/ruby_lsp/utils.rb +37 -81
- metadata +13 -3
@@ -0,0 +1,236 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Listeners
|
6
|
+
class TestStyle < TestDiscovery
|
7
|
+
class << self
|
8
|
+
# Resolves the minimal set of commands required to execute the requested tests
|
9
|
+
#: (Array[Hash[Symbol, untyped]]) -> Array[String]
|
10
|
+
def resolve_test_commands(items)
|
11
|
+
# A nested hash of file_path => test_group => { tags: [], examples: [test_example] } to ensure we build the
|
12
|
+
# minimum amount of commands needed to execute the requested tests. This is only used for specific examples
|
13
|
+
# where we will need more complex regexes to execute it all at the same time
|
14
|
+
aggregated_tests = Hash.new do |hash, key|
|
15
|
+
hash[key] = Hash.new do |inner_h, inner_k|
|
16
|
+
inner_h[inner_k] = { tags: Set.new, examples: [] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Full files are paths that should be executed as a whole e.g.: an entire test file or directory
|
21
|
+
full_files = []
|
22
|
+
queue = items.dup
|
23
|
+
|
24
|
+
until queue.empty?
|
25
|
+
item = T.must(queue.shift)
|
26
|
+
tags = Set.new(item[:tags])
|
27
|
+
next unless tags.include?("framework:minitest") || tags.include?("framework:test_unit")
|
28
|
+
|
29
|
+
children = item[:children]
|
30
|
+
uri = URI(item[:uri])
|
31
|
+
path = uri.full_path
|
32
|
+
next unless path
|
33
|
+
|
34
|
+
if tags.include?("test_dir")
|
35
|
+
if children.empty?
|
36
|
+
full_files.concat(Dir.glob(
|
37
|
+
"#{path}/**/{*_test,test_*}.rb",
|
38
|
+
File::Constants::FNM_EXTGLOB | File::Constants::FNM_PATHNAME,
|
39
|
+
))
|
40
|
+
end
|
41
|
+
elsif tags.include?("test_file")
|
42
|
+
full_files << path if children.empty?
|
43
|
+
elsif tags.include?("test_group")
|
44
|
+
# If all of the children of the current test group are other groups, then there's no need to add it to the
|
45
|
+
# aggregated examples
|
46
|
+
unless children.any? && children.all? { |child| child[:tags].include?("test_group") }
|
47
|
+
aggregated_tests[path][item[:label]] = { tags: tags, examples: [] }
|
48
|
+
end
|
49
|
+
else
|
50
|
+
class_name, method_name = item[:id].split("#")
|
51
|
+
aggregated_tests[path][class_name][:examples] << method_name
|
52
|
+
aggregated_tests[path][class_name][:tags].merge(tags)
|
53
|
+
end
|
54
|
+
|
55
|
+
queue.concat(children) unless children.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
commands = []
|
59
|
+
|
60
|
+
aggregated_tests.each do |file_path, groups_and_examples|
|
61
|
+
# Separate groups into Minitest and Test Unit. You can have both frameworks in the same file, but you cannot
|
62
|
+
# have a group belongs to both at the same time
|
63
|
+
minitest_groups, test_unit_groups = groups_and_examples.partition do |_, info|
|
64
|
+
info[:tags].include?("framework:minitest")
|
65
|
+
end
|
66
|
+
|
67
|
+
if minitest_groups.any?
|
68
|
+
commands << handle_minitest_groups(file_path, minitest_groups)
|
69
|
+
end
|
70
|
+
|
71
|
+
if test_unit_groups.any?
|
72
|
+
commands.concat(handle_test_unit_groups(file_path, test_unit_groups))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
unless full_files.empty?
|
77
|
+
commands << "#{BASE_COMMAND} -Itest -e \"ARGV.each { |f| require f }\" #{full_files.join(" ")}"
|
78
|
+
end
|
79
|
+
|
80
|
+
commands
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
#: (String, Hash[String, Hash[Symbol, untyped]]) -> String
|
86
|
+
def handle_minitest_groups(file_path, groups_and_examples)
|
87
|
+
regexes = groups_and_examples.flat_map do |group, info|
|
88
|
+
examples = info[:examples]
|
89
|
+
group_regex = Shellwords.escape(group).gsub(
|
90
|
+
Shellwords.escape(TestDiscovery::DYNAMIC_REFERENCE_MARKER),
|
91
|
+
".*",
|
92
|
+
)
|
93
|
+
if examples.empty?
|
94
|
+
"^#{group_regex}(#|::)"
|
95
|
+
elsif examples.length == 1
|
96
|
+
"^#{group_regex}##{examples[0]}$"
|
97
|
+
else
|
98
|
+
"^#{group_regex}#(#{examples.join("|")})$"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
regex = if regexes.length == 1
|
103
|
+
regexes[0]
|
104
|
+
else
|
105
|
+
"(#{regexes.join("|")})"
|
106
|
+
end
|
107
|
+
|
108
|
+
"#{BASE_COMMAND} -Itest #{file_path} --name \"/#{regex}/\""
|
109
|
+
end
|
110
|
+
|
111
|
+
#: (String, Hash[String, Hash[Symbol, untyped]]) -> Array[String]
|
112
|
+
def handle_test_unit_groups(file_path, groups_and_examples)
|
113
|
+
groups_and_examples.map do |group, info|
|
114
|
+
examples = info[:examples]
|
115
|
+
group_regex = Shellwords.escape(group).gsub(
|
116
|
+
Shellwords.escape(TestDiscovery::DYNAMIC_REFERENCE_MARKER),
|
117
|
+
".*",
|
118
|
+
)
|
119
|
+
command = +"#{BASE_COMMAND} -Itest #{file_path} --testcase \"/^#{group_regex}$/\""
|
120
|
+
|
121
|
+
unless examples.empty?
|
122
|
+
command << if examples.length == 1
|
123
|
+
" --name \"/#{examples[0]}$/\""
|
124
|
+
else
|
125
|
+
" --name \"/(#{examples.join("|")})$/\""
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
command
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
include Requests::Support::Common
|
135
|
+
|
136
|
+
MINITEST_REPORTER_PATH = File.expand_path("../ruby_lsp_reporter_plugin.rb", __dir__) #: String
|
137
|
+
TEST_UNIT_REPORTER_PATH = File.expand_path("../test_unit_test_runner.rb", __dir__) #: String
|
138
|
+
ACCESS_MODIFIERS = [:public, :private, :protected].freeze
|
139
|
+
BASE_COMMAND = begin
|
140
|
+
Bundler.with_original_env { Bundler.default_lockfile }
|
141
|
+
"bundle exec ruby"
|
142
|
+
rescue Bundler::GemfileNotFound
|
143
|
+
"ruby"
|
144
|
+
end #: String
|
145
|
+
|
146
|
+
#: (ResponseBuilders::TestCollection response_builder, GlobalState global_state, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
147
|
+
def initialize(response_builder, global_state, dispatcher, uri)
|
148
|
+
super
|
149
|
+
|
150
|
+
@framework = :minitest #: Symbol
|
151
|
+
|
152
|
+
dispatcher.register(
|
153
|
+
self,
|
154
|
+
# Common handlers registered in parent class
|
155
|
+
:on_class_node_enter,
|
156
|
+
:on_def_node_enter,
|
157
|
+
:on_call_node_enter,
|
158
|
+
:on_call_node_leave,
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
#: (Prism::ClassNode node) -> void
|
163
|
+
def on_class_node_enter(node)
|
164
|
+
with_test_ancestor_tracking(node) do |name, ancestors|
|
165
|
+
@framework = :test_unit if ancestors.include?("Test::Unit::TestCase")
|
166
|
+
|
167
|
+
if @framework == :test_unit || non_declarative_minitest?(ancestors, name)
|
168
|
+
@response_builder.add(Requests::Support::TestItem.new(
|
169
|
+
name,
|
170
|
+
name,
|
171
|
+
@uri,
|
172
|
+
range_from_node(node),
|
173
|
+
framework: @framework,
|
174
|
+
))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
#: (Prism::DefNode node) -> void
|
180
|
+
def on_def_node_enter(node)
|
181
|
+
return if @visibility_stack.last != :public
|
182
|
+
|
183
|
+
name = node.name.to_s
|
184
|
+
return unless name.start_with?("test_")
|
185
|
+
|
186
|
+
current_group_name = RubyIndexer::Index.actual_nesting(@nesting, nil).join("::")
|
187
|
+
|
188
|
+
# If we're finding a test method, but for the wrong framework, then the group test item will not have been
|
189
|
+
# previously pushed and thus we return early and avoid adding items for a framework this listener is not
|
190
|
+
# interested in
|
191
|
+
test_item = @response_builder[current_group_name]
|
192
|
+
return unless test_item
|
193
|
+
|
194
|
+
test_item.add(Requests::Support::TestItem.new(
|
195
|
+
"#{current_group_name}##{name}",
|
196
|
+
name,
|
197
|
+
@uri,
|
198
|
+
range_from_node(node),
|
199
|
+
framework: @framework,
|
200
|
+
))
|
201
|
+
end
|
202
|
+
|
203
|
+
#: (Prism::CallNode node) -> void
|
204
|
+
def on_call_node_enter(node)
|
205
|
+
name = node.name
|
206
|
+
return unless ACCESS_MODIFIERS.include?(name)
|
207
|
+
|
208
|
+
@visibility_stack << name
|
209
|
+
end
|
210
|
+
|
211
|
+
#: (Prism::CallNode node) -> void
|
212
|
+
def on_call_node_leave(node)
|
213
|
+
name = node.name
|
214
|
+
return unless ACCESS_MODIFIERS.include?(name)
|
215
|
+
return unless node.arguments&.arguments
|
216
|
+
|
217
|
+
@visibility_stack.pop
|
218
|
+
end
|
219
|
+
|
220
|
+
private
|
221
|
+
|
222
|
+
#: (Array[String] attached_ancestors, String fully_qualified_name) -> bool
|
223
|
+
def non_declarative_minitest?(attached_ancestors, fully_qualified_name)
|
224
|
+
return false unless attached_ancestors.include?("Minitest::Test")
|
225
|
+
|
226
|
+
# We only support regular Minitest tests. The declarative syntax provided by ActiveSupport is handled by the
|
227
|
+
# Rails add-on
|
228
|
+
name_parts = fully_qualified_name.split("::")
|
229
|
+
singleton_name = "#{name_parts.join("::")}::<Class:#{name_parts.last}>"
|
230
|
+
!@index.linearized_ancestors_of(singleton_name).include?("ActiveSupport::Testing::Declarative")
|
231
|
+
rescue RubyIndexer::Index::NonExistingNamespaceError
|
232
|
+
true
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
@@ -5,36 +5,19 @@ module RubyLsp
|
|
5
5
|
# This class allows listeners to access contextual information about a node in the AST, such as its parent,
|
6
6
|
# its namespace nesting, and the surrounding CallNode (e.g. a method call).
|
7
7
|
class NodeContext
|
8
|
-
|
9
|
-
|
10
|
-
sig { returns(T.nilable(Prism::Node)) }
|
8
|
+
#: Prism::Node?
|
11
9
|
attr_reader :node, :parent
|
12
10
|
|
13
|
-
|
11
|
+
#: Array[String]
|
14
12
|
attr_reader :nesting
|
15
13
|
|
16
|
-
|
14
|
+
#: Prism::CallNode?
|
17
15
|
attr_reader :call_node
|
18
16
|
|
19
|
-
|
17
|
+
#: String?
|
20
18
|
attr_reader :surrounding_method
|
21
19
|
|
22
|
-
|
23
|
-
params(
|
24
|
-
node: T.nilable(Prism::Node),
|
25
|
-
parent: T.nilable(Prism::Node),
|
26
|
-
nesting_nodes: T::Array[T.any(
|
27
|
-
Prism::ClassNode,
|
28
|
-
Prism::ModuleNode,
|
29
|
-
Prism::SingletonClassNode,
|
30
|
-
Prism::DefNode,
|
31
|
-
Prism::BlockNode,
|
32
|
-
Prism::LambdaNode,
|
33
|
-
Prism::ProgramNode,
|
34
|
-
)],
|
35
|
-
call_node: T.nilable(Prism::CallNode),
|
36
|
-
).void
|
37
|
-
end
|
20
|
+
#: (Prism::Node? node, Prism::Node? parent, Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)] nesting_nodes, Prism::CallNode? call_node) -> void
|
38
21
|
def initialize(node, parent, nesting_nodes, call_node)
|
39
22
|
@node = node
|
40
23
|
@parent = parent
|
@@ -42,16 +25,16 @@ module RubyLsp
|
|
42
25
|
@call_node = call_node
|
43
26
|
|
44
27
|
nesting, surrounding_method = handle_nesting_nodes(nesting_nodes)
|
45
|
-
@nesting =
|
46
|
-
@surrounding_method =
|
28
|
+
@nesting = nesting #: Array[String]
|
29
|
+
@surrounding_method = surrounding_method #: String?
|
47
30
|
end
|
48
31
|
|
49
|
-
|
32
|
+
#: -> String
|
50
33
|
def fully_qualified_name
|
51
|
-
@fully_qualified_name ||=
|
34
|
+
@fully_qualified_name ||= @nesting.join("::") #: String?
|
52
35
|
end
|
53
36
|
|
54
|
-
|
37
|
+
#: -> Array[Symbol]
|
55
38
|
def locals_for_scope
|
56
39
|
locals = []
|
57
40
|
|
@@ -69,20 +52,10 @@ module RubyLsp
|
|
69
52
|
|
70
53
|
private
|
71
54
|
|
72
|
-
|
73
|
-
params(nodes: T::Array[T.any(
|
74
|
-
Prism::ClassNode,
|
75
|
-
Prism::ModuleNode,
|
76
|
-
Prism::SingletonClassNode,
|
77
|
-
Prism::DefNode,
|
78
|
-
Prism::BlockNode,
|
79
|
-
Prism::LambdaNode,
|
80
|
-
Prism::ProgramNode,
|
81
|
-
)]).returns([T::Array[String], T.nilable(String)])
|
82
|
-
end
|
55
|
+
#: (Array[(Prism::ClassNode | Prism::ModuleNode | Prism::SingletonClassNode | Prism::DefNode | Prism::BlockNode | Prism::LambdaNode | Prism::ProgramNode)] nodes) -> [Array[String], String?]
|
83
56
|
def handle_nesting_nodes(nodes)
|
84
57
|
nesting = []
|
85
|
-
surrounding_method =
|
58
|
+
surrounding_method = nil #: String?
|
86
59
|
|
87
60
|
@nesting_nodes.each do |node|
|
88
61
|
case node
|
@@ -3,18 +3,18 @@
|
|
3
3
|
|
4
4
|
module RubyLsp
|
5
5
|
class RBSDocument < Document
|
6
|
-
extend T::Sig
|
7
6
|
extend T::Generic
|
8
7
|
|
9
8
|
ParseResultType = type_member { { fixed: T::Array[RBS::AST::Declarations::Base] } }
|
10
9
|
|
11
|
-
|
10
|
+
#: (source: String, version: Integer, uri: URI::Generic, global_state: GlobalState) -> void
|
12
11
|
def initialize(source:, version:, uri:, global_state:)
|
13
|
-
@syntax_error =
|
12
|
+
@syntax_error = false #: bool
|
14
13
|
super
|
15
14
|
end
|
16
15
|
|
17
|
-
|
16
|
+
# @override
|
17
|
+
#: -> bool
|
18
18
|
def parse!
|
19
19
|
return false unless @needs_parsing
|
20
20
|
|
@@ -29,12 +29,14 @@ module RubyLsp
|
|
29
29
|
true
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
# @override
|
33
|
+
#: -> bool
|
33
34
|
def syntax_error?
|
34
35
|
@syntax_error
|
35
36
|
end
|
36
37
|
|
37
|
-
|
38
|
+
# @override
|
39
|
+
#: -> LanguageId
|
38
40
|
def language_id
|
39
41
|
LanguageId::RBS
|
40
42
|
end
|
@@ -7,7 +7,6 @@ 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"
|
@@ -23,7 +22,7 @@ module RubyLsp
|
|
23
22
|
end
|
24
23
|
end
|
25
24
|
|
26
|
-
|
25
|
+
#: (RubyDocument document, GlobalState global_state, Hash[Symbol, untyped] code_action) -> void
|
27
26
|
def initialize(document, global_state, code_action)
|
28
27
|
super()
|
29
28
|
@document = document
|
@@ -31,7 +30,8 @@ module RubyLsp
|
|
31
30
|
@code_action = code_action
|
32
31
|
end
|
33
32
|
|
34
|
-
|
33
|
+
# @override
|
34
|
+
#: -> (Interface::CodeAction | Error)
|
35
35
|
def perform
|
36
36
|
return Error::EmptySelection if @document.source.empty?
|
37
37
|
|
@@ -53,7 +53,7 @@ module RubyLsp
|
|
53
53
|
|
54
54
|
private
|
55
55
|
|
56
|
-
|
56
|
+
#: -> (Interface::CodeAction | Error)
|
57
57
|
def switch_block_style
|
58
58
|
source_range = @code_action.dig(:data, :range)
|
59
59
|
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
@@ -91,7 +91,7 @@ module RubyLsp
|
|
91
91
|
)
|
92
92
|
end
|
93
93
|
|
94
|
-
|
94
|
+
#: -> (Interface::CodeAction | Error)
|
95
95
|
def refactor_variable
|
96
96
|
source_range = @code_action.dig(:data, :range)
|
97
97
|
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
@@ -189,7 +189,7 @@ module RubyLsp
|
|
189
189
|
)
|
190
190
|
end
|
191
191
|
|
192
|
-
|
192
|
+
#: -> (Interface::CodeAction | Error)
|
193
193
|
def refactor_method
|
194
194
|
source_range = @code_action.dig(:data, :range)
|
195
195
|
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
@@ -261,7 +261,7 @@ module RubyLsp
|
|
261
261
|
)
|
262
262
|
end
|
263
263
|
|
264
|
-
|
264
|
+
#: (Hash[Symbol, untyped] range, String new_text) -> Interface::TextEdit
|
265
265
|
def create_text_edit(range, new_text)
|
266
266
|
Interface::TextEdit.new(
|
267
267
|
range: Interface::Range.new(
|
@@ -272,7 +272,7 @@ module RubyLsp
|
|
272
272
|
)
|
273
273
|
end
|
274
274
|
|
275
|
-
|
275
|
+
#: (Prism::BlockNode node, String? indentation) -> String
|
276
276
|
def recursively_switch_nested_block_styles(node, indentation)
|
277
277
|
parameters = node.parameters
|
278
278
|
body = node.body
|
@@ -301,7 +301,7 @@ module RubyLsp
|
|
301
301
|
source
|
302
302
|
end
|
303
303
|
|
304
|
-
|
304
|
+
#: (Prism::Node body, String? indentation) -> String
|
305
305
|
def switch_block_body(body, indentation)
|
306
306
|
# Check if there are any nested blocks inside of the current block
|
307
307
|
body_loc = body.location
|
@@ -330,7 +330,7 @@ module RubyLsp
|
|
330
330
|
indentation ? body_content.gsub(";", "\n") : "#{body_content.gsub("\n", ";")} "
|
331
331
|
end
|
332
332
|
|
333
|
-
|
333
|
+
#: -> (Interface::CodeAction | Error)
|
334
334
|
def create_attribute_accessor
|
335
335
|
source_range = @code_action.dig(:data, :range)
|
336
336
|
|
@@ -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
|
|
@@ -88,7 +76,7 @@ module RubyLsp
|
|
88
76
|
|
89
77
|
private
|
90
78
|
|
91
|
-
|
79
|
+
#: -> Array[Interface::CodeAction]
|
92
80
|
def attribute_actions
|
93
81
|
return [] unless @document.is_a?(RubyDocument)
|
94
82
|
|
@@ -11,29 +11,17 @@ 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
17
|
Interface::CodeLensOptions.new(resolve_provider: false)
|
22
18
|
end
|
23
19
|
end
|
24
20
|
|
25
|
-
|
26
|
-
params(
|
27
|
-
global_state: GlobalState,
|
28
|
-
uri: URI::Generic,
|
29
|
-
dispatcher: Prism::Dispatcher,
|
30
|
-
).void
|
31
|
-
end
|
21
|
+
#: (GlobalState global_state, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
|
32
22
|
def initialize(global_state, uri, dispatcher)
|
33
|
-
@response_builder =
|
34
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
|
35
|
-
ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
36
|
-
)
|
23
|
+
@response_builder = ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
|
24
|
+
.new #: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens]
|
37
25
|
super()
|
38
26
|
Listeners::CodeLens.new(@response_builder, global_state, uri, dispatcher)
|
39
27
|
|
@@ -42,7 +30,8 @@ module RubyLsp
|
|
42
30
|
end
|
43
31
|
end
|
44
32
|
|
45
|
-
|
33
|
+
# @override
|
34
|
+
#: -> Array[Interface::CodeLens]
|
46
35
|
def perform
|
47
36
|
@response_builder.response
|
48
37
|
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, RubyDocument::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
|
@@ -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[Interface::CompletionItem]
|
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
|
|
@@ -78,7 +78,7 @@ module RubyLsp
|
|
78
78
|
|
79
79
|
private
|
80
80
|
|
81
|
-
|
81
|
+
#: (Hash[Symbol, untyped] item) -> Hash[Symbol, untyped]
|
82
82
|
def keyword_resolve(item)
|
83
83
|
keyword = item[:label]
|
84
84
|
content = KEYWORD_DOCS[keyword]
|