ruby-lsp 0.23.11 → 0.23.12
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_register_with_handler_method.rb +3 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +52 -77
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +61 -144
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +8 -6
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +73 -182
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +48 -181
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +12 -14
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +21 -44
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +40 -58
- 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/configuration_test.rb +32 -2
- data/lib/ruby_indexer/test/method_test.rb +2 -2
- data/lib/ruby_lsp/addon.rb +32 -67
- data/lib/ruby_lsp/base_server.rb +10 -10
- data/lib/ruby_lsp/client_capabilities.rb +4 -6
- data/lib/ruby_lsp/document.rb +21 -32
- data/lib/ruby_lsp/erb_document.rb +17 -27
- data/lib/ruby_lsp/global_state.rb +30 -32
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +21 -39
- data/lib/ruby_lsp/listeners/completion.rb +34 -53
- data/lib/ruby_lsp/listeners/definition.rb +35 -49
- data/lib/ruby_lsp/listeners/document_highlight.rb +60 -69
- data/lib/ruby_lsp/listeners/document_link.rb +9 -19
- data/lib/ruby_lsp/listeners/document_symbol.rb +34 -48
- data/lib/ruby_lsp/listeners/folding_ranges.rb +31 -38
- data/lib/ruby_lsp/listeners/hover.rb +37 -47
- data/lib/ruby_lsp/listeners/inlay_hints.rb +3 -10
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +29 -35
- data/lib/ruby_lsp/listeners/signature_help.rb +4 -23
- data/lib/ruby_lsp/listeners/spec_style.rb +199 -0
- data/lib/ruby_lsp/listeners/test_style.rb +136 -30
- data/lib/ruby_lsp/node_context.rb +8 -35
- data/lib/ruby_lsp/rbs_document.rb +7 -5
- data/lib/ruby_lsp/requests/code_action_resolve.rb +10 -10
- data/lib/ruby_lsp/requests/code_actions.rb +5 -14
- data/lib/ruby_lsp/requests/code_lens.rb +4 -13
- data/lib/ruby_lsp/requests/completion.rb +4 -15
- data/lib/ruby_lsp/requests/completion_resolve.rb +4 -4
- data/lib/ruby_lsp/requests/definition.rb +4 -12
- data/lib/ruby_lsp/requests/diagnostics.rb +6 -9
- data/lib/ruby_lsp/requests/discover_tests.rb +15 -3
- data/lib/ruby_lsp/requests/document_highlight.rb +3 -11
- data/lib/ruby_lsp/requests/document_link.rb +4 -13
- data/lib/ruby_lsp/requests/document_symbol.rb +4 -7
- data/lib/ruby_lsp/requests/folding_ranges.rb +4 -7
- data/lib/ruby_lsp/requests/formatting.rb +4 -7
- data/lib/ruby_lsp/requests/go_to_relevant_file.rb +87 -0
- data/lib/ruby_lsp/requests/hover.rb +6 -16
- data/lib/ruby_lsp/requests/inlay_hints.rb +4 -13
- data/lib/ruby_lsp/requests/on_type_formatting.rb +17 -24
- data/lib/ruby_lsp/requests/prepare_rename.rb +3 -8
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +4 -13
- data/lib/ruby_lsp/requests/range_formatting.rb +3 -4
- data/lib/ruby_lsp/requests/references.rb +5 -35
- data/lib/ruby_lsp/requests/rename.rb +9 -35
- data/lib/ruby_lsp/requests/request.rb +5 -17
- data/lib/ruby_lsp/requests/selection_ranges.rb +3 -3
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +6 -23
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +4 -5
- data/lib/ruby_lsp/requests/signature_help.rb +6 -24
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +12 -49
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +12 -14
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +7 -10
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +9 -15
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -3
- data/lib/ruby_lsp/requests/support/sorbet.rb +1 -7
- data/lib/ruby_lsp/requests/support/source_uri.rb +5 -16
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +7 -10
- data/lib/ruby_lsp/requests/support/test_item.rb +14 -13
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +4 -5
- data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -3
- data/lib/ruby_lsp/response_builders/collection_response_builder.rb +4 -4
- data/lib/ruby_lsp/response_builders/document_symbol.rb +8 -11
- data/lib/ruby_lsp/response_builders/hover.rb +5 -5
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +18 -40
- data/lib/ruby_lsp/response_builders/signature_help.rb +4 -5
- data/lib/ruby_lsp/response_builders/test_collection.rb +5 -9
- data/lib/ruby_lsp/ruby_document.rb +15 -40
- data/lib/ruby_lsp/ruby_lsp_reporter_plugin.rb +106 -0
- data/lib/ruby_lsp/scope.rb +6 -10
- data/lib/ruby_lsp/server.rb +125 -74
- data/lib/ruby_lsp/setup_bundler.rb +22 -15
- data/lib/ruby_lsp/store.rb +12 -28
- data/lib/ruby_lsp/test_helper.rb +3 -12
- data/lib/ruby_lsp/test_reporter.rb +71 -0
- data/lib/ruby_lsp/test_unit_test_runner.rb +96 -0
- data/lib/ruby_lsp/type_inferrer.rb +9 -13
- data/lib/ruby_lsp/utils.rb +27 -65
- metadata +8 -3
@@ -0,0 +1,199 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Listeners
|
6
|
+
class SpecStyle
|
7
|
+
extend T::Sig
|
8
|
+
include Requests::Support::Common
|
9
|
+
|
10
|
+
DYNAMIC_REFERENCE_MARKER = "<dynamic_reference>"
|
11
|
+
|
12
|
+
#: (response_builder: ResponseBuilders::TestCollection, global_state: GlobalState, dispatcher: Prism::Dispatcher, uri: URI::Generic) -> void
|
13
|
+
def initialize(response_builder, global_state, dispatcher, uri)
|
14
|
+
@response_builder = response_builder
|
15
|
+
@uri = uri
|
16
|
+
@index = T.let(global_state.index, RubyIndexer::Index)
|
17
|
+
@visibility_stack = T.let([:public], T::Array[Symbol])
|
18
|
+
@nesting = T.let([], T::Array[String])
|
19
|
+
@describe_block_nesting = T.let([], T::Array[String])
|
20
|
+
@spec_class_stack = T.let([], T::Array[T::Boolean])
|
21
|
+
|
22
|
+
dispatcher.register(
|
23
|
+
self,
|
24
|
+
:on_class_node_enter,
|
25
|
+
:on_class_node_leave,
|
26
|
+
:on_module_node_enter,
|
27
|
+
:on_module_node_leave,
|
28
|
+
:on_call_node_enter, # e.g. `describe` or `it`
|
29
|
+
:on_call_node_leave,
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
#: (node: Prism::ClassNode) -> void
|
34
|
+
def on_class_node_enter(node)
|
35
|
+
@visibility_stack << :public
|
36
|
+
name = constant_name(node.constant_path)
|
37
|
+
name ||= name_with_dynamic_reference(node.constant_path)
|
38
|
+
|
39
|
+
fully_qualified_name = RubyIndexer::Index.actual_nesting(@nesting, name).join("::")
|
40
|
+
|
41
|
+
attached_ancestors = begin
|
42
|
+
@index.linearized_ancestors_of(fully_qualified_name)
|
43
|
+
rescue RubyIndexer::Index::NonExistingNamespaceError
|
44
|
+
# When there are dynamic parts in the constant path, we will not have indexed the namespace. We can still
|
45
|
+
# provide test functionality if the class inherits directly from Test::Unit::TestCase or Minitest::Test
|
46
|
+
[node.superclass&.slice].compact
|
47
|
+
end
|
48
|
+
|
49
|
+
is_spec = attached_ancestors.include?("Minitest::Spec")
|
50
|
+
@spec_class_stack.push(is_spec)
|
51
|
+
|
52
|
+
@nesting << name
|
53
|
+
end
|
54
|
+
|
55
|
+
#: (node: Prism::ModuleNode) -> void
|
56
|
+
def on_module_node_enter(node)
|
57
|
+
@visibility_stack << :public
|
58
|
+
|
59
|
+
name = constant_name(node.constant_path)
|
60
|
+
name ||= name_with_dynamic_reference(node.constant_path)
|
61
|
+
|
62
|
+
@nesting << name
|
63
|
+
end
|
64
|
+
|
65
|
+
#: (node: Prism::ModuleNode) -> void
|
66
|
+
def on_module_node_leave(node)
|
67
|
+
@visibility_stack.pop
|
68
|
+
@nesting.pop
|
69
|
+
end
|
70
|
+
|
71
|
+
#: (node: Prism::ClassNode) -> void
|
72
|
+
def on_class_node_leave(node)
|
73
|
+
@visibility_stack.pop
|
74
|
+
@nesting.pop
|
75
|
+
@spec_class_stack.pop
|
76
|
+
end
|
77
|
+
|
78
|
+
#: (node: Prism::CallNode) -> void
|
79
|
+
def on_call_node_enter(node)
|
80
|
+
case node.name
|
81
|
+
when :describe
|
82
|
+
handle_describe(node)
|
83
|
+
when :it, :specify
|
84
|
+
handle_example(node)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
#: (node: Prism::CallNode) -> void
|
89
|
+
def on_call_node_leave(node)
|
90
|
+
return unless node.name == :describe && !node.receiver
|
91
|
+
|
92
|
+
@describe_block_nesting.pop
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
#: (node: Prism::CallNode) -> void
|
98
|
+
def handle_describe(node)
|
99
|
+
return if node.block.nil?
|
100
|
+
|
101
|
+
description = extract_description(node)
|
102
|
+
return unless description
|
103
|
+
|
104
|
+
return unless in_spec_context?
|
105
|
+
|
106
|
+
if @nesting.empty? && @describe_block_nesting.empty?
|
107
|
+
test_item = Requests::Support::TestItem.new(
|
108
|
+
description,
|
109
|
+
description,
|
110
|
+
@uri,
|
111
|
+
range_from_node(node),
|
112
|
+
tags: [:minitest],
|
113
|
+
)
|
114
|
+
@response_builder.add(test_item)
|
115
|
+
else
|
116
|
+
add_to_parent_test_group(description, node)
|
117
|
+
end
|
118
|
+
|
119
|
+
@describe_block_nesting << description
|
120
|
+
end
|
121
|
+
|
122
|
+
#: (node: Prism::CallNode) -> void
|
123
|
+
def handle_example(node)
|
124
|
+
return unless in_spec_context?
|
125
|
+
|
126
|
+
return if @describe_block_nesting.empty? && @nesting.empty?
|
127
|
+
|
128
|
+
description = extract_description(node)
|
129
|
+
return unless description
|
130
|
+
|
131
|
+
add_to_parent_test_group(description, node)
|
132
|
+
end
|
133
|
+
|
134
|
+
#: (description: String, node: Prism::CallNode) -> void
|
135
|
+
def add_to_parent_test_group(description, node)
|
136
|
+
parent_test_group = find_parent_test_group
|
137
|
+
return unless parent_test_group
|
138
|
+
|
139
|
+
test_item = Requests::Support::TestItem.new(
|
140
|
+
description,
|
141
|
+
description,
|
142
|
+
@uri,
|
143
|
+
range_from_node(node),
|
144
|
+
tags: [:minitest],
|
145
|
+
)
|
146
|
+
parent_test_group.add(test_item)
|
147
|
+
end
|
148
|
+
|
149
|
+
#: -> Requests::Support::TestItem?
|
150
|
+
def find_parent_test_group
|
151
|
+
root_group_name, nested_describe_groups = if @nesting.empty?
|
152
|
+
[@describe_block_nesting.first, @describe_block_nesting[1..]]
|
153
|
+
else
|
154
|
+
[RubyIndexer::Index.actual_nesting(@nesting, nil).join("::"), @describe_block_nesting]
|
155
|
+
end
|
156
|
+
return unless root_group_name
|
157
|
+
|
158
|
+
test_group = T.let(@response_builder[root_group_name], T.nilable(Requests::Support::TestItem))
|
159
|
+
return unless test_group
|
160
|
+
|
161
|
+
return test_group unless nested_describe_groups
|
162
|
+
|
163
|
+
nested_describe_groups.each do |description|
|
164
|
+
test_group = test_group[description]
|
165
|
+
end
|
166
|
+
|
167
|
+
test_group
|
168
|
+
end
|
169
|
+
|
170
|
+
#: (node: Prism::CallNode) -> String?
|
171
|
+
def extract_description(node)
|
172
|
+
first_argument = node.arguments&.arguments&.first
|
173
|
+
return unless first_argument
|
174
|
+
|
175
|
+
case first_argument
|
176
|
+
when Prism::StringNode
|
177
|
+
first_argument.content
|
178
|
+
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
179
|
+
constant_name(first_argument)
|
180
|
+
else
|
181
|
+
first_argument.slice
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
#: -> bool
|
186
|
+
def in_spec_context?
|
187
|
+
return true if @nesting.empty?
|
188
|
+
|
189
|
+
T.must(@spec_class_stack.last)
|
190
|
+
end
|
191
|
+
|
192
|
+
#: (node: Prism::ConstantPathNode | Prism::ConstantReadNode | Prism::ConstantPathTargetNode | Prism::CallNode | Prism::MissingNode) -> String
|
193
|
+
def name_with_dynamic_reference(node)
|
194
|
+
slice = node.slice
|
195
|
+
slice.gsub(/((?<=::)|^)[a-z]\w*/, DYNAMIC_REFERENCE_MARKER)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -4,26 +4,140 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
module Listeners
|
6
6
|
class TestStyle
|
7
|
-
|
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
|
+
|
28
|
+
children = item[:children]
|
29
|
+
uri = URI(item[:uri])
|
30
|
+
path = uri.full_path
|
31
|
+
next unless path
|
32
|
+
|
33
|
+
if tags.include?("test_dir")
|
34
|
+
full_files << "#{path}/**/*" if children.empty?
|
35
|
+
elsif tags.include?("test_file")
|
36
|
+
full_files << path if children.empty?
|
37
|
+
elsif tags.include?("test_group")
|
38
|
+
# If all of the children of the current test group are other groups, then there's no need to add it to the
|
39
|
+
# aggregated examples
|
40
|
+
unless children.any? && children.all? { |child| child[:tags].include?("test_group") }
|
41
|
+
aggregated_tests[path][item[:label]] = { tags: tags, examples: [] }
|
42
|
+
end
|
43
|
+
elsif tags.include?("minitest") || tags.include?("test_unit")
|
44
|
+
class_name, method_name = item[:id].split("#")
|
45
|
+
aggregated_tests[path][class_name][:examples] << method_name
|
46
|
+
aggregated_tests[path][class_name][:tags].merge(tags)
|
47
|
+
end
|
48
|
+
|
49
|
+
queue.concat(children) unless children.empty?
|
50
|
+
end
|
51
|
+
|
52
|
+
commands = []
|
53
|
+
|
54
|
+
aggregated_tests.each do |file_path, groups_and_examples|
|
55
|
+
# Separate groups into Minitest and Test Unit. You can have both frameworks in the same file, but you cannot
|
56
|
+
# have a group belongs to both at the same time
|
57
|
+
minitest_groups, test_unit_groups = groups_and_examples.partition do |_, info|
|
58
|
+
info[:tags].include?("minitest")
|
59
|
+
end
|
60
|
+
|
61
|
+
if minitest_groups.any?
|
62
|
+
commands << handle_minitest_groups(file_path, minitest_groups)
|
63
|
+
end
|
64
|
+
|
65
|
+
if test_unit_groups.any?
|
66
|
+
commands.concat(handle_test_unit_groups(file_path, test_unit_groups))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
commands << "#{BASE_COMMAND} -Itest #{full_files.join(" ")}" unless full_files.empty?
|
71
|
+
commands
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
#: (String, Hash[String, Hash[Symbol, untyped]]) -> String
|
77
|
+
def handle_minitest_groups(file_path, groups_and_examples)
|
78
|
+
regexes = groups_and_examples.flat_map do |group, info|
|
79
|
+
examples = info[:examples]
|
80
|
+
group_regex = Shellwords.escape(group).gsub(Shellwords.escape(DYNAMIC_REFERENCE_MARKER), ".*")
|
81
|
+
if examples.empty?
|
82
|
+
"^#{group_regex}(#|::)"
|
83
|
+
elsif examples.length == 1
|
84
|
+
"^#{group_regex}##{examples[0]}$"
|
85
|
+
else
|
86
|
+
"^#{group_regex}#(#{examples.join("|")})$"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
regex = if regexes.length == 1
|
91
|
+
regexes[0]
|
92
|
+
else
|
93
|
+
"(#{regexes.join("|")})"
|
94
|
+
end
|
95
|
+
|
96
|
+
"#{BASE_COMMAND} -Itest #{file_path} --name \"/#{regex}/\""
|
97
|
+
end
|
98
|
+
|
99
|
+
#: (String, Hash[String, Hash[Symbol, untyped]]) -> Array[String]
|
100
|
+
def handle_test_unit_groups(file_path, groups_and_examples)
|
101
|
+
groups_and_examples.map do |group, info|
|
102
|
+
examples = info[:examples]
|
103
|
+
group_regex = Shellwords.escape(group).gsub(Shellwords.escape(DYNAMIC_REFERENCE_MARKER), ".*")
|
104
|
+
command = +"#{BASE_COMMAND} -Itest #{file_path} --testcase \"/^#{group_regex}$/\""
|
105
|
+
|
106
|
+
unless examples.empty?
|
107
|
+
command << if examples.length == 1
|
108
|
+
" --name \"/#{examples[0]}$/\""
|
109
|
+
else
|
110
|
+
" --name \"/(#{examples.join("|")})$/\""
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
command
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
8
119
|
include Requests::Support::Common
|
9
120
|
|
10
121
|
ACCESS_MODIFIERS = [:public, :private, :protected].freeze
|
11
122
|
DYNAMIC_REFERENCE_MARKER = "<dynamic_reference>"
|
123
|
+
BASE_COMMAND = T.let(
|
124
|
+
begin
|
125
|
+
Bundler.with_original_env { Bundler.default_lockfile }
|
126
|
+
"bundle exec ruby"
|
127
|
+
rescue Bundler::GemfileNotFound
|
128
|
+
"ruby"
|
129
|
+
end,
|
130
|
+
String,
|
131
|
+
)
|
12
132
|
|
13
|
-
|
14
|
-
params(
|
15
|
-
response_builder: ResponseBuilders::TestCollection,
|
16
|
-
global_state: GlobalState,
|
17
|
-
dispatcher: Prism::Dispatcher,
|
18
|
-
uri: URI::Generic,
|
19
|
-
).void
|
20
|
-
end
|
133
|
+
#: (ResponseBuilders::TestCollection response_builder, GlobalState global_state, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
21
134
|
def initialize(response_builder, global_state, dispatcher, uri)
|
22
135
|
@response_builder = response_builder
|
23
136
|
@uri = uri
|
24
137
|
@index = T.let(global_state.index, RubyIndexer::Index)
|
25
138
|
@visibility_stack = T.let([:public], T::Array[Symbol])
|
26
139
|
@nesting = T.let([], T::Array[String])
|
140
|
+
@framework_tag = T.let(:minitest, Symbol)
|
27
141
|
|
28
142
|
dispatcher.register(
|
29
143
|
self,
|
@@ -37,7 +151,7 @@ module RubyLsp
|
|
37
151
|
)
|
38
152
|
end
|
39
153
|
|
40
|
-
|
154
|
+
#: (Prism::ClassNode node) -> void
|
41
155
|
def on_class_node_enter(node)
|
42
156
|
@visibility_stack << :public
|
43
157
|
name = constant_name(node.constant_path)
|
@@ -53,21 +167,22 @@ module RubyLsp
|
|
53
167
|
[node.superclass&.slice].compact
|
54
168
|
end
|
55
169
|
|
56
|
-
if attached_ancestors.include?("Test::Unit::TestCase")
|
57
|
-
non_declarative_minitest?(attached_ancestors, fully_qualified_name)
|
170
|
+
@framework_tag = :test_unit if attached_ancestors.include?("Test::Unit::TestCase")
|
58
171
|
|
172
|
+
if @framework_tag == :test_unit || non_declarative_minitest?(attached_ancestors, fully_qualified_name)
|
59
173
|
@response_builder.add(Requests::Support::TestItem.new(
|
60
174
|
fully_qualified_name,
|
61
175
|
fully_qualified_name,
|
62
176
|
@uri,
|
63
177
|
range_from_node(node),
|
178
|
+
tags: [@framework_tag],
|
64
179
|
))
|
65
180
|
end
|
66
181
|
|
67
182
|
@nesting << name
|
68
183
|
end
|
69
184
|
|
70
|
-
|
185
|
+
#: (Prism::ModuleNode node) -> void
|
71
186
|
def on_module_node_enter(node)
|
72
187
|
@visibility_stack << :public
|
73
188
|
|
@@ -77,19 +192,19 @@ module RubyLsp
|
|
77
192
|
@nesting << name
|
78
193
|
end
|
79
194
|
|
80
|
-
|
195
|
+
#: (Prism::ModuleNode node) -> void
|
81
196
|
def on_module_node_leave(node)
|
82
197
|
@visibility_stack.pop
|
83
198
|
@nesting.pop
|
84
199
|
end
|
85
200
|
|
86
|
-
|
201
|
+
#: (Prism::ClassNode node) -> void
|
87
202
|
def on_class_node_leave(node)
|
88
203
|
@visibility_stack.pop
|
89
204
|
@nesting.pop
|
90
205
|
end
|
91
206
|
|
92
|
-
|
207
|
+
#: (Prism::DefNode node) -> void
|
93
208
|
def on_def_node_enter(node)
|
94
209
|
return if @visibility_stack.last != :public
|
95
210
|
|
@@ -109,10 +224,11 @@ module RubyLsp
|
|
109
224
|
name,
|
110
225
|
@uri,
|
111
226
|
range_from_node(node),
|
227
|
+
tags: [@framework_tag],
|
112
228
|
))
|
113
229
|
end
|
114
230
|
|
115
|
-
|
231
|
+
#: (Prism::CallNode node) -> void
|
116
232
|
def on_call_node_enter(node)
|
117
233
|
name = node.name
|
118
234
|
return unless ACCESS_MODIFIERS.include?(name)
|
@@ -120,7 +236,7 @@ module RubyLsp
|
|
120
236
|
@visibility_stack << name
|
121
237
|
end
|
122
238
|
|
123
|
-
|
239
|
+
#: (Prism::CallNode node) -> void
|
124
240
|
def on_call_node_leave(node)
|
125
241
|
name = node.name
|
126
242
|
return unless ACCESS_MODIFIERS.include?(name)
|
@@ -131,7 +247,7 @@ module RubyLsp
|
|
131
247
|
|
132
248
|
private
|
133
249
|
|
134
|
-
|
250
|
+
#: (Array[String] attached_ancestors, String fully_qualified_name) -> bool
|
135
251
|
def non_declarative_minitest?(attached_ancestors, fully_qualified_name)
|
136
252
|
return false unless attached_ancestors.include?("Minitest::Test")
|
137
253
|
|
@@ -144,17 +260,7 @@ module RubyLsp
|
|
144
260
|
true
|
145
261
|
end
|
146
262
|
|
147
|
-
|
148
|
-
params(
|
149
|
-
node: T.any(
|
150
|
-
Prism::ConstantPathNode,
|
151
|
-
Prism::ConstantReadNode,
|
152
|
-
Prism::ConstantPathTargetNode,
|
153
|
-
Prism::CallNode,
|
154
|
-
Prism::MissingNode,
|
155
|
-
),
|
156
|
-
).returns(String)
|
157
|
-
end
|
263
|
+
#: ((Prism::ConstantPathNode | Prism::ConstantReadNode | Prism::ConstantPathTargetNode | Prism::CallNode | Prism::MissingNode) node) -> String
|
158
264
|
def name_with_dynamic_reference(node)
|
159
265
|
slice = node.slice
|
160
266
|
slice.gsub(/((?<=::)|^)[a-z]\w*/, DYNAMIC_REFERENCE_MARKER)
|
@@ -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
|
@@ -46,12 +29,12 @@ module RubyLsp
|
|
46
29
|
@surrounding_method = T.let(surrounding_method, T.nilable(String))
|
47
30
|
end
|
48
31
|
|
49
|
-
|
32
|
+
#: -> String
|
50
33
|
def fully_qualified_name
|
51
34
|
@fully_qualified_name ||= T.let(@nesting.join("::"), T.nilable(String))
|
52
35
|
end
|
53
36
|
|
54
|
-
|
37
|
+
#: -> Array[Symbol]
|
55
38
|
def locals_for_scope
|
56
39
|
locals = []
|
57
40
|
|
@@ -69,17 +52,7 @@ 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
58
|
surrounding_method = T.let(nil, T.nilable(String))
|
@@ -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
12
|
@syntax_error = T.let(false, T::Boolean)
|
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
|
|