ruby-lsp 0.7.6 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/exe/ruby-lsp-check +2 -2
- data/lib/core_ext/uri.rb +45 -0
- data/lib/ruby_lsp/document.rb +3 -3
- data/lib/ruby_lsp/executor.rb +22 -19
- data/lib/ruby_lsp/extension.rb +24 -0
- data/lib/ruby_lsp/internal.rb +2 -0
- data/lib/ruby_lsp/listener.rb +15 -14
- data/lib/ruby_lsp/requests/code_actions.rb +3 -3
- data/lib/ruby_lsp/requests/code_lens.rb +10 -24
- data/lib/ruby_lsp/requests/definition.rb +5 -5
- data/lib/ruby_lsp/requests/diagnostics.rb +3 -2
- data/lib/ruby_lsp/requests/document_link.rb +4 -3
- data/lib/ruby_lsp/requests/formatting.rb +3 -2
- data/lib/ruby_lsp/requests/hover.rb +4 -18
- data/lib/ruby_lsp/requests/support/formatter_runner.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +2 -2
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +2 -3
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +2 -3
- data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +3 -2
- data/lib/ruby_lsp/server.rb +10 -2
- data/lib/ruby_lsp/setup_bundler.rb +19 -9
- data/lib/ruby_lsp/store.rb +14 -13
- data/lib/ruby_lsp/utils.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed62114ae68bf84cf95f96a2517bc2e729ebaf572500b3871f253bc4b584d7ba
|
4
|
+
data.tar.gz: d34dd2719e3b8088f59f4c38988b3fa7058c866a0d34b8b0b0ea391e18ec64d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9d7bdf1a6ce4d3a7711a0032236d25d3b79682239f801354c15c01661a8e3b1110be90dd503e1d75dcd442520893d6cc852ef5a1eaeeb5a0834305a1c3350c7
|
7
|
+
data.tar.gz: f55f82e138cb65fb7450afe86092d294bca06bcd6043439723567ed6538a1b373eed10ba5f3702e9d17f16fc4faa6b5447c048fb5683388e52bea1588d23dc63
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.8.0
|
data/exe/ruby-lsp-check
CHANGED
@@ -30,13 +30,13 @@ message_queue = Thread::Queue.new
|
|
30
30
|
executor = RubyLsp::Executor.new(store, message_queue)
|
31
31
|
|
32
32
|
files.each_with_index do |file, index|
|
33
|
-
uri = "file://#{file}"
|
33
|
+
uri = URI("file://#{file}")
|
34
34
|
store.set(uri: uri, source: File.read(file), version: 1)
|
35
35
|
|
36
36
|
# Executing any of the automatic requests will execute all of them, so here we just pick one
|
37
37
|
result = executor.execute({
|
38
38
|
method: "textDocument/documentSymbol",
|
39
|
-
params: { textDocument: { uri: uri } },
|
39
|
+
params: { textDocument: { uri: uri.to_s } },
|
40
40
|
})
|
41
41
|
|
42
42
|
error = result.error
|
data/lib/core_ext/uri.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module URI
|
5
|
+
class Generic
|
6
|
+
class << self
|
7
|
+
extend T::Sig
|
8
|
+
|
9
|
+
sig { params(path: String, scheme: String).returns(URI::Generic) }
|
10
|
+
def from_path(path:, scheme: "file")
|
11
|
+
# On Windows, if the path begins with the disk name, we need to add a leading slash to make it a valid URI
|
12
|
+
escaped_path = if /^[A-Z]:/.match?(path)
|
13
|
+
DEFAULT_PARSER.escape("/#{path}")
|
14
|
+
else
|
15
|
+
DEFAULT_PARSER.escape(path)
|
16
|
+
end
|
17
|
+
|
18
|
+
build(scheme: scheme, path: escaped_path)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
extend T::Sig
|
23
|
+
|
24
|
+
sig { returns(T.nilable(String)) }
|
25
|
+
def to_standardized_path
|
26
|
+
parsed_path = path
|
27
|
+
return unless parsed_path
|
28
|
+
|
29
|
+
# On Windows, when we're getting the file system path back from the URI, we need to remove the leading forward
|
30
|
+
# slash
|
31
|
+
actual_path = if %r{^/[A-Z]:}.match?(parsed_path)
|
32
|
+
parsed_path.delete_prefix("/")
|
33
|
+
else
|
34
|
+
parsed_path
|
35
|
+
end
|
36
|
+
|
37
|
+
CGI.unescape(actual_path)
|
38
|
+
end
|
39
|
+
|
40
|
+
sig { returns(String) }
|
41
|
+
def storage_key
|
42
|
+
T.must(to_standardized_path || opaque)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -18,16 +18,16 @@ module RubyLsp
|
|
18
18
|
sig { returns(Integer) }
|
19
19
|
attr_reader :version
|
20
20
|
|
21
|
-
sig { returns(
|
21
|
+
sig { returns(URI::Generic) }
|
22
22
|
attr_reader :uri
|
23
23
|
|
24
|
-
sig { params(source: String, version: Integer, uri:
|
24
|
+
sig { params(source: String, version: Integer, uri: URI::Generic, encoding: String).void }
|
25
25
|
def initialize(source:, version:, uri:, encoding: Constant::PositionEncodingKind::UTF8)
|
26
26
|
@cache = T.let({}, T::Hash[String, T.untyped])
|
27
27
|
@encoding = T.let(encoding, String)
|
28
28
|
@source = T.let(source, String)
|
29
29
|
@version = T.let(version, Integer)
|
30
|
-
@uri = T.let(uri,
|
30
|
+
@uri = T.let(uri, URI::Generic)
|
31
31
|
@unparsed_edits = T.let([], T::Array[EditShape])
|
32
32
|
@syntax_error = T.let(false, T::Boolean)
|
33
33
|
@tree = T.let(SyntaxTree.parse(@source), T.nilable(SyntaxTree::Node))
|
data/lib/ruby_lsp/executor.rb
CHANGED
@@ -35,7 +35,7 @@ module RubyLsp
|
|
35
35
|
|
36
36
|
sig { params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
|
37
37
|
def run(request)
|
38
|
-
uri = request.dig(:params, :textDocument, :uri)
|
38
|
+
uri = URI(request.dig(:params, :textDocument, :uri).to_s)
|
39
39
|
|
40
40
|
case request[:method]
|
41
41
|
when "initialize"
|
@@ -70,7 +70,7 @@ module RubyLsp
|
|
70
70
|
when "textDocument/didClose"
|
71
71
|
@message_queue << Notification.new(
|
72
72
|
message: "textDocument/publishDiagnostics",
|
73
|
-
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: []),
|
73
|
+
params: Interface::PublishDiagnosticsParams.new(uri: uri.to_s, diagnostics: []),
|
74
74
|
)
|
75
75
|
|
76
76
|
text_document_did_close(uri)
|
@@ -174,12 +174,12 @@ module RubyLsp
|
|
174
174
|
end
|
175
175
|
end
|
176
176
|
|
177
|
-
sig { params(uri:
|
177
|
+
sig { params(uri: URI::Generic, range: T.nilable(Document::RangeShape)).returns({ ast: String }) }
|
178
178
|
def show_syntax_tree(uri, range)
|
179
179
|
{ ast: Requests::ShowSyntaxTree.new(@store.get(uri), range).run }
|
180
180
|
end
|
181
181
|
|
182
|
-
sig { params(uri:
|
182
|
+
sig { params(uri: URI::Generic, position: Document::PositionShape).returns(T.nilable(Interface::Location)) }
|
183
183
|
def definition(uri, position)
|
184
184
|
document = @store.get(uri)
|
185
185
|
return if document.syntax_error?
|
@@ -192,7 +192,7 @@ module RubyLsp
|
|
192
192
|
base_listener.response
|
193
193
|
end
|
194
194
|
|
195
|
-
sig { params(uri:
|
195
|
+
sig { params(uri: URI::Generic).returns(T::Array[Interface::FoldingRange]) }
|
196
196
|
def folding_range(uri)
|
197
197
|
@store.cache_fetch(uri, "textDocument/foldingRange") do |document|
|
198
198
|
Requests::FoldingRanges.new(document).run
|
@@ -201,7 +201,7 @@ module RubyLsp
|
|
201
201
|
|
202
202
|
sig do
|
203
203
|
params(
|
204
|
-
uri:
|
204
|
+
uri: URI::Generic,
|
205
205
|
position: Document::PositionShape,
|
206
206
|
).returns(T.nilable(Interface::Hover))
|
207
207
|
end
|
@@ -227,19 +227,19 @@ module RubyLsp
|
|
227
227
|
hover.response
|
228
228
|
end
|
229
229
|
|
230
|
-
sig { params(uri:
|
230
|
+
sig { params(uri: URI::Generic, content_changes: T::Array[Document::EditShape], version: Integer).returns(Object) }
|
231
231
|
def text_document_did_change(uri, content_changes, version)
|
232
232
|
@store.push_edits(uri: uri, edits: content_changes, version: version)
|
233
233
|
VOID
|
234
234
|
end
|
235
235
|
|
236
|
-
sig { params(uri:
|
236
|
+
sig { params(uri: URI::Generic, text: String, version: Integer).returns(Object) }
|
237
237
|
def text_document_did_open(uri, text, version)
|
238
238
|
@store.set(uri: uri, source: text, version: version)
|
239
239
|
VOID
|
240
240
|
end
|
241
241
|
|
242
|
-
sig { params(uri:
|
242
|
+
sig { params(uri: URI::Generic).returns(Object) }
|
243
243
|
def text_document_did_close(uri)
|
244
244
|
@store.delete(uri)
|
245
245
|
VOID
|
@@ -247,7 +247,7 @@ module RubyLsp
|
|
247
247
|
|
248
248
|
sig do
|
249
249
|
params(
|
250
|
-
uri:
|
250
|
+
uri: URI::Generic,
|
251
251
|
positions: T::Array[Document::PositionShape],
|
252
252
|
).returns(T.nilable(T::Array[T.nilable(Requests::Support::SelectionRange)]))
|
253
253
|
end
|
@@ -270,7 +270,7 @@ module RubyLsp
|
|
270
270
|
end
|
271
271
|
end
|
272
272
|
|
273
|
-
sig { params(uri:
|
273
|
+
sig { params(uri: URI::Generic).returns(T.nilable(T::Array[Interface::TextEdit])) }
|
274
274
|
def formatting(uri)
|
275
275
|
# If formatter is set to `auto` but no supported formatting gem is found, don't attempt to format
|
276
276
|
return if @store.formatter == "none"
|
@@ -280,7 +280,7 @@ module RubyLsp
|
|
280
280
|
|
281
281
|
sig do
|
282
282
|
params(
|
283
|
-
uri:
|
283
|
+
uri: URI::Generic,
|
284
284
|
position: Document::PositionShape,
|
285
285
|
character: String,
|
286
286
|
).returns(T::Array[Interface::TextEdit])
|
@@ -291,7 +291,7 @@ module RubyLsp
|
|
291
291
|
|
292
292
|
sig do
|
293
293
|
params(
|
294
|
-
uri:
|
294
|
+
uri: URI::Generic,
|
295
295
|
position: Document::PositionShape,
|
296
296
|
).returns(T.nilable(T::Array[Interface::DocumentHighlight]))
|
297
297
|
end
|
@@ -306,7 +306,7 @@ module RubyLsp
|
|
306
306
|
listener.response
|
307
307
|
end
|
308
308
|
|
309
|
-
sig { params(uri:
|
309
|
+
sig { params(uri: URI::Generic, range: Document::RangeShape).returns(T.nilable(T::Array[Interface::InlayHint])) }
|
310
310
|
def inlay_hint(uri, range)
|
311
311
|
document = @store.get(uri)
|
312
312
|
return if document.syntax_error?
|
@@ -322,7 +322,7 @@ module RubyLsp
|
|
322
322
|
|
323
323
|
sig do
|
324
324
|
params(
|
325
|
-
uri:
|
325
|
+
uri: URI::Generic,
|
326
326
|
range: Document::RangeShape,
|
327
327
|
context: T::Hash[Symbol, T.untyped],
|
328
328
|
).returns(T.nilable(T::Array[Interface::CodeAction]))
|
@@ -335,7 +335,7 @@ module RubyLsp
|
|
335
335
|
|
336
336
|
sig { params(params: T::Hash[Symbol, T.untyped]).returns(Interface::CodeAction) }
|
337
337
|
def code_action_resolve(params)
|
338
|
-
uri = params.dig(:data, :uri)
|
338
|
+
uri = URI(params.dig(:data, :uri))
|
339
339
|
document = @store.get(uri)
|
340
340
|
result = Requests::CodeActionResolve.new(document, params).run
|
341
341
|
|
@@ -363,7 +363,7 @@ module RubyLsp
|
|
363
363
|
end
|
364
364
|
end
|
365
365
|
|
366
|
-
sig { params(uri:
|
366
|
+
sig { params(uri: URI::Generic).returns(T.nilable(Interface::FullDocumentDiagnosticReport)) }
|
367
367
|
def diagnostic(uri)
|
368
368
|
response = @store.cache_fetch(uri, "textDocument/diagnostic") do |document|
|
369
369
|
Requests::Diagnostics.new(document).run
|
@@ -372,7 +372,7 @@ module RubyLsp
|
|
372
372
|
Interface::FullDocumentDiagnosticReport.new(kind: "full", items: response.map(&:to_lsp_diagnostic)) if response
|
373
373
|
end
|
374
374
|
|
375
|
-
sig { params(uri:
|
375
|
+
sig { params(uri: URI::Generic, range: Document::RangeShape).returns(Interface::SemanticTokens) }
|
376
376
|
def semantic_tokens_range(uri, range)
|
377
377
|
document = @store.get(uri)
|
378
378
|
start_line = range.dig(:start, :line)
|
@@ -390,7 +390,10 @@ module RubyLsp
|
|
390
390
|
end
|
391
391
|
|
392
392
|
sig do
|
393
|
-
params(
|
393
|
+
params(
|
394
|
+
uri: URI::Generic,
|
395
|
+
position: Document::PositionShape,
|
396
|
+
).returns(T.nilable(T::Array[Interface::CompletionItem]))
|
394
397
|
end
|
395
398
|
def completion(uri, position)
|
396
399
|
document = @store.get(uri)
|
data/lib/ruby_lsp/extension.rb
CHANGED
@@ -97,8 +97,32 @@ module RubyLsp
|
|
97
97
|
sig { abstract.void }
|
98
98
|
def activate; end
|
99
99
|
|
100
|
+
# Each extension should implement `MyExtension#deactivate` and use to perform any clean up, like shutting down a
|
101
|
+
# child process
|
102
|
+
sig { abstract.void }
|
103
|
+
def deactivate; end
|
104
|
+
|
100
105
|
# Extensions should override the `name` method to return the extension name
|
101
106
|
sig { abstract.returns(String) }
|
102
107
|
def name; end
|
108
|
+
|
109
|
+
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
110
|
+
sig do
|
111
|
+
overridable.params(
|
112
|
+
uri: URI::Generic,
|
113
|
+
emitter: EventEmitter,
|
114
|
+
message_queue: Thread::Queue,
|
115
|
+
).returns(T.nilable(Listener[T::Array[Interface::CodeLens]]))
|
116
|
+
end
|
117
|
+
def create_code_lens_listener(uri, emitter, message_queue); end
|
118
|
+
|
119
|
+
# Creates a new Hover listener. This method is invoked on every Hover request
|
120
|
+
sig do
|
121
|
+
overridable.params(
|
122
|
+
emitter: EventEmitter,
|
123
|
+
message_queue: Thread::Queue,
|
124
|
+
).returns(T.nilable(Listener[T.nilable(Interface::Hover)]))
|
125
|
+
end
|
126
|
+
def create_hover_listener(emitter, message_queue); end
|
103
127
|
end
|
104
128
|
end
|
data/lib/ruby_lsp/internal.rb
CHANGED
data/lib/ruby_lsp/listener.rb
CHANGED
@@ -18,25 +18,26 @@ module RubyLsp
|
|
18
18
|
def initialize(emitter, message_queue)
|
19
19
|
@emitter = emitter
|
20
20
|
@message_queue = message_queue
|
21
|
-
|
22
|
-
|
23
|
-
class << self
|
24
|
-
extend T::Sig
|
25
|
-
|
26
|
-
sig { returns(T::Array[T.class_of(Listener)]) }
|
27
|
-
def listeners
|
28
|
-
@listeners ||= T.let([], T.nilable(T::Array[T.class_of(Listener)]))
|
29
|
-
end
|
30
|
-
|
31
|
-
sig { params(listener: T.class_of(Listener)).void }
|
32
|
-
def add_listener(listener)
|
33
|
-
listeners << listener
|
34
|
-
end
|
21
|
+
@external_listeners = T.let([], T::Array[RubyLsp::Listener[ResponseType]])
|
35
22
|
end
|
36
23
|
|
37
24
|
# Override this method with an attr_reader that returns the response of your listener. The listener should
|
38
25
|
# accumulate results in a @response variable and then provide the reader so that it is accessible
|
39
26
|
sig { abstract.returns(ResponseType) }
|
40
27
|
def response; end
|
28
|
+
|
29
|
+
# Merge responses from all external listeners into the base listener's response. We do this to return a single
|
30
|
+
# response to the editor including the results of all extensions
|
31
|
+
sig { void }
|
32
|
+
def merge_external_listeners_responses!
|
33
|
+
@external_listeners.each { |l| merge_response!(l) }
|
34
|
+
end
|
35
|
+
|
36
|
+
# Does nothing by default. Requests that accept extensions should override this method to define how to merge
|
37
|
+
# responses coming from external listeners
|
38
|
+
sig { overridable.params(other: Listener[T.untyped]).returns(T.self_type) }
|
39
|
+
def merge_response!(other)
|
40
|
+
self
|
41
|
+
end
|
41
42
|
end
|
42
43
|
end
|
@@ -29,7 +29,7 @@ module RubyLsp
|
|
29
29
|
def initialize(document, range, context)
|
30
30
|
super(document)
|
31
31
|
|
32
|
-
@uri = T.let(document.uri,
|
32
|
+
@uri = T.let(document.uri, URI::Generic)
|
33
33
|
@range = range
|
34
34
|
@context = context
|
35
35
|
end
|
@@ -63,14 +63,14 @@ module RubyLsp
|
|
63
63
|
)
|
64
64
|
end
|
65
65
|
|
66
|
-
sig { params(range: Document::RangeShape, uri:
|
66
|
+
sig { params(range: Document::RangeShape, uri: URI::Generic).returns(Interface::CodeAction) }
|
67
67
|
def refactor_code_action(range, uri)
|
68
68
|
Interface::CodeAction.new(
|
69
69
|
title: "Refactor: Extract Variable",
|
70
70
|
kind: Constant::CodeActionKind::REFACTOR_EXTRACT,
|
71
71
|
data: {
|
72
72
|
range: range,
|
73
|
-
uri: uri,
|
73
|
+
uri: uri.to_s,
|
74
74
|
},
|
75
75
|
)
|
76
76
|
end
|
@@ -31,15 +31,17 @@ module RubyLsp
|
|
31
31
|
sig { override.returns(ResponseType) }
|
32
32
|
attr_reader :response
|
33
33
|
|
34
|
-
sig { params(uri:
|
34
|
+
sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue, test_library: String).void }
|
35
35
|
def initialize(uri, emitter, message_queue, test_library)
|
36
36
|
super(emitter, message_queue)
|
37
37
|
|
38
|
-
@uri = T.let(uri,
|
39
|
-
@external_listeners
|
38
|
+
@uri = T.let(uri, URI::Generic)
|
39
|
+
@external_listeners.concat(
|
40
|
+
Extension.extensions.filter_map { |ext| ext.create_code_lens_listener(uri, emitter, message_queue) },
|
41
|
+
)
|
40
42
|
@test_library = T.let(test_library, String)
|
41
43
|
@response = T.let([], ResponseType)
|
42
|
-
@path = T.let(
|
44
|
+
@path = T.let(uri.to_standardized_path, T.nilable(String))
|
43
45
|
# visibility_stack is a stack of [current_visibility, previous_visibility]
|
44
46
|
@visibility_stack = T.let([["public", "public"]], T::Array[T::Array[T.nilable(String)]])
|
45
47
|
@class_stack = T.let([], T::Array[String])
|
@@ -55,22 +57,6 @@ module RubyLsp
|
|
55
57
|
:after_call,
|
56
58
|
:on_vcall,
|
57
59
|
)
|
58
|
-
|
59
|
-
register_external_listeners!
|
60
|
-
end
|
61
|
-
|
62
|
-
sig { void }
|
63
|
-
def register_external_listeners!
|
64
|
-
self.class.listeners.each do |l|
|
65
|
-
@external_listeners << T.unsafe(l).new(@uri, @emitter, @message_queue)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
sig { void }
|
70
|
-
def merge_external_listeners_responses!
|
71
|
-
@external_listeners.each do |l|
|
72
|
-
merge_response!(l)
|
73
|
-
end
|
74
60
|
end
|
75
61
|
|
76
62
|
sig { params(node: SyntaxTree::ClassDeclaration).void }
|
@@ -120,7 +106,7 @@ module RubyLsp
|
|
120
106
|
if ACCESS_MODIFIERS.include?(node_message) && node.arguments.parts.any?
|
121
107
|
visibility, _ = @visibility_stack.pop
|
122
108
|
@visibility_stack.push([node_message, visibility])
|
123
|
-
elsif @path
|
109
|
+
elsif @path&.include?("Gemfile") && node_message.include?("gem") && node.arguments.parts.any?
|
124
110
|
remote = resolve_gem_remote(node)
|
125
111
|
return unless remote
|
126
112
|
|
@@ -163,7 +149,7 @@ module RubyLsp
|
|
163
149
|
end
|
164
150
|
end
|
165
151
|
|
166
|
-
sig { params(other: Listener[ResponseType]).returns(T.self_type) }
|
152
|
+
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
167
153
|
def merge_response!(other)
|
168
154
|
@response.concat(other.response)
|
169
155
|
self
|
@@ -174,7 +160,7 @@ module RubyLsp
|
|
174
160
|
sig { params(node: SyntaxTree::Node, name: String, command: String, kind: Symbol).void }
|
175
161
|
def add_test_code_lens(node, name:, command:, kind:)
|
176
162
|
# don't add code lenses if the test library is not supported or unknown
|
177
|
-
return unless SUPPORTED_TEST_LIBRARIES.include?(@test_library)
|
163
|
+
return unless SUPPORTED_TEST_LIBRARIES.include?(@test_library) && @path
|
178
164
|
|
179
165
|
arguments = [
|
180
166
|
@path,
|
@@ -231,7 +217,7 @@ module RubyLsp
|
|
231
217
|
|
232
218
|
sig { params(class_name: String, method_name: T.nilable(String)).returns(String) }
|
233
219
|
def generate_test_command(class_name:, method_name: nil)
|
234
|
-
command = BASE_COMMAND + @path
|
220
|
+
command = BASE_COMMAND + T.must(@path)
|
235
221
|
|
236
222
|
case @test_library
|
237
223
|
when "minitest"
|
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
sig { override.returns(ResponseType) }
|
26
26
|
attr_reader :response
|
27
27
|
|
28
|
-
sig { params(uri:
|
28
|
+
sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
|
29
29
|
def initialize(uri, emitter, message_queue)
|
30
30
|
super(emitter, message_queue)
|
31
31
|
|
@@ -53,7 +53,7 @@ module RubyLsp
|
|
53
53
|
|
54
54
|
if candidate
|
55
55
|
@response = Interface::Location.new(
|
56
|
-
uri:
|
56
|
+
uri: URI::Generic.from_path(path: candidate).to_s,
|
57
57
|
range: Interface::Range.new(
|
58
58
|
start: Interface::Position.new(line: 0, character: 0),
|
59
59
|
end: Interface::Position.new(line: 0, character: 0),
|
@@ -61,13 +61,13 @@ module RubyLsp
|
|
61
61
|
)
|
62
62
|
end
|
63
63
|
when "require_relative"
|
64
|
-
|
65
|
-
current_folder = Pathname.new(
|
64
|
+
path = @uri.to_standardized_path
|
65
|
+
current_folder = path ? Pathname.new(CGI.unescape(path)).dirname : Dir.pwd
|
66
66
|
candidate = File.expand_path(File.join(current_folder, required_file))
|
67
67
|
|
68
68
|
if candidate
|
69
69
|
@response = Interface::Location.new(
|
70
|
-
uri:
|
70
|
+
uri: URI::Generic.from_path(path: candidate).to_s,
|
71
71
|
range: Interface::Range.new(
|
72
72
|
start: Interface::Position.new(line: 0, character: 0),
|
73
73
|
end: Interface::Position.new(line: 0, character: 0),
|
@@ -25,7 +25,7 @@ module RubyLsp
|
|
25
25
|
def initialize(document)
|
26
26
|
super(document)
|
27
27
|
|
28
|
-
@uri = T.let(document.uri,
|
28
|
+
@uri = T.let(document.uri, URI::Generic)
|
29
29
|
end
|
30
30
|
|
31
31
|
sig { override.returns(T.nilable(T.all(T::Array[Support::RuboCopDiagnostic], Object))) }
|
@@ -36,7 +36,8 @@ module RubyLsp
|
|
36
36
|
return unless defined?(Support::RuboCopDiagnosticsRunner)
|
37
37
|
|
38
38
|
# Don't try to run RuboCop diagnostics for files outside the current working directory
|
39
|
-
|
39
|
+
path = @uri.to_standardized_path
|
40
|
+
return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
|
40
41
|
|
41
42
|
Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
|
42
43
|
end
|
@@ -75,13 +75,14 @@ module RubyLsp
|
|
75
75
|
sig { override.returns(ResponseType) }
|
76
76
|
attr_reader :response
|
77
77
|
|
78
|
-
sig { params(uri:
|
78
|
+
sig { params(uri: URI::Generic, emitter: EventEmitter, message_queue: Thread::Queue).void }
|
79
79
|
def initialize(uri, emitter, message_queue)
|
80
80
|
super(emitter, message_queue)
|
81
81
|
|
82
82
|
# Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
|
83
83
|
# in the URI
|
84
|
-
|
84
|
+
path = uri.to_standardized_path
|
85
|
+
version_match = path ? /(?<=%40)[\d.]+(?=\.rbi$)/.match(path) : nil
|
85
86
|
@gem_version = T.let(version_match && version_match[0], T.nilable(String))
|
86
87
|
@response = T.let([], T::Array[Interface::DocumentLink])
|
87
88
|
|
@@ -95,7 +96,7 @@ module RubyLsp
|
|
95
96
|
|
96
97
|
uri = T.cast(URI(T.must(match[0])), URI::Source)
|
97
98
|
gem_version = T.must(resolve_version(uri))
|
98
|
-
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, uri.path)
|
99
|
+
file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, CGI.unescape(uri.path))
|
99
100
|
return if file_path.nil?
|
100
101
|
|
101
102
|
@response << Interface::DocumentLink.new(
|
@@ -58,7 +58,7 @@ module RubyLsp
|
|
58
58
|
def initialize(document, formatter: "auto")
|
59
59
|
super(document)
|
60
60
|
|
61
|
-
@uri = T.let(document.uri,
|
61
|
+
@uri = T.let(document.uri, URI::Generic)
|
62
62
|
@formatter = formatter
|
63
63
|
end
|
64
64
|
|
@@ -67,7 +67,8 @@ module RubyLsp
|
|
67
67
|
return if @formatter == "none"
|
68
68
|
|
69
69
|
# Don't try to format files outside the current working directory
|
70
|
-
|
70
|
+
path = @uri.to_standardized_path
|
71
|
+
return unless path.nil? || path.start_with?(T.must(WORKSPACE_URI.to_standardized_path))
|
71
72
|
|
72
73
|
return if @document.syntax_error?
|
73
74
|
|
@@ -39,29 +39,15 @@ module RubyLsp
|
|
39
39
|
def initialize(emitter, message_queue)
|
40
40
|
super
|
41
41
|
|
42
|
-
@external_listeners
|
42
|
+
@external_listeners.concat(
|
43
|
+
Extension.extensions.filter_map { |ext| ext.create_hover_listener(emitter, message_queue) },
|
44
|
+
)
|
43
45
|
@response = T.let(nil, ResponseType)
|
44
46
|
emitter.register(self, :on_command, :on_const_path_ref, :on_call)
|
45
|
-
|
46
|
-
register_external_listeners!
|
47
|
-
end
|
48
|
-
|
49
|
-
sig { void }
|
50
|
-
def register_external_listeners!
|
51
|
-
self.class.listeners.each do |l|
|
52
|
-
@external_listeners << T.unsafe(l).new(@emitter, @message_queue)
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
sig { void }
|
57
|
-
def merge_external_listeners_responses!
|
58
|
-
@external_listeners.each do |l|
|
59
|
-
merge_response!(l)
|
60
|
-
end
|
61
47
|
end
|
62
48
|
|
63
49
|
# Merges responses from other hover listeners
|
64
|
-
sig { params(other: Listener[ResponseType]).returns(T.self_type) }
|
50
|
+
sig { override.params(other: Listener[ResponseType]).returns(T.self_type) }
|
65
51
|
def merge_response!(other)
|
66
52
|
other_response = other.response
|
67
53
|
return self unless other_response
|
@@ -19,7 +19,7 @@ module RubyLsp
|
|
19
19
|
T::Hash[Symbol, Integer],
|
20
20
|
)
|
21
21
|
|
22
|
-
sig { params(offense: RuboCop::Cop::Offense, uri:
|
22
|
+
sig { params(offense: RuboCop::Cop::Offense, uri: URI::Generic).void }
|
23
23
|
def initialize(offense, uri)
|
24
24
|
@offense = offense
|
25
25
|
@uri = uri
|
@@ -34,7 +34,7 @@ module RubyLsp
|
|
34
34
|
document_changes: [
|
35
35
|
Interface::TextDocumentEdit.new(
|
36
36
|
text_document: Interface::OptionalVersionedTextDocumentIdentifier.new(
|
37
|
-
uri: @uri,
|
37
|
+
uri: @uri.to_s,
|
38
38
|
version: nil,
|
39
39
|
),
|
40
40
|
edits: @offense.correctable? ? offense_replacements : [],
|
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
5
5
|
|
6
|
-
require "cgi"
|
7
6
|
require "singleton"
|
8
7
|
|
9
8
|
module RubyLsp
|
@@ -19,9 +18,9 @@ module RubyLsp
|
|
19
18
|
@runner = T.let(RuboCopRunner.new, RuboCopRunner)
|
20
19
|
end
|
21
20
|
|
22
|
-
sig { params(uri:
|
21
|
+
sig { params(uri: URI::Generic, document: Document).returns(T::Array[Support::RuboCopDiagnostic]) }
|
23
22
|
def run(uri, document)
|
24
|
-
filename =
|
23
|
+
filename = T.must(uri.to_standardized_path || uri.opaque)
|
25
24
|
# Invoke RuboCop with just this file in `paths`
|
26
25
|
@runner.run(filename, document.source)
|
27
26
|
|
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
return unless defined?(RubyLsp::Requests::Support::RuboCopRunner)
|
5
5
|
|
6
|
-
require "cgi"
|
7
6
|
require "singleton"
|
8
7
|
|
9
8
|
module RubyLsp
|
@@ -21,9 +20,9 @@ module RubyLsp
|
|
21
20
|
@runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
22
21
|
end
|
23
22
|
|
24
|
-
sig { override.params(uri:
|
23
|
+
sig { override.params(uri: URI::Generic, document: Document).returns(String) }
|
25
24
|
def run(uri, document)
|
26
|
-
filename =
|
25
|
+
filename = T.must(uri.to_standardized_path || uri.opaque)
|
27
26
|
|
28
27
|
# Invoke RuboCop with just this file in `paths`
|
29
28
|
@runner.run(filename, document.source)
|
@@ -26,9 +26,10 @@ module RubyLsp
|
|
26
26
|
)
|
27
27
|
end
|
28
28
|
|
29
|
-
sig { override.params(uri:
|
29
|
+
sig { override.params(uri: URI::Generic, document: Document).returns(T.nilable(String)) }
|
30
30
|
def run(uri, document)
|
31
|
-
relative_path = Pathname.new(
|
31
|
+
relative_path = Pathname.new(T.must(uri.to_standardized_path || uri.opaque))
|
32
|
+
.relative_path_from(T.must(WORKSPACE_URI.to_standardized_path))
|
32
33
|
return if @options.ignore_files.any? { |pattern| File.fnmatch(pattern, relative_path) }
|
33
34
|
|
34
35
|
SyntaxTree.format(
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -86,6 +86,7 @@ module RubyLsp
|
|
86
86
|
@message_dispatcher.join
|
87
87
|
@store.clear
|
88
88
|
|
89
|
+
Extension.extensions.each(&:deactivate)
|
89
90
|
finalize_request(Result.new(response: nil), request)
|
90
91
|
when "exit"
|
91
92
|
# We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
|
@@ -105,7 +106,7 @@ module RubyLsp
|
|
105
106
|
# source. Altering the source reference during parsing will put the parser in an invalid internal state,
|
106
107
|
# since it started parsing with one source but then it changed in the middle
|
107
108
|
uri = request.dig(:params, :textDocument, :uri)
|
108
|
-
@store.get(uri).parse if uri
|
109
|
+
@store.get(URI(uri)).parse if uri
|
109
110
|
end
|
110
111
|
|
111
112
|
@job_queue << job
|
@@ -192,7 +193,14 @@ module RubyLsp
|
|
192
193
|
params[:backtrace] = backtrace.map { |bt| bt.sub(/^#{Dir.home}/, "~") }.join("\n") if backtrace
|
193
194
|
end
|
194
195
|
|
195
|
-
|
196
|
+
if uri
|
197
|
+
home = URI::Generic.from_path(path: Dir.home)
|
198
|
+
|
199
|
+
parsed_uri = URI(uri)
|
200
|
+
path = parsed_uri.path
|
201
|
+
params[:uri] = path ? path.sub(T.must(home.path), "~") : parsed_uri.opaque
|
202
|
+
end
|
203
|
+
|
196
204
|
params
|
197
205
|
end
|
198
206
|
end
|
@@ -5,6 +5,7 @@ require "sorbet-runtime"
|
|
5
5
|
require "bundler"
|
6
6
|
require "fileutils"
|
7
7
|
require "pathname"
|
8
|
+
require "digest"
|
8
9
|
|
9
10
|
# This file is a script that will configure a custom bundle for the Ruby LSP. The custom bundle allows developers to use
|
10
11
|
# the Ruby LSP without including the gem in their application's Gemfile while at the same time giving us access to the
|
@@ -24,6 +25,7 @@ module RubyLsp
|
|
24
25
|
@custom_dir = T.let(Pathname.new(".ruby-lsp").expand_path(Dir.pwd), Pathname)
|
25
26
|
@custom_gemfile = T.let(@custom_dir + "Gemfile", Pathname)
|
26
27
|
@custom_lockfile = T.let(@custom_dir + "Gemfile.lock", Pathname)
|
28
|
+
@lockfile_hash_path = T.let(@custom_dir + "main_lockfile_hash", Pathname)
|
27
29
|
|
28
30
|
# Regular bundle paths
|
29
31
|
@gemfile = T.let(
|
@@ -37,7 +39,6 @@ module RubyLsp
|
|
37
39
|
@lockfile = T.let(@gemfile ? Bundler.default_lockfile : nil, T.nilable(Pathname))
|
38
40
|
|
39
41
|
@dependencies = T.let(load_dependencies, T::Hash[String, T.untyped])
|
40
|
-
@custom_bundle_dependencies = T.let(custom_bundle_dependencies, T::Hash[String, T.untyped])
|
41
42
|
end
|
42
43
|
|
43
44
|
# Setups up the custom bundle and returns the `BUNDLE_GEMFILE` and `BUNDLE_PATH` that should be used for running the
|
@@ -69,14 +70,16 @@ module RubyLsp
|
|
69
70
|
return run_bundle_install(@custom_gemfile)
|
70
71
|
end
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
73
|
+
lockfile_contents = @lockfile.read
|
74
|
+
current_lockfile_hash = Digest::SHA256.hexdigest(lockfile_contents)
|
75
|
+
|
76
|
+
if @custom_lockfile.exist? && @lockfile_hash_path.exist? && @lockfile_hash_path.read == current_lockfile_hash
|
75
77
|
warn("Ruby LSP> Skipping custom bundle setup since #{@custom_lockfile} already exists and is up to date")
|
76
78
|
return run_bundle_install(@custom_gemfile)
|
77
79
|
end
|
78
80
|
|
79
81
|
FileUtils.cp(@lockfile.to_s, @custom_lockfile.to_s)
|
82
|
+
@lockfile_hash_path.write(current_lockfile_hash)
|
80
83
|
run_bundle_install(@custom_gemfile)
|
81
84
|
end
|
82
85
|
|
@@ -84,10 +87,17 @@ module RubyLsp
|
|
84
87
|
|
85
88
|
sig { returns(T::Hash[String, T.untyped]) }
|
86
89
|
def custom_bundle_dependencies
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
90
|
+
@custom_bundle_dependencies ||= T.let(
|
91
|
+
begin
|
92
|
+
if @custom_lockfile.exist?
|
93
|
+
ENV["BUNDLE_GEMFILE"] = @custom_gemfile.to_s
|
94
|
+
Bundler::LockfileParser.new(@custom_lockfile.read).dependencies
|
95
|
+
else
|
96
|
+
{}
|
97
|
+
end
|
98
|
+
end,
|
99
|
+
T.nilable(T::Hash[String, T.untyped]),
|
100
|
+
)
|
91
101
|
ensure
|
92
102
|
ENV.delete("BUNDLE_GEMFILE")
|
93
103
|
end
|
@@ -160,7 +170,7 @@ module RubyLsp
|
|
160
170
|
command = +""
|
161
171
|
|
162
172
|
if (@dependencies["ruby-lsp"] && @dependencies["debug"]) ||
|
163
|
-
|
173
|
+
custom_bundle_dependencies["ruby-lsp"].nil? || custom_bundle_dependencies["debug"].nil?
|
164
174
|
# Install gems using the custom bundle
|
165
175
|
command << "bundle install "
|
166
176
|
else
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "cgi"
|
5
|
-
require "uri"
|
6
4
|
require "ruby_lsp/document"
|
7
5
|
|
8
6
|
module RubyLsp
|
@@ -22,24 +20,27 @@ module RubyLsp
|
|
22
20
|
@formatter = T.let("auto", String)
|
23
21
|
end
|
24
22
|
|
25
|
-
sig { params(uri:
|
23
|
+
sig { params(uri: URI::Generic).returns(Document) }
|
26
24
|
def get(uri)
|
27
|
-
|
25
|
+
path = uri.to_standardized_path
|
26
|
+
return T.must(@state[T.must(uri.opaque)]) unless path
|
27
|
+
|
28
|
+
document = @state[path]
|
28
29
|
return document unless document.nil?
|
29
30
|
|
30
|
-
set(uri: uri, source: File.binread(CGI.unescape(
|
31
|
-
T.must(@state[
|
31
|
+
set(uri: uri, source: File.binread(CGI.unescape(path)), version: 0)
|
32
|
+
T.must(@state[path])
|
32
33
|
end
|
33
34
|
|
34
|
-
sig { params(uri:
|
35
|
+
sig { params(uri: URI::Generic, source: String, version: Integer).void }
|
35
36
|
def set(uri:, source:, version:)
|
36
37
|
document = Document.new(source: source, version: version, uri: uri, encoding: @encoding)
|
37
|
-
@state[uri] = document
|
38
|
+
@state[uri.storage_key] = document
|
38
39
|
end
|
39
40
|
|
40
|
-
sig { params(uri:
|
41
|
+
sig { params(uri: URI::Generic, edits: T::Array[Document::EditShape], version: Integer).void }
|
41
42
|
def push_edits(uri:, edits:, version:)
|
42
|
-
T.must(@state[uri]).push_edits(edits, version: version)
|
43
|
+
T.must(@state[uri.storage_key]).push_edits(edits, version: version)
|
43
44
|
end
|
44
45
|
|
45
46
|
sig { void }
|
@@ -52,15 +53,15 @@ module RubyLsp
|
|
52
53
|
@state.empty?
|
53
54
|
end
|
54
55
|
|
55
|
-
sig { params(uri:
|
56
|
+
sig { params(uri: URI::Generic).void }
|
56
57
|
def delete(uri)
|
57
|
-
@state.delete(uri)
|
58
|
+
@state.delete(uri.storage_key)
|
58
59
|
end
|
59
60
|
|
60
61
|
sig do
|
61
62
|
type_parameters(:T)
|
62
63
|
.params(
|
63
|
-
uri:
|
64
|
+
uri: URI::Generic,
|
64
65
|
request_name: String,
|
65
66
|
block: T.proc.params(document: Document).returns(T.type_parameter(:T)),
|
66
67
|
).returns(T.type_parameter(:T))
|
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(
|
9
|
+
WORKSPACE_URI = T.let(URI::Generic.from_path(path: Dir.pwd), URI::Generic)
|
10
10
|
|
11
11
|
# A notification to be sent to the client
|
12
12
|
class Message
|
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.8.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-08-
|
11
|
+
date: 2023-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -72,6 +72,7 @@ files:
|
|
72
72
|
- VERSION
|
73
73
|
- exe/ruby-lsp
|
74
74
|
- exe/ruby-lsp-check
|
75
|
+
- lib/core_ext/uri.rb
|
75
76
|
- lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb
|
76
77
|
- lib/ruby-lsp.rb
|
77
78
|
- lib/ruby_lsp/check_docs.rb
|