ruby-lsp 0.23.11 → 0.23.16
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 +20 -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 +82 -116
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +123 -169
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +9 -7
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +92 -202
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +116 -222
- data/lib/ruby_indexer/lib/ruby_indexer/location.rb +4 -27
- data/lib/ruby_indexer/lib/ruby_indexer/prefix_tree.rb +18 -19
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +22 -45
- data/lib/ruby_indexer/lib/ruby_indexer/reference_finder.rb +47 -61
- data/lib/ruby_indexer/lib/ruby_indexer/uri.rb +17 -19
- data/lib/ruby_indexer/lib/ruby_indexer/visibility_scope.rb +5 -9
- data/lib/ruby_indexer/test/class_variables_test.rb +14 -14
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +65 -40
- data/lib/ruby_indexer/test/configuration_test.rb +48 -7
- data/lib/ruby_indexer/test/constant_test.rb +34 -34
- data/lib/ruby_indexer/test/enhancements_test.rb +1 -1
- data/lib/ruby_indexer/test/index_test.rb +139 -135
- data/lib/ruby_indexer/test/instance_variables_test.rb +37 -37
- data/lib/ruby_indexer/test/method_test.rb +143 -117
- data/lib/ruby_indexer/test/prefix_tree_test.rb +13 -13
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +65 -71
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +15 -2
- data/lib/ruby_lsp/addon.rb +44 -71
- data/lib/ruby_lsp/base_server.rb +29 -32
- data/lib/ruby_lsp/client_capabilities.rb +10 -12
- data/lib/ruby_lsp/document.rb +39 -45
- data/lib/ruby_lsp/erb_document.rb +36 -40
- data/lib/ruby_lsp/global_state.rb +52 -57
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/code_lens.rb +82 -89
- data/lib/ruby_lsp/listeners/completion.rb +60 -66
- data/lib/ruby_lsp/listeners/definition.rb +38 -52
- data/lib/ruby_lsp/listeners/document_highlight.rb +123 -150
- data/lib/ruby_lsp/listeners/document_link.rb +46 -63
- 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 +83 -102
- data/lib/ruby_lsp/listeners/inlay_hints.rb +4 -11
- data/lib/ruby_lsp/listeners/semantic_highlighting.rb +54 -56
- data/lib/ruby_lsp/listeners/signature_help.rb +11 -26
- 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 +160 -88
- 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 +24 -25
- 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 +6 -6
- 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 +18 -5
- 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 +10 -20
- data/lib/ruby_lsp/requests/inlay_hints.rb +6 -17
- data/lib/ruby_lsp/requests/on_type_formatting.rb +32 -40
- data/lib/ruby_lsp/requests/prepare_rename.rb +4 -9
- 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 +8 -37
- data/lib/ruby_lsp/requests/rename.rb +19 -42
- data/lib/ruby_lsp/requests/request.rb +7 -19
- data/lib/ruby_lsp/requests/selection_ranges.rb +6 -6
- 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 +8 -26
- data/lib/ruby_lsp/requests/support/annotation.rb +4 -10
- data/lib/ruby_lsp/requests/support/common.rb +16 -51
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +27 -35
- data/lib/ruby_lsp/requests/support/rubocop_formatter.rb +11 -14
- 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 +20 -32
- data/lib/ruby_lsp/requests/support/syntax_tree_formatter.rb +12 -19
- data/lib/ruby_lsp/requests/support/test_item.rb +10 -14
- 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 +13 -18
- data/lib/ruby_lsp/response_builders/hover.rb +11 -14
- data/lib/ruby_lsp/response_builders/response_builder.rb +1 -1
- data/lib/ruby_lsp/response_builders/semantic_highlighting.rb +60 -88
- data/lib/ruby_lsp/response_builders/signature_help.rb +5 -6
- data/lib/ruby_lsp/response_builders/test_collection.rb +6 -10
- data/lib/ruby_lsp/ruby_document.rb +24 -62
- data/lib/ruby_lsp/scope.rb +7 -11
- data/lib/ruby_lsp/scripts/compose_bundle.rb +6 -4
- data/lib/ruby_lsp/server.rb +147 -79
- data/lib/ruby_lsp/setup_bundler.rb +65 -60
- data/lib/ruby_lsp/static_docs.rb +11 -7
- data/lib/ruby_lsp/store.rb +24 -42
- data/lib/ruby_lsp/test_helper.rb +2 -12
- data/lib/ruby_lsp/test_reporters/lsp_reporter.rb +164 -0
- data/lib/ruby_lsp/test_reporters/minitest_reporter.rb +105 -0
- data/lib/ruby_lsp/test_reporters/test_unit_reporter.rb +94 -0
- data/lib/ruby_lsp/type_inferrer.rb +13 -14
- data/lib/ruby_lsp/utils.rb +49 -83
- metadata +9 -3
@@ -6,16 +6,16 @@ require_relative "test_case"
|
|
6
6
|
module RubyIndexer
|
7
7
|
class RBSIndexerTest < TestCase
|
8
8
|
def test_index_core_classes
|
9
|
-
entries = @index["Array"]
|
9
|
+
entries = @index["Array"] #: as !nil
|
10
10
|
refute_nil(entries)
|
11
11
|
# Array is a class but also an instance method on Kernel
|
12
12
|
assert_equal(2, entries.length)
|
13
|
-
entry = entries.find { |entry| entry.is_a?(
|
13
|
+
entry = entries.find { |entry| entry.is_a?(Entry::Class) } #: as Entry::Class
|
14
14
|
assert_match(%r{/gems/rbs-.*/core/array.rbs}, entry.file_path)
|
15
15
|
assert_equal("array.rbs", entry.file_name)
|
16
16
|
assert_equal("Object", entry.parent_class)
|
17
17
|
assert_equal(1, entry.mixin_operations.length)
|
18
|
-
enumerable_include = entry.mixin_operations.first
|
18
|
+
enumerable_include = entry.mixin_operations.first #: as !nil
|
19
19
|
assert_equal("Enumerable", enumerable_include.module_name)
|
20
20
|
|
21
21
|
# Using fixed positions would be fragile, so let's just check some basics.
|
@@ -26,10 +26,10 @@ module RubyIndexer
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_index_core_modules
|
29
|
-
entries = @index["Kernel"]
|
29
|
+
entries = @index["Kernel"] #: as !nil
|
30
30
|
refute_nil(entries)
|
31
31
|
assert_equal(1, entries.length)
|
32
|
-
entry = entries.first
|
32
|
+
entry = entries.first #: as Entry::Module
|
33
33
|
assert_match(%r{/gems/rbs-.*/core/kernel.rbs}, entry.file_path)
|
34
34
|
assert_equal("kernel.rbs", entry.file_name)
|
35
35
|
|
@@ -41,30 +41,23 @@ module RubyIndexer
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def test_index_core_constants
|
44
|
-
entries = @index["RUBY_VERSION"]
|
44
|
+
entries = @index["RUBY_VERSION"] #: as !nil
|
45
45
|
refute_nil(entries)
|
46
46
|
assert_equal(1, entries.length)
|
47
47
|
|
48
|
-
|
49
|
-
entries = @index["Complex::I"]
|
48
|
+
entries = @index["Complex::I"] #: as !nil
|
50
49
|
refute_nil(entries)
|
51
50
|
assert_equal(1, entries.length)
|
52
51
|
|
53
|
-
|
54
|
-
# ```
|
55
|
-
# module Encoding
|
56
|
-
# US_ASCII = ...
|
57
|
-
# ...
|
58
|
-
# ````
|
59
|
-
entries = @index["Encoding::US_ASCII"]
|
52
|
+
entries = @index["Encoding::US_ASCII"] #: as !nil
|
60
53
|
refute_nil(entries)
|
61
54
|
assert_equal(1, entries.length)
|
62
55
|
end
|
63
56
|
|
64
57
|
def test_index_methods
|
65
|
-
entries = @index["initialize"]
|
58
|
+
entries = @index["initialize"] #: as Array[Entry::Method]
|
66
59
|
refute_nil(entries)
|
67
|
-
entry = entries.find { |entry| entry.owner
|
60
|
+
entry = entries.find { |entry| entry.owner&.name == "Array" } #: as Entry::Method
|
68
61
|
assert_match(%r{/gems/rbs-.*/core/array.rbs}, entry.file_path)
|
69
62
|
assert_equal("array.rbs", entry.file_name)
|
70
63
|
assert_equal(Entry::Visibility::PUBLIC, entry.visibility)
|
@@ -77,11 +70,11 @@ module RubyIndexer
|
|
77
70
|
end
|
78
71
|
|
79
72
|
def test_index_global_declaration
|
80
|
-
entries = @index["$DEBUG"]
|
73
|
+
entries = @index["$DEBUG"] #: as Array[Entry::GlobalVariable]
|
81
74
|
refute_nil(entries)
|
82
75
|
assert_equal(1, entries.length)
|
83
76
|
|
84
|
-
entry = entries.first
|
77
|
+
entry = entries.first #: as Entry::GlobalVariable
|
85
78
|
|
86
79
|
assert_instance_of(Entry::GlobalVariable, entry)
|
87
80
|
assert_equal("$DEBUG", entry.name)
|
@@ -91,10 +84,10 @@ module RubyIndexer
|
|
91
84
|
end
|
92
85
|
|
93
86
|
def test_attaches_correct_owner_to_singleton_methods
|
94
|
-
entries = @index["basename"]
|
87
|
+
entries = @index["basename"] #: as Array[Entry::Method]
|
95
88
|
refute_nil(entries)
|
96
89
|
|
97
|
-
owner = entries.first
|
90
|
+
owner = entries.first&.owner #: as Entry::SingletonClass
|
98
91
|
assert_instance_of(Entry::SingletonClass, owner)
|
99
92
|
assert_equal("File::<Class:File>", owner.name)
|
100
93
|
end
|
@@ -103,47 +96,47 @@ module RubyIndexer
|
|
103
96
|
# NOTE: RBS does not store the name location for classes, modules or methods. This behavior is not exactly what
|
104
97
|
# we would like, but for now we assign the same location to both
|
105
98
|
|
106
|
-
entries = @index["Array"]
|
99
|
+
entries = @index["Array"] #: as Array[Entry::Class]
|
107
100
|
refute_nil(entries)
|
108
|
-
entry = entries.find { |entry| entry.is_a?(Entry::Class) }
|
101
|
+
entry = entries.find { |entry| entry.is_a?(Entry::Class) } #: as Entry::Class
|
109
102
|
|
110
103
|
assert_same(entry.location, entry.name_location)
|
111
104
|
end
|
112
105
|
|
113
106
|
def test_rbs_method_with_required_positionals
|
114
|
-
entries = @index["crypt"]
|
107
|
+
entries = @index["crypt"] #: as Array[Entry::Method]
|
115
108
|
assert_equal(1, entries.length)
|
116
109
|
|
117
|
-
entry = entries.first
|
110
|
+
entry = entries.first #: as Entry::Method
|
118
111
|
signatures = entry.signatures
|
119
112
|
assert_equal(1, signatures.length)
|
120
113
|
|
121
|
-
first_signature = signatures.first
|
114
|
+
first_signature = signatures.first #: as Entry::Signature
|
122
115
|
|
123
116
|
# (::string salt_str) -> ::String
|
124
117
|
|
125
118
|
assert_equal(1, first_signature.parameters.length)
|
126
119
|
assert_kind_of(Entry::RequiredParameter, first_signature.parameters[0])
|
127
|
-
assert_equal(:salt_str, first_signature.parameters[0]
|
120
|
+
assert_equal(:salt_str, first_signature.parameters[0]&.name)
|
128
121
|
end
|
129
122
|
|
130
123
|
def test_rbs_method_with_unnamed_required_positionals
|
131
|
-
entries = @index["try_convert"]
|
132
|
-
entry = entries.find { |entry| entry.owner
|
124
|
+
entries = @index["try_convert"] #: as Array[Entry::Method]
|
125
|
+
entry = entries.find { |entry| entry.owner&.name == "Array::<Class:Array>" } #: as Entry::Method
|
133
126
|
|
134
|
-
parameters = entry.signatures[0]
|
127
|
+
parameters = entry.signatures[0]&.parameters #: as Array[Entry::Parameter]
|
135
128
|
|
136
129
|
assert_equal([:arg0], parameters.map(&:name))
|
137
130
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
138
131
|
end
|
139
132
|
|
140
133
|
def test_rbs_method_with_optional_positionals
|
141
|
-
entries = @index["polar"]
|
142
|
-
entry = entries.find { |entry| entry.owner
|
134
|
+
entries = @index["polar"] #: as Array[Entry::Method]
|
135
|
+
entry = entries.find { |entry| entry.owner&.name == "Complex::<Class:Complex>" } #: as Entry::Method
|
143
136
|
|
144
137
|
# def self.polar: (Numeric, ?Numeric) -> Complex
|
145
138
|
|
146
|
-
parameters = entry.signatures[0]
|
139
|
+
parameters = entry.signatures[0]&.parameters #: as Array[Entry::Parameter]
|
147
140
|
|
148
141
|
assert_equal([:arg0, :arg1], parameters.map(&:name))
|
149
142
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
@@ -151,27 +144,27 @@ module RubyIndexer
|
|
151
144
|
end
|
152
145
|
|
153
146
|
def test_rbs_method_with_optional_parameter
|
154
|
-
entries = @index["chomp"]
|
147
|
+
entries = @index["chomp"] #: as Array[Entry::Method]
|
155
148
|
assert_equal(1, entries.length)
|
156
149
|
|
157
|
-
entry = entries.first
|
150
|
+
entry = entries.first #: as Entry::Method
|
158
151
|
signatures = entry.signatures
|
159
152
|
assert_equal(1, signatures.length)
|
160
153
|
|
161
|
-
first_signature = signatures.first
|
154
|
+
first_signature = signatures.first #: as Entry::Signature
|
162
155
|
|
163
156
|
# (?::string? separator) -> ::String
|
164
157
|
|
165
158
|
assert_equal(1, first_signature.parameters.length)
|
166
159
|
assert_kind_of(Entry::OptionalParameter, first_signature.parameters[0])
|
167
|
-
assert_equal(:separator, first_signature.parameters[0]
|
160
|
+
assert_equal(:separator, first_signature.parameters[0]&.name)
|
168
161
|
end
|
169
162
|
|
170
163
|
def test_rbs_method_with_required_and_optional_parameters
|
171
|
-
entries = @index["gsub"]
|
164
|
+
entries = @index["gsub"] #: as Array[Entry::Method]
|
172
165
|
assert_equal(1, entries.length)
|
173
166
|
|
174
|
-
entry = entries.first
|
167
|
+
entry = entries.first #: as Entry::Method
|
175
168
|
|
176
169
|
signatures = entry.signatures
|
177
170
|
assert_equal(3, signatures.length)
|
@@ -180,37 +173,37 @@ module RubyIndexer
|
|
180
173
|
# | (::Regexp | ::string pattern) -> ::Enumerator[::String, ::String]
|
181
174
|
# | (::Regexp | ::string pattern) { (::String match) -> ::_ToS } -> ::String
|
182
175
|
|
183
|
-
parameters = signatures[0]
|
176
|
+
parameters = signatures[0]&.parameters #: as !nil
|
184
177
|
assert_equal([:pattern, :replacement], parameters.map(&:name))
|
185
178
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
186
179
|
assert_kind_of(Entry::RequiredParameter, parameters[1])
|
187
180
|
|
188
|
-
parameters = signatures[1]
|
181
|
+
parameters = signatures[1]&.parameters #: as !nil
|
189
182
|
assert_equal([:pattern], parameters.map(&:name))
|
190
183
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
191
184
|
|
192
|
-
parameters = signatures[2]
|
185
|
+
parameters = signatures[2]&.parameters #: as !nil
|
193
186
|
assert_equal([:pattern, :"<anonymous block>"], parameters.map(&:name))
|
194
187
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
195
188
|
assert_kind_of(Entry::BlockParameter, parameters[1])
|
196
189
|
end
|
197
190
|
|
198
191
|
def test_rbs_anonymous_block_parameter
|
199
|
-
entries = @index["open"]
|
200
|
-
entry = entries.find { |entry| entry.owner
|
192
|
+
entries = @index["open"] #: as Array[Entry::Method]
|
193
|
+
entry = entries.find { |entry| entry.owner&.name == "File::<Class:File>" } #: as Entry::Method
|
201
194
|
|
202
195
|
assert_equal(2, entry.signatures.length)
|
203
196
|
|
204
197
|
# (::String name, ?::String mode, ?::Integer perm) -> ::IO?
|
205
198
|
# | [T] (::String name, ?::String mode, ?::Integer perm) { (::IO) -> T } -> T
|
206
199
|
|
207
|
-
parameters = entry.signatures[0]
|
200
|
+
parameters = entry.signatures[0]&.parameters #: as !nil
|
208
201
|
assert_equal([:file_name, :mode, :perm], parameters.map(&:name))
|
209
202
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
210
203
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
211
204
|
assert_kind_of(Entry::OptionalParameter, parameters[2])
|
212
205
|
|
213
|
-
parameters = entry.signatures[1]
|
206
|
+
parameters = entry.signatures[1]&.parameters #: as !nil
|
214
207
|
assert_equal([:file_name, :mode, :perm, :"<anonymous block>"], parameters.map(&:name))
|
215
208
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
216
209
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
@@ -219,10 +212,10 @@ module RubyIndexer
|
|
219
212
|
end
|
220
213
|
|
221
214
|
def test_rbs_method_with_rest_positionals
|
222
|
-
entries = @index["count"]
|
223
|
-
entry = entries.find { |entry| entry.owner
|
215
|
+
entries = @index["count"] #: as Array[Entry::Method]
|
216
|
+
entry = entries.find { |entry| entry.owner&.name == "String" } #: as Entry::Method
|
224
217
|
|
225
|
-
parameters = entry.signatures.first
|
218
|
+
parameters = entry.signatures.first&.parameters #: as !nil
|
226
219
|
assert_equal(1, entry.signatures.length)
|
227
220
|
|
228
221
|
# (::String::selector selector_0, *::String::selector more_selectors) -> ::Integer
|
@@ -233,8 +226,8 @@ module RubyIndexer
|
|
233
226
|
end
|
234
227
|
|
235
228
|
def test_rbs_method_with_trailing_positionals
|
236
|
-
entries = @index["select"]
|
237
|
-
entry = entries.find { |entry| entry.owner
|
229
|
+
entries = @index["select"] #: as Array[Entry::Method]
|
230
|
+
entry = entries.find { |entry| entry.owner&.name == "IO::<Class:IO>" } #: as !nil
|
238
231
|
|
239
232
|
signatures = entry.signatures
|
240
233
|
assert_equal(2, signatures.length)
|
@@ -242,13 +235,13 @@ module RubyIndexer
|
|
242
235
|
# def self.select: [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array) -> [ Array[X], Array[Y], Array[Z] ] # rubocop:disable Layout/LineLength
|
243
236
|
# | [X, Y, Z] (::Array[X & io]? read_array, ?::Array[Y & io]? write_array, ?::Array[Z & io]? error_array, Time::_Timeout? timeout) -> [ Array[X], Array[Y], Array[Z] ]? # rubocop:disable Layout/LineLength
|
244
237
|
|
245
|
-
parameters = signatures[0]
|
238
|
+
parameters = signatures[0]&.parameters #: as !nil
|
246
239
|
assert_equal([:read_array, :write_array, :error_array], parameters.map(&:name))
|
247
240
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
248
241
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
249
242
|
assert_kind_of(Entry::OptionalParameter, parameters[2])
|
250
243
|
|
251
|
-
parameters = signatures[1]
|
244
|
+
parameters = signatures[1]&.parameters #: as !nil
|
252
245
|
assert_equal([:read_array, :write_array, :error_array, :timeout], parameters.map(&:name))
|
253
246
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
254
247
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
@@ -257,8 +250,8 @@ module RubyIndexer
|
|
257
250
|
end
|
258
251
|
|
259
252
|
def test_rbs_method_with_optional_keywords
|
260
|
-
entries = @index["step"]
|
261
|
-
entry = entries.find { |entry| entry.owner
|
253
|
+
entries = @index["step"] #: as Array[Entry::Method]
|
254
|
+
entry = entries.find { |entry| entry.owner&.name == "Numeric" } #: as !nil
|
262
255
|
|
263
256
|
signatures = entry.signatures
|
264
257
|
assert_equal(4, signatures.length)
|
@@ -268,24 +261,24 @@ module RubyIndexer
|
|
268
261
|
# | (?by: ::Numeric, ?to: ::Numeric) { (::Numeric) -> void } -> self
|
269
262
|
# | (?by: ::Numeric, ?to: ::Numeric) -> ::Enumerator[::Numeric, self]
|
270
263
|
|
271
|
-
parameters = signatures[0]
|
264
|
+
parameters = signatures[0]&.parameters #: as !nil
|
272
265
|
assert_equal([:limit, :step, :"<anonymous block>"], parameters.map(&:name))
|
273
266
|
assert_kind_of(Entry::OptionalParameter, parameters[0])
|
274
267
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
275
268
|
assert_kind_of(Entry::BlockParameter, parameters[2])
|
276
269
|
|
277
|
-
parameters = signatures[1]
|
270
|
+
parameters = signatures[1]&.parameters #: as !nil
|
278
271
|
assert_equal([:limit, :step], parameters.map(&:name))
|
279
272
|
assert_kind_of(Entry::OptionalParameter, parameters[0])
|
280
273
|
assert_kind_of(Entry::OptionalParameter, parameters[1])
|
281
274
|
|
282
|
-
parameters = signatures[2]
|
275
|
+
parameters = signatures[2]&.parameters #: as !nil
|
283
276
|
assert_equal([:by, :to, :"<anonymous block>"], parameters.map(&:name))
|
284
277
|
assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
|
285
278
|
assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
|
286
279
|
assert_kind_of(Entry::BlockParameter, parameters[2])
|
287
280
|
|
288
|
-
parameters = signatures[3]
|
281
|
+
parameters = signatures[3]&.parameters #: as !nil
|
289
282
|
assert_equal([:by, :to], parameters.map(&:name))
|
290
283
|
assert_kind_of(Entry::OptionalKeywordParameter, parameters[0])
|
291
284
|
assert_kind_of(Entry::OptionalKeywordParameter, parameters[1])
|
@@ -308,14 +301,14 @@ module RubyIndexer
|
|
308
301
|
end
|
309
302
|
|
310
303
|
def test_rbs_method_with_rest_keywords
|
311
|
-
entries = @index["method_missing"]
|
312
|
-
entry = entries.find { |entry| entry.owner
|
304
|
+
entries = @index["method_missing"] #: as Array[Entry::Method]
|
305
|
+
entry = entries.find { |entry| entry.owner&.name == "BasicObject" } #: as !nil
|
313
306
|
signatures = entry.signatures
|
314
307
|
assert_equal(1, signatures.length)
|
315
308
|
|
316
309
|
# (Symbol, *untyped, **untyped) ?{ (*untyped, **untyped) -> untyped } -> untyped
|
317
310
|
|
318
|
-
parameters = signatures[0]
|
311
|
+
parameters = signatures[0]&.parameters #: as !nil
|
319
312
|
assert_equal([:arg0, :"<anonymous splat>", :"<anonymous keyword splat>"], parameters.map(&:name))
|
320
313
|
assert_kind_of(Entry::RequiredParameter, parameters[0])
|
321
314
|
assert_kind_of(Entry::RestParameter, parameters[1])
|
@@ -348,24 +341,24 @@ module RubyIndexer
|
|
348
341
|
def test_signature_alias
|
349
342
|
# In RBS, an alias means that two methods have the same signature.
|
350
343
|
# It does not mean the same thing as a Ruby alias.
|
351
|
-
any_entries = @index["any?"]
|
344
|
+
any_entries = @index["any?"] #: as Array[Entry::UnresolvedMethodAlias]
|
352
345
|
|
353
|
-
assert_equal(["Array", "Enumerable", "Hash"], any_entries.map { _1.owner
|
346
|
+
assert_equal(["Array", "Enumerable", "Hash"], any_entries.map { _1.owner&.name })
|
354
347
|
|
355
|
-
entry = any_entries.find { |entry| entry.owner
|
348
|
+
entry = any_entries.find { |entry| entry.owner&.name == "Array" } #: as !nil
|
356
349
|
|
357
350
|
assert_kind_of(RubyIndexer::Entry::UnresolvedMethodAlias, entry)
|
358
351
|
assert_equal("any?", entry.name)
|
359
352
|
assert_equal("all?", entry.old_name)
|
360
|
-
assert_equal("Array", entry.owner
|
361
|
-
assert(entry.file_path
|
362
|
-
|
353
|
+
assert_equal("Array", entry.owner&.name)
|
354
|
+
assert(entry.file_path&.end_with?("core/array.rbs"))
|
355
|
+
refute_empty(entry.comments)
|
363
356
|
end
|
364
357
|
|
365
358
|
def test_indexing_untyped_functions
|
366
|
-
entries = @index.resolve_method("call", "Method")
|
359
|
+
entries = @index.resolve_method("call", "Method") #: as Array[Entry::Method]
|
367
360
|
|
368
|
-
parameters = entries.first
|
361
|
+
parameters = entries.first&.signatures&.first&.parameters #: as !nil
|
369
362
|
assert_equal(1, parameters.length)
|
370
363
|
assert_instance_of(Entry::ForwardingParameter, parameters.first)
|
371
364
|
end
|
@@ -379,7 +372,8 @@ module RubyIndexer
|
|
379
372
|
indexer = RubyIndexer::RBSIndexer.new(index)
|
380
373
|
pathname = Pathname.new("/file.rbs")
|
381
374
|
indexer.process_signature(pathname, declarations)
|
382
|
-
entry =
|
375
|
+
entry = index[method_name] #: as !nil
|
376
|
+
.first
|
383
377
|
T.cast(entry, Entry::Method).signatures
|
384
378
|
end
|
385
379
|
end
|
@@ -18,11 +18,11 @@ module RubyIndexer
|
|
18
18
|
end
|
19
19
|
|
20
20
|
def assert_entry(expected_name, type, expected_location, visibility: nil)
|
21
|
-
entries = @index[expected_name]
|
21
|
+
entries = @index[expected_name] #: as !nil
|
22
22
|
refute_nil(entries, "Expected #{expected_name} to be indexed")
|
23
23
|
refute_empty(entries, "Expected #{expected_name} to be indexed")
|
24
24
|
|
25
|
-
entry = entries.first
|
25
|
+
entry = entries.first #: as !nil
|
26
26
|
assert_instance_of(type, entry, "Expected #{expected_name} to be a #{type}")
|
27
27
|
|
28
28
|
location = entry.location
|
@@ -12,12 +12,12 @@ module RubyIndexer
|
|
12
12
|
|
13
13
|
def test_from_path_on_windows
|
14
14
|
uri = URI::Generic.from_path(path: "C:/some/windows/path/to/file.rb")
|
15
|
-
assert_equal("/C
|
15
|
+
assert_equal("/C%3A/some/windows/path/to/file.rb", uri.path)
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_from_path_on_windows_with_lowercase_drive
|
19
19
|
uri = URI::Generic.from_path(path: "c:/some/windows/path/to/file.rb")
|
20
|
-
assert_equal("/c
|
20
|
+
assert_equal("/c%3A/some/windows/path/to/file.rb", uri.path)
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_to_standardized_path_on_unix
|
@@ -68,5 +68,18 @@ module RubyIndexer
|
|
68
68
|
uri.add_require_path_from_load_entry("/some/unix/path")
|
69
69
|
assert_equal("to/file", uri.require_path)
|
70
70
|
end
|
71
|
+
|
72
|
+
def test_from_path_escapes_colon_characters
|
73
|
+
uri = URI::Generic.from_path(path: "c:/some/windows/path with/spaces/file.rb")
|
74
|
+
assert_equal("c:/some/windows/path with/spaces/file.rb", uri.to_standardized_path)
|
75
|
+
assert_equal("file:///c%3A/some/windows/path%20with/spaces/file.rb", uri.to_s)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_from_path_with_unicode_characters
|
79
|
+
path = "/path/with/unicode/文件.rb"
|
80
|
+
uri = URI::Generic.from_path(path: path)
|
81
|
+
assert_equal(path, uri.to_standardized_path)
|
82
|
+
assert_equal("file:///path/with/unicode/%E6%96%87%E4%BB%B6.rb", uri.to_s)
|
83
|
+
end
|
71
84
|
end
|
72
85
|
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -25,42 +25,34 @@ module RubyLsp
|
|
25
25
|
|
26
26
|
abstract!
|
27
27
|
|
28
|
-
@addons =
|
29
|
-
@addon_classes =
|
28
|
+
@addons = [] #: Array[Addon]
|
29
|
+
@addon_classes = [] #: Array[singleton(Addon)]
|
30
30
|
# Add-on instances that have declared a handler to accept file watcher events
|
31
|
-
@file_watcher_addons =
|
31
|
+
@file_watcher_addons = [] #: Array[Addon]
|
32
32
|
|
33
33
|
AddonNotFoundError = Class.new(StandardError)
|
34
34
|
|
35
35
|
class IncompatibleApiError < StandardError; end
|
36
36
|
|
37
37
|
class << self
|
38
|
-
|
39
|
-
|
40
|
-
sig { returns(T::Array[Addon]) }
|
38
|
+
#: Array[Addon]
|
41
39
|
attr_accessor :addons
|
42
40
|
|
43
|
-
|
41
|
+
#: Array[Addon]
|
44
42
|
attr_accessor :file_watcher_addons
|
45
43
|
|
46
|
-
|
44
|
+
#: Array[singleton(Addon)]
|
47
45
|
attr_reader :addon_classes
|
48
46
|
|
49
47
|
# Automatically track and instantiate add-on classes
|
50
|
-
|
48
|
+
#: (singleton(Addon) child_class) -> void
|
51
49
|
def inherited(child_class)
|
52
50
|
addon_classes << child_class
|
53
51
|
super
|
54
52
|
end
|
55
53
|
|
56
54
|
# Discovers and loads all add-ons. Returns a list of errors when trying to require add-ons
|
57
|
-
|
58
|
-
params(
|
59
|
-
global_state: GlobalState,
|
60
|
-
outgoing_queue: Thread::Queue,
|
61
|
-
include_project_addons: T::Boolean,
|
62
|
-
).returns(T::Array[StandardError])
|
63
|
-
end
|
55
|
+
#: (GlobalState global_state, Thread::Queue outgoing_queue, ?include_project_addons: bool) -> Array[StandardError]
|
64
56
|
def load_addons(global_state, outgoing_queue, include_project_addons: true)
|
65
57
|
# Require all add-ons entry points, which should be placed under
|
66
58
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb` or in the workspace under
|
@@ -98,7 +90,7 @@ module RubyLsp
|
|
98
90
|
end
|
99
91
|
|
100
92
|
# Unloads all add-ons. Only intended to be invoked once when shutting down the Ruby LSP server
|
101
|
-
|
93
|
+
#: -> void
|
102
94
|
def unload_addons
|
103
95
|
@addons.each(&:deactivate)
|
104
96
|
@addons.clear
|
@@ -112,7 +104,7 @@ module RubyLsp
|
|
112
104
|
# Important: if the add-on is not found, AddonNotFoundError will be raised. If the add-on is found, but its
|
113
105
|
# current version does not satisfy the given version constraint, then IncompatibleApiError will be raised. It is
|
114
106
|
# the responsibility of the add-ons using this API to handle these errors appropriately.
|
115
|
-
|
107
|
+
#: (String addon_name, *String version_constraints) -> Addon
|
116
108
|
def get(addon_name, *version_constraints)
|
117
109
|
if version_constraints.empty?
|
118
110
|
raise IncompatibleApiError, "Must specify version constraints when accessing other add-ons"
|
@@ -144,7 +136,7 @@ module RubyLsp
|
|
144
136
|
# end
|
145
137
|
# end
|
146
138
|
# ```
|
147
|
-
|
139
|
+
#: (*String version_constraints) -> void
|
148
140
|
def depend_on_ruby_lsp!(*version_constraints)
|
149
141
|
version_object = Gem::Version.new(RubyLsp::VERSION)
|
150
142
|
|
@@ -155,23 +147,23 @@ module RubyLsp
|
|
155
147
|
end
|
156
148
|
end
|
157
149
|
|
158
|
-
|
150
|
+
#: -> void
|
159
151
|
def initialize
|
160
|
-
@errors =
|
152
|
+
@errors = [] #: Array[StandardError]
|
161
153
|
end
|
162
154
|
|
163
|
-
|
155
|
+
#: (StandardError error) -> self
|
164
156
|
def add_error(error)
|
165
157
|
@errors << error
|
166
158
|
self
|
167
159
|
end
|
168
160
|
|
169
|
-
|
161
|
+
#: -> bool
|
170
162
|
def error?
|
171
163
|
@errors.any?
|
172
164
|
end
|
173
165
|
|
174
|
-
|
166
|
+
#: -> String
|
175
167
|
def formatted_errors
|
176
168
|
<<~ERRORS
|
177
169
|
#{name}:
|
@@ -179,7 +171,7 @@ module RubyLsp
|
|
179
171
|
ERRORS
|
180
172
|
end
|
181
173
|
|
182
|
-
|
174
|
+
#: -> String
|
183
175
|
def errors_details
|
184
176
|
@errors.map(&:full_message).join("\n\n")
|
185
177
|
end
|
@@ -207,69 +199,50 @@ module RubyLsp
|
|
207
199
|
# original request so that the response is delegated to the correct add-on and must override this method to handle
|
208
200
|
# the response
|
209
201
|
# https://microsoft.github.io/language-server-protocol/specification#window_showMessageRequest
|
210
|
-
|
202
|
+
# @overridable
|
203
|
+
#: (String title) -> void
|
211
204
|
def handle_window_show_message_response(title); end
|
212
205
|
|
213
206
|
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
214
|
-
|
215
|
-
|
216
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens],
|
217
|
-
uri: URI::Generic,
|
218
|
-
dispatcher: Prism::Dispatcher,
|
219
|
-
).void
|
220
|
-
end
|
207
|
+
# @overridable
|
208
|
+
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CodeLens] response_builder, URI::Generic uri, Prism::Dispatcher dispatcher) -> void
|
221
209
|
def create_code_lens_listener(response_builder, uri, dispatcher); end
|
222
210
|
|
223
211
|
# Creates a new Hover listener. This method is invoked on every Hover request
|
224
|
-
|
225
|
-
|
226
|
-
response_builder: ResponseBuilders::Hover,
|
227
|
-
node_context: NodeContext,
|
228
|
-
dispatcher: Prism::Dispatcher,
|
229
|
-
).void
|
230
|
-
end
|
212
|
+
# @overridable
|
213
|
+
#: (ResponseBuilders::Hover response_builder, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
|
231
214
|
def create_hover_listener(response_builder, node_context, dispatcher); end
|
232
215
|
|
233
216
|
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
|
234
|
-
|
235
|
-
|
236
|
-
response_builder: ResponseBuilders::DocumentSymbol,
|
237
|
-
dispatcher: Prism::Dispatcher,
|
238
|
-
).void
|
239
|
-
end
|
217
|
+
# @overridable
|
218
|
+
#: (ResponseBuilders::DocumentSymbol response_builder, Prism::Dispatcher dispatcher) -> void
|
240
219
|
def create_document_symbol_listener(response_builder, dispatcher); end
|
241
220
|
|
242
|
-
|
243
|
-
|
244
|
-
response_builder: ResponseBuilders::SemanticHighlighting,
|
245
|
-
dispatcher: Prism::Dispatcher,
|
246
|
-
).void
|
247
|
-
end
|
221
|
+
# @overridable
|
222
|
+
#: (ResponseBuilders::SemanticHighlighting response_builder, Prism::Dispatcher dispatcher) -> void
|
248
223
|
def create_semantic_highlighting_listener(response_builder, dispatcher); end
|
249
224
|
|
250
225
|
# Creates a new Definition listener. This method is invoked on every Definition request
|
251
|
-
|
252
|
-
|
253
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[T.any(
|
254
|
-
Interface::Location,
|
255
|
-
Interface::LocationLink,
|
256
|
-
)],
|
257
|
-
uri: URI::Generic,
|
258
|
-
node_context: NodeContext,
|
259
|
-
dispatcher: Prism::Dispatcher,
|
260
|
-
).void
|
261
|
-
end
|
226
|
+
# @overridable
|
227
|
+
#: (ResponseBuilders::CollectionResponseBuilder[(Interface::Location | Interface::LocationLink)] response_builder, URI::Generic uri, NodeContext node_context, Prism::Dispatcher dispatcher) -> void
|
262
228
|
def create_definition_listener(response_builder, uri, node_context, dispatcher); end
|
263
229
|
|
264
230
|
# Creates a new Completion listener. This method is invoked on every Completion request
|
265
|
-
|
266
|
-
|
267
|
-
response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem],
|
268
|
-
node_context: NodeContext,
|
269
|
-
dispatcher: Prism::Dispatcher,
|
270
|
-
uri: URI::Generic,
|
271
|
-
).void
|
272
|
-
end
|
231
|
+
# @overridable
|
232
|
+
#: (ResponseBuilders::CollectionResponseBuilder[Interface::CompletionItem] response_builder, NodeContext node_context, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
273
233
|
def create_completion_listener(response_builder, node_context, dispatcher, uri); end
|
234
|
+
|
235
|
+
# Creates a new Discover Tests listener. This method is invoked on every DiscoverTests request
|
236
|
+
# @overridable
|
237
|
+
#: (ResponseBuilders::TestCollection response_builder, Prism::Dispatcher dispatcher, URI::Generic uri) -> void
|
238
|
+
def create_discover_tests_listener(response_builder, dispatcher, uri); end
|
239
|
+
|
240
|
+
# Resolves the minimal set of commands required to execute the requested tests. Add-ons are responsible for only
|
241
|
+
# handling items related to the framework they add support for and have discovered themselves
|
242
|
+
# @overridable
|
243
|
+
#: (Array[Hash[Symbol, untyped]]) -> Array[String]
|
244
|
+
def resolve_test_commands(items)
|
245
|
+
[]
|
246
|
+
end
|
274
247
|
end
|
275
248
|
end
|