ruby-lsp 0.17.4 → 0.17.13
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 +11 -2
- data/VERSION +1 -1
- data/exe/ruby-lsp +26 -1
- data/exe/ruby-lsp-check +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +74 -43
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +26 -0
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +147 -29
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +383 -79
- data/lib/ruby_indexer/lib/ruby_indexer/rbs_indexer.rb +195 -61
- data/lib/ruby_indexer/ruby_indexer.rb +1 -8
- data/lib/ruby_indexer/test/classes_and_modules_test.rb +71 -3
- data/lib/ruby_indexer/test/configuration_test.rb +1 -1
- data/lib/ruby_indexer/test/constant_test.rb +17 -17
- data/lib/ruby_indexer/test/enhancements_test.rb +197 -0
- data/lib/ruby_indexer/test/index_test.rb +367 -17
- data/lib/ruby_indexer/test/method_test.rb +58 -25
- data/lib/ruby_indexer/test/rbs_indexer_test.rb +297 -0
- data/lib/ruby_indexer/test/test_case.rb +1 -5
- data/lib/ruby_lsp/addon.rb +22 -5
- data/lib/ruby_lsp/base_server.rb +8 -3
- data/lib/ruby_lsp/document.rb +27 -46
- data/lib/ruby_lsp/erb_document.rb +125 -0
- data/lib/ruby_lsp/global_state.rb +47 -19
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listeners/completion.rb +161 -57
- data/lib/ruby_lsp/listeners/definition.rb +91 -27
- data/lib/ruby_lsp/listeners/document_highlight.rb +5 -1
- data/lib/ruby_lsp/listeners/hover.rb +61 -19
- data/lib/ruby_lsp/listeners/signature_help.rb +13 -6
- data/lib/ruby_lsp/node_context.rb +65 -5
- data/lib/ruby_lsp/requests/code_action_resolve.rb +107 -9
- data/lib/ruby_lsp/requests/code_actions.rb +11 -2
- data/lib/ruby_lsp/requests/completion.rb +4 -4
- data/lib/ruby_lsp/requests/completion_resolve.rb +14 -9
- data/lib/ruby_lsp/requests/definition.rb +18 -8
- data/lib/ruby_lsp/requests/diagnostics.rb +6 -5
- data/lib/ruby_lsp/requests/document_symbol.rb +2 -7
- data/lib/ruby_lsp/requests/folding_ranges.rb +6 -2
- data/lib/ruby_lsp/requests/formatting.rb +15 -0
- data/lib/ruby_lsp/requests/hover.rb +5 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +6 -4
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -1
- data/lib/ruby_lsp/requests/show_syntax_tree.rb +3 -2
- data/lib/ruby_lsp/requests/signature_help.rb +3 -3
- data/lib/ruby_lsp/requests/support/common.rb +11 -2
- data/lib/ruby_lsp/requests/type_hierarchy_supertypes.rb +2 -6
- data/lib/ruby_lsp/ruby_document.rb +74 -0
- data/lib/ruby_lsp/server.rb +129 -54
- data/lib/ruby_lsp/store.rb +33 -9
- data/lib/ruby_lsp/test_helper.rb +3 -1
- data/lib/ruby_lsp/type_inferrer.rb +61 -25
- data/lib/ruby_lsp/utils.rb +13 -0
- metadata +9 -8
- data/exe/ruby-lsp-doctor +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 042725d7afce428b5c024933a7101151f2f69c57cbb40b4f938384c13d6c974b
|
4
|
+
data.tar.gz: bec8636d402451e1009e87ddd98e6fdedc062643e614b596a0698ffcfcc9b271
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6a6adb40a9ccaaf916f46c041f3eb2cc7a81be73c5d3bf7c05a45472cd9d08e5a9dd04d804b8e15f091645d420037e324368ccbcc619311a1c60c81f241c1b89
|
7
|
+
data.tar.gz: d6b19c8d02cfab8dca9e4d675e8ee549e8b392631a6080757c0413da29a07d1db411d9360b7553a798805d9e6faac7318863e35ba664488c5eb41c869a7e734a
|
data/README.md
CHANGED
@@ -33,7 +33,7 @@ The Ruby LSP features include
|
|
33
33
|
- Completion for classes, modules, constants and require paths
|
34
34
|
- Fuzzy search classes, modules and constants anywhere in the project and its dependencies (workspace symbol)
|
35
35
|
|
36
|
-
|
36
|
+
As of July 2024, Ruby LSP has received significant enhancements to its code navigation features. For an in-depth look at these improvements, including video demonstrations, check out this [article](https://railsatscale.com/2024-07-18-mastering-ruby-code-navigation-major-enhancements-in-ruby-lsp-2024/). Despite these advancements, we plan to continue enhancing its code navigation support even further. You can follow our progress on this [GitHub issue](https://github.com/Shopify/ruby-lsp/issues/899).
|
37
37
|
|
38
38
|
See complete information about features [here](https://shopify.github.io/ruby-lsp/RubyLsp/Requests.html).
|
39
39
|
|
@@ -78,7 +78,12 @@ default gems, except for
|
|
78
78
|
- Gems that only appear under the `:development` group
|
79
79
|
- All Ruby files under `test/**/*.rb`
|
80
80
|
|
81
|
-
|
81
|
+
This behaviour can be overridden and tuned. Learn how to configure it [for VS Code](vscode/README.md#Indexing-Configuration) or [for other editors](EDITORS.md#Indexing-Configuration).
|
82
|
+
|
83
|
+
Note that indexing-dependent behavior, such as definition, hover, completion or workspace symbol will be impacted by
|
84
|
+
the configuration changes.
|
85
|
+
|
86
|
+
The older approach of using a `.index.yml` file has been deprecated and will be removed in a future release.
|
82
87
|
|
83
88
|
```yaml
|
84
89
|
# Exclude files based on a given pattern. Often used to exclude test files or fixtures
|
@@ -109,6 +114,10 @@ features. This is the mechanism that powers addons like
|
|
109
114
|
- [Ruby LSP RSpec](https://github.com/st0012/ruby-lsp-rspec)
|
110
115
|
- [Ruby LSP rubyfmt](https://github.com/jscharf/ruby-lsp-rubyfmt)
|
111
116
|
|
117
|
+
Additionally, some tools may include a Ruby LSP addon directly, like
|
118
|
+
|
119
|
+
- [Standard Ruby (from v1.39.1)](https://github.com/standardrb/standard/wiki/IDE:-vscode#using-ruby-lsp)
|
120
|
+
|
112
121
|
Other community driven addons can be found in [rubygems](https://rubygems.org/search?query=name%3A+ruby-lsp) by
|
113
122
|
searching for the `ruby-lsp` prefix.
|
114
123
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.17.
|
1
|
+
0.17.13
|
data/exe/ruby-lsp
CHANGED
@@ -36,6 +36,10 @@ parser = OptionParser.new do |opts|
|
|
36
36
|
options[:experimental] = true
|
37
37
|
end
|
38
38
|
|
39
|
+
opts.on("--doctor", "Run troubleshooting steps") do
|
40
|
+
options[:doctor] = true
|
41
|
+
end
|
42
|
+
|
39
43
|
opts.on("-h", "--help", "Print this help") do
|
40
44
|
puts opts.help
|
41
45
|
puts
|
@@ -102,9 +106,30 @@ if options[:time_index]
|
|
102
106
|
|
103
107
|
puts <<~MSG
|
104
108
|
Ruby LSP v#{RubyLsp::VERSION}: Indexing took #{result.round(5)} seconds and generated:
|
105
|
-
- #{entries_by_entry_type.map { |k, v| "#{k.name.split("::").last}: #{v.size}" }.join("\n- ")}
|
109
|
+
- #{entries_by_entry_type.sort_by { |k, _| k.to_s }.map { |k, v| "#{k.name.split("::").last}: #{v.size}" }.join("\n- ")}
|
106
110
|
MSG
|
107
111
|
return
|
108
112
|
end
|
109
113
|
|
114
|
+
if options[:doctor]
|
115
|
+
index = RubyIndexer::Index.new
|
116
|
+
|
117
|
+
if File.exist?(".index.yml")
|
118
|
+
begin
|
119
|
+
config = YAML.parse_file(".index.yml").to_ruby
|
120
|
+
rescue => e
|
121
|
+
abort("Error parsing config: #{e.message}")
|
122
|
+
end
|
123
|
+
index.configuration.apply_config(config)
|
124
|
+
end
|
125
|
+
|
126
|
+
puts "Globbing for indexable files"
|
127
|
+
|
128
|
+
index.configuration.indexables.each do |indexable|
|
129
|
+
puts "indexing: #{indexable.full_path}"
|
130
|
+
index.index_single(indexable)
|
131
|
+
end
|
132
|
+
return
|
133
|
+
end
|
134
|
+
|
110
135
|
RubyLsp::Server.new.start
|
data/exe/ruby-lsp-check
CHANGED
@@ -44,7 +44,7 @@ puts "\n"
|
|
44
44
|
puts "Verifying that indexing executes successfully. This may take a while..."
|
45
45
|
|
46
46
|
index = RubyIndexer::Index.new
|
47
|
-
indexables =
|
47
|
+
indexables = index.configuration.indexables
|
48
48
|
|
49
49
|
indexables.each_with_index do |indexable, i|
|
50
50
|
index.index_single(indexable)
|
@@ -8,12 +8,22 @@ module RubyIndexer
|
|
8
8
|
OBJECT_NESTING = T.let(["Object"].freeze, T::Array[String])
|
9
9
|
BASIC_OBJECT_NESTING = T.let(["BasicObject"].freeze, T::Array[String])
|
10
10
|
|
11
|
+
sig { returns(T::Array[String]) }
|
12
|
+
attr_reader :indexing_errors
|
13
|
+
|
11
14
|
sig do
|
12
|
-
params(
|
15
|
+
params(
|
16
|
+
index: Index,
|
17
|
+
dispatcher: Prism::Dispatcher,
|
18
|
+
parse_result: Prism::ParseResult,
|
19
|
+
file_path: String,
|
20
|
+
enhancements: T::Array[Enhancement],
|
21
|
+
).void
|
13
22
|
end
|
14
|
-
def initialize(index, dispatcher, parse_result, file_path)
|
23
|
+
def initialize(index, dispatcher, parse_result, file_path, enhancements: [])
|
15
24
|
@index = index
|
16
25
|
@file_path = file_path
|
26
|
+
@enhancements = enhancements
|
17
27
|
@visibility_stack = T.let([Entry::Visibility::PUBLIC], T::Array[Entry::Visibility])
|
18
28
|
@comments_by_line = T.let(
|
19
29
|
parse_result.comments.to_h do |c|
|
@@ -29,6 +39,7 @@ module RubyIndexer
|
|
29
39
|
|
30
40
|
# A stack of namespace entries that represent where we currently are. Used to properly assign methods to an owner
|
31
41
|
@owner_stack = T.let([], T::Array[Entry::Namespace])
|
42
|
+
@indexing_errors = T.let([], T::Array[String])
|
32
43
|
|
33
44
|
dispatcher.register(
|
34
45
|
self,
|
@@ -64,13 +75,14 @@ module RubyIndexer
|
|
64
75
|
sig { params(node: Prism::ClassNode).void }
|
65
76
|
def on_class_node_enter(node)
|
66
77
|
@visibility_stack.push(Entry::Visibility::PUBLIC)
|
67
|
-
|
78
|
+
constant_path = node.constant_path
|
79
|
+
name = constant_path.slice
|
68
80
|
|
69
81
|
comments = collect_comments(node)
|
70
82
|
|
71
83
|
superclass = node.superclass
|
72
84
|
|
73
|
-
nesting =
|
85
|
+
nesting = actual_nesting(name)
|
74
86
|
|
75
87
|
parent_class = case superclass
|
76
88
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
@@ -93,6 +105,7 @@ module RubyIndexer
|
|
93
105
|
nesting,
|
94
106
|
@file_path,
|
95
107
|
node.location,
|
108
|
+
constant_path.location,
|
96
109
|
comments,
|
97
110
|
parent_class,
|
98
111
|
)
|
@@ -112,12 +125,12 @@ module RubyIndexer
|
|
112
125
|
sig { params(node: Prism::ModuleNode).void }
|
113
126
|
def on_module_node_enter(node)
|
114
127
|
@visibility_stack.push(Entry::Visibility::PUBLIC)
|
115
|
-
|
128
|
+
constant_path = node.constant_path
|
129
|
+
name = constant_path.slice
|
116
130
|
|
117
131
|
comments = collect_comments(node)
|
118
132
|
|
119
|
-
|
120
|
-
entry = Entry::Module.new(nesting, @file_path, node.location, comments)
|
133
|
+
entry = Entry::Module.new(actual_nesting(name), @file_path, node.location, constant_path.location, comments)
|
121
134
|
|
122
135
|
@owner_stack << entry
|
123
136
|
@index.add(entry)
|
@@ -145,9 +158,16 @@ module RubyIndexer
|
|
145
158
|
|
146
159
|
if existing_entries
|
147
160
|
entry = T.must(existing_entries.first)
|
148
|
-
entry.update_singleton_information(node.location, collect_comments(node))
|
161
|
+
entry.update_singleton_information(node.location, expression.location, collect_comments(node))
|
149
162
|
else
|
150
|
-
entry = Entry::SingletonClass.new(
|
163
|
+
entry = Entry::SingletonClass.new(
|
164
|
+
@stack,
|
165
|
+
@file_path,
|
166
|
+
node.location,
|
167
|
+
expression.location,
|
168
|
+
collect_comments(node),
|
169
|
+
nil,
|
170
|
+
)
|
151
171
|
@index.add(entry, skip_prefix_tree: true)
|
152
172
|
end
|
153
173
|
|
@@ -270,6 +290,12 @@ module RubyIndexer
|
|
270
290
|
when :private
|
271
291
|
@visibility_stack.push(Entry::Visibility::PRIVATE)
|
272
292
|
end
|
293
|
+
|
294
|
+
@enhancements.each do |enhancement|
|
295
|
+
enhancement.on_call_node(@index, @owner_stack.last, node, @file_path)
|
296
|
+
rescue StandardError => e
|
297
|
+
@indexing_errors << "Indexing error in #{@file_path} with '#{enhancement.class.name}' enhancement: #{e.message}"
|
298
|
+
end
|
273
299
|
end
|
274
300
|
|
275
301
|
sig { params(node: Prism::CallNode).void }
|
@@ -297,25 +323,29 @@ module RubyIndexer
|
|
297
323
|
method_name,
|
298
324
|
@file_path,
|
299
325
|
node.location,
|
326
|
+
node.name_loc,
|
300
327
|
comments,
|
301
|
-
list_params(node.parameters),
|
328
|
+
[Entry::Signature.new(list_params(node.parameters))],
|
302
329
|
current_visibility,
|
303
330
|
@owner_stack.last,
|
304
331
|
))
|
305
332
|
when Prism::SelfNode
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
333
|
+
owner = @owner_stack.last
|
334
|
+
|
335
|
+
if owner
|
336
|
+
singleton = @index.existing_or_new_singleton_class(owner.name)
|
337
|
+
|
338
|
+
@index.add(Entry::Method.new(
|
339
|
+
method_name,
|
340
|
+
@file_path,
|
341
|
+
node.location,
|
342
|
+
node.name_loc,
|
343
|
+
comments,
|
344
|
+
[Entry::Signature.new(list_params(node.parameters))],
|
345
|
+
current_visibility,
|
346
|
+
singleton,
|
347
|
+
))
|
317
348
|
|
318
|
-
if singleton
|
319
349
|
@owner_stack << singleton
|
320
350
|
@stack << "<Class:#{@stack.last}>"
|
321
351
|
end
|
@@ -393,7 +423,12 @@ module RubyIndexer
|
|
393
423
|
|
394
424
|
# When instance variables are declared inside the class body, they turn into class instance variables rather than
|
395
425
|
# regular instance variables
|
396
|
-
owner = @
|
426
|
+
owner = @owner_stack.last
|
427
|
+
|
428
|
+
if owner && !@inside_def
|
429
|
+
owner = @index.existing_or_new_singleton_class(owner.name)
|
430
|
+
end
|
431
|
+
|
397
432
|
@index.add(Entry::InstanceVariable.new(name, @file_path, loc, collect_comments(node), owner))
|
398
433
|
end
|
399
434
|
|
@@ -486,17 +521,17 @@ module RubyIndexer
|
|
486
521
|
@index.add(
|
487
522
|
case value
|
488
523
|
when Prism::ConstantReadNode, Prism::ConstantPathNode
|
489
|
-
Entry::
|
524
|
+
Entry::UnresolvedConstantAlias.new(value.slice, @stack.dup, name, @file_path, node.location, comments)
|
490
525
|
when Prism::ConstantWriteNode, Prism::ConstantAndWriteNode, Prism::ConstantOrWriteNode,
|
491
526
|
Prism::ConstantOperatorWriteNode
|
492
527
|
|
493
528
|
# If the right hand side is another constant assignment, we need to visit it because that constant has to be
|
494
529
|
# indexed too
|
495
|
-
Entry::
|
530
|
+
Entry::UnresolvedConstantAlias.new(value.name.to_s, @stack.dup, name, @file_path, node.location, comments)
|
496
531
|
when Prism::ConstantPathWriteNode, Prism::ConstantPathOrWriteNode, Prism::ConstantPathOperatorWriteNode,
|
497
532
|
Prism::ConstantPathAndWriteNode
|
498
533
|
|
499
|
-
Entry::
|
534
|
+
Entry::UnresolvedConstantAlias.new(value.target.slice, @stack.dup, name, @file_path, node.location, comments)
|
500
535
|
else
|
501
536
|
Entry::Constant.new(name, @file_path, node.location, comments)
|
502
537
|
end,
|
@@ -517,7 +552,7 @@ module RubyIndexer
|
|
517
552
|
comment_content = comment.location.slice.chomp
|
518
553
|
|
519
554
|
# invalid encodings would raise an "invalid byte sequence" exception
|
520
|
-
if !comment_content.valid_encoding? || comment_content.match?(
|
555
|
+
if !comment_content.valid_encoding? || comment_content.match?(@index.configuration.magic_comment_regex)
|
521
556
|
next
|
522
557
|
end
|
523
558
|
|
@@ -593,7 +628,8 @@ module RubyIndexer
|
|
593
628
|
when :prepend
|
594
629
|
owner.mixin_operations << Entry::Prepend.new(node.full_name)
|
595
630
|
when :extend
|
596
|
-
|
631
|
+
singleton = @index.existing_or_new_singleton_class(owner.name)
|
632
|
+
singleton.mixin_operations << Entry::Include.new(node.full_name)
|
597
633
|
end
|
598
634
|
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
599
635
|
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
@@ -690,23 +726,18 @@ module RubyIndexer
|
|
690
726
|
end
|
691
727
|
end
|
692
728
|
|
693
|
-
sig { returns(T
|
694
|
-
def
|
695
|
-
|
696
|
-
|
729
|
+
sig { params(name: String).returns(T::Array[String]) }
|
730
|
+
def actual_nesting(name)
|
731
|
+
nesting = @stack + [name]
|
732
|
+
corrected_nesting = []
|
697
733
|
|
698
|
-
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
return owner.first if owner
|
734
|
+
nesting.reverse_each do |name|
|
735
|
+
corrected_nesting.prepend(name.delete_prefix("::"))
|
736
|
+
|
737
|
+
break if name.start_with?("::")
|
738
|
+
end
|
704
739
|
|
705
|
-
|
706
|
-
nesting = @stack + ["<Class:#{@stack.last}>"]
|
707
|
-
entry = Entry::SingletonClass.new(nesting, @file_path, attached_class.location, [], nil)
|
708
|
-
@index.add(entry, skip_prefix_tree: true)
|
709
|
-
entry
|
740
|
+
corrected_nesting
|
710
741
|
end
|
711
742
|
end
|
712
743
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyIndexer
|
5
|
+
module Enhancement
|
6
|
+
extend T::Sig
|
7
|
+
extend T::Helpers
|
8
|
+
|
9
|
+
interface!
|
10
|
+
|
11
|
+
requires_ancestor { Object }
|
12
|
+
|
13
|
+
# The `on_extend` indexing enhancement is invoked whenever an extend is encountered in the code. It can be used to
|
14
|
+
# register for an included callback, similar to what `ActiveSupport::Concern` does in order to auto-extend the
|
15
|
+
# `ClassMethods` modules
|
16
|
+
sig do
|
17
|
+
abstract.params(
|
18
|
+
index: Index,
|
19
|
+
owner: T.nilable(Entry::Namespace),
|
20
|
+
node: Prism::CallNode,
|
21
|
+
file_path: String,
|
22
|
+
).void
|
23
|
+
end
|
24
|
+
def on_call_node(index, owner, node, file_path); end
|
25
|
+
end
|
26
|
+
end
|