ruby-lsp 0.17.10 → 0.17.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/VERSION +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb +19 -2
- data/lib/ruby_indexer/lib/ruby_indexer/enhancement.rb +26 -0
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +23 -0
- data/lib/ruby_indexer/lib/ruby_indexer/index.rb +70 -1
- data/lib/ruby_indexer/ruby_indexer.rb +1 -0
- data/lib/ruby_indexer/test/enhancements_test.rb +197 -0
- data/lib/ruby_lsp/document.rb +34 -0
- data/lib/ruby_lsp/listeners/definition.rb +24 -3
- data/lib/ruby_lsp/listeners/hover.rb +4 -1
- data/lib/ruby_lsp/requests/code_action_resolve.rb +104 -6
- data/lib/ruby_lsp/requests/code_actions.rb +11 -2
- data/lib/ruby_lsp/requests/completion_resolve.rb +1 -0
- data/lib/ruby_lsp/requests/definition.rb +9 -2
- 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 +13 -0
- data/lib/ruby_lsp/requests/hover.rb +2 -2
- data/lib/ruby_lsp/requests/on_type_formatting.rb +3 -2
- data/lib/ruby_lsp/server.rb +2 -9
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 34cae8b53cfb0811cb26d3b3dd4198a72585d1f15a98a7d8f656fd1676886630
|
|
4
|
+
data.tar.gz: f4868222c46c4cbad9a099fce69562838b5dda567f1666a82752f45fe3f501c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: db8e991497aa6e9388b2778fb9a417adbef07c6bb29165ff9a1718ab7cf1db6d2a6586453320d72adf0cffe78b846b553c3a0ba24b63807c52170f02f1b7d2e3
|
|
7
|
+
data.tar.gz: 80aac045ca6aaf7dbb9344f947a9b1419eaac4711448d997c902f0fb9da68e7c2338e0a5b1d81a30c0a2609defe1b656457d1a4a23b0ba5288162d142cf7c9e9
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.17.
|
|
1
|
+
0.17.12
|
|
@@ -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,
|
|
@@ -279,6 +290,12 @@ module RubyIndexer
|
|
|
279
290
|
when :private
|
|
280
291
|
@visibility_stack.push(Entry::Visibility::PRIVATE)
|
|
281
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
|
|
282
299
|
end
|
|
283
300
|
|
|
284
301
|
sig { params(node: Prism::CallNode).void }
|
|
@@ -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
|
|
@@ -342,6 +342,19 @@ module RubyIndexer
|
|
|
342
342
|
|
|
343
343
|
"(#{first_signature.format})"
|
|
344
344
|
end
|
|
345
|
+
|
|
346
|
+
sig { returns(String) }
|
|
347
|
+
def formatted_signatures
|
|
348
|
+
overloads_count = signatures.size
|
|
349
|
+
case overloads_count
|
|
350
|
+
when 1
|
|
351
|
+
""
|
|
352
|
+
when 2
|
|
353
|
+
"\n(+1 overload)"
|
|
354
|
+
else
|
|
355
|
+
"\n(+#{overloads_count - 1} overloads)"
|
|
356
|
+
end
|
|
357
|
+
end
|
|
345
358
|
end
|
|
346
359
|
|
|
347
360
|
class Accessor < Member
|
|
@@ -542,6 +555,16 @@ module RubyIndexer
|
|
|
542
555
|
def decorated_parameters
|
|
543
556
|
@target.decorated_parameters
|
|
544
557
|
end
|
|
558
|
+
|
|
559
|
+
sig { returns(String) }
|
|
560
|
+
def formatted_signatures
|
|
561
|
+
@target.formatted_signatures
|
|
562
|
+
end
|
|
563
|
+
|
|
564
|
+
sig { returns(T::Array[Signature]) }
|
|
565
|
+
def signatures
|
|
566
|
+
@target.signatures
|
|
567
|
+
end
|
|
545
568
|
end
|
|
546
569
|
|
|
547
570
|
# Ruby doesn't support method overloading, so a method will have only one signature.
|
|
@@ -35,6 +35,27 @@ module RubyIndexer
|
|
|
35
35
|
|
|
36
36
|
# Holds the linearized ancestors list for every namespace
|
|
37
37
|
@ancestors = T.let({}, T::Hash[String, T::Array[String]])
|
|
38
|
+
|
|
39
|
+
# List of classes that are enhancing the index
|
|
40
|
+
@enhancements = T.let([], T::Array[Enhancement])
|
|
41
|
+
|
|
42
|
+
# Map of module name to included hooks that have to be executed when we include the given module
|
|
43
|
+
@included_hooks = T.let(
|
|
44
|
+
{},
|
|
45
|
+
T::Hash[String, T::Array[T.proc.params(index: Index, base: Entry::Namespace).void]],
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Register an enhancement to the index. Enhancements must conform to the `Enhancement` interface
|
|
50
|
+
sig { params(enhancement: Enhancement).void }
|
|
51
|
+
def register_enhancement(enhancement)
|
|
52
|
+
@enhancements << enhancement
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Register an included `hook` that will be executed when `module_name` is included into any namespace
|
|
56
|
+
sig { params(module_name: String, hook: T.proc.params(index: Index, base: Entry::Namespace).void).void }
|
|
57
|
+
def register_included_hook(module_name, &hook)
|
|
58
|
+
(@included_hooks[module_name] ||= []) << hook
|
|
38
59
|
end
|
|
39
60
|
|
|
40
61
|
sig { params(indexable: IndexablePath).void }
|
|
@@ -296,11 +317,25 @@ module RubyIndexer
|
|
|
296
317
|
dispatcher = Prism::Dispatcher.new
|
|
297
318
|
|
|
298
319
|
result = Prism.parse(content)
|
|
299
|
-
DeclarationListener.new(
|
|
320
|
+
listener = DeclarationListener.new(
|
|
321
|
+
self,
|
|
322
|
+
dispatcher,
|
|
323
|
+
result,
|
|
324
|
+
indexable_path.full_path,
|
|
325
|
+
enhancements: @enhancements,
|
|
326
|
+
)
|
|
300
327
|
dispatcher.dispatch(result.value)
|
|
301
328
|
|
|
329
|
+
indexing_errors = listener.indexing_errors.uniq
|
|
330
|
+
|
|
302
331
|
require_path = indexable_path.require_path
|
|
303
332
|
@require_paths_tree.insert(require_path, indexable_path) if require_path
|
|
333
|
+
|
|
334
|
+
if indexing_errors.any?
|
|
335
|
+
indexing_errors.each do |error|
|
|
336
|
+
$stderr.puts error
|
|
337
|
+
end
|
|
338
|
+
end
|
|
304
339
|
rescue Errno::EISDIR, Errno::ENOENT
|
|
305
340
|
# If `path` is a directory, just ignore it and continue indexing. If the file doesn't exist, then we also ignore
|
|
306
341
|
# it
|
|
@@ -457,6 +492,12 @@ module RubyIndexer
|
|
|
457
492
|
end
|
|
458
493
|
end
|
|
459
494
|
|
|
495
|
+
# We only need to run included hooks when linearizing singleton classes. Included hooks are typically used to add
|
|
496
|
+
# new singleton methods or to extend a module through an include. There's no need to support instance methods, the
|
|
497
|
+
# inclusion of another module or the prepending of another module, because those features are already a part of
|
|
498
|
+
# Ruby and can be used directly without any metaprogramming
|
|
499
|
+
run_included_hooks(attached_class_name, nesting) if singleton_levels > 0
|
|
500
|
+
|
|
460
501
|
linearize_mixins(ancestors, namespaces, nesting)
|
|
461
502
|
linearize_superclass(
|
|
462
503
|
ancestors,
|
|
@@ -570,6 +611,34 @@ module RubyIndexer
|
|
|
570
611
|
|
|
571
612
|
private
|
|
572
613
|
|
|
614
|
+
# Runs the registered included hooks
|
|
615
|
+
sig { params(fully_qualified_name: String, nesting: T::Array[String]).void }
|
|
616
|
+
def run_included_hooks(fully_qualified_name, nesting)
|
|
617
|
+
return if @included_hooks.empty?
|
|
618
|
+
|
|
619
|
+
namespaces = self[fully_qualified_name]&.grep(Entry::Namespace)
|
|
620
|
+
return unless namespaces
|
|
621
|
+
|
|
622
|
+
namespaces.each do |namespace|
|
|
623
|
+
namespace.mixin_operations.each do |operation|
|
|
624
|
+
next unless operation.is_a?(Entry::Include)
|
|
625
|
+
|
|
626
|
+
# First we resolve the include name, so that we know the actual module being referred to in the include
|
|
627
|
+
resolved_modules = resolve(operation.module_name, nesting)
|
|
628
|
+
next unless resolved_modules
|
|
629
|
+
|
|
630
|
+
module_name = T.must(resolved_modules.first).name
|
|
631
|
+
|
|
632
|
+
# Then we grab any hooks registered for that module
|
|
633
|
+
hooks = @included_hooks[module_name]
|
|
634
|
+
next unless hooks
|
|
635
|
+
|
|
636
|
+
# We invoke the hooks with the index and the namespace that included the module
|
|
637
|
+
hooks.each { |hook| hook.call(self, namespace) }
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
end
|
|
641
|
+
|
|
573
642
|
# Linearize mixins for an array of namespace entries. This method will mutate the `ancestors` array with the
|
|
574
643
|
# linearized ancestors of the mixins
|
|
575
644
|
sig do
|
|
@@ -6,6 +6,7 @@ require "did_you_mean"
|
|
|
6
6
|
|
|
7
7
|
require "ruby_indexer/lib/ruby_indexer/indexable_path"
|
|
8
8
|
require "ruby_indexer/lib/ruby_indexer/declaration_listener"
|
|
9
|
+
require "ruby_indexer/lib/ruby_indexer/enhancement"
|
|
9
10
|
require "ruby_indexer/lib/ruby_indexer/index"
|
|
10
11
|
require "ruby_indexer/lib/ruby_indexer/entry"
|
|
11
12
|
require "ruby_indexer/lib/ruby_indexer/configuration"
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative "test_case"
|
|
5
|
+
|
|
6
|
+
module RubyIndexer
|
|
7
|
+
class EnhancementTest < TestCase
|
|
8
|
+
def test_enhancing_indexing_included_hook
|
|
9
|
+
enhancement_class = Class.new do
|
|
10
|
+
include Enhancement
|
|
11
|
+
|
|
12
|
+
def on_call_node(index, owner, node, file_path)
|
|
13
|
+
return unless owner
|
|
14
|
+
return unless node.name == :extend
|
|
15
|
+
|
|
16
|
+
arguments = node.arguments&.arguments
|
|
17
|
+
return unless arguments
|
|
18
|
+
|
|
19
|
+
location = node.location
|
|
20
|
+
|
|
21
|
+
arguments.each do |node|
|
|
22
|
+
next unless node.is_a?(Prism::ConstantReadNode) || node.is_a?(Prism::ConstantPathNode)
|
|
23
|
+
|
|
24
|
+
module_name = node.full_name
|
|
25
|
+
next unless module_name == "ActiveSupport::Concern"
|
|
26
|
+
|
|
27
|
+
index.register_included_hook(owner.name) do |index, base|
|
|
28
|
+
class_methods_name = "#{owner.name}::ClassMethods"
|
|
29
|
+
|
|
30
|
+
if index.indexed?(class_methods_name)
|
|
31
|
+
singleton = index.existing_or_new_singleton_class(base.name)
|
|
32
|
+
singleton.mixin_operations << Entry::Include.new(class_methods_name)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
index.add(Entry::Method.new(
|
|
37
|
+
"new_method",
|
|
38
|
+
file_path,
|
|
39
|
+
location,
|
|
40
|
+
location,
|
|
41
|
+
[],
|
|
42
|
+
[Entry::Signature.new([Entry::RequiredParameter.new(name: :a)])],
|
|
43
|
+
Entry::Visibility::PUBLIC,
|
|
44
|
+
owner,
|
|
45
|
+
))
|
|
46
|
+
rescue Prism::ConstantPathNode::DynamicPartsInConstantPathError,
|
|
47
|
+
Prism::ConstantPathNode::MissingNodesInConstantPathError
|
|
48
|
+
# Do nothing
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@index.register_enhancement(enhancement_class.new)
|
|
54
|
+
index(<<~RUBY)
|
|
55
|
+
module ActiveSupport
|
|
56
|
+
module Concern
|
|
57
|
+
def self.extended(base)
|
|
58
|
+
base.class_eval("def new_method(a); end")
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
module ActiveRecord
|
|
64
|
+
module Associations
|
|
65
|
+
extend ActiveSupport::Concern
|
|
66
|
+
|
|
67
|
+
module ClassMethods
|
|
68
|
+
def belongs_to(something); end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class Base
|
|
73
|
+
include Associations
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
class User < ActiveRecord::Base
|
|
78
|
+
end
|
|
79
|
+
RUBY
|
|
80
|
+
|
|
81
|
+
assert_equal(
|
|
82
|
+
[
|
|
83
|
+
"User::<Class:User>",
|
|
84
|
+
"ActiveRecord::Base::<Class:Base>",
|
|
85
|
+
"ActiveRecord::Associations::ClassMethods",
|
|
86
|
+
"Object::<Class:Object>",
|
|
87
|
+
"BasicObject::<Class:BasicObject>",
|
|
88
|
+
"Class",
|
|
89
|
+
"Module",
|
|
90
|
+
"Object",
|
|
91
|
+
"Kernel",
|
|
92
|
+
"BasicObject",
|
|
93
|
+
],
|
|
94
|
+
@index.linearized_ancestors_of("User::<Class:User>"),
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
assert_entry("new_method", Entry::Method, "/fake/path/foo.rb:10-4:10-33")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def test_enhancing_indexing_configuration_dsl
|
|
101
|
+
enhancement_class = Class.new do
|
|
102
|
+
include Enhancement
|
|
103
|
+
|
|
104
|
+
def on_call_node(index, owner, node, file_path)
|
|
105
|
+
return unless owner
|
|
106
|
+
|
|
107
|
+
name = node.name
|
|
108
|
+
return unless name == :has_many
|
|
109
|
+
|
|
110
|
+
arguments = node.arguments&.arguments
|
|
111
|
+
return unless arguments
|
|
112
|
+
|
|
113
|
+
association_name = arguments.first
|
|
114
|
+
return unless association_name.is_a?(Prism::SymbolNode)
|
|
115
|
+
|
|
116
|
+
location = association_name.location
|
|
117
|
+
|
|
118
|
+
index.add(Entry::Method.new(
|
|
119
|
+
T.must(association_name.value),
|
|
120
|
+
file_path,
|
|
121
|
+
location,
|
|
122
|
+
location,
|
|
123
|
+
[],
|
|
124
|
+
[],
|
|
125
|
+
Entry::Visibility::PUBLIC,
|
|
126
|
+
owner,
|
|
127
|
+
))
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
@index.register_enhancement(enhancement_class.new)
|
|
132
|
+
index(<<~RUBY)
|
|
133
|
+
module ActiveSupport
|
|
134
|
+
module Concern
|
|
135
|
+
def self.extended(base)
|
|
136
|
+
base.class_eval("def new_method(a); end")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
module ActiveRecord
|
|
142
|
+
module Associations
|
|
143
|
+
extend ActiveSupport::Concern
|
|
144
|
+
|
|
145
|
+
module ClassMethods
|
|
146
|
+
def belongs_to(something); end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
class Base
|
|
151
|
+
include Associations
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
class User < ActiveRecord::Base
|
|
156
|
+
has_many :posts
|
|
157
|
+
end
|
|
158
|
+
RUBY
|
|
159
|
+
|
|
160
|
+
assert_entry("posts", Entry::Method, "/fake/path/foo.rb:23-11:23-17")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def test_error_handling_in_enhancement
|
|
164
|
+
enhancement_class = Class.new do
|
|
165
|
+
include Enhancement
|
|
166
|
+
|
|
167
|
+
def on_call_node(index, owner, node, file_path)
|
|
168
|
+
raise "Error"
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
class << self
|
|
172
|
+
def name
|
|
173
|
+
"TestEnhancement"
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
@index.register_enhancement(enhancement_class.new)
|
|
179
|
+
|
|
180
|
+
_stdout, stderr = capture_io do
|
|
181
|
+
index(<<~RUBY)
|
|
182
|
+
module ActiveSupport
|
|
183
|
+
module Concern
|
|
184
|
+
def self.extended(base)
|
|
185
|
+
base.class_eval("def new_method(a); end")
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
RUBY
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
assert_match(%r{Indexing error in /fake/path/foo\.rb with 'TestEnhancement' enhancement}, stderr)
|
|
193
|
+
# The module should still be indexed
|
|
194
|
+
assert_entry("ActiveSupport::Concern", Entry::Module, "/fake/path/foo.rb:1-2:5-5")
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
end
|
data/lib/ruby_lsp/document.rb
CHANGED
|
@@ -223,6 +223,40 @@ module RubyLsp
|
|
|
223
223
|
NodeContext.new(closest, parent, nesting_nodes, call_node)
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
+
sig do
|
|
227
|
+
params(
|
|
228
|
+
range: T::Hash[Symbol, T.untyped],
|
|
229
|
+
node_types: T::Array[T.class_of(Prism::Node)],
|
|
230
|
+
).returns(T.nilable(Prism::Node))
|
|
231
|
+
end
|
|
232
|
+
def locate_first_within_range(range, node_types: [])
|
|
233
|
+
scanner = create_scanner
|
|
234
|
+
start_position = scanner.find_char_position(range[:start])
|
|
235
|
+
end_position = scanner.find_char_position(range[:end])
|
|
236
|
+
desired_range = (start_position...end_position)
|
|
237
|
+
queue = T.let(@parse_result.value.child_nodes.compact, T::Array[T.nilable(Prism::Node)])
|
|
238
|
+
|
|
239
|
+
until queue.empty?
|
|
240
|
+
candidate = queue.shift
|
|
241
|
+
|
|
242
|
+
# Skip nil child nodes
|
|
243
|
+
next if candidate.nil?
|
|
244
|
+
|
|
245
|
+
# Add the next child_nodes to the queue to be processed. The order here is important! We want to move in the
|
|
246
|
+
# same order as the visiting mechanism, which means searching the child nodes before moving on to the next
|
|
247
|
+
# sibling
|
|
248
|
+
T.unsafe(queue).unshift(*candidate.child_nodes)
|
|
249
|
+
|
|
250
|
+
# Skip if the current node doesn't cover the desired position
|
|
251
|
+
loc = candidate.location
|
|
252
|
+
|
|
253
|
+
if desired_range.cover?(loc.start_offset...loc.end_offset) &&
|
|
254
|
+
(node_types.empty? || node_types.any? { |type| candidate.class == type })
|
|
255
|
+
return candidate
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
|
|
226
260
|
sig { returns(SorbetLevel) }
|
|
227
261
|
def sorbet_level
|
|
228
262
|
sigil = parse_result.magic_comments.find do |comment|
|
|
@@ -46,6 +46,7 @@ module RubyLsp
|
|
|
46
46
|
:on_instance_variable_or_write_node_enter,
|
|
47
47
|
:on_instance_variable_target_node_enter,
|
|
48
48
|
:on_string_node_enter,
|
|
49
|
+
:on_symbol_node_enter,
|
|
49
50
|
:on_super_node_enter,
|
|
50
51
|
:on_forwarding_super_node_enter,
|
|
51
52
|
)
|
|
@@ -54,9 +55,7 @@ module RubyLsp
|
|
|
54
55
|
sig { params(node: Prism::CallNode).void }
|
|
55
56
|
def on_call_node_enter(node)
|
|
56
57
|
# Sorbet can handle go to definition for methods invoked on self on typed true or higher
|
|
57
|
-
if (@sorbet_level
|
|
58
|
-
self_receiver?(node)
|
|
59
|
-
end
|
|
58
|
+
return if sorbet_level_true_or_higher?(@sorbet_level) && self_receiver?(node)
|
|
60
59
|
|
|
61
60
|
message = node.message
|
|
62
61
|
return unless message
|
|
@@ -83,6 +82,17 @@ module RubyLsp
|
|
|
83
82
|
handle_require_definition(node, name)
|
|
84
83
|
end
|
|
85
84
|
|
|
85
|
+
sig { params(node: Prism::SymbolNode).void }
|
|
86
|
+
def on_symbol_node_enter(node)
|
|
87
|
+
enclosing_call = @node_context.call_node
|
|
88
|
+
return unless enclosing_call
|
|
89
|
+
|
|
90
|
+
name = enclosing_call.name
|
|
91
|
+
return unless name == :autoload
|
|
92
|
+
|
|
93
|
+
handle_autoload_definition(enclosing_call)
|
|
94
|
+
end
|
|
95
|
+
|
|
86
96
|
sig { params(node: Prism::BlockArgumentNode).void }
|
|
87
97
|
def on_block_argument_node_enter(node)
|
|
88
98
|
expression = node.expression
|
|
@@ -253,6 +263,17 @@ module RubyLsp
|
|
|
253
263
|
end
|
|
254
264
|
end
|
|
255
265
|
|
|
266
|
+
sig { params(node: Prism::CallNode).void }
|
|
267
|
+
def handle_autoload_definition(node)
|
|
268
|
+
argument = node.arguments&.arguments&.first
|
|
269
|
+
return unless argument.is_a?(Prism::SymbolNode)
|
|
270
|
+
|
|
271
|
+
constant_name = argument.value
|
|
272
|
+
return unless constant_name
|
|
273
|
+
|
|
274
|
+
find_in_index(constant_name)
|
|
275
|
+
end
|
|
276
|
+
|
|
256
277
|
sig { params(value: String).void }
|
|
257
278
|
def find_in_index(value)
|
|
258
279
|
entries = @index.resolve(value, @node_context.nesting)
|
|
@@ -174,7 +174,10 @@ module RubyLsp
|
|
|
174
174
|
methods = @index.resolve_method(message, type.name, inherited_only: inherited_only)
|
|
175
175
|
return unless methods
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
first_method = T.must(methods.first)
|
|
178
|
+
|
|
179
|
+
title = "#{message}#{first_method.decorated_parameters}"
|
|
180
|
+
title << first_method.formatted_signatures
|
|
178
181
|
|
|
179
182
|
if type.is_a?(TypeInferrer::GuessedType)
|
|
180
183
|
title << "\n\nGuessed receiver: #{type.name}"
|
|
@@ -23,6 +23,8 @@ module RubyLsp
|
|
|
23
23
|
#
|
|
24
24
|
class CodeActionResolve < Request
|
|
25
25
|
extend T::Sig
|
|
26
|
+
include Support::Common
|
|
27
|
+
|
|
26
28
|
NEW_VARIABLE_NAME = "new_variable"
|
|
27
29
|
NEW_METHOD_NAME = "new_method"
|
|
28
30
|
|
|
@@ -45,20 +47,62 @@ module RubyLsp
|
|
|
45
47
|
|
|
46
48
|
sig { override.returns(T.any(Interface::CodeAction, Error)) }
|
|
47
49
|
def perform
|
|
50
|
+
return Error::EmptySelection if @document.source.empty?
|
|
51
|
+
|
|
48
52
|
case @code_action[:title]
|
|
49
53
|
when CodeActions::EXTRACT_TO_VARIABLE_TITLE
|
|
50
54
|
refactor_variable
|
|
51
55
|
when CodeActions::EXTRACT_TO_METHOD_TITLE
|
|
52
56
|
refactor_method
|
|
57
|
+
when CodeActions::SWITCH_BLOCK_STYLE_TITLE
|
|
58
|
+
switch_block_style
|
|
53
59
|
else
|
|
54
60
|
Error::UnknownCodeAction
|
|
55
61
|
end
|
|
56
62
|
end
|
|
57
63
|
|
|
64
|
+
private
|
|
65
|
+
|
|
58
66
|
sig { returns(T.any(Interface::CodeAction, Error)) }
|
|
59
|
-
def
|
|
60
|
-
|
|
67
|
+
def switch_block_style
|
|
68
|
+
source_range = @code_action.dig(:data, :range)
|
|
69
|
+
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
|
70
|
+
|
|
71
|
+
target = @document.locate_first_within_range(
|
|
72
|
+
@code_action.dig(:data, :range),
|
|
73
|
+
node_types: [Prism::CallNode],
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
return Error::InvalidTargetRange unless target.is_a?(Prism::CallNode)
|
|
77
|
+
|
|
78
|
+
node = target.block
|
|
79
|
+
return Error::InvalidTargetRange unless node.is_a?(Prism::BlockNode)
|
|
61
80
|
|
|
81
|
+
indentation = " " * target.location.start_column unless node.opening_loc.slice == "do"
|
|
82
|
+
|
|
83
|
+
Interface::CodeAction.new(
|
|
84
|
+
title: CodeActions::SWITCH_BLOCK_STYLE_TITLE,
|
|
85
|
+
edit: Interface::WorkspaceEdit.new(
|
|
86
|
+
document_changes: [
|
|
87
|
+
Interface::TextDocumentEdit.new(
|
|
88
|
+
text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
|
|
89
|
+
uri: @code_action.dig(:data, :uri),
|
|
90
|
+
version: nil,
|
|
91
|
+
),
|
|
92
|
+
edits: [
|
|
93
|
+
Interface::TextEdit.new(
|
|
94
|
+
range: range_from_location(node.location),
|
|
95
|
+
new_text: recursively_switch_nested_block_styles(node, indentation),
|
|
96
|
+
),
|
|
97
|
+
],
|
|
98
|
+
),
|
|
99
|
+
],
|
|
100
|
+
),
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
sig { returns(T.any(Interface::CodeAction, Error)) }
|
|
105
|
+
def refactor_variable
|
|
62
106
|
source_range = @code_action.dig(:data, :range)
|
|
63
107
|
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
|
64
108
|
|
|
@@ -153,8 +197,6 @@ module RubyLsp
|
|
|
153
197
|
|
|
154
198
|
sig { returns(T.any(Interface::CodeAction, Error)) }
|
|
155
199
|
def refactor_method
|
|
156
|
-
return Error::EmptySelection if @document.source.empty?
|
|
157
|
-
|
|
158
200
|
source_range = @code_action.dig(:data, :range)
|
|
159
201
|
return Error::EmptySelection if source_range[:start] == source_range[:end]
|
|
160
202
|
|
|
@@ -206,8 +248,6 @@ module RubyLsp
|
|
|
206
248
|
)
|
|
207
249
|
end
|
|
208
250
|
|
|
209
|
-
private
|
|
210
|
-
|
|
211
251
|
sig { params(range: T::Hash[Symbol, T.untyped], new_text: String).returns(Interface::TextEdit) }
|
|
212
252
|
def create_text_edit(range, new_text)
|
|
213
253
|
Interface::TextEdit.new(
|
|
@@ -218,6 +258,64 @@ module RubyLsp
|
|
|
218
258
|
new_text: new_text,
|
|
219
259
|
)
|
|
220
260
|
end
|
|
261
|
+
|
|
262
|
+
sig { params(node: Prism::BlockNode, indentation: T.nilable(String)).returns(String) }
|
|
263
|
+
def recursively_switch_nested_block_styles(node, indentation)
|
|
264
|
+
parameters = node.parameters
|
|
265
|
+
body = node.body
|
|
266
|
+
|
|
267
|
+
# We use the indentation to differentiate between do...end and brace style blocks because only the do...end
|
|
268
|
+
# style requires the indentation to build the edit.
|
|
269
|
+
#
|
|
270
|
+
# If the block is using `do...end` style, we change it to a single line brace block. Newlines are turned into
|
|
271
|
+
# semi colons, so that the result is valid Ruby code and still a one liner. If the block is using brace style,
|
|
272
|
+
# we do the opposite and turn it into a `do...end` block, making all semi colons into newlines.
|
|
273
|
+
source = +""
|
|
274
|
+
|
|
275
|
+
if indentation
|
|
276
|
+
source << "do"
|
|
277
|
+
source << " #{parameters.slice}" if parameters
|
|
278
|
+
source << "\n#{indentation} "
|
|
279
|
+
source << switch_block_body(body, indentation) if body
|
|
280
|
+
source << "\n#{indentation}end"
|
|
281
|
+
else
|
|
282
|
+
source << "{ "
|
|
283
|
+
source << "#{parameters.slice} " if parameters
|
|
284
|
+
source << switch_block_body(body, nil) if body
|
|
285
|
+
source << "}"
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
source
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
sig { params(body: Prism::Node, indentation: T.nilable(String)).returns(String) }
|
|
292
|
+
def switch_block_body(body, indentation)
|
|
293
|
+
# Check if there are any nested blocks inside of the current block
|
|
294
|
+
body_loc = body.location
|
|
295
|
+
nested_block = @document.locate_first_within_range(
|
|
296
|
+
{
|
|
297
|
+
start: { line: body_loc.start_line - 1, character: body_loc.start_column },
|
|
298
|
+
end: { line: body_loc.end_line - 1, character: body_loc.end_column },
|
|
299
|
+
},
|
|
300
|
+
node_types: [Prism::BlockNode],
|
|
301
|
+
)
|
|
302
|
+
|
|
303
|
+
body_content = body.slice.dup
|
|
304
|
+
|
|
305
|
+
# If there are nested blocks, then we change their style too and we have to mutate the string using the
|
|
306
|
+
# relative position in respect to the beginning of the body
|
|
307
|
+
if nested_block.is_a?(Prism::BlockNode)
|
|
308
|
+
location = nested_block.location
|
|
309
|
+
correction_start = location.start_offset - body_loc.start_offset
|
|
310
|
+
correction_end = location.end_offset - body_loc.start_offset
|
|
311
|
+
next_indentation = indentation ? "#{indentation} " : nil
|
|
312
|
+
|
|
313
|
+
body_content[correction_start...correction_end] =
|
|
314
|
+
recursively_switch_nested_block_styles(nested_block, next_indentation)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
indentation ? body_content.gsub(";", "\n") : "#{body_content.gsub("\n", ";")} "
|
|
318
|
+
end
|
|
221
319
|
end
|
|
222
320
|
end
|
|
223
321
|
end
|
|
@@ -21,13 +21,17 @@ module RubyLsp
|
|
|
21
21
|
|
|
22
22
|
EXTRACT_TO_VARIABLE_TITLE = "Refactor: Extract Variable"
|
|
23
23
|
EXTRACT_TO_METHOD_TITLE = "Refactor: Extract Method"
|
|
24
|
+
SWITCH_BLOCK_STYLE_TITLE = "Refactor: Switch block style"
|
|
24
25
|
|
|
25
26
|
class << self
|
|
26
27
|
extend T::Sig
|
|
27
28
|
|
|
28
|
-
sig { returns(Interface::
|
|
29
|
+
sig { returns(Interface::CodeActionRegistrationOptions) }
|
|
29
30
|
def provider
|
|
30
|
-
Interface::
|
|
31
|
+
Interface::CodeActionRegistrationOptions.new(
|
|
32
|
+
document_selector: [Interface::DocumentFilter.new(language: "ruby")],
|
|
33
|
+
resolve_provider: true,
|
|
34
|
+
)
|
|
31
35
|
end
|
|
32
36
|
end
|
|
33
37
|
|
|
@@ -66,6 +70,11 @@ module RubyLsp
|
|
|
66
70
|
kind: Constant::CodeActionKind::REFACTOR_EXTRACT,
|
|
67
71
|
data: { range: @range, uri: @uri.to_s },
|
|
68
72
|
)
|
|
73
|
+
code_actions << Interface::CodeAction.new(
|
|
74
|
+
title: SWITCH_BLOCK_STYLE_TITLE,
|
|
75
|
+
kind: Constant::CodeActionKind::REFACTOR_REWRITE,
|
|
76
|
+
data: { range: @range, uri: @uri.to_s },
|
|
77
|
+
)
|
|
69
78
|
end
|
|
70
79
|
|
|
71
80
|
code_actions
|
|
@@ -30,6 +30,12 @@ module RubyLsp
|
|
|
30
30
|
extend T::Sig
|
|
31
31
|
extend T::Generic
|
|
32
32
|
|
|
33
|
+
SPECIAL_METHOD_CALLS = [
|
|
34
|
+
:require,
|
|
35
|
+
:require_relative,
|
|
36
|
+
:autoload,
|
|
37
|
+
].freeze
|
|
38
|
+
|
|
33
39
|
sig do
|
|
34
40
|
params(
|
|
35
41
|
document: Document,
|
|
@@ -78,8 +84,9 @@ module RubyLsp
|
|
|
78
84
|
parent,
|
|
79
85
|
position,
|
|
80
86
|
)
|
|
81
|
-
elsif target.is_a?(Prism::CallNode) && target.
|
|
82
|
-
|
|
87
|
+
elsif target.is_a?(Prism::CallNode) && !SPECIAL_METHOD_CALLS.include?(target.message) && !covers_position?(
|
|
88
|
+
target.message_loc, position
|
|
89
|
+
)
|
|
83
90
|
# If the target is a method call, we need to ensure that the requested position is exactly on top of the
|
|
84
91
|
# method identifier. Otherwise, we risk showing definitions for unrelated things
|
|
85
92
|
target = nil
|
|
@@ -22,12 +22,13 @@ module RubyLsp
|
|
|
22
22
|
class << self
|
|
23
23
|
extend T::Sig
|
|
24
24
|
|
|
25
|
-
sig { returns(
|
|
25
|
+
sig { returns(Interface::DiagnosticRegistrationOptions) }
|
|
26
26
|
def provider
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
Interface::DiagnosticRegistrationOptions.new(
|
|
28
|
+
document_selector: [Interface::DocumentFilter.new(language: "ruby")],
|
|
29
|
+
inter_file_dependencies: false,
|
|
30
|
+
workspace_diagnostics: false,
|
|
31
|
+
)
|
|
31
32
|
end
|
|
32
33
|
end
|
|
33
34
|
|
|
@@ -34,14 +34,9 @@ module RubyLsp
|
|
|
34
34
|
class << self
|
|
35
35
|
extend T::Sig
|
|
36
36
|
|
|
37
|
-
sig { returns(Interface::
|
|
37
|
+
sig { returns(Interface::DocumentSymbolOptions) }
|
|
38
38
|
def provider
|
|
39
|
-
Interface::
|
|
40
|
-
hierarchical_document_symbol_support: true,
|
|
41
|
-
symbol_kind: {
|
|
42
|
-
value_set: (Constant::SymbolKind::FILE..Constant::SymbolKind::TYPE_PARAMETER).to_a,
|
|
43
|
-
},
|
|
44
|
-
)
|
|
39
|
+
Interface::DocumentSymbolOptions.new
|
|
45
40
|
end
|
|
46
41
|
end
|
|
47
42
|
|
|
@@ -23,9 +23,13 @@ module RubyLsp
|
|
|
23
23
|
class << self
|
|
24
24
|
extend T::Sig
|
|
25
25
|
|
|
26
|
-
sig { returns(Interface::
|
|
26
|
+
sig { returns(Interface::FoldingRangeRegistrationOptions) }
|
|
27
27
|
def provider
|
|
28
|
-
Interface::
|
|
28
|
+
Interface::FoldingRangeRegistrationOptions.new(
|
|
29
|
+
document_selector: [
|
|
30
|
+
Interface::DocumentFilter.new(language: "ruby"),
|
|
31
|
+
],
|
|
32
|
+
)
|
|
29
33
|
end
|
|
30
34
|
end
|
|
31
35
|
|
|
@@ -27,6 +27,19 @@ module RubyLsp
|
|
|
27
27
|
|
|
28
28
|
class Error < StandardError; end
|
|
29
29
|
|
|
30
|
+
class << self
|
|
31
|
+
extend T::Sig
|
|
32
|
+
|
|
33
|
+
sig { returns(Interface::DocumentFormattingRegistrationOptions) }
|
|
34
|
+
def provider
|
|
35
|
+
Interface::DocumentFormattingRegistrationOptions.new(
|
|
36
|
+
document_selector: [
|
|
37
|
+
Interface::DocumentFilter.new(language: "ruby"),
|
|
38
|
+
],
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
30
43
|
sig { params(global_state: GlobalState, document: Document).void }
|
|
31
44
|
def initialize(global_state, document)
|
|
32
45
|
super()
|
|
@@ -22,9 +22,9 @@ module RubyLsp
|
|
|
22
22
|
class << self
|
|
23
23
|
extend T::Sig
|
|
24
24
|
|
|
25
|
-
sig { returns(Interface::
|
|
25
|
+
sig { returns(Interface::HoverOptions) }
|
|
26
26
|
def provider
|
|
27
|
-
Interface::
|
|
27
|
+
Interface::HoverOptions.new
|
|
28
28
|
end
|
|
29
29
|
end
|
|
30
30
|
|
|
@@ -21,9 +21,10 @@ module RubyLsp
|
|
|
21
21
|
class << self
|
|
22
22
|
extend T::Sig
|
|
23
23
|
|
|
24
|
-
sig { returns(Interface::
|
|
24
|
+
sig { returns(Interface::DocumentOnTypeFormattingRegistrationOptions) }
|
|
25
25
|
def provider
|
|
26
|
-
Interface::
|
|
26
|
+
Interface::DocumentOnTypeFormattingRegistrationOptions.new(
|
|
27
|
+
document_selector: [Interface::DocumentFilter.new(language: "ruby")],
|
|
27
28
|
first_trigger_character: "{",
|
|
28
29
|
more_trigger_character: ["\n", "|", "d"],
|
|
29
30
|
)
|
data/lib/ruby_lsp/server.rb
CHANGED
|
@@ -181,6 +181,7 @@ module RubyLsp
|
|
|
181
181
|
hover_provider = Requests::Hover.provider if enabled_features["hover"]
|
|
182
182
|
folding_ranges_provider = Requests::FoldingRanges.provider if enabled_features["foldingRanges"]
|
|
183
183
|
semantic_tokens_provider = Requests::SemanticHighlighting.provider if enabled_features["semanticHighlighting"]
|
|
184
|
+
document_formatting_provider = Requests::Formatting.provider if enabled_features["formatting"]
|
|
184
185
|
diagnostics_provider = Requests::Diagnostics.provider if enabled_features["diagnostics"]
|
|
185
186
|
on_type_formatting_provider = Requests::OnTypeFormatting.provider if enabled_features["onTypeFormatting"]
|
|
186
187
|
code_action_provider = Requests::CodeActions.provider if enabled_features["codeActions"]
|
|
@@ -202,7 +203,7 @@ module RubyLsp
|
|
|
202
203
|
document_link_provider: document_link_provider,
|
|
203
204
|
folding_range_provider: folding_ranges_provider,
|
|
204
205
|
semantic_tokens_provider: semantic_tokens_provider,
|
|
205
|
-
document_formatting_provider:
|
|
206
|
+
document_formatting_provider: document_formatting_provider && @global_state.formatter != "none",
|
|
206
207
|
document_highlight_provider: enabled_features["documentHighlights"],
|
|
207
208
|
code_action_provider: code_action_provider,
|
|
208
209
|
document_on_type_formatting_provider: on_type_formatting_provider,
|
|
@@ -421,8 +422,6 @@ module RubyLsp
|
|
|
421
422
|
|
|
422
423
|
document = @store.get(uri)
|
|
423
424
|
|
|
424
|
-
return send_empty_response(message[:id]) if document.is_a?(ERBDocument)
|
|
425
|
-
|
|
426
425
|
response = Requests::Formatting.new(@global_state, document).perform
|
|
427
426
|
send_message(Result.new(id: message[:id], response: response))
|
|
428
427
|
rescue Requests::Request::InvalidFormatter => error
|
|
@@ -448,8 +447,6 @@ module RubyLsp
|
|
|
448
447
|
params = message[:params]
|
|
449
448
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
450
449
|
|
|
451
|
-
return send_empty_response(message[:id]) if document.is_a?(ERBDocument)
|
|
452
|
-
|
|
453
450
|
send_message(
|
|
454
451
|
Result.new(
|
|
455
452
|
id: message[:id],
|
|
@@ -506,8 +503,6 @@ module RubyLsp
|
|
|
506
503
|
params = message[:params]
|
|
507
504
|
document = @store.get(params.dig(:textDocument, :uri))
|
|
508
505
|
|
|
509
|
-
return send_empty_response(message[:id]) if document.is_a?(ERBDocument)
|
|
510
|
-
|
|
511
506
|
send_message(
|
|
512
507
|
Result.new(
|
|
513
508
|
id: message[:id],
|
|
@@ -563,8 +558,6 @@ module RubyLsp
|
|
|
563
558
|
|
|
564
559
|
document = @store.get(uri)
|
|
565
560
|
|
|
566
|
-
return send_empty_response(message[:id]) if document.is_a?(ERBDocument)
|
|
567
|
-
|
|
568
561
|
response = document.cache_fetch("textDocument/diagnostic") do |document|
|
|
569
562
|
Requests::Diagnostics.new(@global_state, document).perform
|
|
570
563
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby-lsp
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.17.
|
|
4
|
+
version: 0.17.12
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Shopify
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2024-
|
|
11
|
+
date: 2024-08-08 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: language_server-protocol
|
|
@@ -98,6 +98,7 @@ files:
|
|
|
98
98
|
- lib/ruby-lsp.rb
|
|
99
99
|
- lib/ruby_indexer/lib/ruby_indexer/configuration.rb
|
|
100
100
|
- lib/ruby_indexer/lib/ruby_indexer/declaration_listener.rb
|
|
101
|
+
- lib/ruby_indexer/lib/ruby_indexer/enhancement.rb
|
|
101
102
|
- lib/ruby_indexer/lib/ruby_indexer/entry.rb
|
|
102
103
|
- lib/ruby_indexer/lib/ruby_indexer/index.rb
|
|
103
104
|
- lib/ruby_indexer/lib/ruby_indexer/indexable_path.rb
|
|
@@ -108,6 +109,7 @@ files:
|
|
|
108
109
|
- lib/ruby_indexer/test/classes_and_modules_test.rb
|
|
109
110
|
- lib/ruby_indexer/test/configuration_test.rb
|
|
110
111
|
- lib/ruby_indexer/test/constant_test.rb
|
|
112
|
+
- lib/ruby_indexer/test/enhancements_test.rb
|
|
111
113
|
- lib/ruby_indexer/test/index_test.rb
|
|
112
114
|
- lib/ruby_indexer/test/instance_variables_test.rb
|
|
113
115
|
- lib/ruby_indexer/test/method_test.rb
|