ruby-lsp 0.5.0 → 0.6.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/README.md +4 -0
- data/VERSION +1 -1
- data/exe/ruby-lsp +33 -1
- data/lib/ruby_lsp/check_docs.rb +1 -1
- data/lib/ruby_lsp/event_emitter.rb +61 -0
- data/lib/ruby_lsp/executor.rb +31 -46
- data/lib/ruby_lsp/internal.rb +1 -0
- data/lib/ruby_lsp/requests/base_request.rb +2 -6
- data/lib/ruby_lsp/requests/code_lens.rb +121 -33
- data/lib/ruby_lsp/requests/diagnostics.rb +2 -0
- data/lib/ruby_lsp/requests/folding_ranges.rb +2 -1
- data/lib/ruby_lsp/requests/formatting.rb +30 -11
- data/lib/ruby_lsp/requests/inlay_hints.rb +17 -15
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +85 -113
- data/lib/ruby_lsp/requests/support/common.rb +6 -17
- data/lib/ruby_lsp/requests/support/dependency_detector.rb +41 -0
- data/lib/ruby_lsp/requests/support/formatter_runner.rb +18 -0
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +2 -1
- data/lib/ruby_lsp/requests/support/source_uri.rb +1 -1
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +2 -1
- data/lib/ruby_lsp/requests.rb +1 -0
- data/lib/ruby_lsp/server.rb +5 -2
- data/lib/ruby_lsp/utils.rb +1 -1
- metadata +6 -4
@@ -13,7 +13,7 @@ module RubyLsp
|
|
13
13
|
# registering the ruby-lsp as the Ruby formatter.
|
14
14
|
#
|
15
15
|
# The `rubyLsp.formatter` setting specifies which formatter to use.
|
16
|
-
# If set to `auto
|
16
|
+
# If set to `auto` then it behaves as follows:
|
17
17
|
# * It will use RuboCop if it is part of the bundle.
|
18
18
|
# * If RuboCop is not available, and `syntax_tree` is a direct dependency, it will use that.
|
19
19
|
# * Otherwise, no formatting will be applied.
|
@@ -29,6 +29,29 @@ module RubyLsp
|
|
29
29
|
class Error < StandardError; end
|
30
30
|
class InvalidFormatter < StandardError; end
|
31
31
|
|
32
|
+
@formatters = T.let(
|
33
|
+
{
|
34
|
+
"syntax_tree" => Support::SyntaxTreeFormattingRunner.instance,
|
35
|
+
},
|
36
|
+
T::Hash[String, Support::FormatterRunner],
|
37
|
+
)
|
38
|
+
|
39
|
+
class << self
|
40
|
+
extend T::Sig
|
41
|
+
|
42
|
+
sig { returns(T::Hash[String, Support::FormatterRunner]) }
|
43
|
+
attr_reader :formatters
|
44
|
+
|
45
|
+
sig { params(identifier: String, instance: Support::FormatterRunner).void }
|
46
|
+
def register_formatter(identifier, instance)
|
47
|
+
@formatters[identifier] = instance
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if defined?(Support::RuboCopFormattingRunner)
|
52
|
+
register_formatter("rubocop", Support::RuboCopFormattingRunner.instance)
|
53
|
+
end
|
54
|
+
|
32
55
|
extend T::Sig
|
33
56
|
|
34
57
|
sig { params(document: Document, formatter: String).void }
|
@@ -41,6 +64,8 @@ module RubyLsp
|
|
41
64
|
|
42
65
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
43
66
|
def run
|
67
|
+
return if @formatter == "none"
|
68
|
+
|
44
69
|
# Don't try to format files outside the current working directory
|
45
70
|
return unless @uri.sub("file://", "").start_with?(Dir.pwd)
|
46
71
|
|
@@ -67,16 +92,10 @@ module RubyLsp
|
|
67
92
|
|
68
93
|
sig { returns(T.nilable(String)) }
|
69
94
|
def formatted_file
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
end
|
75
|
-
when "syntax_tree"
|
76
|
-
Support::SyntaxTreeFormattingRunner.instance.run(@uri, @document)
|
77
|
-
else
|
78
|
-
raise InvalidFormatter, "Unknown formatter: #{@formatter}"
|
79
|
-
end
|
95
|
+
formatter_runner = Formatting.formatters[@formatter]
|
96
|
+
raise InvalidFormatter, "Formatter is not available: #{@formatter}" unless formatter_runner
|
97
|
+
|
98
|
+
formatter_runner.run(@uri, @document)
|
80
99
|
end
|
81
100
|
end
|
82
101
|
end
|
@@ -18,39 +18,41 @@ module RubyLsp
|
|
18
18
|
# puts "handle some rescue"
|
19
19
|
# end
|
20
20
|
# ```
|
21
|
-
class InlayHints <
|
21
|
+
class InlayHints < Listener
|
22
|
+
extend T::Sig
|
23
|
+
extend T::Generic
|
24
|
+
|
25
|
+
ResponseType = type_member { { fixed: T::Array[Interface::InlayHint] } }
|
26
|
+
|
22
27
|
RESCUE_STRING_LENGTH = T.let("rescue".length, Integer)
|
23
28
|
|
24
|
-
sig {
|
25
|
-
|
26
|
-
|
29
|
+
sig { override.returns(ResponseType) }
|
30
|
+
attr_reader :response
|
31
|
+
|
32
|
+
sig { params(range: T::Range[Integer], emitter: EventEmitter, message_queue: Thread::Queue).void }
|
33
|
+
def initialize(range, emitter, message_queue)
|
34
|
+
super(emitter, message_queue)
|
27
35
|
|
28
|
-
@
|
36
|
+
@response = T.let([], ResponseType)
|
29
37
|
@range = range
|
30
|
-
end
|
31
38
|
|
32
|
-
|
33
|
-
def run
|
34
|
-
visit(@document.tree) if @document.parsed?
|
35
|
-
@hints
|
39
|
+
emitter.register(self, :on_rescue)
|
36
40
|
end
|
37
41
|
|
38
|
-
sig {
|
39
|
-
def
|
42
|
+
sig { params(node: SyntaxTree::Rescue).void }
|
43
|
+
def on_rescue(node)
|
40
44
|
exception = node.exception
|
41
45
|
return unless exception.nil? || exception.exceptions.nil?
|
42
46
|
|
43
47
|
loc = node.location
|
44
48
|
return unless visible?(node, @range)
|
45
49
|
|
46
|
-
@
|
50
|
+
@response << Interface::InlayHint.new(
|
47
51
|
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
48
52
|
label: "StandardError",
|
49
53
|
padding_left: true,
|
50
54
|
tooltip: "StandardError is implied in a bare rescue",
|
51
55
|
)
|
52
|
-
|
53
|
-
super
|
54
56
|
end
|
55
57
|
end
|
56
58
|
end
|
@@ -18,9 +18,11 @@ module RubyLsp
|
|
18
18
|
# var # --> semantic highlighting: local variable
|
19
19
|
# end
|
20
20
|
# ```
|
21
|
-
class SemanticHighlighting <
|
21
|
+
class SemanticHighlighting < Listener
|
22
22
|
extend T::Sig
|
23
|
-
|
23
|
+
extend T::Generic
|
24
|
+
|
25
|
+
ResponseType = type_member { { fixed: T::Array[SemanticToken] } }
|
24
26
|
|
25
27
|
TOKEN_TYPES = T.let(
|
26
28
|
{
|
@@ -102,99 +104,91 @@ module RubyLsp
|
|
102
104
|
end
|
103
105
|
end
|
104
106
|
|
107
|
+
sig { override.returns(ResponseType) }
|
108
|
+
attr_reader :response
|
109
|
+
|
105
110
|
sig do
|
106
111
|
params(
|
107
|
-
|
112
|
+
emitter: EventEmitter,
|
113
|
+
message_queue: Thread::Queue,
|
108
114
|
range: T.nilable(T::Range[Integer]),
|
109
|
-
encoder: T.nilable(Support::SemanticTokenEncoder),
|
110
115
|
).void
|
111
116
|
end
|
112
|
-
def initialize(
|
113
|
-
super(
|
117
|
+
def initialize(emitter, message_queue, range: nil)
|
118
|
+
super(emitter, message_queue)
|
114
119
|
|
115
|
-
@
|
116
|
-
@tokens = T.let([], T::Array[SemanticToken])
|
117
|
-
@tree = T.let(T.must(document.tree), SyntaxTree::Node)
|
120
|
+
@response = T.let([], ResponseType)
|
118
121
|
@range = range
|
119
122
|
@special_methods = T.let(nil, T.nilable(T::Array[String]))
|
120
|
-
end
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
124
|
+
emitter.register(
|
125
|
+
self,
|
126
|
+
:after_binary,
|
127
|
+
:on_block_var,
|
128
|
+
:on_call,
|
129
|
+
:on_class,
|
130
|
+
:on_command,
|
131
|
+
:on_command_call,
|
132
|
+
:on_const,
|
133
|
+
:on_def,
|
134
|
+
:on_field,
|
135
|
+
:on_kw,
|
136
|
+
:on_lambda_var,
|
137
|
+
:on_module,
|
138
|
+
:on_params,
|
139
|
+
:on_var_field,
|
140
|
+
:on_var_ref,
|
141
|
+
:on_vcall,
|
128
142
|
)
|
129
143
|
end
|
130
|
-
def run
|
131
|
-
return @tokens unless @document.parsed?
|
132
144
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
@encoder.encode(@tokens)
|
137
|
-
end
|
138
|
-
|
139
|
-
sig { override.params(node: SyntaxTree::CallNode).void }
|
140
|
-
def visit_call(node)
|
141
|
-
return super unless visible?(node, @range)
|
142
|
-
|
143
|
-
visit(node.receiver)
|
145
|
+
sig { params(node: SyntaxTree::CallNode).void }
|
146
|
+
def on_call(node)
|
147
|
+
return unless visible?(node, @range)
|
144
148
|
|
145
149
|
message = node.message
|
146
150
|
if !message.is_a?(Symbol) && !special_method?(message.value)
|
147
151
|
type = Support::Sorbet.annotation?(node) ? :type : :method
|
148
|
-
|
149
152
|
add_token(message.location, type)
|
150
153
|
end
|
151
|
-
|
152
|
-
visit(node.arguments)
|
153
154
|
end
|
154
155
|
|
155
|
-
sig {
|
156
|
-
def
|
157
|
-
return
|
156
|
+
sig { params(node: SyntaxTree::Command).void }
|
157
|
+
def on_command(node)
|
158
|
+
return unless visible?(node, @range)
|
158
159
|
|
159
|
-
unless special_method?(node.message.value)
|
160
|
-
add_token(node.message.location, :method)
|
161
|
-
end
|
162
|
-
visit(node.arguments)
|
163
|
-
visit(node.block)
|
160
|
+
add_token(node.message.location, :method) unless special_method?(node.message.value)
|
164
161
|
end
|
165
162
|
|
166
|
-
sig {
|
167
|
-
def
|
168
|
-
return
|
163
|
+
sig { params(node: SyntaxTree::CommandCall).void }
|
164
|
+
def on_command_call(node)
|
165
|
+
return unless visible?(node, @range)
|
169
166
|
|
170
|
-
visit(node.receiver)
|
171
167
|
message = node.message
|
172
168
|
add_token(message.location, :method) unless message.is_a?(Symbol)
|
173
|
-
visit(node.arguments)
|
174
|
-
visit(node.block)
|
175
169
|
end
|
176
170
|
|
177
|
-
sig {
|
178
|
-
def
|
179
|
-
return
|
171
|
+
sig { params(node: SyntaxTree::Const).void }
|
172
|
+
def on_const(node)
|
173
|
+
return unless visible?(node, @range)
|
174
|
+
# When finding a module or class definition, we will have already pushed a token related to this constant. We
|
175
|
+
# need to look at the previous two tokens and if they match this locatione exactly, avoid pushing another token
|
176
|
+
# on top of the previous one
|
177
|
+
return if @response.last(2).any? { |token| token.location == node.location }
|
180
178
|
|
181
179
|
add_token(node.location, :namespace)
|
182
180
|
end
|
183
181
|
|
184
|
-
sig {
|
185
|
-
def
|
186
|
-
return
|
182
|
+
sig { params(node: SyntaxTree::DefNode).void }
|
183
|
+
def on_def(node)
|
184
|
+
return unless visible?(node, @range)
|
187
185
|
|
188
186
|
add_token(node.name.location, :method, [:declaration])
|
189
|
-
visit(node.params)
|
190
|
-
visit(node.bodystmt)
|
191
|
-
visit(node.target) if node.target
|
192
|
-
visit(node.operator) if node.operator
|
193
187
|
end
|
194
188
|
|
195
|
-
sig {
|
196
|
-
def
|
197
|
-
return
|
189
|
+
sig { params(node: SyntaxTree::Kw).void }
|
190
|
+
def on_kw(node)
|
191
|
+
return unless visible?(node, @range)
|
198
192
|
|
199
193
|
case node.value
|
200
194
|
when "self"
|
@@ -202,9 +196,9 @@ module RubyLsp
|
|
202
196
|
end
|
203
197
|
end
|
204
198
|
|
205
|
-
sig {
|
206
|
-
def
|
207
|
-
return
|
199
|
+
sig { params(node: SyntaxTree::Params).void }
|
200
|
+
def on_params(node)
|
201
|
+
return unless visible?(node, @range)
|
208
202
|
|
209
203
|
node.keywords.each do |keyword, *|
|
210
204
|
location = keyword.location
|
@@ -220,22 +214,18 @@ module RubyLsp
|
|
220
214
|
name = rest.name
|
221
215
|
add_token(name.location, :parameter) if name
|
222
216
|
end
|
223
|
-
|
224
|
-
super
|
225
217
|
end
|
226
218
|
|
227
|
-
sig {
|
228
|
-
def
|
229
|
-
return
|
219
|
+
sig { params(node: SyntaxTree::Field).void }
|
220
|
+
def on_field(node)
|
221
|
+
return unless visible?(node, @range)
|
230
222
|
|
231
223
|
add_token(node.name.location, :method)
|
232
|
-
|
233
|
-
super
|
234
224
|
end
|
235
225
|
|
236
|
-
sig {
|
237
|
-
def
|
238
|
-
return
|
226
|
+
sig { params(node: SyntaxTree::VarField).void }
|
227
|
+
def on_var_field(node)
|
228
|
+
return unless visible?(node, @range)
|
239
229
|
|
240
230
|
value = node.value
|
241
231
|
|
@@ -243,18 +233,12 @@ module RubyLsp
|
|
243
233
|
when SyntaxTree::Ident
|
244
234
|
type = type_for_local(value)
|
245
235
|
add_token(value.location, type)
|
246
|
-
when Symbol
|
247
|
-
# do nothing
|
248
|
-
else
|
249
|
-
visit(value)
|
250
236
|
end
|
251
|
-
|
252
|
-
super
|
253
237
|
end
|
254
238
|
|
255
|
-
sig {
|
256
|
-
def
|
257
|
-
return
|
239
|
+
sig { params(node: SyntaxTree::VarRef).void }
|
240
|
+
def on_var_ref(node)
|
241
|
+
return unless visible?(node, @range)
|
258
242
|
|
259
243
|
value = node.value
|
260
244
|
|
@@ -262,35 +246,29 @@ module RubyLsp
|
|
262
246
|
when SyntaxTree::Ident
|
263
247
|
type = type_for_local(value)
|
264
248
|
add_token(value.location, type)
|
265
|
-
when Symbol
|
266
|
-
# do nothing
|
267
|
-
else
|
268
|
-
visit(value)
|
269
249
|
end
|
270
250
|
end
|
271
251
|
|
272
252
|
# All block locals are variables. E.g.: [].each do |x; block_local|
|
273
|
-
sig {
|
274
|
-
def
|
253
|
+
sig { params(node: SyntaxTree::BlockVar).void }
|
254
|
+
def on_block_var(node)
|
275
255
|
node.locals.each { |local| add_token(local.location, :variable) }
|
276
|
-
super
|
277
256
|
end
|
278
257
|
|
279
258
|
# All lambda locals are variables. E.g.: ->(x; lambda_local) {}
|
280
|
-
sig {
|
281
|
-
def
|
259
|
+
sig { params(node: SyntaxTree::LambdaVar).void }
|
260
|
+
def on_lambda_var(node)
|
282
261
|
node.locals.each { |local| add_token(local.location, :variable) }
|
283
|
-
super
|
284
262
|
end
|
285
263
|
|
286
|
-
sig {
|
287
|
-
def
|
288
|
-
return
|
264
|
+
sig { params(node: SyntaxTree::VCall).void }
|
265
|
+
def on_vcall(node)
|
266
|
+
return unless visible?(node, @range)
|
289
267
|
|
290
268
|
# A VCall may exist as a local in the current_scope. This happens when used named capture groups in a regexp
|
291
269
|
ident = node.value
|
292
270
|
value = ident.value
|
293
|
-
local = current_scope.find_local(value)
|
271
|
+
local = @emitter.current_scope.find_local(value)
|
294
272
|
return if local.nil? && special_method?(value)
|
295
273
|
|
296
274
|
type = if local
|
@@ -304,11 +282,8 @@ module RubyLsp
|
|
304
282
|
add_token(node.value.location, type)
|
305
283
|
end
|
306
284
|
|
307
|
-
sig {
|
308
|
-
def
|
309
|
-
# It's important to visit the regexp first in the WithScope module
|
310
|
-
super
|
311
|
-
|
285
|
+
sig { params(node: SyntaxTree::Binary).void }
|
286
|
+
def after_binary(node)
|
312
287
|
# You can only capture local variables with regexp by using the =~ operator
|
313
288
|
return unless node.operator == :=~
|
314
289
|
|
@@ -324,38 +299,35 @@ module RubyLsp
|
|
324
299
|
|
325
300
|
# For each capture name we find in the regexp, look for a local in the current_scope
|
326
301
|
Regexp.new(content.value, Regexp::FIXEDENCODING).names.each do |name|
|
327
|
-
local = current_scope.find_local(name)
|
302
|
+
local = @emitter.current_scope.find_local(name)
|
328
303
|
next unless local
|
329
304
|
|
330
305
|
local.definitions.each { |definition| add_token(definition, :variable) }
|
331
306
|
end
|
332
307
|
end
|
333
308
|
|
334
|
-
sig {
|
335
|
-
def
|
336
|
-
return
|
309
|
+
sig { params(node: SyntaxTree::ClassDeclaration).void }
|
310
|
+
def on_class(node)
|
311
|
+
return unless visible?(node, @range)
|
337
312
|
|
338
313
|
add_token(node.constant.location, :class, [:declaration])
|
339
314
|
|
340
315
|
superclass = node.superclass
|
341
316
|
add_token(superclass.location, :class) if superclass
|
342
|
-
|
343
|
-
visit(node.bodystmt)
|
344
317
|
end
|
345
318
|
|
346
|
-
sig {
|
347
|
-
def
|
348
|
-
return
|
319
|
+
sig { params(node: SyntaxTree::ModuleDeclaration).void }
|
320
|
+
def on_module(node)
|
321
|
+
return unless visible?(node, @range)
|
349
322
|
|
350
|
-
add_token(node.constant.location, :
|
351
|
-
visit(node.bodystmt)
|
323
|
+
add_token(node.constant.location, :namespace, [:declaration])
|
352
324
|
end
|
353
325
|
|
354
326
|
sig { params(location: SyntaxTree::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
|
355
327
|
def add_token(location, type, modifiers = [])
|
356
328
|
length = location.end_char - location.start_char
|
357
329
|
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
358
|
-
@
|
330
|
+
@response.push(
|
359
331
|
SemanticToken.new(
|
360
332
|
location: location,
|
361
333
|
length: length,
|
@@ -393,7 +365,7 @@ module RubyLsp
|
|
393
365
|
|
394
366
|
sig { params(value: SyntaxTree::Ident).returns(Symbol) }
|
395
367
|
def type_for_local(value)
|
396
|
-
local = current_scope.find_local(value.value)
|
368
|
+
local = @emitter.current_scope.find_local(value.value)
|
397
369
|
|
398
370
|
if local.nil? || local.type == :variable
|
399
371
|
:variable
|
@@ -5,6 +5,8 @@ module RubyLsp
|
|
5
5
|
module Requests
|
6
6
|
module Support
|
7
7
|
module Common
|
8
|
+
# WARNING: Methods in this class may be used by Ruby LSP extensions such as https://github.com/Shopify/ruby-lsp-rails,
|
9
|
+
# or extensions by created by developers outside of Shopify, so be cautious of changing anything.
|
8
10
|
extend T::Sig
|
9
11
|
|
10
12
|
sig { params(node: SyntaxTree::Node).returns(Interface::Range) }
|
@@ -55,25 +57,12 @@ module RubyLsp
|
|
55
57
|
node: SyntaxTree::Node,
|
56
58
|
title: String,
|
57
59
|
command_name: String,
|
58
|
-
|
59
|
-
|
60
|
-
test_command: String,
|
61
|
-
type: String,
|
60
|
+
arguments: T.nilable(T::Array[T.untyped]),
|
61
|
+
data: T.nilable(T::Hash[T.untyped, T.untyped]),
|
62
62
|
).returns(Interface::CodeLens)
|
63
63
|
end
|
64
|
-
def create_code_lens(node, title:, command_name:,
|
64
|
+
def create_code_lens(node, title:, command_name:, arguments:, data:)
|
65
65
|
range = range_from_syntax_tree_node(node)
|
66
|
-
arguments = [
|
67
|
-
path,
|
68
|
-
name,
|
69
|
-
test_command,
|
70
|
-
{
|
71
|
-
start_line: node.location.start_line - 1,
|
72
|
-
start_column: node.location.start_column,
|
73
|
-
end_line: node.location.end_line - 1,
|
74
|
-
end_column: node.location.end_column,
|
75
|
-
},
|
76
|
-
]
|
77
66
|
|
78
67
|
Interface::CodeLens.new(
|
79
68
|
range: range,
|
@@ -82,7 +71,7 @@ module RubyLsp
|
|
82
71
|
command: command_name,
|
83
72
|
arguments: arguments,
|
84
73
|
),
|
85
|
-
data:
|
74
|
+
data: data,
|
86
75
|
)
|
87
76
|
end
|
88
77
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module DependencyDetector
|
6
|
+
class << self
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { returns(String) }
|
10
|
+
def detected_formatter
|
11
|
+
# NOTE: Intentionally no $ at end, since we want to match rubocop-shopify, etc.
|
12
|
+
if direct_dependency?(/^rubocop/)
|
13
|
+
"rubocop"
|
14
|
+
elsif direct_dependency?(/^syntax_tree$/)
|
15
|
+
"syntax_tree"
|
16
|
+
else
|
17
|
+
"none"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
sig { returns(String) }
|
22
|
+
def detected_test_library
|
23
|
+
if direct_dependency?(/^minitest/)
|
24
|
+
"minitest"
|
25
|
+
elsif direct_dependency?(/^test-unit/)
|
26
|
+
"test-unit"
|
27
|
+
elsif direct_dependency?(/^rspec/)
|
28
|
+
"rspec"
|
29
|
+
else
|
30
|
+
warn("WARNING: No test library detected. Assuming minitest.")
|
31
|
+
"minitest"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
sig { params(gem_pattern: Regexp).returns(T::Boolean) }
|
36
|
+
def direct_dependency?(gem_pattern)
|
37
|
+
Bundler.locked_gems.dependencies.keys.grep(gem_pattern).any?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
module Support
|
7
|
+
module FormatterRunner
|
8
|
+
extend T::Sig
|
9
|
+
extend T::Helpers
|
10
|
+
|
11
|
+
interface!
|
12
|
+
|
13
|
+
sig { abstract.params(uri: String, document: Document).returns(T.nilable(String)) }
|
14
|
+
def run(uri, document); end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -13,6 +13,7 @@ module RubyLsp
|
|
13
13
|
class RuboCopFormattingRunner
|
14
14
|
extend T::Sig
|
15
15
|
include Singleton
|
16
|
+
include Support::FormatterRunner
|
16
17
|
|
17
18
|
sig { void }
|
18
19
|
def initialize
|
@@ -20,7 +21,7 @@ module RubyLsp
|
|
20
21
|
@runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
21
22
|
end
|
22
23
|
|
23
|
-
sig { params(uri: String, document: Document).returns(String) }
|
24
|
+
sig { override.params(uri: String, document: Document).returns(String) }
|
24
25
|
def run(uri, document)
|
25
26
|
filename = CGI.unescape(URI.parse(uri).path)
|
26
27
|
|
@@ -78,7 +78,7 @@ module URI
|
|
78
78
|
if URI.respond_to?(:register_scheme)
|
79
79
|
URI.register_scheme("SOURCE", self)
|
80
80
|
else
|
81
|
-
@@schemes = T.let(@@schemes, T::Hash[String, Class]) # rubocop:disable Style/ClassVars
|
81
|
+
@@schemes = T.let(@@schemes, T::Hash[String, T::Class[T.anything]]) # rubocop:disable Style/ClassVars
|
82
82
|
@@schemes["SOURCE"] = self
|
83
83
|
end
|
84
84
|
end
|
@@ -11,6 +11,7 @@ module RubyLsp
|
|
11
11
|
class SyntaxTreeFormattingRunner
|
12
12
|
extend T::Sig
|
13
13
|
include Singleton
|
14
|
+
include Support::FormatterRunner
|
14
15
|
|
15
16
|
sig { void }
|
16
17
|
def initialize
|
@@ -25,7 +26,7 @@ module RubyLsp
|
|
25
26
|
)
|
26
27
|
end
|
27
28
|
|
28
|
-
sig { params(uri: String, document: Document).returns(T.nilable(String)) }
|
29
|
+
sig { override.params(uri: String, document: Document).returns(T.nilable(String)) }
|
29
30
|
def run(uri, document)
|
30
31
|
relative_path = Pathname.new(URI(uri).path).relative_path_from(T.must(WORKSPACE_URI.path))
|
31
32
|
return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -49,6 +49,7 @@ module RubyLsp
|
|
49
49
|
autoload :RailsDocumentClient, "ruby_lsp/requests/support/rails_document_client"
|
50
50
|
autoload :PrefixTree, "ruby_lsp/requests/support/prefix_tree"
|
51
51
|
autoload :Common, "ruby_lsp/requests/support/common"
|
52
|
+
autoload :FormatterRunner, "ruby_lsp/requests/support/formatter_runner"
|
52
53
|
end
|
53
54
|
end
|
54
55
|
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -27,6 +27,9 @@ module RubyLsp
|
|
27
27
|
# The messages queue includes requests and notifications to be sent to the client
|
28
28
|
@message_queue = T.let(Thread::Queue.new, Thread::Queue)
|
29
29
|
|
30
|
+
# The executor is responsible for executing requests
|
31
|
+
@executor = T.let(Executor.new(@store, @message_queue), Executor)
|
32
|
+
|
30
33
|
# Create a thread to watch the messages queue and send them to the client
|
31
34
|
@message_dispatcher = T.let(
|
32
35
|
Thread.new do
|
@@ -62,7 +65,7 @@ module RubyLsp
|
|
62
65
|
@reader.read do |request|
|
63
66
|
case request[:method]
|
64
67
|
when "initialize", "initialized", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
65
|
-
result =
|
68
|
+
result = @executor.execute(request)
|
66
69
|
finalize_request(result, request)
|
67
70
|
when "$/cancelRequest"
|
68
71
|
# Cancel the job if it's still in the queue
|
@@ -126,7 +129,7 @@ module RubyLsp
|
|
126
129
|
# We need to return nil to the client even if the request was cancelled
|
127
130
|
Result.new(response: nil)
|
128
131
|
else
|
129
|
-
|
132
|
+
@executor.execute(request)
|
130
133
|
end
|
131
134
|
|
132
135
|
finalize_request(result, request)
|
data/lib/ruby_lsp/utils.rb
CHANGED
@@ -6,7 +6,7 @@ module RubyLsp
|
|
6
6
|
VOID = T.let(Object.new.freeze, Object)
|
7
7
|
|
8
8
|
# This freeze is not redundant since the interpolated string is mutable
|
9
|
-
WORKSPACE_URI = T.let(URI("file://#{Dir.pwd}".freeze), URI::Generic)
|
9
|
+
WORKSPACE_URI = T.let(URI("file://#{Dir.pwd}".freeze), URI::Generic)
|
10
10
|
|
11
11
|
# A notification to be sent to the client
|
12
12
|
class Message
|