ruby-lsp 0.23.10 → 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 +74 -183
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +55 -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/classes_and_modules_test.rb +75 -0
- data/lib/ruby_indexer/test/configuration_test.rb +32 -2
- data/lib/ruby_indexer/test/index_test.rb +21 -0
- 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 +12 -11
- 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 +6 -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 +270 -0
- 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 +74 -0
- 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 -47
- 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 +60 -0
- 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 +34 -0
- 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 +169 -72
- data/lib/ruby_lsp/setup_bundler.rb +25 -17
- 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 +12 -3
@@ -3,8 +3,6 @@
|
|
3
3
|
|
4
4
|
module RubyIndexer
|
5
5
|
class Index
|
6
|
-
extend T::Sig
|
7
|
-
|
8
6
|
class UnresolvableAliasError < StandardError; end
|
9
7
|
class NonExistingNamespaceError < StandardError; end
|
10
8
|
class IndexNotEmptyError < StandardError; end
|
@@ -12,18 +10,19 @@ module RubyIndexer
|
|
12
10
|
# The minimum Jaro-Winkler similarity score for an entry to be considered a match for a given fuzzy search query
|
13
11
|
ENTRY_SIMILARITY_THRESHOLD = 0.7
|
14
12
|
|
15
|
-
|
13
|
+
#: Configuration
|
16
14
|
attr_reader :configuration
|
17
15
|
|
18
|
-
|
19
|
-
|
16
|
+
#: bool
|
17
|
+
attr_reader :initial_indexing_completed
|
20
18
|
|
19
|
+
class << self
|
21
20
|
# Returns the real nesting of a constant name taking into account top level
|
22
21
|
# references that may be included anywhere in the name or nesting where that
|
23
22
|
# constant was found
|
24
|
-
|
23
|
+
#: (Array[String] stack, String? name) -> Array[String]
|
25
24
|
def actual_nesting(stack, name)
|
26
|
-
nesting = stack + [name]
|
25
|
+
nesting = name ? stack + [name] : stack
|
27
26
|
corrected_nesting = []
|
28
27
|
|
29
28
|
nesting.reverse_each do |name|
|
@@ -37,24 +36,21 @@ module RubyIndexer
|
|
37
36
|
|
38
37
|
# Returns the unresolved name for a constant reference including all parts of a constant path, or `nil` if the
|
39
38
|
# constant contains dynamic or incomplete parts
|
40
|
-
|
41
|
-
params(
|
42
|
-
node: T.any(
|
43
|
-
Prism::ConstantPathNode,
|
44
|
-
Prism::ConstantReadNode,
|
45
|
-
Prism::ConstantPathTargetNode,
|
46
|
-
),
|
47
|
-
).returns(T.nilable(String))
|
48
|
-
end
|
39
|
+
#: ((Prism::ConstantPathNode | Prism::ConstantReadNode | Prism::ConstantPathTargetNode | Prism::CallNode | Prism::MissingNode) node) -> String?
|
49
40
|
def constant_name(node)
|
50
|
-
node
|
41
|
+
case node
|
42
|
+
when Prism::CallNode, Prism::MissingNode
|
43
|
+
nil
|
44
|
+
else
|
45
|
+
node.full_name
|
46
|
+
end
|
51
47
|
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
52
48
|
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
53
49
|
nil
|
54
50
|
end
|
55
51
|
end
|
56
52
|
|
57
|
-
|
53
|
+
#: -> void
|
58
54
|
def initialize
|
59
55
|
# Holds all entries in the index using the following format:
|
60
56
|
# {
|
@@ -92,12 +88,12 @@ module RubyIndexer
|
|
92
88
|
end
|
93
89
|
|
94
90
|
# Register an included `hook` that will be executed when `module_name` is included into any namespace
|
95
|
-
|
91
|
+
#: (String module_name) { (Index index, Entry::Namespace base) -> void } -> void
|
96
92
|
def register_included_hook(module_name, &hook)
|
97
93
|
(@included_hooks[module_name] ||= []) << hook
|
98
94
|
end
|
99
95
|
|
100
|
-
|
96
|
+
#: (URI::Generic uri, ?skip_require_paths_tree: bool) -> void
|
101
97
|
def delete(uri, skip_require_paths_tree: false)
|
102
98
|
key = uri.to_s
|
103
99
|
# For each constant discovered in `path`, delete the associated entry from the index. If there are no entries
|
@@ -127,7 +123,7 @@ module RubyIndexer
|
|
127
123
|
@require_paths_tree.delete(require_path) if require_path
|
128
124
|
end
|
129
125
|
|
130
|
-
|
126
|
+
#: (Entry entry, ?skip_prefix_tree: bool) -> void
|
131
127
|
def add(entry, skip_prefix_tree: false)
|
132
128
|
name = entry.name
|
133
129
|
|
@@ -136,28 +132,19 @@ module RubyIndexer
|
|
136
132
|
@entries_tree.insert(name, T.must(@entries[name])) unless skip_prefix_tree
|
137
133
|
end
|
138
134
|
|
139
|
-
|
135
|
+
#: (String fully_qualified_name) -> Array[Entry]?
|
140
136
|
def [](fully_qualified_name)
|
141
137
|
@entries[fully_qualified_name.delete_prefix("::")]
|
142
138
|
end
|
143
139
|
|
144
|
-
|
140
|
+
#: (String query) -> Array[URI::Generic]
|
145
141
|
def search_require_paths(query)
|
146
142
|
@require_paths_tree.search(query)
|
147
143
|
end
|
148
144
|
|
149
145
|
# Searches for a constant based on an unqualified name and returns the first possible match regardless of whether
|
150
146
|
# there are more possible matching entries
|
151
|
-
|
152
|
-
params(
|
153
|
-
name: String,
|
154
|
-
).returns(T.nilable(T::Array[T.any(
|
155
|
-
Entry::Namespace,
|
156
|
-
Entry::ConstantAlias,
|
157
|
-
Entry::UnresolvedConstantAlias,
|
158
|
-
Entry::Constant,
|
159
|
-
)]))
|
160
|
-
end
|
147
|
+
#: (String name) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias | Entry::Constant)]?
|
161
148
|
def first_unqualified_const(name)
|
162
149
|
# Look for an exact match first
|
163
150
|
_name, entries = @entries.find do |const_name, _entries|
|
@@ -195,7 +182,7 @@ module RubyIndexer
|
|
195
182
|
# [#<Entry::Class name="Foo::Baz">],
|
196
183
|
# ]
|
197
184
|
# ```
|
198
|
-
|
185
|
+
#: (String query, ?Array[String]? nesting) -> Array[Array[Entry]]
|
199
186
|
def prefix_search(query, nesting = nil)
|
200
187
|
unless nesting
|
201
188
|
results = @entries_tree.search(query)
|
@@ -214,7 +201,7 @@ module RubyIndexer
|
|
214
201
|
end
|
215
202
|
|
216
203
|
# Fuzzy searches index entries based on Jaro-Winkler similarity. If no query is provided, all entries are returned
|
217
|
-
|
204
|
+
#: (String? query) -> Array[Entry]
|
218
205
|
def fuzzy_search(query)
|
219
206
|
unless query
|
220
207
|
entries = @entries.filter_map do |_name, entries|
|
@@ -238,12 +225,7 @@ module RubyIndexer
|
|
238
225
|
results.flat_map(&:first)
|
239
226
|
end
|
240
227
|
|
241
|
-
|
242
|
-
params(
|
243
|
-
name: T.nilable(String),
|
244
|
-
receiver_name: String,
|
245
|
-
).returns(T::Array[T.any(Entry::Member, Entry::MethodAlias)])
|
246
|
-
end
|
228
|
+
#: (String? name, String receiver_name) -> Array[(Entry::Member | Entry::MethodAlias)]
|
247
229
|
def method_completion_candidates(name, receiver_name)
|
248
230
|
ancestors = linearized_ancestors_of(receiver_name)
|
249
231
|
|
@@ -286,17 +268,7 @@ module RubyIndexer
|
|
286
268
|
completion_items.values.map!(&:first)
|
287
269
|
end
|
288
270
|
|
289
|
-
|
290
|
-
params(
|
291
|
-
name: String,
|
292
|
-
nesting: T::Array[String],
|
293
|
-
).returns(T::Array[T::Array[T.any(
|
294
|
-
Entry::Constant,
|
295
|
-
Entry::ConstantAlias,
|
296
|
-
Entry::Namespace,
|
297
|
-
Entry::UnresolvedConstantAlias,
|
298
|
-
)]])
|
299
|
-
end
|
271
|
+
#: (String name, Array[String] nesting) -> Array[Array[(Entry::Constant | Entry::ConstantAlias | Entry::Namespace | Entry::UnresolvedConstantAlias)]]
|
300
272
|
def constant_completion_candidates(name, nesting)
|
301
273
|
# If we have a top level reference, then we don't need to include completions inside the current nesting
|
302
274
|
if name.start_with?("::")
|
@@ -351,17 +323,7 @@ module RubyIndexer
|
|
351
323
|
# nesting: the nesting structure where the reference was found (e.g.: ["Foo", "Bar"])
|
352
324
|
# seen_names: this parameter should not be used by consumers of the api. It is used to avoid infinite recursion when
|
353
325
|
# resolving circular references
|
354
|
-
|
355
|
-
params(
|
356
|
-
name: String,
|
357
|
-
nesting: T::Array[String],
|
358
|
-
seen_names: T::Array[String],
|
359
|
-
).returns(T.nilable(T::Array[T.any(
|
360
|
-
Entry::Namespace,
|
361
|
-
Entry::ConstantAlias,
|
362
|
-
Entry::UnresolvedConstantAlias,
|
363
|
-
)]))
|
364
|
-
end
|
326
|
+
#: (String name, Array[String] nesting, ?Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
365
327
|
def resolve(name, nesting, seen_names = [])
|
366
328
|
# If we have a top level reference, then we just search for it straight away ignoring the nesting
|
367
329
|
if name.start_with?("::")
|
@@ -397,12 +359,7 @@ module RubyIndexer
|
|
397
359
|
# Index all files for the given URIs, which defaults to what is configured. A block can be used to track and control
|
398
360
|
# indexing progress. That block is invoked with the current progress percentage and should return `true` to continue
|
399
361
|
# indexing or `false` to stop indexing.
|
400
|
-
|
401
|
-
params(
|
402
|
-
uris: T::Array[URI::Generic],
|
403
|
-
block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
|
404
|
-
).void
|
405
|
-
end
|
362
|
+
#: (?uris: Array[URI::Generic]) ?{ (Integer progress) -> bool } -> void
|
406
363
|
def index_all(uris: @configuration.indexable_uris, &block)
|
407
364
|
# When troubleshooting an indexing issue, e.g. through irb, it's not obvious that `index_all` will augment the
|
408
365
|
# existing index values, meaning it may contain 'stale' entries. This check ensures that the user is aware of this
|
@@ -412,8 +369,6 @@ module RubyIndexer
|
|
412
369
|
"The index is not empty. To prevent invalid entries, `index_all` can only be called once."
|
413
370
|
end
|
414
371
|
|
415
|
-
@initial_indexing_completed = true
|
416
|
-
|
417
372
|
RBSIndexer.new(self).index_ruby_core
|
418
373
|
# Calculate how many paths are worth 1% of progress
|
419
374
|
progress_step = (uris.length / 100.0).ceil
|
@@ -426,9 +381,11 @@ module RubyIndexer
|
|
426
381
|
|
427
382
|
index_file(uri, collect_comments: false)
|
428
383
|
end
|
384
|
+
|
385
|
+
@initial_indexing_completed = true
|
429
386
|
end
|
430
387
|
|
431
|
-
|
388
|
+
#: (URI::Generic uri, String source, ?collect_comments: bool) -> void
|
432
389
|
def index_single(uri, source, collect_comments: true)
|
433
390
|
dispatcher = Prism::Dispatcher.new
|
434
391
|
|
@@ -450,7 +407,7 @@ module RubyIndexer
|
|
450
407
|
end
|
451
408
|
|
452
409
|
# Indexes a File URI by reading the contents from disk
|
453
|
-
|
410
|
+
#: (URI::Generic uri, ?collect_comments: bool) -> void
|
454
411
|
def index_file(uri, collect_comments: true)
|
455
412
|
index_single(uri, File.read(T.must(uri.full_path)), collect_comments: collect_comments)
|
456
413
|
rescue Errno::EISDIR, Errno::ENOENT
|
@@ -468,7 +425,7 @@ module RubyIndexer
|
|
468
425
|
# If we find an alias, then we want to follow its target. In the same example, if `Foo::Bar` is an alias to
|
469
426
|
# `Something::Else`, then we first discover `Something::Else::Baz`. But `Something::Else::Baz` might contain other
|
470
427
|
# aliases, so we have to invoke `follow_aliased_namespace` again to check until we only return a real name
|
471
|
-
|
428
|
+
#: (String name, ?Array[String] seen_names) -> String
|
472
429
|
def follow_aliased_namespace(name, seen_names = [])
|
473
430
|
parts = name.split("::")
|
474
431
|
real_parts = []
|
@@ -501,14 +458,7 @@ module RubyIndexer
|
|
501
458
|
# Attempts to find methods for a resolved fully qualified receiver name. Do not provide the `seen_names` parameter
|
502
459
|
# as it is used only internally to prevent infinite loops when resolving circular aliases
|
503
460
|
# Returns `nil` if the method does not exist on that receiver
|
504
|
-
|
505
|
-
params(
|
506
|
-
method_name: String,
|
507
|
-
receiver_name: String,
|
508
|
-
seen_names: T::Array[String],
|
509
|
-
inherited_only: T::Boolean,
|
510
|
-
).returns(T.nilable(T::Array[T.any(Entry::Member, Entry::MethodAlias)]))
|
511
|
-
end
|
461
|
+
#: (String method_name, String receiver_name, ?Array[String] seen_names, ?inherited_only: bool) -> Array[(Entry::Member | Entry::MethodAlias)]?
|
512
462
|
def resolve_method(method_name, receiver_name, seen_names = [], inherited_only: false)
|
513
463
|
method_entries = self[method_name]
|
514
464
|
return unless method_entries
|
@@ -546,7 +496,7 @@ module RubyIndexer
|
|
546
496
|
# module that prepends another module, then the prepend module appears before the included module.
|
547
497
|
#
|
548
498
|
# The order of ancestors is [linearized_prepends, self, linearized_includes, linearized_superclass]
|
549
|
-
|
499
|
+
#: (String fully_qualified_name) -> Array[String]
|
550
500
|
def linearized_ancestors_of(fully_qualified_name)
|
551
501
|
# If we already computed the ancestors for this namespace, return it straight away
|
552
502
|
cached_ancestors = @ancestors[fully_qualified_name]
|
@@ -624,7 +574,7 @@ module RubyIndexer
|
|
624
574
|
|
625
575
|
# Resolves an instance variable name for a given owner name. This method will linearize the ancestors of the owner
|
626
576
|
# and find inherited instance variables as well
|
627
|
-
|
577
|
+
#: (String variable_name, String owner_name) -> Array[Entry::InstanceVariable]?
|
628
578
|
def resolve_instance_variable(variable_name, owner_name)
|
629
579
|
entries = T.cast(self[variable_name], T.nilable(T::Array[Entry::InstanceVariable]))
|
630
580
|
return unless entries
|
@@ -635,7 +585,7 @@ module RubyIndexer
|
|
635
585
|
entries.select { |e| ancestors.include?(e.owner&.name) }
|
636
586
|
end
|
637
587
|
|
638
|
-
|
588
|
+
#: (String variable_name, String owner_name) -> Array[Entry::ClassVariable]?
|
639
589
|
def resolve_class_variable(variable_name, owner_name)
|
640
590
|
entries = self[variable_name]&.grep(Entry::ClassVariable)
|
641
591
|
return unless entries&.any?
|
@@ -648,9 +598,7 @@ module RubyIndexer
|
|
648
598
|
|
649
599
|
# Returns a list of possible candidates for completion of instance variables for a given owner name. The name must
|
650
600
|
# include the `@` prefix
|
651
|
-
|
652
|
-
params(name: String, owner_name: String).returns(T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
|
653
|
-
end
|
601
|
+
#: (String name, String owner_name) -> Array[(Entry::InstanceVariable | Entry::ClassVariable)]
|
654
602
|
def instance_variable_completion_candidates(name, owner_name)
|
655
603
|
entries = T.cast(prefix_search(name).flatten, T::Array[T.any(Entry::InstanceVariable, Entry::ClassVariable)])
|
656
604
|
# Avoid wasting time linearizing ancestors if we didn't find anything
|
@@ -679,7 +627,7 @@ module RubyIndexer
|
|
679
627
|
variables
|
680
628
|
end
|
681
629
|
|
682
|
-
|
630
|
+
#: (String name, String owner_name) -> Array[Entry::ClassVariable]
|
683
631
|
def class_variable_completion_candidates(name, owner_name)
|
684
632
|
entries = T.cast(prefix_search(name).flatten, T::Array[Entry::ClassVariable])
|
685
633
|
# Avoid wasting time linearizing ancestors if we didn't find anything
|
@@ -695,9 +643,7 @@ module RubyIndexer
|
|
695
643
|
# declarations removed and that the ancestor linearization cache is cleared if necessary. If a block is passed, the
|
696
644
|
# consumer of this API has to handle deleting and inserting/updating entries in the index instead of passing the
|
697
645
|
# document's source (used to handle unsaved changes to files)
|
698
|
-
|
699
|
-
params(uri: URI::Generic, source: T.nilable(String), block: T.nilable(T.proc.params(index: Index).void)).void
|
700
|
-
end
|
646
|
+
#: (URI::Generic uri, ?String? source) ?{ (Index index) -> void } -> void
|
701
647
|
def handle_change(uri, source = nil, &block)
|
702
648
|
key = uri.to_s
|
703
649
|
original_entries = @uris_to_entries[key]
|
@@ -729,27 +675,27 @@ module RubyIndexer
|
|
729
675
|
@ancestors.clear if original_map.any? { |name, hash| updated_map[name] != hash }
|
730
676
|
end
|
731
677
|
|
732
|
-
|
678
|
+
#: -> bool
|
733
679
|
def empty?
|
734
680
|
@entries.empty?
|
735
681
|
end
|
736
682
|
|
737
|
-
|
683
|
+
#: -> Array[String]
|
738
684
|
def names
|
739
685
|
@entries.keys
|
740
686
|
end
|
741
687
|
|
742
|
-
|
688
|
+
#: (String name) -> bool
|
743
689
|
def indexed?(name)
|
744
690
|
@entries.key?(name)
|
745
691
|
end
|
746
692
|
|
747
|
-
|
693
|
+
#: -> Integer
|
748
694
|
def length
|
749
695
|
@entries.count
|
750
696
|
end
|
751
697
|
|
752
|
-
|
698
|
+
#: (String name) -> Entry::SingletonClass
|
753
699
|
def existing_or_new_singleton_class(name)
|
754
700
|
*_namespace, unqualified_name = name.split("::")
|
755
701
|
full_singleton_name = "#{name}::<Class:#{unqualified_name}>"
|
@@ -772,12 +718,7 @@ module RubyIndexer
|
|
772
718
|
singleton
|
773
719
|
end
|
774
720
|
|
775
|
-
|
776
|
-
type_parameters(:T).params(
|
777
|
-
uri: String,
|
778
|
-
type: T.nilable(T::Class[T.all(T.type_parameter(:T), Entry)]),
|
779
|
-
).returns(T.nilable(T.any(T::Array[Entry], T::Array[T.type_parameter(:T)])))
|
780
|
-
end
|
721
|
+
#: [T] (String uri, ?Class[(T & Entry)]? type) -> (Array[Entry] | Array[T])?
|
781
722
|
def entries_for(uri, type = nil)
|
782
723
|
entries = @uris_to_entries[uri.to_s]
|
783
724
|
return entries unless type
|
@@ -789,7 +730,7 @@ module RubyIndexer
|
|
789
730
|
|
790
731
|
# Always returns the linearized ancestors for the attached class, regardless of whether `name` refers to a singleton
|
791
732
|
# or attached namespace
|
792
|
-
|
733
|
+
#: (String name) -> Array[String]
|
793
734
|
def linearized_attached_ancestors(name)
|
794
735
|
name_parts = name.split("::")
|
795
736
|
|
@@ -802,7 +743,7 @@ module RubyIndexer
|
|
802
743
|
end
|
803
744
|
|
804
745
|
# Runs the registered included hooks
|
805
|
-
|
746
|
+
#: (String fully_qualified_name, Array[String] nesting) -> void
|
806
747
|
def run_included_hooks(fully_qualified_name, nesting)
|
807
748
|
return if @included_hooks.empty?
|
808
749
|
|
@@ -831,13 +772,7 @@ module RubyIndexer
|
|
831
772
|
|
832
773
|
# Linearize mixins for an array of namespace entries. This method will mutate the `ancestors` array with the
|
833
774
|
# linearized ancestors of the mixins
|
834
|
-
|
835
|
-
params(
|
836
|
-
ancestors: T::Array[String],
|
837
|
-
namespace_entries: T::Array[Entry::Namespace],
|
838
|
-
nesting: T::Array[String],
|
839
|
-
).void
|
840
|
-
end
|
775
|
+
#: (Array[String] ancestors, Array[Entry::Namespace] namespace_entries, Array[String] nesting) -> void
|
841
776
|
def linearize_mixins(ancestors, namespace_entries, nesting)
|
842
777
|
mixin_operations = namespace_entries.flat_map(&:mixin_operations)
|
843
778
|
main_namespace_index = 0
|
@@ -878,16 +813,7 @@ module RubyIndexer
|
|
878
813
|
|
879
814
|
# Linearize the superclass of a given namespace (including modules with the implicit `Module` superclass). This
|
880
815
|
# method will mutate the `ancestors` array with the linearized ancestors of the superclass
|
881
|
-
|
882
|
-
params(
|
883
|
-
ancestors: T::Array[String],
|
884
|
-
attached_class_name: String,
|
885
|
-
fully_qualified_name: String,
|
886
|
-
namespace_entries: T::Array[Entry::Namespace],
|
887
|
-
nesting: T::Array[String],
|
888
|
-
singleton_levels: Integer,
|
889
|
-
).void
|
890
|
-
end
|
816
|
+
#: (Array[String] ancestors, String attached_class_name, String fully_qualified_name, Array[Entry::Namespace] namespace_entries, Array[String] nesting, Integer singleton_levels) -> void
|
891
817
|
def linearize_superclass( # rubocop:disable Metrics/ParameterLists
|
892
818
|
ancestors,
|
893
819
|
attached_class_name,
|
@@ -955,12 +881,7 @@ module RubyIndexer
|
|
955
881
|
|
956
882
|
# Attempts to resolve an UnresolvedAlias into a resolved Alias. If the unresolved alias is pointing to a constant
|
957
883
|
# that doesn't exist, then we return the same UnresolvedAlias
|
958
|
-
|
959
|
-
params(
|
960
|
-
entry: Entry::UnresolvedConstantAlias,
|
961
|
-
seen_names: T::Array[String],
|
962
|
-
).returns(T.any(Entry::ConstantAlias, Entry::UnresolvedConstantAlias))
|
963
|
-
end
|
884
|
+
#: (Entry::UnresolvedConstantAlias entry, Array[String] seen_names) -> (Entry::ConstantAlias | Entry::UnresolvedConstantAlias)
|
964
885
|
def resolve_alias(entry, seen_names)
|
965
886
|
alias_name = entry.name
|
966
887
|
return entry if seen_names.include?(alias_name)
|
@@ -983,17 +904,7 @@ module RubyIndexer
|
|
983
904
|
resolved_alias
|
984
905
|
end
|
985
906
|
|
986
|
-
|
987
|
-
params(
|
988
|
-
name: String,
|
989
|
-
nesting: T::Array[String],
|
990
|
-
seen_names: T::Array[String],
|
991
|
-
).returns(T.nilable(T::Array[T.any(
|
992
|
-
Entry::Namespace,
|
993
|
-
Entry::ConstantAlias,
|
994
|
-
Entry::UnresolvedConstantAlias,
|
995
|
-
)]))
|
996
|
-
end
|
907
|
+
#: (String name, Array[String] nesting, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
997
908
|
def lookup_enclosing_scopes(name, nesting, seen_names)
|
998
909
|
nesting.length.downto(1) do |i|
|
999
910
|
namespace = T.must(nesting[0...i]).join("::")
|
@@ -1012,17 +923,7 @@ module RubyIndexer
|
|
1012
923
|
nil
|
1013
924
|
end
|
1014
925
|
|
1015
|
-
|
1016
|
-
params(
|
1017
|
-
name: String,
|
1018
|
-
nesting: T::Array[String],
|
1019
|
-
seen_names: T::Array[String],
|
1020
|
-
).returns(T.nilable(T::Array[T.any(
|
1021
|
-
Entry::Namespace,
|
1022
|
-
Entry::ConstantAlias,
|
1023
|
-
Entry::UnresolvedConstantAlias,
|
1024
|
-
)]))
|
1025
|
-
end
|
926
|
+
#: (String name, Array[String] nesting, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
1026
927
|
def lookup_ancestor_chain(name, nesting, seen_names)
|
1027
928
|
*nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
|
1028
929
|
return if nesting_parts.empty?
|
@@ -1042,17 +943,7 @@ module RubyIndexer
|
|
1042
943
|
nil
|
1043
944
|
end
|
1044
945
|
|
1045
|
-
|
1046
|
-
params(
|
1047
|
-
name: T.nilable(String),
|
1048
|
-
nesting: T::Array[String],
|
1049
|
-
).returns(T::Array[T::Array[T.any(
|
1050
|
-
Entry::Namespace,
|
1051
|
-
Entry::ConstantAlias,
|
1052
|
-
Entry::UnresolvedConstantAlias,
|
1053
|
-
Entry::Constant,
|
1054
|
-
)]])
|
1055
|
-
end
|
946
|
+
#: (String? name, Array[String] nesting) -> Array[Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias | Entry::Constant)]]
|
1056
947
|
def inherited_constant_completion_candidates(name, nesting)
|
1057
948
|
namespace_entries = if name
|
1058
949
|
*nesting_parts, constant_name = build_non_redundant_full_name(name, nesting).split("::")
|
@@ -1091,7 +982,7 @@ module RubyIndexer
|
|
1091
982
|
# inside of the ["A", "B"] nesting, then we should not concatenate the nesting with the name or else we'll end up
|
1092
983
|
# with `A::B::A::B::Foo`. This method will remove any redundant parts from the final name based on the reference and
|
1093
984
|
# the nesting
|
1094
|
-
|
985
|
+
#: (String name, Array[String] nesting) -> String
|
1095
986
|
def build_non_redundant_full_name(name, nesting)
|
1096
987
|
# If there's no nesting, then we can just return the name as is
|
1097
988
|
return name if nesting.empty?
|
@@ -1112,18 +1003,7 @@ module RubyIndexer
|
|
1112
1003
|
name_parts.join("::")
|
1113
1004
|
end
|
1114
1005
|
|
1115
|
-
|
1116
|
-
params(
|
1117
|
-
full_name: String,
|
1118
|
-
seen_names: T::Array[String],
|
1119
|
-
).returns(
|
1120
|
-
T.nilable(T::Array[T.any(
|
1121
|
-
Entry::Namespace,
|
1122
|
-
Entry::ConstantAlias,
|
1123
|
-
Entry::UnresolvedConstantAlias,
|
1124
|
-
)]),
|
1125
|
-
)
|
1126
|
-
end
|
1006
|
+
#: (String full_name, Array[String] seen_names) -> Array[(Entry::Namespace | Entry::ConstantAlias | Entry::UnresolvedConstantAlias)]?
|
1127
1007
|
def direct_or_aliased_constant(full_name, seen_names)
|
1128
1008
|
entries = @entries[full_name] || @entries[follow_aliased_namespace(full_name)]
|
1129
1009
|
|
@@ -1139,13 +1019,7 @@ module RubyIndexer
|
|
1139
1019
|
|
1140
1020
|
# Attempt to resolve a given unresolved method alias. This method returns the resolved alias if we managed to
|
1141
1021
|
# identify the target or the same unresolved alias entry if we couldn't
|
1142
|
-
|
1143
|
-
params(
|
1144
|
-
entry: Entry::UnresolvedMethodAlias,
|
1145
|
-
receiver_name: String,
|
1146
|
-
seen_names: T::Array[String],
|
1147
|
-
).returns(T.any(Entry::MethodAlias, Entry::UnresolvedMethodAlias))
|
1148
|
-
end
|
1022
|
+
#: (Entry::UnresolvedMethodAlias entry, String receiver_name, Array[String] seen_names) -> (Entry::MethodAlias | Entry::UnresolvedMethodAlias)
|
1149
1023
|
def resolve_method_alias(entry, receiver_name, seen_names)
|
1150
1024
|
new_name = entry.new_name
|
1151
1025
|
return entry if new_name == entry.old_name
|
@@ -3,20 +3,8 @@
|
|
3
3
|
|
4
4
|
module RubyIndexer
|
5
5
|
class Location
|
6
|
-
extend T::Sig
|
7
|
-
|
8
6
|
class << self
|
9
|
-
|
10
|
-
|
11
|
-
sig do
|
12
|
-
params(
|
13
|
-
prism_location: Prism::Location,
|
14
|
-
code_units_cache: T.any(
|
15
|
-
T.proc.params(arg0: Integer).returns(Integer),
|
16
|
-
Prism::CodeUnitsCache,
|
17
|
-
),
|
18
|
-
).returns(T.attached_class)
|
19
|
-
end
|
7
|
+
#: (Prism::Location prism_location, (^(Integer arg0) -> Integer | Prism::CodeUnitsCache) code_units_cache) -> instance
|
20
8
|
def from_prism_location(prism_location, code_units_cache)
|
21
9
|
new(
|
22
10
|
prism_location.start_line,
|
@@ -27,17 +15,10 @@ module RubyIndexer
|
|
27
15
|
end
|
28
16
|
end
|
29
17
|
|
30
|
-
|
18
|
+
#: Integer
|
31
19
|
attr_reader :start_line, :end_line, :start_column, :end_column
|
32
20
|
|
33
|
-
|
34
|
-
params(
|
35
|
-
start_line: Integer,
|
36
|
-
end_line: Integer,
|
37
|
-
start_column: Integer,
|
38
|
-
end_column: Integer,
|
39
|
-
).void
|
40
|
-
end
|
21
|
+
#: (Integer start_line, Integer end_line, Integer start_column, Integer end_column) -> void
|
41
22
|
def initialize(start_line, end_line, start_column, end_column)
|
42
23
|
@start_line = start_line
|
43
24
|
@end_line = end_line
|
@@ -45,11 +26,7 @@ module RubyIndexer
|
|
45
26
|
@end_column = end_column
|
46
27
|
end
|
47
28
|
|
48
|
-
|
49
|
-
params(
|
50
|
-
other: T.any(Location, Prism::Location),
|
51
|
-
).returns(T::Boolean)
|
52
|
-
end
|
29
|
+
#: ((Location | Prism::Location) other) -> bool
|
53
30
|
def ==(other)
|
54
31
|
start_line == other.start_line &&
|
55
32
|
end_line == other.end_line &&
|
@@ -33,12 +33,11 @@ module RubyIndexer
|
|
33
33
|
#
|
34
34
|
# See https://en.wikipedia.org/wiki/Trie for more information
|
35
35
|
class PrefixTree
|
36
|
-
extend T::Sig
|
37
36
|
extend T::Generic
|
38
37
|
|
39
38
|
Value = type_member
|
40
39
|
|
41
|
-
|
40
|
+
#: -> void
|
42
41
|
def initialize
|
43
42
|
@root = T.let(Node.new("", ""), Node[Value])
|
44
43
|
end
|
@@ -47,7 +46,7 @@ module RubyIndexer
|
|
47
46
|
# return it as a result. The result is always an array of the type of value attribute to the generic `Value` type.
|
48
47
|
# Notice that if the `Value` is an array, this method will return an array of arrays, where each entry is the array
|
49
48
|
# of values for a given match
|
50
|
-
|
49
|
+
#: (String prefix) -> Array[Value]
|
51
50
|
def search(prefix)
|
52
51
|
node = find_node(prefix)
|
53
52
|
return [] unless node
|
@@ -56,7 +55,7 @@ module RubyIndexer
|
|
56
55
|
end
|
57
56
|
|
58
57
|
# Inserts a `value` using the given `key`
|
59
|
-
|
58
|
+
#: (String key, Value value) -> void
|
60
59
|
def insert(key, value)
|
61
60
|
node = @root
|
62
61
|
|
@@ -73,7 +72,7 @@ module RubyIndexer
|
|
73
72
|
|
74
73
|
# Deletes the entry identified by `key` from the tree. Notice that a partial match will still delete all entries
|
75
74
|
# that match it. For example, if the tree contains `foo` and we ask to delete `fo`, then `foo` will be deleted
|
76
|
-
|
75
|
+
#: (String key) -> void
|
77
76
|
def delete(key)
|
78
77
|
node = find_node(key)
|
79
78
|
return unless node
|
@@ -93,7 +92,7 @@ module RubyIndexer
|
|
93
92
|
private
|
94
93
|
|
95
94
|
# Find a node that matches the given `key`
|
96
|
-
|
95
|
+
#: (String key) -> Node[Value]?
|
97
96
|
def find_node(key)
|
98
97
|
node = @root
|
99
98
|
|
@@ -108,27 +107,26 @@ module RubyIndexer
|
|
108
107
|
end
|
109
108
|
|
110
109
|
class Node
|
111
|
-
extend T::Sig
|
112
110
|
extend T::Generic
|
113
111
|
|
114
112
|
Value = type_member
|
115
113
|
|
116
|
-
|
114
|
+
#: Hash[String, Node[Value]]
|
117
115
|
attr_reader :children
|
118
116
|
|
119
|
-
|
117
|
+
#: String
|
120
118
|
attr_reader :key
|
121
119
|
|
122
|
-
|
120
|
+
#: Value
|
123
121
|
attr_accessor :value
|
124
122
|
|
125
|
-
|
123
|
+
#: bool
|
126
124
|
attr_accessor :leaf
|
127
125
|
|
128
|
-
|
126
|
+
#: Node[Value]?
|
129
127
|
attr_reader :parent
|
130
128
|
|
131
|
-
|
129
|
+
#: (String key, Value value, ?Node[Value]? parent) -> void
|
132
130
|
def initialize(key, value, parent = nil)
|
133
131
|
@key = key
|
134
132
|
@value = value
|
@@ -137,7 +135,7 @@ module RubyIndexer
|
|
137
135
|
@leaf = false
|
138
136
|
end
|
139
137
|
|
140
|
-
|
138
|
+
#: -> Array[Value]
|
141
139
|
def collect
|
142
140
|
result = []
|
143
141
|
result << @value if @leaf
|