ruby-lsp 0.12.5 → 0.13.0
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/exe/ruby-lsp-check +20 -4
- data/lib/ruby_indexer/lib/ruby_indexer/collector.rb +36 -2
- data/lib/ruby_indexer/lib/ruby_indexer/configuration.rb +1 -1
- data/lib/ruby_indexer/lib/ruby_indexer/entry.rb +83 -12
- data/lib/ruby_indexer/test/configuration_test.rb +10 -0
- data/lib/ruby_indexer/test/index_test.rb +11 -0
- data/lib/ruby_indexer/test/method_test.rb +66 -0
- data/lib/ruby_lsp/addon.rb +9 -13
- data/lib/ruby_lsp/executor.rb +25 -27
- data/lib/ruby_lsp/listener.rb +4 -5
- data/lib/ruby_lsp/requests/code_lens.rb +16 -7
- data/lib/ruby_lsp/requests/completion.rb +11 -8
- data/lib/ruby_lsp/requests/definition.rb +3 -4
- data/lib/ruby_lsp/requests/diagnostics.rb +0 -5
- data/lib/ruby_lsp/requests/document_highlight.rb +2 -3
- data/lib/ruby_lsp/requests/document_link.rb +2 -3
- data/lib/ruby_lsp/requests/document_symbol.rb +3 -3
- data/lib/ruby_lsp/requests/folding_ranges.rb +12 -15
- data/lib/ruby_lsp/requests/formatting.rb +0 -5
- data/lib/ruby_lsp/requests/hover.rb +3 -4
- data/lib/ruby_lsp/requests/inlay_hints.rb +3 -3
- data/lib/ruby_lsp/requests/on_type_formatting.rb +2 -3
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +28 -11
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +3 -8
- data/lib/ruby_lsp/requests/workspace_symbol.rb +2 -0
- data/lib/ruby_lsp/store.rb +4 -0
- data/lib/ruby_lsp/utils.rb +0 -4
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d6bace664e1540c1333df9dabfb2e7bdd8bda0f910033b47b188e4a82ddacb15
|
4
|
+
data.tar.gz: be9e5da0492b26b5cb6e07074d01d7874104b70286c1578342b9639158fed147
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d8e61433686271a68dafe8db79765ed509a115ab6f06060d7669d279f48218fe2eada2c12e3b45f155d27a41774771681cdab92700d27f426e75ed89287ca03
|
7
|
+
data.tar.gz: 611c050b751050934d0fd93e9e52089fe63fc4d947be75a440dfa0465933814d2682268a10135d036c2cee83fa739156d2b11e42e679ecbed7de62acfee9d621
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.13.0
|
data/exe/ruby-lsp-check
CHANGED
@@ -17,8 +17,6 @@ end
|
|
17
17
|
$LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
|
18
18
|
require "ruby_lsp/internal"
|
19
19
|
|
20
|
-
RubyLsp::Addon.load_addons
|
21
|
-
|
22
20
|
T::Utils.run_all_sig_blocks
|
23
21
|
|
24
22
|
files = Dir.glob("#{Dir.pwd}/**/*.rb")
|
@@ -28,6 +26,7 @@ puts "Verifying that all automatic LSP requests execute successfully. This may t
|
|
28
26
|
errors = {}
|
29
27
|
store = RubyLsp::Store.new
|
30
28
|
message_queue = Thread::Queue.new
|
29
|
+
RubyLsp::Addon.load_addons(message_queue)
|
31
30
|
executor = RubyLsp::Executor.new(store, message_queue)
|
32
31
|
|
33
32
|
files.each_with_index do |file, index|
|
@@ -50,13 +49,30 @@ end
|
|
50
49
|
puts "\n"
|
51
50
|
message_queue.close
|
52
51
|
|
52
|
+
# Indexing
|
53
|
+
puts "Verifying that indexing executes successfully. This may take a while..."
|
54
|
+
|
55
|
+
index = RubyIndexer::Index.new
|
56
|
+
indexables = RubyIndexer.configuration.indexables
|
57
|
+
|
58
|
+
indexables.each_with_index do |indexable, i|
|
59
|
+
result = Prism.parse(File.read(indexable.full_path))
|
60
|
+
collector = RubyIndexer::Collector.new(index, result, indexable.full_path)
|
61
|
+
collector.collect(result.value)
|
62
|
+
rescue => e
|
63
|
+
errors[indexable.full_path] = e
|
64
|
+
ensure
|
65
|
+
print("\033[M\033[0KIndexed #{i + 1}/#{indexables.length}") unless ENV["CI"]
|
66
|
+
end
|
67
|
+
puts "\n"
|
68
|
+
|
53
69
|
if errors.empty?
|
54
|
-
puts "All
|
70
|
+
puts "All operations completed successfully!"
|
55
71
|
exit
|
56
72
|
end
|
57
73
|
|
58
74
|
puts <<~ERRORS
|
59
|
-
Errors while executing
|
75
|
+
Errors while executing:
|
60
76
|
|
61
77
|
#{errors.map { |file, error| "#{file}: #{error.message}" }.join("\n")}
|
62
78
|
ERRORS
|
@@ -141,8 +141,18 @@ module RubyIndexer
|
|
141
141
|
|
142
142
|
sig { params(node: Prism::CallNode).void }
|
143
143
|
def handle_call_node(node)
|
144
|
-
message = node.
|
145
|
-
|
144
|
+
message = node.name
|
145
|
+
|
146
|
+
case message
|
147
|
+
when :private_constant
|
148
|
+
handle_private_constant(node)
|
149
|
+
when :attr_reader
|
150
|
+
handle_attribute(node, reader: true, writer: false)
|
151
|
+
when :attr_writer
|
152
|
+
handle_attribute(node, reader: false, writer: true)
|
153
|
+
when :attr_accessor
|
154
|
+
handle_attribute(node, reader: true, writer: true)
|
155
|
+
end
|
146
156
|
end
|
147
157
|
|
148
158
|
sig { params(node: Prism::DefNode).void }
|
@@ -312,5 +322,29 @@ module RubyIndexer
|
|
312
322
|
"#{@stack.join("::")}::#{name}"
|
313
323
|
end.delete_prefix("::")
|
314
324
|
end
|
325
|
+
|
326
|
+
sig { params(node: Prism::CallNode, reader: T::Boolean, writer: T::Boolean).void }
|
327
|
+
def handle_attribute(node, reader:, writer:)
|
328
|
+
arguments = node.arguments&.arguments
|
329
|
+
return unless arguments
|
330
|
+
|
331
|
+
receiver = node.receiver
|
332
|
+
return unless receiver.nil? || receiver.is_a?(Prism::SelfNode)
|
333
|
+
|
334
|
+
comments = collect_comments(node)
|
335
|
+
arguments.each do |argument|
|
336
|
+
name, loc = case argument
|
337
|
+
when Prism::SymbolNode
|
338
|
+
[argument.value, argument.value_loc]
|
339
|
+
when Prism::StringNode
|
340
|
+
[argument.content, argument.content_loc]
|
341
|
+
end
|
342
|
+
|
343
|
+
next unless name && loc
|
344
|
+
|
345
|
+
@index << Entry::Accessor.new(name, @file_path, loc, comments, @current_owner) if reader
|
346
|
+
@index << Entry::Accessor.new("#{name}=", @file_path, loc, comments, @current_owner) if writer
|
347
|
+
end
|
348
|
+
end
|
315
349
|
end
|
316
350
|
end
|
@@ -120,7 +120,7 @@ module RubyIndexer
|
|
120
120
|
IndexablePath.new(RbConfig::CONFIG["rubylibdir"], path)
|
121
121
|
end,
|
122
122
|
)
|
123
|
-
|
123
|
+
elsif pathname.extname == ".rb"
|
124
124
|
# If the default_path is a Ruby file, we index it
|
125
125
|
indexables << IndexablePath.new(RbConfig::CONFIG["rubylibdir"], default_path)
|
126
126
|
end
|
@@ -90,20 +90,69 @@ module RubyIndexer
|
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
93
|
+
# A required method parameter, e.g. `def foo(a)`
|
93
94
|
class RequiredParameter < Parameter
|
94
95
|
end
|
95
96
|
|
96
|
-
|
97
|
+
# An optional method parameter, e.g. `def foo(a = 123)`
|
98
|
+
class OptionalParameter < Parameter
|
99
|
+
end
|
100
|
+
|
101
|
+
# An required keyword method parameter, e.g. `def foo(a:)`
|
102
|
+
class KeywordParameter < Parameter
|
103
|
+
end
|
104
|
+
|
105
|
+
# An optional keyword method parameter, e.g. `def foo(a: 123)`
|
106
|
+
class OptionalKeywordParameter < Parameter
|
107
|
+
end
|
108
|
+
|
109
|
+
class Member < Entry
|
97
110
|
extend T::Sig
|
98
111
|
extend T::Helpers
|
99
|
-
abstract!
|
100
112
|
|
101
|
-
|
102
|
-
attr_reader :parameters
|
113
|
+
abstract!
|
103
114
|
|
104
115
|
sig { returns(T.nilable(Entry::Namespace)) }
|
105
116
|
attr_reader :owner
|
106
117
|
|
118
|
+
sig do
|
119
|
+
params(
|
120
|
+
name: String,
|
121
|
+
file_path: String,
|
122
|
+
location: Prism::Location,
|
123
|
+
comments: T::Array[String],
|
124
|
+
owner: T.nilable(Entry::Namespace),
|
125
|
+
).void
|
126
|
+
end
|
127
|
+
def initialize(name, file_path, location, comments, owner)
|
128
|
+
super(name, file_path, location, comments)
|
129
|
+
@owner = owner
|
130
|
+
end
|
131
|
+
|
132
|
+
sig { abstract.returns(T::Array[Parameter]) }
|
133
|
+
def parameters; end
|
134
|
+
end
|
135
|
+
|
136
|
+
class Accessor < Member
|
137
|
+
extend T::Sig
|
138
|
+
|
139
|
+
sig { override.returns(T::Array[Parameter]) }
|
140
|
+
def parameters
|
141
|
+
params = []
|
142
|
+
params << RequiredParameter.new(name: name.delete_suffix("=").to_sym) if name.end_with?("=")
|
143
|
+
params
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
class Method < Member
|
148
|
+
extend T::Sig
|
149
|
+
extend T::Helpers
|
150
|
+
|
151
|
+
abstract!
|
152
|
+
|
153
|
+
sig { override.returns(T::Array[Parameter]) }
|
154
|
+
attr_reader :parameters
|
155
|
+
|
107
156
|
sig do
|
108
157
|
params(
|
109
158
|
name: String,
|
@@ -115,9 +164,9 @@ module RubyIndexer
|
|
115
164
|
).void
|
116
165
|
end
|
117
166
|
def initialize(name, file_path, location, comments, parameters_node, owner) # rubocop:disable Metrics/ParameterLists
|
118
|
-
super(name, file_path, location, comments)
|
167
|
+
super(name, file_path, location, comments, owner)
|
168
|
+
|
119
169
|
@parameters = T.let(list_params(parameters_node), T::Array[Parameter])
|
120
|
-
@owner = owner
|
121
170
|
end
|
122
171
|
|
123
172
|
private
|
@@ -126,20 +175,42 @@ module RubyIndexer
|
|
126
175
|
def list_params(parameters_node)
|
127
176
|
return [] unless parameters_node
|
128
177
|
|
129
|
-
|
178
|
+
parameters = []
|
179
|
+
|
180
|
+
parameters_node.requireds.each do |required|
|
130
181
|
name = parameter_name(required)
|
131
182
|
next unless name
|
132
183
|
|
133
|
-
RequiredParameter.new(name: name)
|
184
|
+
parameters << RequiredParameter.new(name: name)
|
134
185
|
end
|
135
|
-
end
|
136
186
|
|
137
|
-
|
138
|
-
|
187
|
+
parameters_node.optionals.each do |optional|
|
188
|
+
name = parameter_name(optional)
|
189
|
+
next unless name
|
190
|
+
|
191
|
+
parameters << OptionalParameter.new(name: name)
|
192
|
+
end
|
193
|
+
|
194
|
+
parameters_node.keywords.each do |keyword|
|
195
|
+
name = parameter_name(keyword)
|
196
|
+
next unless name
|
197
|
+
|
198
|
+
case keyword
|
199
|
+
when Prism::RequiredKeywordParameterNode
|
200
|
+
parameters << KeywordParameter.new(name: name)
|
201
|
+
when Prism::OptionalKeywordParameterNode
|
202
|
+
parameters << OptionalKeywordParameter.new(name: name)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
parameters
|
139
207
|
end
|
208
|
+
|
209
|
+
sig { params(node: Prism::Node).returns(T.nilable(Symbol)) }
|
140
210
|
def parameter_name(node)
|
141
211
|
case node
|
142
|
-
when Prism::RequiredParameterNode
|
212
|
+
when Prism::RequiredParameterNode, Prism::OptionalParameterNode,
|
213
|
+
Prism::RequiredKeywordParameterNode, Prism::OptionalKeywordParameterNode
|
143
214
|
node.name
|
144
215
|
when Prism::MultiTargetNode
|
145
216
|
names = [*node.lefts, *node.rest, *node.rights].map { |parameter_node| parameter_name(parameter_node) }
|
@@ -84,6 +84,16 @@ module RubyIndexer
|
|
84
84
|
)
|
85
85
|
end
|
86
86
|
|
87
|
+
def test_indexables_does_not_include_non_ruby_files_inside_rubylibdir
|
88
|
+
path = Pathname.new(RbConfig::CONFIG["rubylibdir"]).join("extra_file.txt").to_s
|
89
|
+
FileUtils.touch(path)
|
90
|
+
indexables = @config.indexables
|
91
|
+
|
92
|
+
assert(indexables.none? { |indexable| indexable.full_path == path })
|
93
|
+
ensure
|
94
|
+
FileUtils.rm(T.must(path))
|
95
|
+
end
|
96
|
+
|
87
97
|
def test_paths_are_unique
|
88
98
|
@config.load_config
|
89
99
|
indexables = @config.indexables
|
@@ -246,5 +246,16 @@ module RubyIndexer
|
|
246
246
|
entry = T.must(entries.first).first
|
247
247
|
assert_equal("baz", entry.name)
|
248
248
|
end
|
249
|
+
|
250
|
+
def test_indexing_prism_fixtures_succeeds
|
251
|
+
fixtures = Dir.glob("test/fixtures/prism/test/prism/fixtures/**/*.txt")
|
252
|
+
|
253
|
+
fixtures.each do |fixture|
|
254
|
+
indexable_path = IndexablePath.new("", fixture)
|
255
|
+
@index.index_single(indexable_path)
|
256
|
+
end
|
257
|
+
|
258
|
+
refute_empty(@index.instance_variable_get(:@entries))
|
259
|
+
end
|
249
260
|
end
|
250
261
|
end
|
@@ -70,6 +70,42 @@ module RubyIndexer
|
|
70
70
|
assert_instance_of(Entry::RequiredParameter, parameter)
|
71
71
|
end
|
72
72
|
|
73
|
+
def test_method_with_optional_parameters
|
74
|
+
index(<<~RUBY)
|
75
|
+
class Foo
|
76
|
+
def bar(a = 123)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
RUBY
|
80
|
+
|
81
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
82
|
+
entry = T.must(@index["bar"].first)
|
83
|
+
assert_equal(1, entry.parameters.length)
|
84
|
+
parameter = entry.parameters.first
|
85
|
+
assert_equal(:a, parameter.name)
|
86
|
+
assert_instance_of(Entry::OptionalParameter, parameter)
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_method_with_keyword_parameters
|
90
|
+
index(<<~RUBY)
|
91
|
+
class Foo
|
92
|
+
def bar(a:, b: 123)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
RUBY
|
96
|
+
|
97
|
+
assert_entry("bar", Entry::InstanceMethod, "/fake/path/foo.rb:1-2:2-5")
|
98
|
+
entry = T.must(@index["bar"].first)
|
99
|
+
assert_equal(2, entry.parameters.length)
|
100
|
+
a, b = entry.parameters
|
101
|
+
|
102
|
+
assert_equal(:a, a.name)
|
103
|
+
assert_instance_of(Entry::KeywordParameter, a)
|
104
|
+
|
105
|
+
assert_equal(:b, b.name)
|
106
|
+
assert_instance_of(Entry::OptionalKeywordParameter, b)
|
107
|
+
end
|
108
|
+
|
73
109
|
def test_keeps_track_of_method_owner
|
74
110
|
index(<<~RUBY)
|
75
111
|
class Foo
|
@@ -83,5 +119,35 @@ module RubyIndexer
|
|
83
119
|
|
84
120
|
assert_equal("Foo", owner_name)
|
85
121
|
end
|
122
|
+
|
123
|
+
def test_keeps_track_of_attributes
|
124
|
+
index(<<~RUBY)
|
125
|
+
class Foo
|
126
|
+
# Hello there
|
127
|
+
attr_reader :bar, :other
|
128
|
+
attr_writer :baz
|
129
|
+
attr_accessor :qux
|
130
|
+
end
|
131
|
+
RUBY
|
132
|
+
|
133
|
+
assert_entry("bar", Entry::Accessor, "/fake/path/foo.rb:2-15:2-18")
|
134
|
+
assert_equal("Hello there", @index["bar"].first.comments.join("\n"))
|
135
|
+
assert_entry("other", Entry::Accessor, "/fake/path/foo.rb:2-21:2-26")
|
136
|
+
assert_equal("Hello there", @index["other"].first.comments.join("\n"))
|
137
|
+
assert_entry("baz=", Entry::Accessor, "/fake/path/foo.rb:3-15:3-18")
|
138
|
+
assert_entry("qux", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
139
|
+
assert_entry("qux=", Entry::Accessor, "/fake/path/foo.rb:4-17:4-20")
|
140
|
+
end
|
141
|
+
|
142
|
+
def test_ignores_attributes_invoked_on_constant
|
143
|
+
index(<<~RUBY)
|
144
|
+
class Foo
|
145
|
+
end
|
146
|
+
|
147
|
+
Foo.attr_reader :bar
|
148
|
+
RUBY
|
149
|
+
|
150
|
+
assert_no_entry("bar")
|
151
|
+
end
|
86
152
|
end
|
87
153
|
end
|
data/lib/ruby_lsp/addon.rb
CHANGED
@@ -41,8 +41,8 @@ module RubyLsp
|
|
41
41
|
end
|
42
42
|
|
43
43
|
# Discovers and loads all addons. Returns the list of activated addons
|
44
|
-
sig { returns(T::Array[Addon]) }
|
45
|
-
def load_addons
|
44
|
+
sig { params(message_queue: Thread::Queue).returns(T::Array[Addon]) }
|
45
|
+
def load_addons(message_queue)
|
46
46
|
# Require all addons entry points, which should be placed under
|
47
47
|
# `some_gem/lib/ruby_lsp/your_gem_name/addon.rb`
|
48
48
|
Gem.find_files("ruby_lsp/**/addon.rb").each do |addon|
|
@@ -55,7 +55,7 @@ module RubyLsp
|
|
55
55
|
# Activate each one of the discovered addons. If any problems occur in the addons, we don't want to
|
56
56
|
# fail to boot the server
|
57
57
|
addons.each do |addon|
|
58
|
-
addon.activate
|
58
|
+
addon.activate(message_queue)
|
59
59
|
nil
|
60
60
|
rescue => e
|
61
61
|
addon.add_error(e)
|
@@ -94,8 +94,8 @@ module RubyLsp
|
|
94
94
|
|
95
95
|
# Each addon should implement `MyAddon#activate` and use to perform any sort of initialization, such as
|
96
96
|
# reading information into memory or even spawning a separate process
|
97
|
-
sig { abstract.void }
|
98
|
-
def activate; end
|
97
|
+
sig { abstract.params(message_queue: Thread::Queue).void }
|
98
|
+
def activate(message_queue); end
|
99
99
|
|
100
100
|
# Each addon should implement `MyAddon#deactivate` and use to perform any clean up, like shutting down a
|
101
101
|
# child process
|
@@ -111,10 +111,9 @@ module RubyLsp
|
|
111
111
|
overridable.params(
|
112
112
|
uri: URI::Generic,
|
113
113
|
dispatcher: Prism::Dispatcher,
|
114
|
-
message_queue: Thread::Queue,
|
115
114
|
).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
|
116
115
|
end
|
117
|
-
def create_code_lens_listener(uri, dispatcher
|
116
|
+
def create_code_lens_listener(uri, dispatcher); end
|
118
117
|
|
119
118
|
# Creates a new Hover listener. This method is invoked on every Hover request
|
120
119
|
sig do
|
@@ -122,19 +121,17 @@ module RubyLsp
|
|
122
121
|
nesting: T::Array[String],
|
123
122
|
index: RubyIndexer::Index,
|
124
123
|
dispatcher: Prism::Dispatcher,
|
125
|
-
message_queue: Thread::Queue,
|
126
124
|
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
|
127
125
|
end
|
128
|
-
def create_hover_listener(nesting, index, dispatcher
|
126
|
+
def create_hover_listener(nesting, index, dispatcher); end
|
129
127
|
|
130
128
|
# Creates a new DocumentSymbol listener. This method is invoked on every DocumentSymbol request
|
131
129
|
sig do
|
132
130
|
overridable.params(
|
133
131
|
dispatcher: Prism::Dispatcher,
|
134
|
-
message_queue: Thread::Queue,
|
135
132
|
).returns(T.nilable(Listener[T::Array[Interface::DocumentSymbol]]))
|
136
133
|
end
|
137
|
-
def create_document_symbol_listener(dispatcher
|
134
|
+
def create_document_symbol_listener(dispatcher); end
|
138
135
|
|
139
136
|
# Creates a new Definition listener. This method is invoked on every Definition request
|
140
137
|
sig do
|
@@ -143,9 +140,8 @@ module RubyLsp
|
|
143
140
|
nesting: T::Array[String],
|
144
141
|
index: RubyIndexer::Index,
|
145
142
|
dispatcher: Prism::Dispatcher,
|
146
|
-
message_queue: Thread::Queue,
|
147
143
|
).returns(T.nilable(Listener[T.nilable(T.any(T::Array[Interface::Location], Interface::Location))]))
|
148
144
|
end
|
149
|
-
def create_definition_listener(uri, nesting, index, dispatcher
|
145
|
+
def create_definition_listener(uri, nesting, index, dispatcher); end
|
150
146
|
end
|
151
147
|
end
|
data/lib/ruby_lsp/executor.rb
CHANGED
@@ -41,7 +41,7 @@ module RubyLsp
|
|
41
41
|
when "initialize"
|
42
42
|
initialize_request(request.dig(:params))
|
43
43
|
when "initialized"
|
44
|
-
Addon.load_addons
|
44
|
+
Addon.load_addons(@message_queue)
|
45
45
|
|
46
46
|
errored_addons = Addon.addons.select(&:error?)
|
47
47
|
|
@@ -95,12 +95,12 @@ module RubyLsp
|
|
95
95
|
|
96
96
|
# Run listeners for the document
|
97
97
|
dispatcher = Prism::Dispatcher.new
|
98
|
-
folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher
|
99
|
-
document_symbol = Requests::DocumentSymbol.new(dispatcher
|
100
|
-
document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher
|
101
|
-
code_lens = Requests::CodeLens.new(uri, dispatcher
|
98
|
+
folding_range = Requests::FoldingRanges.new(document.parse_result.comments, dispatcher)
|
99
|
+
document_symbol = Requests::DocumentSymbol.new(dispatcher)
|
100
|
+
document_link = Requests::DocumentLink.new(uri, document.comments, dispatcher)
|
101
|
+
code_lens = Requests::CodeLens.new(uri, dispatcher)
|
102
102
|
|
103
|
-
semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher
|
103
|
+
semantic_highlighting = Requests::SemanticHighlighting.new(dispatcher)
|
104
104
|
dispatcher.dispatch(document.tree)
|
105
105
|
|
106
106
|
# Store all responses retrieve in this round of visits in the cache and then return the response for the request
|
@@ -265,13 +265,7 @@ module RubyLsp
|
|
265
265
|
target = parent if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
|
266
266
|
|
267
267
|
dispatcher = Prism::Dispatcher.new
|
268
|
-
base_listener = Requests::Definition.new(
|
269
|
-
uri,
|
270
|
-
nesting,
|
271
|
-
@index,
|
272
|
-
dispatcher,
|
273
|
-
@message_queue,
|
274
|
-
)
|
268
|
+
base_listener = Requests::Definition.new(uri, nesting, @index, dispatcher)
|
275
269
|
dispatcher.dispatch_once(target)
|
276
270
|
base_listener.response
|
277
271
|
end
|
@@ -297,7 +291,7 @@ module RubyLsp
|
|
297
291
|
|
298
292
|
# Instantiate all listeners
|
299
293
|
dispatcher = Prism::Dispatcher.new
|
300
|
-
hover = Requests::Hover.new(@index, nesting, dispatcher
|
294
|
+
hover = Requests::Hover.new(@index, nesting, dispatcher)
|
301
295
|
|
302
296
|
# Emit events for all listeners
|
303
297
|
dispatcher.dispatch_once(target)
|
@@ -355,6 +349,11 @@ module RubyLsp
|
|
355
349
|
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
356
350
|
return if @store.formatter == "none"
|
357
351
|
|
352
|
+
# Do not format files outside of the workspace. For example, if someone is looking at a gem's source code, we
|
353
|
+
# don't want to format it
|
354
|
+
path = uri.to_standardized_path
|
355
|
+
return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
|
356
|
+
|
358
357
|
Requests::Formatting.new(@store.get(uri), formatter: @store.formatter).run
|
359
358
|
end
|
360
359
|
|
@@ -380,7 +379,7 @@ module RubyLsp
|
|
380
379
|
|
381
380
|
target, parent = document.locate_node(position)
|
382
381
|
dispatcher = Prism::Dispatcher.new
|
383
|
-
listener = Requests::DocumentHighlight.new(target, parent, dispatcher
|
382
|
+
listener = Requests::DocumentHighlight.new(target, parent, dispatcher)
|
384
383
|
dispatcher.visit(document.tree)
|
385
384
|
listener.response
|
386
385
|
end
|
@@ -393,7 +392,7 @@ module RubyLsp
|
|
393
392
|
end_line = range.dig(:end, :line)
|
394
393
|
|
395
394
|
dispatcher = Prism::Dispatcher.new
|
396
|
-
listener = Requests::InlayHints.new(start_line..end_line, dispatcher
|
395
|
+
listener = Requests::InlayHints.new(start_line..end_line, dispatcher)
|
397
396
|
dispatcher.visit(document.tree)
|
398
397
|
listener.response
|
399
398
|
end
|
@@ -443,6 +442,11 @@ module RubyLsp
|
|
443
442
|
|
444
443
|
sig { params(uri: URI::Generic).returns(T.nilable(Interface::FullDocumentDiagnosticReport)) }
|
445
444
|
def diagnostic(uri)
|
445
|
+
# Do not compute diagnostics for files outside of the workspace. For example, if someone is looking at a gem's
|
446
|
+
# source code, we don't want to show diagnostics for it
|
447
|
+
path = uri.to_standardized_path
|
448
|
+
return unless path.nil? || path.start_with?(T.must(@store.workspace_uri.to_standardized_path))
|
449
|
+
|
446
450
|
response = @store.cache_fetch(uri, "textDocument/diagnostic") do |document|
|
447
451
|
Requests::Diagnostics.new(document).run
|
448
452
|
end
|
@@ -457,11 +461,7 @@ module RubyLsp
|
|
457
461
|
end_line = range.dig(:end, :line)
|
458
462
|
|
459
463
|
dispatcher = Prism::Dispatcher.new
|
460
|
-
listener = Requests::SemanticHighlighting.new(
|
461
|
-
dispatcher,
|
462
|
-
@message_queue,
|
463
|
-
range: start_line..end_line,
|
464
|
-
)
|
464
|
+
listener = Requests::SemanticHighlighting.new(dispatcher, range: start_line..end_line)
|
465
465
|
dispatcher.visit(document.tree)
|
466
466
|
|
467
467
|
Requests::Support::SemanticTokenEncoder.new.encode(listener.response)
|
@@ -513,12 +513,7 @@ module RubyLsp
|
|
513
513
|
return unless target
|
514
514
|
|
515
515
|
dispatcher = Prism::Dispatcher.new
|
516
|
-
listener = Requests::Completion.new(
|
517
|
-
@index,
|
518
|
-
nesting,
|
519
|
-
dispatcher,
|
520
|
-
@message_queue,
|
521
|
-
)
|
516
|
+
listener = Requests::Completion.new(@index, nesting, dispatcher)
|
522
517
|
dispatcher.dispatch_once(target)
|
523
518
|
listener.response
|
524
519
|
end
|
@@ -583,6 +578,9 @@ module RubyLsp
|
|
583
578
|
def initialize_request(options)
|
584
579
|
@store.clear
|
585
580
|
|
581
|
+
workspace_uri = options.dig(:workspaceFolders, 0, :uri)
|
582
|
+
@store.workspace_uri = URI(workspace_uri) if workspace_uri
|
583
|
+
|
586
584
|
encodings = options.dig(:capabilities, :general, :positionEncodings)
|
587
585
|
@store.encoding = if encodings.nil? || encodings.empty?
|
588
586
|
Constant::PositionEncodingKind::UTF16
|
data/lib/ruby_lsp/listener.rb
CHANGED
@@ -14,10 +14,9 @@ module RubyLsp
|
|
14
14
|
|
15
15
|
abstract!
|
16
16
|
|
17
|
-
sig { params(dispatcher: Prism::Dispatcher
|
18
|
-
def initialize(dispatcher
|
17
|
+
sig { params(dispatcher: Prism::Dispatcher).void }
|
18
|
+
def initialize(dispatcher)
|
19
19
|
@dispatcher = dispatcher
|
20
|
-
@message_queue = message_queue
|
21
20
|
end
|
22
21
|
|
23
22
|
sig { returns(ResponseType) }
|
@@ -43,8 +42,8 @@ module RubyLsp
|
|
43
42
|
# When inheriting from ExtensibleListener, the `super` of constructor must be called **after** the subclass's own
|
44
43
|
# ivars have been initialized. This is because the constructor of ExtensibleListener calls
|
45
44
|
# `initialize_external_listener` which may depend on the subclass's ivars.
|
46
|
-
sig { params(dispatcher: Prism::Dispatcher
|
47
|
-
def initialize(dispatcher
|
45
|
+
sig { params(dispatcher: Prism::Dispatcher).void }
|
46
|
+
def initialize(dispatcher)
|
48
47
|
super
|
49
48
|
@response_merged = T.let(false, T::Boolean)
|
50
49
|
@external_listeners = T.let(
|
@@ -47,16 +47,18 @@ module RubyLsp
|
|
47
47
|
sig { override.returns(ResponseType) }
|
48
48
|
attr_reader :_response
|
49
49
|
|
50
|
-
sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher
|
51
|
-
def initialize(uri, dispatcher
|
50
|
+
sig { params(uri: URI::Generic, dispatcher: Prism::Dispatcher).void }
|
51
|
+
def initialize(uri, dispatcher)
|
52
52
|
@uri = T.let(uri, URI::Generic)
|
53
53
|
@_response = T.let([], ResponseType)
|
54
54
|
@path = T.let(uri.to_standardized_path, T.nilable(String))
|
55
55
|
# visibility_stack is a stack of [current_visibility, previous_visibility]
|
56
56
|
@visibility_stack = T.let([[:public, :public]], T::Array[T::Array[T.nilable(Symbol)]])
|
57
57
|
@class_stack = T.let([], T::Array[String])
|
58
|
+
@group_id = T.let(1, Integer)
|
59
|
+
@group_id_stack = T.let([], T::Array[Integer])
|
58
60
|
|
59
|
-
super(dispatcher
|
61
|
+
super(dispatcher)
|
60
62
|
|
61
63
|
dispatcher.register(
|
62
64
|
self,
|
@@ -82,12 +84,16 @@ module RubyLsp
|
|
82
84
|
kind: :group,
|
83
85
|
)
|
84
86
|
end
|
87
|
+
|
88
|
+
@group_id_stack.push(@group_id)
|
89
|
+
@group_id += 1
|
85
90
|
end
|
86
91
|
|
87
92
|
sig { params(node: Prism::ClassNode).void }
|
88
93
|
def on_class_node_leave(node)
|
89
94
|
@visibility_stack.pop
|
90
95
|
@class_stack.pop
|
96
|
+
@group_id_stack.pop
|
91
97
|
end
|
92
98
|
|
93
99
|
sig { params(node: Prism::DefNode).void }
|
@@ -146,7 +152,7 @@ module RubyLsp
|
|
146
152
|
|
147
153
|
sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
|
148
154
|
def initialize_external_listener(addon)
|
149
|
-
addon.create_code_lens_listener(@uri, @dispatcher
|
155
|
+
addon.create_code_lens_listener(@uri, @dispatcher)
|
150
156
|
end
|
151
157
|
|
152
158
|
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
@@ -174,12 +180,15 @@ module RubyLsp
|
|
174
180
|
},
|
175
181
|
]
|
176
182
|
|
183
|
+
grouping_data = { group_id: @group_id_stack.last, kind: kind }
|
184
|
+
grouping_data[:id] = @group_id if kind == :group
|
185
|
+
|
177
186
|
@_response << create_code_lens(
|
178
187
|
node,
|
179
188
|
title: "Run",
|
180
189
|
command_name: "rubyLsp.runTest",
|
181
190
|
arguments: arguments,
|
182
|
-
data: { type: "test",
|
191
|
+
data: { type: "test", **grouping_data },
|
183
192
|
)
|
184
193
|
|
185
194
|
@_response << create_code_lens(
|
@@ -187,7 +196,7 @@ module RubyLsp
|
|
187
196
|
title: "Run In Terminal",
|
188
197
|
command_name: "rubyLsp.runTestInTerminal",
|
189
198
|
arguments: arguments,
|
190
|
-
data: { type: "test_in_terminal",
|
199
|
+
data: { type: "test_in_terminal", **grouping_data },
|
191
200
|
)
|
192
201
|
|
193
202
|
@_response << create_code_lens(
|
@@ -195,7 +204,7 @@ module RubyLsp
|
|
195
204
|
title: "Debug",
|
196
205
|
command_name: "rubyLsp.debugTest",
|
197
206
|
arguments: arguments,
|
198
|
-
data: { type: "debug",
|
207
|
+
data: { type: "debug", **grouping_data },
|
199
208
|
)
|
200
209
|
end
|
201
210
|
|
@@ -36,11 +36,10 @@ module RubyLsp
|
|
36
36
|
index: RubyIndexer::Index,
|
37
37
|
nesting: T::Array[String],
|
38
38
|
dispatcher: Prism::Dispatcher,
|
39
|
-
message_queue: Thread::Queue,
|
40
39
|
).void
|
41
40
|
end
|
42
|
-
def initialize(index, nesting, dispatcher
|
43
|
-
super(dispatcher
|
41
|
+
def initialize(index, nesting, dispatcher)
|
42
|
+
super(dispatcher)
|
44
43
|
@_response = T.let([], ResponseType)
|
45
44
|
@index = index
|
46
45
|
@nesting = nesting
|
@@ -137,18 +136,22 @@ module RubyLsp
|
|
137
136
|
|
138
137
|
receiver = T.must(receiver_entries.first)
|
139
138
|
|
140
|
-
|
141
|
-
|
142
|
-
entry = entries.find { |e| e.owner&.name == receiver.name }
|
139
|
+
@index.prefix_search(name).each do |entries|
|
140
|
+
entry = entries.find { |e| e.is_a?(RubyIndexer::Entry::Member) && e.owner&.name == receiver.name }
|
143
141
|
next unless entry
|
144
142
|
|
145
|
-
@_response << build_method_completion(entry, node)
|
143
|
+
@_response << build_method_completion(T.cast(entry, RubyIndexer::Entry::Member), node)
|
146
144
|
end
|
147
145
|
end
|
148
146
|
|
149
147
|
private
|
150
148
|
|
151
|
-
sig
|
149
|
+
sig do
|
150
|
+
params(
|
151
|
+
entry: RubyIndexer::Entry::Member,
|
152
|
+
node: Prism::CallNode,
|
153
|
+
).returns(Interface::CompletionItem)
|
154
|
+
end
|
152
155
|
def build_method_completion(entry, node)
|
153
156
|
name = entry.name
|
154
157
|
parameters = entry.parameters
|
@@ -37,16 +37,15 @@ module RubyLsp
|
|
37
37
|
nesting: T::Array[String],
|
38
38
|
index: RubyIndexer::Index,
|
39
39
|
dispatcher: Prism::Dispatcher,
|
40
|
-
message_queue: Thread::Queue,
|
41
40
|
).void
|
42
41
|
end
|
43
|
-
def initialize(uri, nesting, index, dispatcher
|
42
|
+
def initialize(uri, nesting, index, dispatcher)
|
44
43
|
@uri = uri
|
45
44
|
@nesting = nesting
|
46
45
|
@index = index
|
47
46
|
@_response = T.let(nil, ResponseType)
|
48
47
|
|
49
|
-
super(dispatcher
|
48
|
+
super(dispatcher)
|
50
49
|
|
51
50
|
dispatcher.register(
|
52
51
|
self,
|
@@ -58,7 +57,7 @@ module RubyLsp
|
|
58
57
|
|
59
58
|
sig { override.params(addon: Addon).returns(T.nilable(RubyLsp::Listener[ResponseType])) }
|
60
59
|
def initialize_external_listener(addon)
|
61
|
-
addon.create_definition_listener(@uri, @nesting, @index, @dispatcher
|
60
|
+
addon.create_definition_listener(@uri, @nesting, @index, @dispatcher)
|
62
61
|
end
|
63
62
|
|
64
63
|
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
@@ -32,13 +32,8 @@ module RubyLsp
|
|
32
32
|
def run
|
33
33
|
# Running RuboCop is slow, so to avoid excessive runs we only do so if the file is syntactically valid
|
34
34
|
return syntax_error_diagnostics if @document.syntax_error?
|
35
|
-
|
36
35
|
return unless defined?(Support::RuboCopDiagnosticsRunner)
|
37
36
|
|
38
|
-
# Don't try to run RuboCop diagnostics for files outside the current working directory
|
39
|
-
path = @uri.to_standardized_path
|
40
|
-
return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
|
41
|
-
|
42
37
|
Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document).map!(&:to_lsp_diagnostic)
|
43
38
|
end
|
44
39
|
|
@@ -114,11 +114,10 @@ module RubyLsp
|
|
114
114
|
target: T.nilable(Prism::Node),
|
115
115
|
parent: T.nilable(Prism::Node),
|
116
116
|
dispatcher: Prism::Dispatcher,
|
117
|
-
message_queue: Thread::Queue,
|
118
117
|
).void
|
119
118
|
end
|
120
|
-
def initialize(target, parent, dispatcher
|
121
|
-
super(dispatcher
|
119
|
+
def initialize(target, parent, dispatcher)
|
120
|
+
super(dispatcher)
|
122
121
|
|
123
122
|
@_response = T.let([], T::Array[Interface::DocumentHighlight])
|
124
123
|
|
@@ -80,11 +80,10 @@ module RubyLsp
|
|
80
80
|
uri: URI::Generic,
|
81
81
|
comments: T::Array[Prism::Comment],
|
82
82
|
dispatcher: Prism::Dispatcher,
|
83
|
-
message_queue: Thread::Queue,
|
84
83
|
).void
|
85
84
|
end
|
86
|
-
def initialize(uri, comments, dispatcher
|
87
|
-
super(dispatcher
|
85
|
+
def initialize(uri, comments, dispatcher)
|
86
|
+
super(dispatcher)
|
88
87
|
|
89
88
|
# Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
|
90
89
|
# in the URI
|
@@ -49,8 +49,8 @@ module RubyLsp
|
|
49
49
|
sig { override.returns(T::Array[Interface::DocumentSymbol]) }
|
50
50
|
attr_reader :_response
|
51
51
|
|
52
|
-
sig { params(dispatcher: Prism::Dispatcher
|
53
|
-
def initialize(dispatcher
|
52
|
+
sig { params(dispatcher: Prism::Dispatcher).void }
|
53
|
+
def initialize(dispatcher)
|
54
54
|
@root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
|
55
55
|
@_response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
|
56
56
|
@stack = T.let(
|
@@ -80,7 +80,7 @@ module RubyLsp
|
|
80
80
|
|
81
81
|
sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
|
82
82
|
def initialize_external_listener(addon)
|
83
|
-
addon.create_document_symbol_listener(@dispatcher
|
83
|
+
addon.create_document_symbol_listener(@dispatcher)
|
84
84
|
end
|
85
85
|
|
86
86
|
# Merges responses from other listeners
|
@@ -21,9 +21,9 @@ module RubyLsp
|
|
21
21
|
|
22
22
|
ResponseType = type_member { { fixed: T::Array[Interface::FoldingRange] } }
|
23
23
|
|
24
|
-
sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher
|
25
|
-
def initialize(comments, dispatcher
|
26
|
-
super(dispatcher
|
24
|
+
sig { params(comments: T::Array[Prism::Comment], dispatcher: Prism::Dispatcher).void }
|
25
|
+
def initialize(comments, dispatcher)
|
26
|
+
super(dispatcher)
|
27
27
|
|
28
28
|
@_response = T.let([], ResponseType)
|
29
29
|
@requires = T.let([], T::Array[Prism::CallNode])
|
@@ -40,6 +40,7 @@ module RubyLsp
|
|
40
40
|
:on_array_node_enter,
|
41
41
|
:on_block_node_enter,
|
42
42
|
:on_case_node_enter,
|
43
|
+
:on_case_match_node_enter,
|
43
44
|
:on_class_node_enter,
|
44
45
|
:on_module_node_enter,
|
45
46
|
:on_for_node_enter,
|
@@ -51,7 +52,6 @@ module RubyLsp
|
|
51
52
|
:on_else_node_enter,
|
52
53
|
:on_ensure_node_enter,
|
53
54
|
:on_begin_node_enter,
|
54
|
-
:on_string_concat_node_enter,
|
55
55
|
:on_def_node_enter,
|
56
56
|
:on_call_node_enter,
|
57
57
|
:on_lambda_node_enter,
|
@@ -91,10 +91,10 @@ module RubyLsp
|
|
91
91
|
|
92
92
|
sig { params(node: Prism::InterpolatedStringNode).void }
|
93
93
|
def on_interpolated_string_node_enter(node)
|
94
|
-
opening_loc = node.opening_loc
|
95
|
-
closing_loc = node.closing_loc
|
94
|
+
opening_loc = node.opening_loc || node.location
|
95
|
+
closing_loc = node.closing_loc || node.parts.last&.location || node.location
|
96
96
|
|
97
|
-
add_lines_range(opening_loc.start_line, closing_loc.start_line - 1)
|
97
|
+
add_lines_range(opening_loc.start_line, closing_loc.start_line - 1)
|
98
98
|
end
|
99
99
|
|
100
100
|
sig { params(node: Prism::ArrayNode).void }
|
@@ -112,6 +112,11 @@ module RubyLsp
|
|
112
112
|
add_simple_range(node)
|
113
113
|
end
|
114
114
|
|
115
|
+
sig { params(node: Prism::CaseMatchNode).void }
|
116
|
+
def on_case_match_node_enter(node)
|
117
|
+
add_simple_range(node)
|
118
|
+
end
|
119
|
+
|
115
120
|
sig { params(node: Prism::ClassNode).void }
|
116
121
|
def on_class_node_enter(node)
|
117
122
|
add_simple_range(node)
|
@@ -167,14 +172,6 @@ module RubyLsp
|
|
167
172
|
add_simple_range(node)
|
168
173
|
end
|
169
174
|
|
170
|
-
sig { params(node: Prism::StringConcatNode).void }
|
171
|
-
def on_string_concat_node_enter(node)
|
172
|
-
left = T.let(node.left, Prism::Node)
|
173
|
-
left = left.left while left.is_a?(Prism::StringConcatNode)
|
174
|
-
|
175
|
-
add_lines_range(left.location.start_line, node.right.location.end_line - 1)
|
176
|
-
end
|
177
|
-
|
178
175
|
sig { params(node: Prism::DefNode).void }
|
179
176
|
def on_def_node_enter(node)
|
180
177
|
params = node.parameters
|
@@ -64,11 +64,6 @@ module RubyLsp
|
|
64
64
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
65
65
|
def run
|
66
66
|
return if @formatter == "none"
|
67
|
-
|
68
|
-
# Don't try to format files outside the current working directory
|
69
|
-
path = @uri.to_standardized_path
|
70
|
-
return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
|
71
|
-
|
72
67
|
return if @document.syntax_error?
|
73
68
|
|
74
69
|
formatted_text = formatted_file
|
@@ -37,15 +37,14 @@ module RubyLsp
|
|
37
37
|
index: RubyIndexer::Index,
|
38
38
|
nesting: T::Array[String],
|
39
39
|
dispatcher: Prism::Dispatcher,
|
40
|
-
message_queue: Thread::Queue,
|
41
40
|
).void
|
42
41
|
end
|
43
|
-
def initialize(index, nesting, dispatcher
|
42
|
+
def initialize(index, nesting, dispatcher)
|
44
43
|
@index = index
|
45
44
|
@nesting = nesting
|
46
45
|
@_response = T.let(nil, ResponseType)
|
47
46
|
|
48
|
-
super(dispatcher
|
47
|
+
super(dispatcher)
|
49
48
|
dispatcher.register(
|
50
49
|
self,
|
51
50
|
:on_constant_read_node_enter,
|
@@ -57,7 +56,7 @@ module RubyLsp
|
|
57
56
|
|
58
57
|
sig { override.params(addon: Addon).returns(T.nilable(Listener[ResponseType])) }
|
59
58
|
def initialize_external_listener(addon)
|
60
|
-
addon.create_hover_listener(@nesting, @index, @dispatcher
|
59
|
+
addon.create_hover_listener(@nesting, @index, @dispatcher)
|
61
60
|
end
|
62
61
|
|
63
62
|
# Merges responses from other hover listeners
|
@@ -39,9 +39,9 @@ module RubyLsp
|
|
39
39
|
sig { override.returns(ResponseType) }
|
40
40
|
attr_reader :_response
|
41
41
|
|
42
|
-
sig { params(range: T::Range[Integer], dispatcher: Prism::Dispatcher
|
43
|
-
def initialize(range, dispatcher
|
44
|
-
super(dispatcher
|
42
|
+
sig { params(range: T::Range[Integer], dispatcher: Prism::Dispatcher).void }
|
43
|
+
def initialize(range, dispatcher)
|
44
|
+
super(dispatcher)
|
45
45
|
|
46
46
|
@_response = T.let([], ResponseType)
|
47
47
|
@range = range
|
@@ -20,8 +20,8 @@ module RubyLsp
|
|
20
20
|
|
21
21
|
END_REGEXES = T.let(
|
22
22
|
[
|
23
|
-
|
24
|
-
/.*\
|
23
|
+
/\b(if|unless|for|while|class|module|until|def|case)\b.*/,
|
24
|
+
/.*\s\bdo\b/,
|
25
25
|
],
|
26
26
|
T::Array[Regexp],
|
27
27
|
)
|
@@ -139,7 +139,6 @@ module RubyLsp
|
|
139
139
|
sig { params(spaces: String).void }
|
140
140
|
def handle_comment_line(spaces)
|
141
141
|
add_edit_with_text("##{spaces}")
|
142
|
-
move_cursor_to(@position[:line], @indentation + spaces.size + 1)
|
143
142
|
end
|
144
143
|
|
145
144
|
sig { params(text: String, position: Document::PositionShape).void }
|
@@ -107,20 +107,15 @@ module RubyLsp
|
|
107
107
|
sig { override.returns(ResponseType) }
|
108
108
|
attr_reader :_response
|
109
109
|
|
110
|
-
sig
|
111
|
-
|
112
|
-
|
113
|
-
message_queue: Thread::Queue,
|
114
|
-
range: T.nilable(T::Range[Integer]),
|
115
|
-
).void
|
116
|
-
end
|
117
|
-
def initialize(dispatcher, message_queue, range: nil)
|
118
|
-
super(dispatcher, message_queue)
|
110
|
+
sig { params(dispatcher: Prism::Dispatcher, range: T.nilable(T::Range[Integer])).void }
|
111
|
+
def initialize(dispatcher, range: nil)
|
112
|
+
super(dispatcher)
|
119
113
|
|
120
114
|
@_response = T.let([], ResponseType)
|
121
115
|
@range = range
|
122
116
|
@special_methods = T.let(nil, T.nilable(T::Array[String]))
|
123
117
|
@current_scope = T.let(ParameterScope.new, ParameterScope)
|
118
|
+
@inside_regex_capture = T.let(false, T::Boolean)
|
124
119
|
|
125
120
|
dispatcher.register(
|
126
121
|
self,
|
@@ -152,6 +147,8 @@ module RubyLsp
|
|
152
147
|
:on_local_variable_or_write_node_enter,
|
153
148
|
:on_local_variable_target_node_enter,
|
154
149
|
:on_block_local_variable_node_enter,
|
150
|
+
:on_match_write_node_enter,
|
151
|
+
:on_match_write_node_leave,
|
155
152
|
)
|
156
153
|
end
|
157
154
|
|
@@ -165,14 +162,28 @@ module RubyLsp
|
|
165
162
|
# We can't push a semantic token for [] and []= because the argument inside the brackets is a part of
|
166
163
|
# the message_loc
|
167
164
|
return if message.start_with?("[") && (message.end_with?("]") || message.end_with?("]="))
|
168
|
-
|
169
|
-
return process_regexp_locals(node) if message == "=~"
|
165
|
+
return if message == "=~"
|
170
166
|
return if special_method?(message)
|
171
167
|
|
172
168
|
type = Support::Sorbet.annotation?(node) ? :type : :method
|
173
169
|
add_token(T.must(node.message_loc), type)
|
174
170
|
end
|
175
171
|
|
172
|
+
sig { params(node: Prism::MatchWriteNode).void }
|
173
|
+
def on_match_write_node_enter(node)
|
174
|
+
call = node.call
|
175
|
+
|
176
|
+
if call.message == "=~"
|
177
|
+
@inside_regex_capture = true
|
178
|
+
process_regexp_locals(call)
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
sig { params(node: Prism::MatchWriteNode).void }
|
183
|
+
def on_match_write_node_leave(node)
|
184
|
+
@inside_regex_capture = true if node.call.message == "=~"
|
185
|
+
end
|
186
|
+
|
176
187
|
sig { params(node: Prism::ConstantReadNode).void }
|
177
188
|
def on_constant_read_node_enter(node)
|
178
189
|
return unless visible?(node, @range)
|
@@ -359,6 +370,12 @@ module RubyLsp
|
|
359
370
|
|
360
371
|
sig { params(node: Prism::LocalVariableTargetNode).void }
|
361
372
|
def on_local_variable_target_node_enter(node)
|
373
|
+
# If we're inside a regex capture, Prism will add LocalVariableTarget nodes for each captured variable.
|
374
|
+
# Unfortunately, if the regex contains a backslash, the location will be incorrect and we'll end up highlighting
|
375
|
+
# the entire regex as a local variable. We process these captures in process_regexp_locals instead and then
|
376
|
+
# prevent pushing local variable target tokens. See https://github.com/ruby/prism/issues/1912
|
377
|
+
return if @inside_regex_capture
|
378
|
+
|
362
379
|
return unless visible?(node, @range)
|
363
380
|
|
364
381
|
add_token(node.location, @current_scope.type_for(node.name))
|
@@ -34,15 +34,10 @@ module RubyLsp
|
|
34
34
|
|
35
35
|
sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
36
36
|
def run(uri, document)
|
37
|
-
|
38
|
-
|
39
|
-
return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
|
37
|
+
path = uri.to_standardized_path
|
38
|
+
return if path && @options.ignore_files.any? { |pattern| File.fnmatch?("*/#{pattern}", path) }
|
40
39
|
|
41
|
-
SyntaxTree.format(
|
42
|
-
document.source,
|
43
|
-
@options.print_width,
|
44
|
-
options: @options.formatter_options,
|
45
|
-
)
|
40
|
+
SyntaxTree.format(document.source, @options.print_width, options: @options.formatter_options)
|
46
41
|
end
|
47
42
|
end
|
48
43
|
end
|
@@ -75,6 +75,8 @@ module RubyLsp
|
|
75
75
|
Constant::SymbolKind::CONSTANT
|
76
76
|
when RubyIndexer::Entry::Method
|
77
77
|
entry.name == "initialize" ? Constant::SymbolKind::CONSTRUCTOR : Constant::SymbolKind::METHOD
|
78
|
+
when RubyIndexer::Entry::Accessor
|
79
|
+
Constant::SymbolKind::PROPERTY
|
78
80
|
end
|
79
81
|
end
|
80
82
|
end
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -17,6 +17,9 @@ module RubyLsp
|
|
17
17
|
sig { returns(T::Boolean) }
|
18
18
|
attr_accessor :experimental_features
|
19
19
|
|
20
|
+
sig { returns(URI::Generic) }
|
21
|
+
attr_accessor :workspace_uri
|
22
|
+
|
20
23
|
sig { void }
|
21
24
|
def initialize
|
22
25
|
@state = T.let({}, T::Hash[String, Document])
|
@@ -24,6 +27,7 @@ module RubyLsp
|
|
24
27
|
@formatter = T.let("auto", String)
|
25
28
|
@supports_progress = T.let(true, T::Boolean)
|
26
29
|
@experimental_features = T.let(false, T::Boolean)
|
30
|
+
@workspace_uri = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
27
31
|
end
|
28
32
|
|
29
33
|
sig { params(uri: URI::Generic).returns(Document) }
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -4,10 +4,6 @@
|
|
4
4
|
module RubyLsp
|
5
5
|
# Used to indicate that a request shouldn't return a response
|
6
6
|
VOID = T.let(Object.new.freeze, Object)
|
7
|
-
|
8
|
-
# This freeze is not redundant since the interpolated string is mutable
|
9
|
-
WORKSPACE_URI = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
10
|
-
|
11
7
|
BUNDLE_PATH = T.let(
|
12
8
|
begin
|
13
9
|
Bundler.bundle_path.to_s
|
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.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-11-
|
11
|
+
date: 2023-11-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -30,20 +30,20 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.
|
33
|
+
version: 0.18.0
|
34
34
|
- - "<"
|
35
35
|
- !ruby/object:Gem::Version
|
36
|
-
version: '0.
|
36
|
+
version: '0.19'
|
37
37
|
type: :runtime
|
38
38
|
prerelease: false
|
39
39
|
version_requirements: !ruby/object:Gem::Requirement
|
40
40
|
requirements:
|
41
41
|
- - ">="
|
42
42
|
- !ruby/object:Gem::Version
|
43
|
-
version: 0.
|
43
|
+
version: 0.18.0
|
44
44
|
- - "<"
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: '0.
|
46
|
+
version: '0.19'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: sorbet-runtime
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|