ruby-lsp 0.12.5 → 0.13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp-check +20 -4
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +36 -2
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +132 -13
- data/lib/ruby_indexer/test/configuration_test.rb +10 -0
- data/lib/ruby_indexer/test/index_test.rb +11 -0
- data/lib/ruby_indexer/test/method_test.rb +202 -0
- data/lib/ruby_lsp/addon.rb +9 -13
- data/lib/ruby_lsp/document.rb +3 -0
- data/lib/ruby_lsp/executor.rb +33 -28
- data/lib/ruby_lsp/listener.rb +4 -5
- data/lib/ruby_lsp/requests/code_actions.rb +2 -16
- data/lib/ruby_lsp/requests/code_lens.rb +29 -7
- data/lib/ruby_lsp/requests/completion.rb +11 -8
- data/lib/ruby_lsp/requests/definition.rb +3 -4
- data/lib/ruby_lsp/requests/diagnostics.rb +0 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +2 -3
- data/lib/ruby_lsp/requests/document_link.rb +2 -3
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/folding_ranges.rb +12 -15
- data/lib/ruby_lsp/requests/formatting.rb +0 -5
- data/lib/ruby_lsp/requests/hover.rb +3 -4
- data/lib/ruby_lsp/requests/inlay_hints.rb +20 -3
- data/lib/ruby_lsp/requests/on_type_formatting.rb +31 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +28 -11
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +92 -21
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +1 -1
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +3 -8
- data/lib/ruby_lsp/requests/workspace_symbol.rb +2 -0
- data/lib/ruby_lsp/store.rb +21 -0
- data/lib/ruby_lsp/utils.rb +18 -4
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 78df9c8d35fc18cea6fc06a0f679b48b69e3daaaf504d762d2f5ae4df9d99ad0
|
4
|
+
data.tar.gz: 3c251eed7939e81c5aa115d303b2876d3769c509ef0487b0faa26d1a2de79c50
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af33b81309429318e7fe61dc4a2bd989328b8e9127097ab621eab162e61e1b2d93f1be1b192307d3b48f47659489343e093d92125e9c68895c40517803dba5ed
|
7
|
+
data.tar.gz: 6373eb77209eb865e29026fba603f4db8d3249949bcff7c0aee3f550569a7225c84b76d5872fd61a8798c0ef04da2d538b50b4d3045697ef40cc85336a2c715b
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.13.1
|
data/exe/ruby-lsp-check
CHANGED
@@ -17,8 +17,6 @@ end
|
|
17
17
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
18
18
|
require "ruby_lsp/internal"
|
19
19
|
|
20
|
-
RubyLsp::Addon.load_addons
|
21
|
-
|
22
20
|
T::Utils.run_all_sig_blocks
|
23
21
|
|
24
22
|
files = Dir.glob("#{Dir.pwd}/**/*.rb")
|
@@ -28,6 +26,7 @@ puts "Verifying that all automatic LSP requests execute successfully. This may t
|
|
28
26
|
errors = {}
|
29
27
|
store = RubyLsp::Store.new
|
30
28
|
message_queue = Thread::Queue.new
|
29
|
+
RubyLsp::Addon.load_addons(message_queue)
|
31
30
|
executor = RubyLsp::Executor.new(store, message_queue)
|
32
31
|
|
33
32
|
files.each_with_index do |file, index|
|
@@ -50,13 +49,30 @@ end
|
|
50
49
|
puts "\n"
|
51
50
|
message_queue.close
|
52
51
|
|
52
|
+
# Indexing
|
53
|
+
puts "Verifying that indexing executes successfully. This may take a while..."
|
54
|
+
|
55
|
+
index = RubyIndexer::Index.new
|
56
|
+
indexables = RubyIndexer.configuration.indexables
|
57
|
+
|
58
|
+
indexables.each_with_index do |indexable, i|
|
59
|
+
result = Prism.parse(File.read(indexable.full_path))
|
60
|
+
collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
|
61
|
+
collector.collect(result.value)
|
62
|
+
rescue => e
|
63
|
+
errors[indexable.full_path] = e
|
64
|
+
ensure
|
65
|
+
print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
|
66
|
+
end
|
67
|
+
puts "\n"
|
68
|
+
|
53
69
|
if errors.empty?
|
54
|
-
puts "All
|
70
|
+
puts "All operations completed successfully!"
|
55
71
|
exit
|
56
72
|
end
|
57
73
|
|
58
74
|
puts <<~ERRORS
|
59
|
-
Errors while executing
|
75
|
+
Errors while executing:
|
60
76
|
|
61
77
|
#{errors.map { |file, error| "#{file}: #{error.message}" }.join("\n")}
|
62
78
|
ERRORS
|
@@ -141,8 +141,18 @@ module RubyIndexer
|
|
141
141
|
|
142
142
|
sig { params(node: Prism::CallNode).void }
|
143
143
|
def handle_call_node(node)
|
144
|
-
message = node.
|
145
|
-
|
144
|
+
message = node.name
|
145
|
+
|
146
|
+
case message
|
147
|
+
when :private_constant
|
148
|
+
handle_private_constant(node)
|
149
|
+
when :attr_reader
|
150
|
+
handle_attribute(node, reader: true, writer: false)
|
151
|
+
when :attr_writer
|
152
|
+
handle_attribute(node, reader: false, writer: true)
|
153
|
+
when :attr_accessor
|
154
|
+
handle_attribute(node, reader: true, writer: true)
|
155
|
+
end
|
146
156
|
end
|
147
157
|
|
148
158
|
sig { params(node: Prism::DefNode).void }
|
@@ -312,5 +322,29 @@ module RubyIndexer
|
|
312
322
|
"#{@stack.join("::")}::#{name}"
|
313
323
|
end.delete_prefix("::")
|
314
324
|
end
|
325
|
+
|
326
|
+
sig { params(node: Prism::CallNode, reader: T::Boolean, writer: T::Boolean).void }
|
327
|
+
def handle_attribute(node, reader:, writer:)
|
328
|
+
arguments = node.arguments&.arguments
|
329
|
+
return unless arguments
|
330
|
+
|
331
|
+
receiver = node.receiver
|
332
|
+
return unless receiver.nil? || receiver.is_a?(Prism::SelfNode)
|
333
|
+
|
334
|
+
comments = collect_comments(node)
|
335
|
+
arguments.each do |argument|
|
336
|
+
name, loc = case argument
|
337
|
+
when Prism::SymbolNode
|
338
|
+
[argument.value, argument.value_loc]
|
339
|
+
when Prism::StringNode
|
340
|
+
[argument.content, argument.content_loc]
|
341
|
+
end
|
342
|
+
|
343
|
+
next unless name && loc
|
344
|
+
|
345
|
+
@index << Entry::Accessor.new(name, @file_path, loc, comments, @current_owner) if reader
|
346
|
+
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @current_owner) if writer
|
347
|
+
end
|
348
|
+
end
|
315
349
|
end
|
316
350
|
end
|
@@ -120,7 +120,7 @@ module RubyIndexer
|
|
120
120
|
IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
|
121
121
|
end,
|
122
122
|
)
|
123
|
-
|
123
|
+
elsif pathname.extname == ".rb"
|
124
124
|
# If the default_path is a Ruby file, we index it
|
125
125
|
indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
|
126
126
|
end
|
@@ -90,20 +90,84 @@ module RubyIndexer
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
+
# A required method parameter, e.g. `def foo(a)`
|
93
94
|
class RequiredParameter < Parameter
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
|
+
# An optional method parameter, e.g. `def foo(a = 123)`
|
98
|
+
class OptionalParameter < Parameter
|
99
|
+
end
|
100
|
+
|
101
|
+
# An required keyword method parameter, e.g. `def foo(a:)`
|
102
|
+
class KeywordParameter < Parameter
|
103
|
+
end
|
104
|
+
|
105
|
+
# An optional keyword method parameter, e.g. `def foo(a: 123)`
|
106
|
+
class OptionalKeywordParameter < Parameter
|
107
|
+
end
|
108
|
+
|
109
|
+
# A rest method parameter, e.g. `def foo(*a)`
|
110
|
+
class RestParameter < Parameter
|
111
|
+
DEFAULT_NAME = T.let(:"<anonymous splat>", Symbol)
|
112
|
+
end
|
113
|
+
|
114
|
+
# A keyword rest method parameter, e.g. `def foo(**a)`
|
115
|
+
class KeywordRestParameter < Parameter
|
116
|
+
DEFAULT_NAME = T.let(:"<anonymous keyword splat>", Symbol)
|
117
|
+
end
|
118
|
+
|
119
|
+
# A block method parameter, e.g. `def foo(&block)`
|
120
|
+
class BlockParameter < Parameter
|
121
|
+
DEFAULT_NAME = T.let(:"<anonymous block>", Symbol)
|
122
|
+
end
|
123
|
+
|
124
|
+
class Member < Entry
|
97
125
|
extend T::Sig
|
98
126
|
extend T::Helpers
|
99
|
-
abstract!
|
100
127
|
|
101
|
-
|
102
|
-
attr_reader :parameters
|
128
|
+
abstract!
|
103
129
|
|
104
130
|
sig { returns(T.nilable(Entry::Namespace)) }
|
105
131
|
attr_reader :owner
|
106
132
|
|
133
|
+
sig do
|
134
|
+
params(
|
135
|
+
name: String,
|
136
|
+
file_path: String,
|
137
|
+
location: Prism::Location,
|
138
|
+
comments: T::Array[String],
|
139
|
+
owner: T.nilable(Entry::Namespace),
|
140
|
+
).void
|
141
|
+
end
|
142
|
+
def initialize(name, file_path, location, comments, owner)
|
143
|
+
super(name, file_path, location, comments)
|
144
|
+
@owner = owner
|
145
|
+
end
|
146
|
+
|
147
|
+
sig { abstract.returns(T::Array[Parameter]) }
|
148
|
+
def parameters; end
|
149
|
+
end
|
150
|
+
|
151
|
+
class Accessor < Member
|
152
|
+
extend T::Sig
|
153
|
+
|
154
|
+
sig { override.returns(T::Array[Parameter]) }
|
155
|
+
def parameters
|
156
|
+
params = []
|
157
|
+
params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
|
158
|
+
params
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
class Method < Member
|
163
|
+
extend T::Sig
|
164
|
+
extend T::Helpers
|
165
|
+
|
166
|
+
abstract!
|
167
|
+
|
168
|
+
sig { override.returns(T::Array[Parameter]) }
|
169
|
+
attr_reader :parameters
|
170
|
+
|
107
171
|
sig do
|
108
172
|
params(
|
109
173
|
name: String,
|
@@ -115,9 +179,9 @@ module RubyIndexer
|
|
115
179
|
).void
|
116
180
|
end
|
117
181
|
def initialize(name, file_path, location, comments, parameters_node, owner) # rubocop:disable Metrics/ParameterLists
|
118
|
-
super(name, file_path, location, comments)
|
182
|
+
super(name, file_path, location, comments, owner)
|
183
|
+
|
119
184
|
@parameters = T.let(list_params(parameters_node), T::Array[Parameter])
|
120
|
-
@owner = owner
|
121
185
|
end
|
122
186
|
|
123
187
|
private
|
@@ -126,23 +190,78 @@ module RubyIndexer
|
|
126
190
|
def list_params(parameters_node)
|
127
191
|
return [] unless parameters_node
|
128
192
|
|
129
|
-
|
193
|
+
parameters = []
|
194
|
+
|
195
|
+
parameters_node.requireds.each do |required|
|
130
196
|
name = parameter_name(required)
|
131
197
|
next unless name
|
132
198
|
|
133
|
-
RequiredParameter.new(name: name)
|
199
|
+
parameters << RequiredParameter.new(name: name)
|
134
200
|
end
|
135
|
-
end
|
136
201
|
|
137
|
-
|
138
|
-
|
202
|
+
parameters_node.optionals.each do |optional|
|
203
|
+
name = parameter_name(optional)
|
204
|
+
next unless name
|
205
|
+
|
206
|
+
parameters << OptionalParameter.new(name: name)
|
207
|
+
end
|
208
|
+
|
209
|
+
parameters_node.keywords.each do |keyword|
|
210
|
+
name = parameter_name(keyword)
|
211
|
+
next unless name
|
212
|
+
|
213
|
+
case keyword
|
214
|
+
when Prism::RequiredKeywordParameterNode
|
215
|
+
parameters << KeywordParameter.new(name: name)
|
216
|
+
when Prism::OptionalKeywordParameterNode
|
217
|
+
parameters << OptionalKeywordParameter.new(name: name)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
rest = parameters_node.rest
|
222
|
+
|
223
|
+
if rest
|
224
|
+
rest_name = rest.name || RestParameter::DEFAULT_NAME
|
225
|
+
parameters << RestParameter.new(name: rest_name)
|
226
|
+
end
|
227
|
+
|
228
|
+
keyword_rest = parameters_node.keyword_rest
|
229
|
+
|
230
|
+
if keyword_rest.is_a?(Prism::KeywordRestParameterNode)
|
231
|
+
keyword_rest_name = parameter_name(keyword_rest) || KeywordRestParameter::DEFAULT_NAME
|
232
|
+
parameters << KeywordRestParameter.new(name: keyword_rest_name)
|
233
|
+
end
|
234
|
+
|
235
|
+
parameters_node.posts.each do |post|
|
236
|
+
name = parameter_name(post)
|
237
|
+
next unless name
|
238
|
+
|
239
|
+
parameters << RequiredParameter.new(name: name)
|
240
|
+
end
|
241
|
+
|
242
|
+
block = parameters_node.block
|
243
|
+
parameters << BlockParameter.new(name: block.name || BlockParameter::DEFAULT_NAME) if block
|
244
|
+
|
245
|
+
parameters
|
139
246
|
end
|
247
|
+
|
248
|
+
sig { params(node: T.nilable(Prism::Node)).returns(T.nilable(Symbol)) }
|
140
249
|
def parameter_name(node)
|
141
250
|
case node
|
142
|
-
when Prism::RequiredParameterNode
|
251
|
+
when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
|
252
|
+
Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode,
|
253
|
+
Prism::RestParameterNode, Prism::KeywordRestParameterNode
|
143
254
|
node.name
|
144
255
|
when Prism::MultiTargetNode
|
145
|
-
names =
|
256
|
+
names = node.lefts.map { |parameter_node| parameter_name(parameter_node) }
|
257
|
+
|
258
|
+
rest = node.rest
|
259
|
+
if rest.is_a?(Prism::SplatNode)
|
260
|
+
name = rest.expression&.slice
|
261
|
+
names << (rest.operator == "*" ? "*#{name}".to_sym : name&.to_sym)
|
262
|
+
end
|
263
|
+
|
264
|
+
names.concat(node.rights.map { |parameter_node| parameter_name(parameter_node) })
|
146
265
|
|
147
266
|
names_with_commas = names.join(", ")
|
148
267
|
:"(#{names_with_commas})"
|
@@ -84,6 +84,16 @@ module RubyIndexer
|
|
84
84
|
)
|
85
85
|
end
|
86
86
|
|
87
|
+
def test_indexables_does_not_include_non_ruby_files_inside_rubylibdir
|
88
|
+
path = Pathname.new(RbConfig::CONFIG["rubylibdir"]).join("extra_file.txt").to_s
|
89
|
+
FileUtils.touch(path)
|
90
|
+
indexables = @config.indexables
|
91
|
+
|
92
|
+
assert(indexables.none? { |indexable| indexable.full_path == path })
|
93
|
+
ensure
|
94
|
+
FileUtils.rm(T.must(path))
|
95
|
+
end
|
96
|
+
|
87
97
|
def test_paths_are_unique
|
88
98
|
@config.load_config
|
89
99
|
indexables = @config.indexables
|
@@ -246,5 +246,16 @@ module RubyIndexer
|
|
246
246
|
entry = T.must(entries.first).first
|
247
247
|
assert_equal("baz", entry.name)
|
248
248
|
end
|
249
|
+
|
250
|
+
def test_indexing_prism_fixtures_succeeds
|
251
|
+
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
252
|
+
|
253
|
+
fixtures.each do |fixture|
|
254
|
+
indexable_path = IndexablePath.new("", fixture)
|
255
|
+
@index.index_single(indexable_path)
|
256
|
+
end
|
257
|
+
|
258
|
+
refute_empty(@index.instance_variable_get(:@entries))
|
259
|
+
end
|
249
260
|
end
|
250
261
|
end
|
@@ -70,6 +70,178 @@ module RubyIndexer
|
|
70
70
|
assert_instance_of(Entry::RequiredParameter, parameter)
|
71
71
|
end
|
72
72
|
|
73
|
+
def test_method_with_optional_parameters
|
74
|
+
index(<<~RUBY)
|
75
|
+
class Foo
|
76
|
+
def bar(a = 123)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
82
|
+
entry = T.must(@index["bar"].first)
|
83
|
+
assert_equal(1, entry.parameters.length)
|
84
|
+
parameter = entry.parameters.first
|
85
|
+
assert_equal(:a, parameter.name)
|
86
|
+
assert_instance_of(Entry::OptionalParameter, parameter)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_method_with_keyword_parameters
|
90
|
+
index(<<~RUBY)
|
91
|
+
class Foo
|
92
|
+
def bar(a:, b: 123)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
RUBY
|
96
|
+
|
97
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
98
|
+
entry = T.must(@index["bar"].first)
|
99
|
+
assert_equal(2, entry.parameters.length)
|
100
|
+
a, b = entry.parameters
|
101
|
+
|
102
|
+
assert_equal(:a, a.name)
|
103
|
+
assert_instance_of(Entry::KeywordParameter, a)
|
104
|
+
|
105
|
+
assert_equal(:b, b.name)
|
106
|
+
assert_instance_of(Entry::OptionalKeywordParameter, b)
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_method_with_rest_and_keyword_rest_parameters
|
110
|
+
index(<<~RUBY)
|
111
|
+
class Foo
|
112
|
+
def bar(*a, **b)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
116
|
+
|
117
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
118
|
+
entry = T.must(@index["bar"].first)
|
119
|
+
assert_equal(2, entry.parameters.length)
|
120
|
+
a, b = entry.parameters
|
121
|
+
|
122
|
+
assert_equal(:a, a.name)
|
123
|
+
assert_instance_of(Entry::RestParameter, a)
|
124
|
+
|
125
|
+
assert_equal(:b, b.name)
|
126
|
+
assert_instance_of(Entry::KeywordRestParameter, b)
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_method_with_post_parameters
|
130
|
+
index(<<~RUBY)
|
131
|
+
class Foo
|
132
|
+
def bar(*a, b)
|
133
|
+
end
|
134
|
+
|
135
|
+
def baz(**a, b)
|
136
|
+
end
|
137
|
+
|
138
|
+
def qux(*a, (b, c))
|
139
|
+
end
|
140
|
+
RUBY
|
141
|
+
|
142
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
143
|
+
entry = T.must(@index["bar"].first)
|
144
|
+
assert_equal(2, entry.parameters.length)
|
145
|
+
a, b = entry.parameters
|
146
|
+
|
147
|
+
assert_equal(:a, a.name)
|
148
|
+
assert_instance_of(Entry::RestParameter, a)
|
149
|
+
|
150
|
+
assert_equal(:b, b.name)
|
151
|
+
assert_instance_of(Entry::RequiredParameter, b)
|
152
|
+
|
153
|
+
entry = T.must(@index["baz"].first)
|
154
|
+
assert_equal(2, entry.parameters.length)
|
155
|
+
a, b = entry.parameters
|
156
|
+
|
157
|
+
assert_equal(:a, a.name)
|
158
|
+
assert_instance_of(Entry::KeywordRestParameter, a)
|
159
|
+
|
160
|
+
assert_equal(:b, b.name)
|
161
|
+
assert_instance_of(Entry::RequiredParameter, b)
|
162
|
+
|
163
|
+
entry = T.must(@index["qux"].first)
|
164
|
+
assert_equal(2, entry.parameters.length)
|
165
|
+
_a, second = entry.parameters
|
166
|
+
|
167
|
+
assert_equal(:"(b, c)", second.name)
|
168
|
+
assert_instance_of(Entry::RequiredParameter, second)
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_method_with_destructured_rest_parameters
|
172
|
+
index(<<~RUBY)
|
173
|
+
class Foo
|
174
|
+
def bar((a, *b))
|
175
|
+
end
|
176
|
+
end
|
177
|
+
RUBY
|
178
|
+
|
179
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
180
|
+
entry = T.must(@index["bar"].first)
|
181
|
+
assert_equal(1, entry.parameters.length)
|
182
|
+
param = entry.parameters.first
|
183
|
+
|
184
|
+
assert_equal(:"(a, *b)", param.name)
|
185
|
+
assert_instance_of(Entry::RequiredParameter, param)
|
186
|
+
end
|
187
|
+
|
188
|
+
def test_method_with_block_parameters
|
189
|
+
index(<<~RUBY)
|
190
|
+
class Foo
|
191
|
+
def bar(&block)
|
192
|
+
end
|
193
|
+
|
194
|
+
def baz(&)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
RUBY
|
198
|
+
|
199
|
+
entry = T.must(@index["bar"].first)
|
200
|
+
param = entry.parameters.first
|
201
|
+
assert_equal(:block, param.name)
|
202
|
+
assert_instance_of(Entry::BlockParameter, param)
|
203
|
+
|
204
|
+
entry = T.must(@index["baz"].first)
|
205
|
+
assert_equal(1, entry.parameters.length)
|
206
|
+
|
207
|
+
param = entry.parameters.first
|
208
|
+
assert_equal(Entry::BlockParameter::DEFAULT_NAME, param.name)
|
209
|
+
assert_instance_of(Entry::BlockParameter, param)
|
210
|
+
end
|
211
|
+
|
212
|
+
def test_method_with_anonymous_rest_parameters
|
213
|
+
index(<<~RUBY)
|
214
|
+
class Foo
|
215
|
+
def bar(*, **)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
RUBY
|
219
|
+
|
220
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
221
|
+
entry = T.must(@index["bar"].first)
|
222
|
+
assert_equal(2, entry.parameters.length)
|
223
|
+
first, second = entry.parameters
|
224
|
+
|
225
|
+
assert_equal(Entry::RestParameter::DEFAULT_NAME, first.name)
|
226
|
+
assert_instance_of(Entry::RestParameter, first)
|
227
|
+
|
228
|
+
assert_equal(Entry::KeywordRestParameter::DEFAULT_NAME, second.name)
|
229
|
+
assert_instance_of(Entry::KeywordRestParameter, second)
|
230
|
+
end
|
231
|
+
|
232
|
+
def test_method_with_forbidden_keyword_splat_parameter
|
233
|
+
index(<<~RUBY)
|
234
|
+
class Foo
|
235
|
+
def bar(**nil)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
RUBY
|
239
|
+
|
240
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
241
|
+
entry = T.must(@index["bar"].first)
|
242
|
+
assert_empty(entry.parameters)
|
243
|
+
end
|
244
|
+
|
73
245
|
def test_keeps_track_of_method_owner
|
74
246
|
index(<<~RUBY)
|
75
247
|
class Foo
|
@@ -83,5 +255,35 @@ module RubyIndexer
|
|
83
255
|
|
84
256
|
assert_equal("Foo", owner_name)
|
85
257
|
end
|
258
|
+
|
259
|
+
def test_keeps_track_of_attributes
|
260
|
+
index(<<~RUBY)
|
261
|
+
class Foo
|
262
|
+
# Hello there
|
263
|
+
attr_reader :bar, :other
|
264
|
+
attr_writer :baz
|
265
|
+
attr_accessor :qux
|
266
|
+
end
|
267
|
+
RUBY
|
268
|
+
|
269
|
+
assert_entry("bar", Entry::Accessor, "/fake/path/foo.rb:2-15:2-18")
|
270
|
+
assert_equal("Hello there", @index["bar"].first.comments.join("\n"))
|
271
|
+
assert_entry("other", Entry::Accessor, "/fake/path/foo.rb:2-21:2-26")
|
272
|
+
assert_equal("Hello there", @index["other"].first.comments.join("\n"))
|
273
|
+
assert_entry("baz=", Entry::Accessor, "/fake/path/foo.rb:3-15:3-18")
|
274
|
+
assert_entry("qux", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
275
|
+
assert_entry("qux=", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_ignores_attributes_invoked_on_constant
|
279
|
+
index(<<~RUBY)
|
280
|
+
class Foo
|
281
|
+
end
|
282
|
+
|
283
|
+
Foo.attr_reader :bar
|
284
|
+
RUBY
|
285
|
+
|
286
|
+
assert_no_entry("bar")
|
287
|
+
end
|
86
288
|
end
|
87
289
|
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -41,8 +41,8 @@ module RubyLsp
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Discovers and loads all addons. Returns the list of activated addons
|
44
|
-
sig { returns(T::Array[Addon]) }
|
45
|
-
def load_addons
|
44
|
+
sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
|
45
|
+
def load_addons(message_queue)
|
46
46
|
# Require all addons entry points, which should be placed under
|
47
47
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
|
48
48
|
Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
|
@@ -55,7 +55,7 @@ module RubyLsp
|
|
55
55
|
# Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
|
56
56
|
# fail to boot the server
|
57
57
|
addons.each do |addon|
|
58
|
-
addon.activate
|
58
|
+
addon.activate(message_queue)
|
59
59
|
nil
|
60
60
|
rescue => e
|
61
61
|
addon.add_error(e)
|
@@ -94,8 +94,8 @@ module RubyLsp
|
|
94
94
|
|
95
95
|
# Each addon should implement `MyAddon#activate` and use to perform any sort of initialization, such as
|
96
96
|
# reading information into memory or even spawning a separate process
|
97
|
-
sig { abstract.void }
|
98
|
-
def activate; end
|
97
|
+
sig { abstract.params(message_queue: Thread::Queue).void }
|
98
|
+
def activate(message_queue); end
|
99
99
|
|
100
100
|
# Each addon should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
|
101
101
|
# child process
|
@@ -111,10 +111,9 @@ module RubyLsp
|
|
111
111
|
overridable.params(
|
112
112
|
uri: URI::Generic,
|
113
113
|
dispatcher: Prism::Dispatcher,
|
114
|
-
message_queue: Thread::Queue,
|
115
114
|
).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
|
116
115
|
end
|
117
|
-
def create_code_lens_listener(uri, dispatcher
|
116
|
+
def create_code_lens_listener(uri, dispatcher); end
|
118
117
|
|
119
118
|
# Creates a new Hover listener. This method is invoked on every Hover request
|
120
119
|
sig do
|
@@ -122,19 +121,17 @@ module RubyLsp
|
|
122
121
|
nesting: T::Array[String],
|
123
122
|
index: RubyIndexer::Index,
|
124
123
|
dispatcher: Prism::Dispatcher,
|
125
|
-
message_queue: Thread::Queue,
|
126
124
|
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
|
127
125
|
end
|
128
|
-
def create_hover_listener(nesting, index, dispatcher
|
126
|
+
def create_hover_listener(nesting, index, dispatcher); end
|
129
127
|
|
130
128
|
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
|
131
129
|
sig do
|
132
130
|
overridable.params(
|
133
131
|
dispatcher: Prism::Dispatcher,
|
134
|
-
message_queue: Thread::Queue,
|
135
132
|
).returns(T.nilable(Listener[T::Array[Interface::DocumentSymbol]]))
|
136
133
|
end
|
137
|
-
def create_document_symbol_listener(dispatcher
|
134
|
+
def create_document_symbol_listener(dispatcher); end
|
138
135
|
|
139
136
|
# Creates a new Definition listener. This method is invoked on every Definition request
|
140
137
|
sig do
|
@@ -143,9 +140,8 @@ module RubyLsp
|
|
143
140
|
nesting: T::Array[String],
|
144
141
|
index: RubyIndexer::Index,
|
145
142
|
dispatcher: Prism::Dispatcher,
|
146
|
-
message_queue: Thread::Queue,
|
147
143
|
).returns(T.nilable(Listener[T.nilable(T.any(T::Array[Interface::Location], Interface::Location))]))
|
148
144
|
end
|
149
|
-
def create_definition_listener(uri, nesting, index, dispatcher
|
145
|
+
def create_definition_listener(uri, nesting, index, dispatcher); end
|
150
146
|
end
|
151
147
|
end
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -24,6 +24,9 @@ module RubyLsp
|
|
24
24
|
sig { returns(URI::Generic) }
|
25
25
|
attr_reader :uri
|
26
26
|
|
27
|
+
sig { returns(String) }
|
28
|
+
attr_reader :encoding
|
29
|
+
|
27
30
|
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: String).void }
|
28
31
|
def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)
|
29
32
|
@cache = T.let({}, T::Hash[String, T.untyped])
|