ruby-lsp 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/VERSION +1 -1
- data/lib/ruby_lsp/handler.rb +2 -2
- data/lib/ruby_lsp/queue.rb +22 -16
- data/lib/ruby_lsp/requests/formatting.rb +2 -0
- data/lib/ruby_lsp/requests/on_type_formatting.rb +16 -2
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +17 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +9 -34
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +9 -23
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +69 -0
- data/lib/ruby_lsp/server.rb +15 -17
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9762389a7b7979afb57d6e6d2cf0d65b0b0a0b31f5a1fdd7045311c33a0c21d6
|
4
|
+
data.tar.gz: 35cc2318946e650ee311129955d3674c7e693a87d25c5cc2f29c5a55e479d880
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4735e18c297c992727d0a151ed7948cf6d4ea32b01fe411ed0774efdda7cdc0cf6533f5d71ad288aad9e6e717149932744376fdceda9fa4cd039b560934a9b47
|
7
|
+
data.tar.gz: bd6e0c9a81a373c509f2f96b480543657a8d241a6e58ea25ec21c62ac60094f299af1c5f85d1555ad6ca1908c325e46569119271d4c6b7117f33f9919cf40bca
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,19 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
+
## [0.3.1]
|
10
|
+
|
11
|
+
- Resolve TODO for LSP v3.17 (https://github.com/Shopify/ruby-lsp/pull/268)
|
12
|
+
- Add dependency constraint for LSP v3.17 (https://github.com/Shopify/ruby-lsp/pull/269)
|
13
|
+
- Handle class/module declarations as a class token with declaration modifier (https://github.com/Shopify/ruby-lsp/pull/260)
|
14
|
+
- Handle required parameters in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/271)
|
15
|
+
- Add comment continuation via on type on_type_formatting (https://github.com/Shopify/ruby-lsp/pull/274)
|
16
|
+
- Make RuboCop runner use composition instead of inheritance (https://github.com/Shopify/ruby-lsp/pull/278)
|
17
|
+
- Protect worker against cancellation during popping (https://github.com/Shopify/ruby-lsp/pull/280)
|
18
|
+
- Handle formatting errors in on_error block (https://github.com/Shopify/ruby-lsp/pull/279)
|
19
|
+
- Fix on type formatting pipe completion for regular or expressions (https://github.com/Shopify/ruby-lsp/pull/282)
|
20
|
+
- Do not fail on LoadError (https://github.com/Shopify/ruby-lsp/pull/292)
|
21
|
+
|
9
22
|
## [0.3.0]
|
10
23
|
- Add on type formatting completions (https://github.com/Shopify/ruby-lsp/pull/253)
|
11
24
|
- Upgrade syntax_tree requirement to >= 3.4 (https://github.com/Shopify/ruby-lsp/pull/254)
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.1
|
data/lib/ruby_lsp/handler.rb
CHANGED
@@ -20,13 +20,13 @@ module RubyLsp
|
|
20
20
|
const :action, T.proc.params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
21
21
|
const :parallel, T::Boolean
|
22
22
|
prop :error_handler,
|
23
|
-
T.nilable(T.proc.params(error:
|
23
|
+
T.nilable(T.proc.params(error: Exception, request: T::Hash[Symbol, T.untyped]).void)
|
24
24
|
|
25
25
|
# A proc that runs in case a request has errored. Receives the error and the original request as arguments. Useful
|
26
26
|
# for displaying window messages on errors
|
27
27
|
sig do
|
28
28
|
params(
|
29
|
-
block: T.proc.bind(Handler).params(error:
|
29
|
+
block: T.proc.bind(Handler).params(error: Exception, request: T::Hash[Symbol, T.untyped]).void
|
30
30
|
).void
|
31
31
|
end
|
32
32
|
def on_error(&block)
|
data/lib/ruby_lsp/queue.rb
CHANGED
@@ -7,11 +7,11 @@ module RubyLsp
|
|
7
7
|
class Queue
|
8
8
|
extend T::Sig
|
9
9
|
|
10
|
-
class Cancelled <
|
10
|
+
class Cancelled < StandardError; end
|
11
11
|
|
12
12
|
class Result < T::Struct
|
13
13
|
const :response, T.untyped # rubocop:disable Sorbet/ForbidUntypedStructProps
|
14
|
-
const :error, T.nilable(
|
14
|
+
const :error, T.nilable(Exception)
|
15
15
|
const :request_time, T.nilable(Float)
|
16
16
|
end
|
17
17
|
|
@@ -88,11 +88,13 @@ module RubyLsp
|
|
88
88
|
sig { params(request: T::Hash[Symbol, T.untyped]).returns(Queue::Result) }
|
89
89
|
def execute(request)
|
90
90
|
response = T.let(nil, T.untyped)
|
91
|
-
error = T.let(nil, T.nilable(
|
91
|
+
error = T.let(nil, T.nilable(Exception))
|
92
92
|
|
93
93
|
request_time = Benchmark.realtime do
|
94
94
|
response = T.must(@handlers[request[:method]]).action.call(request)
|
95
|
-
rescue
|
95
|
+
rescue Cancelled
|
96
|
+
raise
|
97
|
+
rescue StandardError, LoadError => e
|
96
98
|
error = e
|
97
99
|
end
|
98
100
|
|
@@ -135,7 +137,10 @@ module RubyLsp
|
|
135
137
|
def new_worker
|
136
138
|
Thread.new do
|
137
139
|
# Thread::Queue#pop is thread safe and will wait until an item is available
|
138
|
-
|
140
|
+
loop do
|
141
|
+
job = T.let(@job_queue.pop, T.nilable(Job))
|
142
|
+
break if job.nil?
|
143
|
+
|
139
144
|
# The only time when the job is nil is when the queue is closed and we can then terminate the thread
|
140
145
|
|
141
146
|
request = job.request
|
@@ -144,17 +149,18 @@ module RubyLsp
|
|
144
149
|
@current_job = job
|
145
150
|
end
|
146
151
|
|
147
|
-
|
148
|
-
next if job.cancelled
|
152
|
+
next if job.cancelled
|
149
153
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
154
|
+
result = execute(request)
|
155
|
+
rescue Cancelled
|
156
|
+
# We need to return nil to the client even if the request was cancelled
|
157
|
+
result = Queue::Result.new(response: nil, error: nil, request_time: nil)
|
158
|
+
ensure
|
159
|
+
@mutex.synchronize { @current_job = nil }
|
160
|
+
|
161
|
+
# If there's request, it means the worker was cancelled while waiting to pop from the queue or immediately
|
162
|
+
# after
|
163
|
+
finalize_request(result, request) unless result.nil? || request.nil?
|
158
164
|
end
|
159
165
|
end
|
160
166
|
end
|
@@ -163,7 +169,7 @@ module RubyLsp
|
|
163
169
|
params(
|
164
170
|
request: T::Hash[Symbol, T.untyped],
|
165
171
|
request_time: Float,
|
166
|
-
error: T.nilable(
|
172
|
+
error: T.nilable(Exception)
|
167
173
|
).returns(T::Hash[Symbol, T.any(String, Float)])
|
168
174
|
end
|
169
175
|
def telemetry_params(request, request_time, error)
|
@@ -41,7 +41,9 @@ module RubyLsp
|
|
41
41
|
|
42
42
|
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
43
43
|
def run
|
44
|
-
|
44
|
+
handle_comment_line
|
45
|
+
|
46
|
+
return @edits unless @document.syntax_errors?
|
45
47
|
|
46
48
|
case @trigger_character
|
47
49
|
when "{"
|
@@ -59,7 +61,7 @@ module RubyLsp
|
|
59
61
|
|
60
62
|
sig { void }
|
61
63
|
def handle_pipe
|
62
|
-
return unless /
|
64
|
+
return unless /((?<=do)|(?<={))\s+\|/.match?(@previous_line)
|
63
65
|
|
64
66
|
add_edit_with_text("|")
|
65
67
|
move_cursor_to(@position[:line], @position[:character])
|
@@ -83,6 +85,18 @@ module RubyLsp
|
|
83
85
|
move_cursor_to(@position[:line], @indentation + 2)
|
84
86
|
end
|
85
87
|
|
88
|
+
sig { void }
|
89
|
+
def handle_comment_line
|
90
|
+
return unless @trigger_character == "\n"
|
91
|
+
|
92
|
+
is_comment_match = @previous_line.match(/^#(\s*)/)
|
93
|
+
return unless is_comment_match
|
94
|
+
|
95
|
+
spaces = T.must(is_comment_match[1])
|
96
|
+
add_edit_with_text("##{spaces}")
|
97
|
+
move_cursor_to(@position[:line], @indentation + spaces.size + 1)
|
98
|
+
end
|
99
|
+
|
86
100
|
sig { params(text: String).void }
|
87
101
|
def add_edit_with_text(text)
|
88
102
|
position = Interface::Position.new(
|
@@ -185,6 +185,10 @@ module RubyLsp
|
|
185
185
|
add_token(location_without_colon(location), :variable)
|
186
186
|
end
|
187
187
|
|
188
|
+
node.requireds.each do |required|
|
189
|
+
add_token(required.location, :variable)
|
190
|
+
end
|
191
|
+
|
188
192
|
rest = node.keyword_rest
|
189
193
|
return if rest.nil? || rest.is_a?(SyntaxTree::ArgsForward)
|
190
194
|
|
@@ -217,6 +221,19 @@ module RubyLsp
|
|
217
221
|
add_token(node.value.location, :method) unless special_method?(node.value.value)
|
218
222
|
end
|
219
223
|
|
224
|
+
sig { params(node: SyntaxTree::ClassDeclaration).void }
|
225
|
+
def visit_class(node)
|
226
|
+
add_token(node.constant.location, :class, [:declaration])
|
227
|
+
add_token(node.superclass.location, :class) if node.superclass
|
228
|
+
visit(node.bodystmt)
|
229
|
+
end
|
230
|
+
|
231
|
+
sig { params(node: SyntaxTree::ModuleDeclaration).void }
|
232
|
+
def visit_module(node)
|
233
|
+
add_token(node.constant.location, :class, [:declaration])
|
234
|
+
visit(node.bodystmt)
|
235
|
+
end
|
236
|
+
|
220
237
|
sig { params(location: SyntaxTree::Location, type: Symbol, modifiers: T::Array[Symbol]).void }
|
221
238
|
def add_token(location, type, modifiers = [])
|
222
239
|
length = location.end_char - location.start_char
|
@@ -1,11 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
rescue LoadError
|
7
|
-
return
|
8
|
-
end
|
4
|
+
require "ruby_lsp/requests/support/rubocop_runner"
|
5
|
+
return unless defined?(::RubyLsp::Requests::Support::RuboCopRunner)
|
9
6
|
|
10
7
|
require "cgi"
|
11
8
|
require "singleton"
|
@@ -14,46 +11,24 @@ module RubyLsp
|
|
14
11
|
module Requests
|
15
12
|
module Support
|
16
13
|
# :nodoc:
|
17
|
-
class RuboCopDiagnosticsRunner
|
14
|
+
class RuboCopDiagnosticsRunner
|
18
15
|
extend T::Sig
|
19
16
|
include Singleton
|
20
17
|
|
21
18
|
sig { void }
|
22
19
|
def initialize
|
23
|
-
@
|
24
|
-
@uri = T.let(nil, T.nilable(String))
|
25
|
-
@diagnostics = T.let([], T::Array[Support::RuboCopDiagnostic])
|
26
|
-
|
27
|
-
super(
|
28
|
-
::RuboCop::Options.new.parse([
|
29
|
-
"--stderr", # Print any output to stderr so that our stdout does not get polluted
|
30
|
-
"--force-exclusion",
|
31
|
-
"--format",
|
32
|
-
"RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
|
33
|
-
]).first,
|
34
|
-
::RuboCop::ConfigStore.new
|
35
|
-
)
|
20
|
+
@runner = T.let(RuboCopRunner.new, RuboCopRunner)
|
36
21
|
end
|
37
22
|
|
38
23
|
sig { params(uri: String, document: Document).returns(T::Array[Support::RuboCopDiagnostic]) }
|
39
24
|
def run(uri, document)
|
40
|
-
|
41
|
-
@uri = uri
|
42
|
-
|
43
|
-
file = CGI.unescape(URI.parse(uri).path)
|
44
|
-
# We communicate with Rubocop via stdin
|
45
|
-
@options[:stdin] = document.source
|
46
|
-
|
25
|
+
filename = CGI.unescape(URI.parse(uri).path)
|
47
26
|
# Invoke RuboCop with just this file in `paths`
|
48
|
-
|
49
|
-
@diagnostics
|
50
|
-
end
|
51
|
-
|
52
|
-
private
|
27
|
+
@runner.run(filename, document.source)
|
53
28
|
|
54
|
-
|
55
|
-
|
56
|
-
|
29
|
+
@runner.offenses.map do |offense|
|
30
|
+
Support::RuboCopDiagnostic.new(offense, uri)
|
31
|
+
end
|
57
32
|
end
|
58
33
|
end
|
59
34
|
end
|
@@ -1,11 +1,8 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
rescue LoadError
|
7
|
-
return
|
8
|
-
end
|
4
|
+
require "ruby_lsp/requests/support/rubocop_runner"
|
5
|
+
return unless defined?(::RubyLsp::Requests::Support::RuboCopRunner)
|
9
6
|
|
10
7
|
require "cgi"
|
11
8
|
require "singleton"
|
@@ -14,35 +11,24 @@ module RubyLsp
|
|
14
11
|
module Requests
|
15
12
|
module Support
|
16
13
|
# :nodoc:
|
17
|
-
class RuboCopFormattingRunner
|
14
|
+
class RuboCopFormattingRunner
|
18
15
|
extend T::Sig
|
19
16
|
include Singleton
|
20
17
|
|
21
18
|
sig { void }
|
22
19
|
def initialize
|
23
|
-
|
24
|
-
|
25
|
-
super(
|
26
|
-
::RuboCop::Options.new.parse([
|
27
|
-
"--stderr", # Print any output to stderr so that our stdout does not get polluted
|
28
|
-
"--force-exclusion",
|
29
|
-
"--format",
|
30
|
-
"RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
|
31
|
-
"-a", # --auto-correct
|
32
|
-
]).first,
|
33
|
-
::RuboCop::ConfigStore.new
|
34
|
-
)
|
20
|
+
# -a is for "--auto-correct" (or "--autocorrect" on newer versions of RuboCop)
|
21
|
+
@runner = T.let(RuboCopRunner.new("-a"), RuboCopRunner)
|
35
22
|
end
|
36
23
|
|
37
24
|
sig { params(uri: String, document: Document).returns(T.nilable(String)) }
|
38
25
|
def run(uri, document)
|
39
|
-
|
40
|
-
# We communicate with Rubocop via stdin
|
41
|
-
@options[:stdin] = document.source
|
26
|
+
filename = CGI.unescape(URI.parse(uri).path)
|
42
27
|
|
43
28
|
# Invoke RuboCop with just this file in `paths`
|
44
|
-
|
45
|
-
|
29
|
+
@runner.run(filename, document.source)
|
30
|
+
|
31
|
+
@runner.formatted_source
|
46
32
|
end
|
47
33
|
end
|
48
34
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
begin
|
5
|
+
require "rubocop"
|
6
|
+
rescue LoadError
|
7
|
+
return
|
8
|
+
end
|
9
|
+
|
10
|
+
module RubyLsp
|
11
|
+
module Requests
|
12
|
+
module Support
|
13
|
+
# :nodoc:
|
14
|
+
class RuboCopRunner < RuboCop::Runner
|
15
|
+
extend T::Sig
|
16
|
+
|
17
|
+
sig { returns(T::Array[RuboCop::Cop::Offense]) }
|
18
|
+
attr_reader :offenses
|
19
|
+
|
20
|
+
DEFAULT_ARGS = T.let([
|
21
|
+
"--stderr", # Print any output to stderr so that our stdout does not get polluted
|
22
|
+
"--force-exclusion",
|
23
|
+
"--format",
|
24
|
+
"RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
|
25
|
+
].freeze, T::Array[String])
|
26
|
+
|
27
|
+
sig { params(args: String).void }
|
28
|
+
def initialize(*args)
|
29
|
+
@options = T.let({}, T::Hash[Symbol, T.untyped])
|
30
|
+
@offenses = T.let([], T::Array[RuboCop::Cop::Offense])
|
31
|
+
@errors = T.let([], T::Array[String])
|
32
|
+
@warnings = T.let([], T::Array[String])
|
33
|
+
|
34
|
+
args += DEFAULT_ARGS
|
35
|
+
rubocop_options = ::RuboCop::Options.new.parse(args).first
|
36
|
+
config_store = ::RuboCop::ConfigStore.new
|
37
|
+
|
38
|
+
super(rubocop_options, config_store)
|
39
|
+
end
|
40
|
+
|
41
|
+
sig { params(path: String, contents: String).void }
|
42
|
+
def run(path, contents)
|
43
|
+
# Clear Runner state between runs since we get a single instance of this class
|
44
|
+
# on every use site.
|
45
|
+
@errors = []
|
46
|
+
@warnings = []
|
47
|
+
@offenses = []
|
48
|
+
@options[:stdin] = contents
|
49
|
+
|
50
|
+
super([path])
|
51
|
+
rescue RuboCop::Runner::InfiniteCorrectionLoop => error
|
52
|
+
raise Formatting::Error, error.message
|
53
|
+
end
|
54
|
+
|
55
|
+
sig { returns(String) }
|
56
|
+
def formatted_source
|
57
|
+
@options[:stdin]
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
sig { params(_file: String, offenses: T::Array[RuboCop::Cop::Offense]).void }
|
63
|
+
def file_finished(_file, offenses)
|
64
|
+
@offenses = offenses
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -55,24 +55,23 @@ module RubyLsp
|
|
55
55
|
)
|
56
56
|
end
|
57
57
|
|
58
|
-
# TODO: switch back to using Interface::ServerCapabilities once the gem is updated for spec 3.17
|
59
58
|
Interface::InitializeResult.new(
|
60
|
-
capabilities:
|
61
|
-
|
59
|
+
capabilities: Interface::ServerCapabilities.new(
|
60
|
+
text_document_sync: Interface::TextDocumentSyncOptions.new(
|
62
61
|
change: Constant::TextDocumentSyncKind::INCREMENTAL,
|
63
62
|
open_close: true,
|
64
63
|
),
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
64
|
+
selection_range_provider: enabled_features.include?("selectionRanges"),
|
65
|
+
document_symbol_provider: document_symbol_provider,
|
66
|
+
document_link_provider: document_link_provider,
|
67
|
+
folding_range_provider: folding_ranges_provider,
|
68
|
+
semantic_tokens_provider: semantic_tokens_provider,
|
69
|
+
document_formatting_provider: enabled_features.include?("formatting"),
|
70
|
+
document_highlight_provider: enabled_features.include?("documentHighlights"),
|
71
|
+
code_action_provider: enabled_features.include?("codeActions"),
|
72
|
+
document_on_type_formatting_provider: on_type_formatting_provider,
|
73
|
+
diagnostic_provider: diagnostics_provider,
|
74
|
+
)
|
76
75
|
)
|
77
76
|
end
|
78
77
|
|
@@ -156,9 +155,8 @@ module RubyLsp
|
|
156
155
|
uri = request.dig(:params, :textDocument, :uri)
|
157
156
|
|
158
157
|
Requests::Formatting.new(uri, store.get(uri)).run
|
159
|
-
|
160
|
-
show_message(Constant::MessageType::ERROR, "
|
161
|
-
nil
|
158
|
+
end.on_error do |error|
|
159
|
+
show_message(Constant::MessageType::ERROR, "Formatting error: #{error.message}")
|
162
160
|
end
|
163
161
|
|
164
162
|
on("textDocument/onTypeFormatting", parallel: true) do |request|
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-lsp
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.17.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.17.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: sorbet-runtime
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
|
87
87
|
- lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
|
88
88
|
- lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
|
89
|
+
- lib/ruby_lsp/requests/support/rubocop_runner.rb
|
89
90
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
90
91
|
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
91
92
|
- lib/ruby_lsp/requests/support/source_uri.rb
|