ruby-lsp 0.22.0 → 0.23.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp +10 -9
- data/exe/ruby-lsp-check +5 -5
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +26 -20
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +131 -23
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +60 -30
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +73 -55
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +16 -14
- data/lib/{core_ext → ruby_indexer/lib/ruby_indexer}/uri.rb +29 -3
- data/lib/ruby_indexer/ruby_indexer.rb +1 -1
- data/lib/ruby_indexer/test/class_variables_test.rb +140 -0
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +11 -6
- data/lib/ruby_indexer/test/configuration_test.rb +116 -51
- data/lib/ruby_indexer/test/enhancements_test.rb +2 -2
- data/lib/ruby_indexer/test/index_test.rb +72 -43
- data/lib/ruby_indexer/test/method_test.rb +80 -0
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +1 -1
- data/lib/ruby_indexer/test/reference_finder_test.rb +1 -1
- data/lib/ruby_indexer/test/test_case.rb +2 -2
- data/lib/ruby_indexer/test/uri_test.rb +72 -0
- data/lib/ruby_lsp/addon.rb +9 -0
- data/lib/ruby_lsp/base_server.rb +15 -6
- data/lib/ruby_lsp/document.rb +10 -1
- data/lib/ruby_lsp/global_state.rb +1 -1
- data/lib/ruby_lsp/internal.rb +1 -1
- data/lib/ruby_lsp/listeners/code_lens.rb +8 -4
- data/lib/ruby_lsp/listeners/completion.rb +73 -4
- data/lib/ruby_lsp/listeners/definition.rb +73 -17
- data/lib/ruby_lsp/listeners/document_symbol.rb +49 -5
- data/lib/ruby_lsp/listeners/folding_ranges.rb +1 -1
- data/lib/ruby_lsp/listeners/hover.rb +57 -0
- data/lib/ruby_lsp/requests/completion.rb +6 -0
- data/lib/ruby_lsp/requests/completion_resolve.rb +2 -1
- data/lib/ruby_lsp/requests/definition.rb +6 -0
- data/lib/ruby_lsp/requests/prepare_rename.rb +51 -0
- data/lib/ruby_lsp/requests/prepare_type_hierarchy.rb +1 -1
- data/lib/ruby_lsp/requests/rename.rb +14 -4
- data/lib/ruby_lsp/requests/support/common.rb +1 -5
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +1 -1
- data/lib/ruby_lsp/requests/workspace_symbol.rb +3 -2
- data/lib/ruby_lsp/scripts/compose_bundle.rb +1 -1
- data/lib/ruby_lsp/server.rb +42 -7
- data/lib/ruby_lsp/setup_bundler.rb +54 -46
- data/lib/ruby_lsp/test_helper.rb +45 -11
- data/lib/ruby_lsp/type_inferrer.rb +22 -0
- data/lib/ruby_lsp/utils.rb +3 -0
- metadata +7 -8
- data/lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb +0 -29
@@ -16,8 +16,8 @@ module RubyIndexer
|
|
16
16
|
sig { returns(String) }
|
17
17
|
attr_reader :name
|
18
18
|
|
19
|
-
sig { returns(
|
20
|
-
attr_reader :
|
19
|
+
sig { returns(URI::Generic) }
|
20
|
+
attr_reader :uri
|
21
21
|
|
22
22
|
sig { returns(RubyIndexer::Location) }
|
23
23
|
attr_reader :location
|
@@ -30,14 +30,14 @@ module RubyIndexer
|
|
30
30
|
sig do
|
31
31
|
params(
|
32
32
|
name: String,
|
33
|
-
|
33
|
+
uri: URI::Generic,
|
34
34
|
location: Location,
|
35
35
|
comments: T.nilable(String),
|
36
36
|
).void
|
37
37
|
end
|
38
|
-
def initialize(name,
|
38
|
+
def initialize(name, uri, location, comments)
|
39
39
|
@name = name
|
40
|
-
@
|
40
|
+
@uri = uri
|
41
41
|
@comments = comments
|
42
42
|
@visibility = T.let(Visibility::PUBLIC, Visibility)
|
43
43
|
@location = location
|
@@ -60,14 +60,24 @@ module RubyIndexer
|
|
60
60
|
|
61
61
|
sig { returns(String) }
|
62
62
|
def file_name
|
63
|
-
|
63
|
+
if @uri.scheme == "untitled"
|
64
|
+
T.must(@uri.opaque)
|
65
|
+
else
|
66
|
+
File.basename(T.must(file_path))
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { returns(T.nilable(String)) }
|
71
|
+
def file_path
|
72
|
+
@uri.full_path
|
64
73
|
end
|
65
74
|
|
66
75
|
sig { returns(String) }
|
67
76
|
def comments
|
68
77
|
@comments ||= begin
|
69
78
|
# Parse only the comments based on the file path, which is much faster than parsing the entire file
|
70
|
-
|
79
|
+
path = file_path
|
80
|
+
parsed_comments = path ? Prism.parse_file_comments(path) : []
|
71
81
|
|
72
82
|
# Group comments based on whether they belong to a single block of comments
|
73
83
|
grouped = parsed_comments.slice_when do |left, right|
|
@@ -137,18 +147,18 @@ module RubyIndexer
|
|
137
147
|
sig do
|
138
148
|
params(
|
139
149
|
nesting: T::Array[String],
|
140
|
-
|
150
|
+
uri: URI::Generic,
|
141
151
|
location: Location,
|
142
152
|
name_location: Location,
|
143
153
|
comments: T.nilable(String),
|
144
154
|
).void
|
145
155
|
end
|
146
|
-
def initialize(nesting,
|
156
|
+
def initialize(nesting, uri, location, name_location, comments)
|
147
157
|
@name = T.let(nesting.join("::"), String)
|
148
158
|
# The original nesting where this namespace was discovered
|
149
159
|
@nesting = nesting
|
150
160
|
|
151
|
-
super(@name,
|
161
|
+
super(@name, uri, location, comments)
|
152
162
|
|
153
163
|
@name_location = name_location
|
154
164
|
end
|
@@ -186,15 +196,15 @@ module RubyIndexer
|
|
186
196
|
sig do
|
187
197
|
params(
|
188
198
|
nesting: T::Array[String],
|
189
|
-
|
199
|
+
uri: URI::Generic,
|
190
200
|
location: Location,
|
191
201
|
name_location: Location,
|
192
202
|
comments: T.nilable(String),
|
193
203
|
parent_class: T.nilable(String),
|
194
204
|
).void
|
195
205
|
end
|
196
|
-
def initialize(nesting,
|
197
|
-
super(nesting,
|
206
|
+
def initialize(nesting, uri, location, name_location, comments, parent_class) # rubocop:disable Metrics/ParameterLists
|
207
|
+
super(nesting, uri, location, name_location, comments)
|
198
208
|
@parent_class = parent_class
|
199
209
|
end
|
200
210
|
|
@@ -332,15 +342,15 @@ module RubyIndexer
|
|
332
342
|
sig do
|
333
343
|
params(
|
334
344
|
name: String,
|
335
|
-
|
345
|
+
uri: URI::Generic,
|
336
346
|
location: Location,
|
337
347
|
comments: T.nilable(String),
|
338
348
|
visibility: Visibility,
|
339
349
|
owner: T.nilable(Entry::Namespace),
|
340
350
|
).void
|
341
351
|
end
|
342
|
-
def initialize(name,
|
343
|
-
super(name,
|
352
|
+
def initialize(name, uri, location, comments, visibility, owner) # rubocop:disable Metrics/ParameterLists
|
353
|
+
super(name, uri, location, comments)
|
344
354
|
@visibility = visibility
|
345
355
|
@owner = owner
|
346
356
|
end
|
@@ -399,7 +409,7 @@ module RubyIndexer
|
|
399
409
|
sig do
|
400
410
|
params(
|
401
411
|
name: String,
|
402
|
-
|
412
|
+
uri: URI::Generic,
|
403
413
|
location: Location,
|
404
414
|
name_location: Location,
|
405
415
|
comments: T.nilable(String),
|
@@ -408,8 +418,8 @@ module RubyIndexer
|
|
408
418
|
owner: T.nilable(Entry::Namespace),
|
409
419
|
).void
|
410
420
|
end
|
411
|
-
def initialize(name,
|
412
|
-
super(name,
|
421
|
+
def initialize(name, uri, location, name_location, comments, signatures, visibility, owner) # rubocop:disable Metrics/ParameterLists
|
422
|
+
super(name, uri, location, comments, visibility, owner)
|
413
423
|
@signatures = signatures
|
414
424
|
@name_location = name_location
|
415
425
|
end
|
@@ -439,13 +449,13 @@ module RubyIndexer
|
|
439
449
|
target: String,
|
440
450
|
nesting: T::Array[String],
|
441
451
|
name: String,
|
442
|
-
|
452
|
+
uri: URI::Generic,
|
443
453
|
location: Location,
|
444
454
|
comments: T.nilable(String),
|
445
455
|
).void
|
446
456
|
end
|
447
|
-
def initialize(target, nesting, name,
|
448
|
-
super(name,
|
457
|
+
def initialize(target, nesting, name, uri, location, comments) # rubocop:disable Metrics/ParameterLists
|
458
|
+
super(name, uri, location, comments)
|
449
459
|
|
450
460
|
@target = target
|
451
461
|
@nesting = nesting
|
@@ -463,7 +473,7 @@ module RubyIndexer
|
|
463
473
|
def initialize(target, unresolved_alias)
|
464
474
|
super(
|
465
475
|
unresolved_alias.name,
|
466
|
-
unresolved_alias.
|
476
|
+
unresolved_alias.uri,
|
467
477
|
unresolved_alias.location,
|
468
478
|
unresolved_alias.comments,
|
469
479
|
)
|
@@ -476,6 +486,26 @@ module RubyIndexer
|
|
476
486
|
# Represents a global variable e.g.: $DEBUG
|
477
487
|
class GlobalVariable < Entry; end
|
478
488
|
|
489
|
+
# Represents a class variable e.g.: @@a = 1
|
490
|
+
class ClassVariable < Entry
|
491
|
+
sig { returns(T.nilable(Entry::Namespace)) }
|
492
|
+
attr_reader :owner
|
493
|
+
|
494
|
+
sig do
|
495
|
+
params(
|
496
|
+
name: String,
|
497
|
+
uri: URI::Generic,
|
498
|
+
location: Location,
|
499
|
+
comments: T.nilable(String),
|
500
|
+
owner: T.nilable(Entry::Namespace),
|
501
|
+
).void
|
502
|
+
end
|
503
|
+
def initialize(name, uri, location, comments, owner)
|
504
|
+
super(name, uri, location, comments)
|
505
|
+
@owner = owner
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
479
509
|
# Represents an instance variable e.g.: @a = 1
|
480
510
|
class InstanceVariable < Entry
|
481
511
|
sig { returns(T.nilable(Entry::Namespace)) }
|
@@ -484,14 +514,14 @@ module RubyIndexer
|
|
484
514
|
sig do
|
485
515
|
params(
|
486
516
|
name: String,
|
487
|
-
|
517
|
+
uri: URI::Generic,
|
488
518
|
location: Location,
|
489
519
|
comments: T.nilable(String),
|
490
520
|
owner: T.nilable(Entry::Namespace),
|
491
521
|
).void
|
492
522
|
end
|
493
|
-
def initialize(name,
|
494
|
-
super(name,
|
523
|
+
def initialize(name, uri, location, comments, owner)
|
524
|
+
super(name, uri, location, comments)
|
495
525
|
@owner = owner
|
496
526
|
end
|
497
527
|
end
|
@@ -513,13 +543,13 @@ module RubyIndexer
|
|
513
543
|
new_name: String,
|
514
544
|
old_name: String,
|
515
545
|
owner: T.nilable(Entry::Namespace),
|
516
|
-
|
546
|
+
uri: URI::Generic,
|
517
547
|
location: Location,
|
518
548
|
comments: T.nilable(String),
|
519
549
|
).void
|
520
550
|
end
|
521
|
-
def initialize(new_name, old_name, owner,
|
522
|
-
super(new_name,
|
551
|
+
def initialize(new_name, old_name, owner, uri, location, comments) # rubocop:disable Metrics/ParameterLists
|
552
|
+
super(new_name, uri, location, comments)
|
523
553
|
|
524
554
|
@new_name = new_name
|
525
555
|
@old_name = old_name
|
@@ -547,7 +577,7 @@ module RubyIndexer
|
|
547
577
|
|
548
578
|
super(
|
549
579
|
unresolved_alias.new_name,
|
550
|
-
unresolved_alias.
|
580
|
+
unresolved_alias.uri,
|
551
581
|
unresolved_alias.location,
|
552
582
|
full_comments,
|
553
583
|
)
|
@@ -29,13 +29,14 @@ module RubyIndexer
|
|
29
29
|
|
30
30
|
# Holds references to where entries where discovered so that we can easily delete them
|
31
31
|
# {
|
32
|
-
# "
|
33
|
-
# "
|
32
|
+
# "file:///my/project/foo.rb" => [#<Entry::Class>, #<Entry::Class>],
|
33
|
+
# "file:///my/project/bar.rb" => [#<Entry::Class>],
|
34
|
+
# "untitled:Untitled-1" => [#<Entry::Class>],
|
34
35
|
# }
|
35
|
-
@
|
36
|
+
@uris_to_entries = T.let({}, T::Hash[String, T::Array[Entry]])
|
36
37
|
|
37
38
|
# Holds all require paths for every indexed item so that we can provide autocomplete for requires
|
38
|
-
@require_paths_tree = T.let(PrefixTree[
|
39
|
+
@require_paths_tree = T.let(PrefixTree[URI::Generic].new, PrefixTree[URI::Generic])
|
39
40
|
|
40
41
|
# Holds the linearized ancestors list for every namespace
|
41
42
|
@ancestors = T.let({}, T::Hash[String, T::Array[String]])
|
@@ -55,11 +56,12 @@ module RubyIndexer
|
|
55
56
|
(@included_hooks[module_name] ||= []) << hook
|
56
57
|
end
|
57
58
|
|
58
|
-
sig { params(
|
59
|
-
def delete(
|
59
|
+
sig { params(uri: URI::Generic).void }
|
60
|
+
def delete(uri)
|
61
|
+
key = uri.to_s
|
60
62
|
# For each constant discovered in `path`, delete the associated entry from the index. If there are no entries
|
61
63
|
# left, delete the constant from the index.
|
62
|
-
@
|
64
|
+
@uris_to_entries[key]&.each do |entry|
|
63
65
|
name = entry.name
|
64
66
|
entries = @entries[name]
|
65
67
|
next unless entries
|
@@ -77,9 +79,9 @@ module RubyIndexer
|
|
77
79
|
end
|
78
80
|
end
|
79
81
|
|
80
|
-
@
|
82
|
+
@uris_to_entries.delete(key)
|
81
83
|
|
82
|
-
require_path =
|
84
|
+
require_path = uri.require_path
|
83
85
|
@require_paths_tree.delete(require_path) if require_path
|
84
86
|
end
|
85
87
|
|
@@ -88,7 +90,7 @@ module RubyIndexer
|
|
88
90
|
name = entry.name
|
89
91
|
|
90
92
|
(@entries[name] ||= []) << entry
|
91
|
-
(@
|
93
|
+
(@uris_to_entries[entry.uri.to_s] ||= []) << entry
|
92
94
|
@entries_tree.insert(name, T.must(@entries[name])) unless skip_prefix_tree
|
93
95
|
end
|
94
96
|
|
@@ -97,7 +99,7 @@ module RubyIndexer
|
|
97
99
|
@entries[fully_qualified_name.delete_prefix("::")]
|
98
100
|
end
|
99
101
|
|
100
|
-
sig { params(query: String).returns(T::Array[
|
102
|
+
sig { params(query: String).returns(T::Array[URI::Generic]) }
|
101
103
|
def search_require_paths(query)
|
102
104
|
@require_paths_tree.search(query)
|
103
105
|
end
|
@@ -342,16 +344,16 @@ module RubyIndexer
|
|
342
344
|
nil
|
343
345
|
end
|
344
346
|
|
345
|
-
# Index all files for the given
|
346
|
-
#
|
347
|
-
#
|
347
|
+
# Index all files for the given URIs, which defaults to what is configured. A block can be used to track and control
|
348
|
+
# indexing progress. That block is invoked with the current progress percentage and should return `true` to continue
|
349
|
+
# indexing or `false` to stop indexing.
|
348
350
|
sig do
|
349
351
|
params(
|
350
|
-
|
352
|
+
uris: T::Array[URI::Generic],
|
351
353
|
block: T.nilable(T.proc.params(progress: Integer).returns(T::Boolean)),
|
352
354
|
).void
|
353
355
|
end
|
354
|
-
def index_all(
|
356
|
+
def index_all(uris: @configuration.indexable_uris, &block)
|
355
357
|
# When troubleshooting an indexing issue, e.g. through irb, it's not obvious that `index_all` will augment the
|
356
358
|
# existing index values, meaning it may contain 'stale' entries. This check ensures that the user is aware of this
|
357
359
|
# behavior and can take appropriate action.
|
@@ -363,54 +365,48 @@ module RubyIndexer
|
|
363
365
|
|
364
366
|
RBSIndexer.new(self).index_ruby_core
|
365
367
|
# Calculate how many paths are worth 1% of progress
|
366
|
-
progress_step = (
|
368
|
+
progress_step = (uris.length / 100.0).ceil
|
367
369
|
|
368
|
-
|
370
|
+
uris.each_with_index do |uri, index|
|
369
371
|
if block && index % progress_step == 0
|
370
372
|
progress = (index / progress_step) + 1
|
371
373
|
break unless block.call(progress)
|
372
374
|
end
|
373
375
|
|
374
|
-
|
376
|
+
index_file(uri, collect_comments: false)
|
375
377
|
end
|
376
378
|
end
|
377
379
|
|
378
|
-
sig { params(
|
379
|
-
def index_single(
|
380
|
-
content = source || File.read(indexable_path.full_path)
|
380
|
+
sig { params(uri: URI::Generic, source: String, collect_comments: T::Boolean).void }
|
381
|
+
def index_single(uri, source, collect_comments: true)
|
381
382
|
dispatcher = Prism::Dispatcher.new
|
382
383
|
|
383
|
-
result = Prism.parse(
|
384
|
-
listener = DeclarationListener.new(
|
385
|
-
self,
|
386
|
-
dispatcher,
|
387
|
-
result,
|
388
|
-
indexable_path.full_path,
|
389
|
-
collect_comments: collect_comments,
|
390
|
-
)
|
384
|
+
result = Prism.parse(source)
|
385
|
+
listener = DeclarationListener.new(self, dispatcher, result, uri, collect_comments: collect_comments)
|
391
386
|
dispatcher.dispatch(result.value)
|
392
387
|
|
393
|
-
|
394
|
-
|
395
|
-
require_path = indexable_path.require_path
|
396
|
-
@require_paths_tree.insert(require_path, indexable_path) if require_path
|
388
|
+
require_path = uri.require_path
|
389
|
+
@require_paths_tree.insert(require_path, uri) if require_path
|
397
390
|
|
398
|
-
|
399
|
-
|
400
|
-
$stderr.puts error
|
401
|
-
end
|
402
|
-
end
|
403
|
-
rescue Errno::EISDIR, Errno::ENOENT
|
404
|
-
# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
|
405
|
-
# it
|
391
|
+
indexing_errors = listener.indexing_errors.uniq
|
392
|
+
indexing_errors.each { |error| $stderr.puts(error) } if indexing_errors.any?
|
406
393
|
rescue SystemStackError => e
|
407
394
|
if e.backtrace&.first&.include?("prism")
|
408
|
-
$stderr.puts "Prism error indexing #{
|
395
|
+
$stderr.puts "Prism error indexing #{uri}: #{e.message}"
|
409
396
|
else
|
410
397
|
raise
|
411
398
|
end
|
412
399
|
end
|
413
400
|
|
401
|
+
# Indexes a File URI by reading the contents from disk
|
402
|
+
sig { params(uri: URI::Generic, collect_comments: T::Boolean).void }
|
403
|
+
def index_file(uri, collect_comments: true)
|
404
|
+
index_single(uri, File.read(T.must(uri.full_path)), collect_comments: collect_comments)
|
405
|
+
rescue Errno::EISDIR, Errno::ENOENT
|
406
|
+
# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
|
407
|
+
# it
|
408
|
+
end
|
409
|
+
|
414
410
|
# Follows aliases in a namespace. The algorithm keeps checking if the name is an alias and then recursively follows
|
415
411
|
# it. The idea is that we test the name in parts starting from the complete name to the first namespace. For
|
416
412
|
# `Foo::Bar::Baz`, we would test:
|
@@ -588,6 +584,17 @@ module RubyIndexer
|
|
588
584
|
entries.select { |e| ancestors.include?(e.owner&.name) }
|
589
585
|
end
|
590
586
|
|
587
|
+
sig { params(variable_name: String, owner_name: String).returns(T.nilable(T::Array[Entry::ClassVariable])) }
|
588
|
+
def resolve_class_variable(variable_name, owner_name)
|
589
|
+
entries = self[variable_name]&.grep(Entry::ClassVariable)
|
590
|
+
return unless entries&.any?
|
591
|
+
|
592
|
+
ancestors = linearized_ancestors_of(owner_name)
|
593
|
+
return if ancestors.empty?
|
594
|
+
|
595
|
+
entries.select { |e| ancestors.include?(e.owner&.name) }
|
596
|
+
end
|
597
|
+
|
591
598
|
# Returns a list of possible candidates for completion of instance variables for a given owner name. The name must
|
592
599
|
# include the `@` prefix
|
593
600
|
sig { params(name: String, owner_name: String).returns(T::Array[Entry::InstanceVariable]) }
|
@@ -600,16 +607,27 @@ module RubyIndexer
|
|
600
607
|
variables
|
601
608
|
end
|
602
609
|
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
610
|
+
sig { params(name: String, owner_name: String).returns(T::Array[Entry::ClassVariable]) }
|
611
|
+
def class_variable_completion_candidates(name, owner_name)
|
612
|
+
entries = T.cast(prefix_search(name).flatten, T::Array[Entry::ClassVariable])
|
613
|
+
ancestors = linearized_ancestors_of(owner_name)
|
614
|
+
|
615
|
+
variables = entries.select { |e| ancestors.any?(e.owner&.name) }
|
616
|
+
variables.uniq!(&:name)
|
617
|
+
variables
|
618
|
+
end
|
619
|
+
|
620
|
+
# Synchronizes a change made to the given URI. This method will ensure that new declarations are indexed, removed
|
621
|
+
# declarations removed and that the ancestor linearization cache is cleared if necessary
|
622
|
+
sig { params(uri: URI::Generic, source: String).void }
|
623
|
+
def handle_change(uri, source)
|
624
|
+
key = uri.to_s
|
625
|
+
original_entries = @uris_to_entries[key]
|
608
626
|
|
609
|
-
delete(
|
610
|
-
index_single(
|
627
|
+
delete(uri)
|
628
|
+
index_single(uri, source)
|
611
629
|
|
612
|
-
updated_entries = @
|
630
|
+
updated_entries = @uris_to_entries[key]
|
613
631
|
|
614
632
|
return unless original_entries && updated_entries
|
615
633
|
|
@@ -661,7 +679,7 @@ module RubyIndexer
|
|
661
679
|
|
662
680
|
singleton = Entry::SingletonClass.new(
|
663
681
|
[full_singleton_name],
|
664
|
-
attached_ancestor.
|
682
|
+
attached_ancestor.uri,
|
665
683
|
attached_ancestor.location,
|
666
684
|
attached_ancestor.name_location,
|
667
685
|
nil,
|
@@ -675,12 +693,12 @@ module RubyIndexer
|
|
675
693
|
|
676
694
|
sig do
|
677
695
|
type_parameters(:T).params(
|
678
|
-
|
696
|
+
uri: String,
|
679
697
|
type: T.nilable(T::Class[T.all(T.type_parameter(:T), Entry)]),
|
680
698
|
).returns(T.nilable(T.any(T::Array[Entry], T::Array[T.type_parameter(:T)])))
|
681
699
|
end
|
682
|
-
def entries_for(
|
683
|
-
entries = @
|
700
|
+
def entries_for(uri, type = nil)
|
701
|
+
entries = @uris_to_entries[uri.to_s]
|
684
702
|
return entries unless type
|
685
703
|
|
686
704
|
entries&.grep(type)
|
@@ -43,7 +43,7 @@ module RubyIndexer
|
|
43
43
|
handle_class_or_module_declaration(declaration, pathname)
|
44
44
|
when RBS::AST::Declarations::Constant
|
45
45
|
namespace_nesting = declaration.name.namespace.path.map(&:to_s)
|
46
|
-
handle_constant(declaration, namespace_nesting, pathname.to_s)
|
46
|
+
handle_constant(declaration, namespace_nesting, URI::Generic.from_path(path: pathname.to_s))
|
47
47
|
when RBS::AST::Declarations::Global
|
48
48
|
handle_global_variable(declaration, pathname)
|
49
49
|
else # rubocop:disable Style/EmptyElse
|
@@ -56,23 +56,25 @@ module RubyIndexer
|
|
56
56
|
end
|
57
57
|
def handle_class_or_module_declaration(declaration, pathname)
|
58
58
|
nesting = [declaration.name.name.to_s]
|
59
|
-
|
59
|
+
uri = URI::Generic.from_path(path: pathname.to_s)
|
60
60
|
location = to_ruby_indexer_location(declaration.location)
|
61
61
|
comments = comments_to_string(declaration)
|
62
62
|
entry = if declaration.is_a?(RBS::AST::Declarations::Class)
|
63
63
|
parent_class = declaration.super_class&.name&.name&.to_s
|
64
|
-
Entry::Class.new(nesting,
|
64
|
+
Entry::Class.new(nesting, uri, location, location, comments, parent_class)
|
65
65
|
else
|
66
|
-
Entry::Module.new(nesting,
|
66
|
+
Entry::Module.new(nesting, uri, location, location, comments)
|
67
67
|
end
|
68
|
+
|
68
69
|
add_declaration_mixins_to_entry(declaration, entry)
|
69
70
|
@index.add(entry)
|
71
|
+
|
70
72
|
declaration.members.each do |member|
|
71
73
|
case member
|
72
74
|
when RBS::AST::Members::MethodDefinition
|
73
75
|
handle_method(member, entry)
|
74
76
|
when RBS::AST::Declarations::Constant
|
75
|
-
handle_constant(member, nesting,
|
77
|
+
handle_constant(member, nesting, uri)
|
76
78
|
when RBS::AST::Members::Alias
|
77
79
|
# In RBS, an alias means that two methods have the same signature.
|
78
80
|
# It does not mean the same thing as a Ruby alias.
|
@@ -115,7 +117,7 @@ module RubyIndexer
|
|
115
117
|
sig { params(member: RBS::AST::Members::MethodDefinition, owner: Entry::Namespace).void }
|
116
118
|
def handle_method(member, owner)
|
117
119
|
name = member.name.name
|
118
|
-
|
120
|
+
uri = URI::Generic.from_path(path: member.location.buffer.name)
|
119
121
|
location = to_ruby_indexer_location(member.location)
|
120
122
|
comments = comments_to_string(member)
|
121
123
|
|
@@ -132,7 +134,7 @@ module RubyIndexer
|
|
132
134
|
signatures = signatures(member)
|
133
135
|
@index.add(Entry::Method.new(
|
134
136
|
name,
|
135
|
-
|
137
|
+
uri,
|
136
138
|
location,
|
137
139
|
location,
|
138
140
|
comments,
|
@@ -260,12 +262,12 @@ module RubyIndexer
|
|
260
262
|
# Complex::I = ... # Complex::I is a top-level constant
|
261
263
|
#
|
262
264
|
# And we need to handle their nesting differently.
|
263
|
-
sig { params(declaration: RBS::AST::Declarations::Constant, nesting: T::Array[String],
|
264
|
-
def handle_constant(declaration, nesting,
|
265
|
+
sig { params(declaration: RBS::AST::Declarations::Constant, nesting: T::Array[String], uri: URI::Generic).void }
|
266
|
+
def handle_constant(declaration, nesting, uri)
|
265
267
|
fully_qualified_name = [*nesting, declaration.name.name.to_s].join("::")
|
266
268
|
@index.add(Entry::Constant.new(
|
267
269
|
fully_qualified_name,
|
268
|
-
|
270
|
+
uri,
|
269
271
|
to_ruby_indexer_location(declaration.location),
|
270
272
|
comments_to_string(declaration),
|
271
273
|
))
|
@@ -274,13 +276,13 @@ module RubyIndexer
|
|
274
276
|
sig { params(declaration: RBS::AST::Declarations::Global, pathname: Pathname).void }
|
275
277
|
def handle_global_variable(declaration, pathname)
|
276
278
|
name = declaration.name.to_s
|
277
|
-
|
279
|
+
uri = URI::Generic.from_path(path: pathname.to_s)
|
278
280
|
location = to_ruby_indexer_location(declaration.location)
|
279
281
|
comments = comments_to_string(declaration)
|
280
282
|
|
281
283
|
@index.add(Entry::GlobalVariable.new(
|
282
284
|
name,
|
283
|
-
|
285
|
+
uri,
|
284
286
|
location,
|
285
287
|
comments,
|
286
288
|
))
|
@@ -288,14 +290,14 @@ module RubyIndexer
|
|
288
290
|
|
289
291
|
sig { params(member: RBS::AST::Members::Alias, owner_entry: Entry::Namespace).void }
|
290
292
|
def handle_signature_alias(member, owner_entry)
|
291
|
-
|
293
|
+
uri = URI::Generic.from_path(path: member.location.buffer.name)
|
292
294
|
comments = comments_to_string(member)
|
293
295
|
|
294
296
|
entry = Entry::UnresolvedMethodAlias.new(
|
295
297
|
member.new_name.to_s,
|
296
298
|
member.old_name.to_s,
|
297
299
|
owner_entry,
|
298
|
-
|
300
|
+
uri,
|
299
301
|
to_ruby_indexer_location(member.location),
|
300
302
|
comments,
|
301
303
|
)
|
@@ -13,8 +13,15 @@ module URI
|
|
13
13
|
class << self
|
14
14
|
extend T::Sig
|
15
15
|
|
16
|
-
sig
|
17
|
-
|
16
|
+
sig do
|
17
|
+
params(
|
18
|
+
path: String,
|
19
|
+
fragment: T.nilable(String),
|
20
|
+
scheme: String,
|
21
|
+
load_path_entry: T.nilable(String),
|
22
|
+
).returns(URI::Generic)
|
23
|
+
end
|
24
|
+
def from_path(path:, fragment: nil, scheme: "file", load_path_entry: nil)
|
18
25
|
# On Windows, if the path begins with the disk name, we need to add a leading slash to make it a valid URI
|
19
26
|
escaped_path = if /^[A-Z]:/i.match?(path)
|
20
27
|
PARSER.escape("/#{path}")
|
@@ -25,10 +32,27 @@ module URI
|
|
25
32
|
PARSER.escape(path)
|
26
33
|
end
|
27
34
|
|
28
|
-
build(scheme: scheme, path: escaped_path, fragment: fragment)
|
35
|
+
uri = build(scheme: scheme, path: escaped_path, fragment: fragment)
|
36
|
+
|
37
|
+
if load_path_entry
|
38
|
+
uri.require_path = path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb")
|
39
|
+
end
|
40
|
+
|
41
|
+
uri
|
29
42
|
end
|
30
43
|
end
|
31
44
|
|
45
|
+
sig { returns(T.nilable(String)) }
|
46
|
+
attr_accessor :require_path
|
47
|
+
|
48
|
+
sig { params(load_path_entry: String).void }
|
49
|
+
def add_require_path_from_load_entry(load_path_entry)
|
50
|
+
path = to_standardized_path
|
51
|
+
return unless path
|
52
|
+
|
53
|
+
self.require_path = path.delete_prefix("#{load_path_entry}/").delete_suffix(".rb")
|
54
|
+
end
|
55
|
+
|
32
56
|
sig { returns(T.nilable(String)) }
|
33
57
|
def to_standardized_path
|
34
58
|
parsed_path = path
|
@@ -44,5 +68,7 @@ module URI
|
|
44
68
|
unescaped_path
|
45
69
|
end
|
46
70
|
end
|
71
|
+
|
72
|
+
alias_method :full_path, :to_standardized_path
|
47
73
|
end
|
48
74
|
end
|
@@ -4,7 +4,7 @@
|
|
4
4
|
require "yaml"
|
5
5
|
require "did_you_mean"
|
6
6
|
|
7
|
-
require "ruby_indexer/lib/ruby_indexer/
|
7
|
+
require "ruby_indexer/lib/ruby_indexer/uri"
|
8
8
|
require "ruby_indexer/lib/ruby_indexer/declaration_listener"
|
9
9
|
require "ruby_indexer/lib/ruby_indexer/reference_finder"
|
10
10
|
require "ruby_indexer/lib/ruby_indexer/enhancement"
|