ruby-lsp 0.2.4 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +23 -26
- data/VERSION +1 -1
- data/lib/ruby_lsp/handler.rb +54 -66
- data/lib/ruby_lsp/queue.rb +176 -0
- data/lib/ruby_lsp/requests/folding_ranges.rb +7 -3
- data/lib/ruby_lsp/requests/formatting.rb +2 -0
- data/lib/ruby_lsp/requests/on_type_formatting.rb +149 -0
- 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 +73 -0
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/server.rb +46 -25
- metadata +11 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e09a85000549c0b7b7dd2886b49d44ca2e32b830616a4af7181a2d7952f948f
|
4
|
+
data.tar.gz: f19b017ebffce3a090d9fe9c39c94cb0dad75a7a74856c099443839524d513f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0b75fa95c43a4a15a46e3cd663b5dd637c9288497116b356eb69dc3f831cfdbb3e167c1c578b68feee715e85c72d26c7d63236e3250552ddbf0f2db334e8f46
|
7
|
+
data.tar.gz: c80518dba77375f07f9944f0401f6836ca69bba60ba6723677e33e366104dd69b70832e8ce76c05312b47c3a032a5308711505e88be2ce69f3f837bec2db3c21
|
data/CHANGELOG.md
CHANGED
@@ -6,32 +6,29 @@ Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how
|
|
6
6
|
|
7
7
|
## [Unreleased]
|
8
8
|
|
9
|
-
## [0.2
|
10
|
-
|
11
|
-
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
-
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
20
|
-
-
|
21
|
-
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
-
|
26
|
-
|
27
|
-
|
28
|
-
-
|
29
|
-
-
|
30
|
-
-
|
31
|
-
-
|
32
|
-
- Fix handling of argument fowarding in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/228)
|
33
|
-
- Recover from initial syntax errors when opening documents (https://github.com/Shopify/ruby-lsp/pull/224)
|
34
|
-
- Highlight occurrences and definitions in document highlight (https://github.com/Shopify/ruby-lsp/pull/187)
|
9
|
+
## [0.3.2]
|
10
|
+
|
11
|
+
- Make the diagnostic request parallel (https://github.com/Shopify/ruby-lsp/pull/293)
|
12
|
+
- Improve worker stability (https://github.com/Shopify/ruby-lsp/pull/295)
|
13
|
+
|
14
|
+
## [0.3.1]
|
15
|
+
|
16
|
+
- Resolve TODO for LSP v3.17 (https://github.com/Shopify/ruby-lsp/pull/268)
|
17
|
+
- Add dependency constraint for LSP v3.17 (https://github.com/Shopify/ruby-lsp/pull/269)
|
18
|
+
- Handle class/module declarations as a class token with declaration modifier (https://github.com/Shopify/ruby-lsp/pull/260)
|
19
|
+
- Handle required parameters in semantic highlighting (https://github.com/Shopify/ruby-lsp/pull/271)
|
20
|
+
- Add comment continuation via on type on_type_formatting (https://github.com/Shopify/ruby-lsp/pull/274)
|
21
|
+
- Make RuboCop runner use composition instead of inheritance (https://github.com/Shopify/ruby-lsp/pull/278)
|
22
|
+
- Protect worker against cancellation during popping (https://github.com/Shopify/ruby-lsp/pull/280)
|
23
|
+
- Handle formatting errors in on_error block (https://github.com/Shopify/ruby-lsp/pull/279)
|
24
|
+
- Fix on type formatting pipe completion for regular or expressions (https://github.com/Shopify/ruby-lsp/pull/282)
|
25
|
+
- Do not fail on LoadError (https://github.com/Shopify/ruby-lsp/pull/292)
|
26
|
+
|
27
|
+
## [0.3.0]
|
28
|
+
- Add on type formatting completions (https://github.com/Shopify/ruby-lsp/pull/253)
|
29
|
+
- Upgrade syntax_tree requirement to >= 3.4 (https://github.com/Shopify/ruby-lsp/pull/254)
|
30
|
+
- Show error message when there's a InfiniteCorrectionLoop exception (https://github.com/Shopify/ruby-lsp/pull/252)
|
31
|
+
- Add request cancellation (https://github.com/Shopify/ruby-lsp/pull/243)
|
35
32
|
|
36
33
|
## [0.2.0]
|
37
34
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2
|
1
|
+
0.3.2
|
data/lib/ruby_lsp/handler.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require "ruby_lsp/requests"
|
5
5
|
require "ruby_lsp/store"
|
6
|
-
require "
|
6
|
+
require "ruby_lsp/queue"
|
7
7
|
|
8
8
|
module RubyLsp
|
9
9
|
Interface = LanguageServer::Protocol::Interface
|
@@ -14,11 +14,35 @@ module RubyLsp
|
|
14
14
|
extend T::Sig
|
15
15
|
VOID = T.let(Object.new.freeze, Object)
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
class RequestHandler < T::Struct
|
18
|
+
extend T::Sig
|
19
|
+
|
20
|
+
const :action, T.proc.params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
21
|
+
const :parallel, T::Boolean
|
22
|
+
prop :error_handler,
|
23
|
+
T.nilable(T.proc.params(error: Exception, request: T::Hash[Symbol, T.untyped]).void)
|
24
|
+
|
25
|
+
# A proc that runs in case a request has errored. Receives the error and the original request as arguments. Useful
|
26
|
+
# for displaying window messages on errors
|
27
|
+
sig do
|
28
|
+
params(
|
29
|
+
block: T.proc.bind(Handler).params(error: Exception, request: T::Hash[Symbol, T.untyped]).void
|
30
|
+
).void
|
31
|
+
end
|
32
|
+
def on_error(&block)
|
33
|
+
self.error_handler = block
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class << self
|
38
|
+
extend T::Sig
|
39
|
+
|
40
|
+
sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
|
41
|
+
def start(&blk)
|
42
|
+
handler = new
|
43
|
+
handler.instance_exec(&blk)
|
44
|
+
handler.start
|
45
|
+
end
|
22
46
|
end
|
23
47
|
|
24
48
|
sig { returns(Store) }
|
@@ -28,61 +52,50 @@ module RubyLsp
|
|
28
52
|
def initialize
|
29
53
|
@writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
|
30
54
|
@reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
|
31
|
-
@handlers = T.let({}, T::Hash[String,
|
55
|
+
@handlers = T.let({}, T::Hash[String, RequestHandler])
|
32
56
|
@store = T.let(Store.new, Store)
|
57
|
+
@queue = T.let(Queue.new(@writer, @handlers), Queue)
|
33
58
|
end
|
34
59
|
|
35
60
|
sig { void }
|
36
61
|
def start
|
37
62
|
$stderr.puts "Starting Ruby LSP..."
|
38
|
-
|
63
|
+
|
64
|
+
@reader.read do |request|
|
65
|
+
handler = @handlers[request[:method]]
|
66
|
+
next if handler.nil?
|
67
|
+
|
68
|
+
if handler.parallel
|
69
|
+
@queue.push(request)
|
70
|
+
else
|
71
|
+
result = @queue.execute(request)
|
72
|
+
@queue.finalize_request(result, request)
|
73
|
+
end
|
74
|
+
end
|
39
75
|
end
|
40
76
|
|
41
77
|
private
|
42
78
|
|
79
|
+
sig { params(id: T.any(String, Integer)).void }
|
80
|
+
def cancel_request(id)
|
81
|
+
@queue.cancel(id)
|
82
|
+
end
|
83
|
+
|
43
84
|
sig do
|
44
85
|
params(
|
45
86
|
msg: String,
|
87
|
+
parallel: T::Boolean,
|
46
88
|
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
47
|
-
).
|
89
|
+
).returns(RequestHandler)
|
48
90
|
end
|
49
|
-
def on(msg, &blk)
|
50
|
-
@handlers[msg] = blk
|
51
|
-
end
|
52
|
-
|
53
|
-
sig { params(request: T::Hash[Symbol, T.untyped]).void }
|
54
|
-
def handle(request)
|
55
|
-
result = T.let(nil, T.untyped)
|
56
|
-
error = T.let(nil, T.nilable(StandardError))
|
57
|
-
handler = @handlers[request[:method]]
|
58
|
-
|
59
|
-
request_time = Benchmark.realtime do
|
60
|
-
if handler
|
61
|
-
begin
|
62
|
-
result = handler.call(request)
|
63
|
-
rescue StandardError => e
|
64
|
-
error = e
|
65
|
-
end
|
66
|
-
|
67
|
-
if error
|
68
|
-
@writer.write(
|
69
|
-
{
|
70
|
-
id: request[:id],
|
71
|
-
error: { code: Constant::ErrorCodes::INTERNAL_ERROR, message: error.inspect, data: request.to_json },
|
72
|
-
}
|
73
|
-
)
|
74
|
-
elsif result != VOID
|
75
|
-
@writer.write(id: request[:id], result: result)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
|
91
|
+
def on(msg, parallel: false, &blk)
|
92
|
+
@handlers[msg] = RequestHandler.new(action: blk, parallel: parallel)
|
81
93
|
end
|
82
94
|
|
83
95
|
sig { void }
|
84
96
|
def shutdown
|
85
97
|
$stderr.puts "Shutting down Ruby LSP..."
|
98
|
+
@queue.shutdown
|
86
99
|
store.clear
|
87
100
|
end
|
88
101
|
|
@@ -101,30 +114,5 @@ module RubyLsp
|
|
101
114
|
params: Interface::ShowMessageParams.new(type: type, message: message)
|
102
115
|
)
|
103
116
|
end
|
104
|
-
|
105
|
-
sig do
|
106
|
-
params(
|
107
|
-
request: T::Hash[Symbol, T.untyped],
|
108
|
-
request_time: Float,
|
109
|
-
error: T.nilable(StandardError)
|
110
|
-
).returns(T::Hash[Symbol, T.any(String, Float)])
|
111
|
-
end
|
112
|
-
def telemetry_params(request, request_time, error)
|
113
|
-
uri = request.dig(:params, :textDocument, :uri)
|
114
|
-
|
115
|
-
params = {
|
116
|
-
request: request[:method],
|
117
|
-
lspVersion: RubyLsp::VERSION,
|
118
|
-
requestTime: request_time,
|
119
|
-
}
|
120
|
-
|
121
|
-
if error
|
122
|
-
params[:errorClass] = error.class.name
|
123
|
-
params[:errorMessage] = error.message
|
124
|
-
end
|
125
|
-
|
126
|
-
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
127
|
-
params
|
128
|
-
end
|
129
117
|
end
|
130
118
|
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require "benchmark"
|
5
|
+
|
6
|
+
module RubyLsp
|
7
|
+
class Queue
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
class Result < T::Struct
|
11
|
+
const :response, T.untyped # rubocop:disable Sorbet/ForbidUntypedStructProps
|
12
|
+
const :error, T.nilable(Exception)
|
13
|
+
const :request_time, T.nilable(Float)
|
14
|
+
end
|
15
|
+
|
16
|
+
class Job < T::Struct
|
17
|
+
extend T::Sig
|
18
|
+
|
19
|
+
const :request, T::Hash[Symbol, T.untyped]
|
20
|
+
prop :cancelled, T::Boolean
|
21
|
+
|
22
|
+
sig { void }
|
23
|
+
def cancel
|
24
|
+
self.cancelled = true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
sig do
|
29
|
+
params(
|
30
|
+
writer: LanguageServer::Protocol::Transport::Stdio::Writer,
|
31
|
+
handlers: T::Hash[String, Handler::RequestHandler]
|
32
|
+
).void
|
33
|
+
end
|
34
|
+
def initialize(writer, handlers)
|
35
|
+
@writer = writer
|
36
|
+
@handlers = handlers
|
37
|
+
# The job queue is the actual list of requests we have to process
|
38
|
+
@job_queue = T.let(Thread::Queue.new, Thread::Queue)
|
39
|
+
# The jobs hash is just a way of keeping a handle to jobs based on the request ID, so we can cancel them
|
40
|
+
@jobs = T.let({}, T::Hash[T.any(String, Integer), Job])
|
41
|
+
@mutex = T.let(Mutex.new, Mutex)
|
42
|
+
@worker = T.let(new_worker, Thread)
|
43
|
+
|
44
|
+
Thread.main.priority = 1
|
45
|
+
end
|
46
|
+
|
47
|
+
sig { params(request: T::Hash[Symbol, T.untyped]).void }
|
48
|
+
def push(request)
|
49
|
+
job = Job.new(request: request, cancelled: false)
|
50
|
+
|
51
|
+
# Remember a handle to the job, so that we can cancel it
|
52
|
+
@mutex.synchronize do
|
53
|
+
@jobs[request[:id]] = job
|
54
|
+
end
|
55
|
+
|
56
|
+
@job_queue << job
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { params(id: T.any(String, Integer)).void }
|
60
|
+
def cancel(id)
|
61
|
+
@mutex.synchronize do
|
62
|
+
# Cancel the job if it's still in the queue
|
63
|
+
@jobs[id]&.cancel
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
sig { void }
|
68
|
+
def shutdown
|
69
|
+
# Close the queue so that we can no longer receive items
|
70
|
+
@job_queue.close
|
71
|
+
# Clear any remaining jobs so that the thread can terminate
|
72
|
+
@job_queue.clear
|
73
|
+
# Wait until the thread is finished
|
74
|
+
@worker.join
|
75
|
+
end
|
76
|
+
|
77
|
+
# Executes a request and returns a Queue::Result. No IO should happen in this method, because it can be cancelled in
|
78
|
+
# the middle with a raise
|
79
|
+
sig { params(request: T::Hash[Symbol, T.untyped]).returns(Queue::Result) }
|
80
|
+
def execute(request)
|
81
|
+
response = T.let(nil, T.untyped)
|
82
|
+
error = T.let(nil, T.nilable(Exception))
|
83
|
+
|
84
|
+
request_time = Benchmark.realtime do
|
85
|
+
response = T.must(@handlers[request[:method]]).action.call(request)
|
86
|
+
rescue StandardError, LoadError => e
|
87
|
+
error = e
|
88
|
+
end
|
89
|
+
|
90
|
+
Queue::Result.new(response: response, error: error, request_time: request_time)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Finalize a Queue::Result. All IO operations should happen here to avoid any issues with cancelling requests
|
94
|
+
sig do
|
95
|
+
params(
|
96
|
+
result: Result,
|
97
|
+
request: T::Hash[Symbol, T.untyped]
|
98
|
+
).void
|
99
|
+
end
|
100
|
+
def finalize_request(result, request)
|
101
|
+
@mutex.synchronize do
|
102
|
+
error = result.error
|
103
|
+
if error
|
104
|
+
T.must(@handlers[request[:method]]).error_handler&.call(error, request)
|
105
|
+
|
106
|
+
@writer.write(
|
107
|
+
id: request[:id],
|
108
|
+
error: {
|
109
|
+
code: LanguageServer::Protocol::Constant::ErrorCodes::INTERNAL_ERROR,
|
110
|
+
message: result.error.inspect,
|
111
|
+
data: request.to_json,
|
112
|
+
},
|
113
|
+
)
|
114
|
+
elsif result.response != Handler::VOID
|
115
|
+
@writer.write(id: request[:id], result: result.response)
|
116
|
+
end
|
117
|
+
|
118
|
+
request_time = result.request_time
|
119
|
+
if request_time
|
120
|
+
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, result.error))
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
|
127
|
+
sig { returns(Thread) }
|
128
|
+
def new_worker
|
129
|
+
Thread.new do
|
130
|
+
# Thread::Queue#pop is thread safe and will wait until an item is available
|
131
|
+
loop do
|
132
|
+
job = T.let(@job_queue.pop, T.nilable(Job))
|
133
|
+
# The only time when the job is nil is when the queue is closed and we can then terminate the thread
|
134
|
+
break if job.nil?
|
135
|
+
|
136
|
+
request = job.request
|
137
|
+
@mutex.synchronize { @jobs.delete(request[:id]) }
|
138
|
+
|
139
|
+
result = if job.cancelled
|
140
|
+
# We need to return nil to the client even if the request was cancelled
|
141
|
+
Queue::Result.new(response: nil, error: nil, request_time: nil)
|
142
|
+
else
|
143
|
+
execute(request)
|
144
|
+
end
|
145
|
+
|
146
|
+
finalize_request(result, request)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
sig do
|
152
|
+
params(
|
153
|
+
request: T::Hash[Symbol, T.untyped],
|
154
|
+
request_time: Float,
|
155
|
+
error: T.nilable(Exception)
|
156
|
+
).returns(T::Hash[Symbol, T.any(String, Float)])
|
157
|
+
end
|
158
|
+
def telemetry_params(request, request_time, error)
|
159
|
+
uri = request.dig(:params, :textDocument, :uri)
|
160
|
+
|
161
|
+
params = {
|
162
|
+
request: request[:method],
|
163
|
+
lspVersion: RubyLsp::VERSION,
|
164
|
+
requestTime: request_time,
|
165
|
+
}
|
166
|
+
|
167
|
+
if error
|
168
|
+
params[:errorClass] = error.class.name
|
169
|
+
params[:errorMessage] = error.message
|
170
|
+
end
|
171
|
+
|
172
|
+
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
173
|
+
params
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -105,9 +105,13 @@ module RubyLsp
|
|
105
105
|
sig { returns(Integer) }
|
106
106
|
attr_reader :end_line
|
107
107
|
|
108
|
-
|
109
|
-
|
110
|
-
|
108
|
+
class << self
|
109
|
+
extend T::Sig
|
110
|
+
|
111
|
+
sig { params(node: SyntaxTree::Node, kind: String).returns(PartialRange) }
|
112
|
+
def from(node, kind)
|
113
|
+
new(node.location.start_line - 1, node.location.end_line - 1, kind)
|
114
|
+
end
|
111
115
|
end
|
112
116
|
|
113
117
|
sig { params(start_line: Integer, end_line: Integer, kind: String).void }
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
module Requests
|
6
|
+
# ![On type formatting demo](../../misc/on_type_formatting.gif)
|
7
|
+
#
|
8
|
+
# The [on type formatting](https://microsoft.github.io/language-server-protocol/specification#textDocument_onTypeFormatting)
|
9
|
+
# request formats code as the user is typing. For example, automatically adding `end` to class definitions.
|
10
|
+
#
|
11
|
+
# # Example
|
12
|
+
#
|
13
|
+
# ```ruby
|
14
|
+
# class Foo # <-- upon adding a line break, on type formatting is triggered
|
15
|
+
# # <-- cursor ends up here
|
16
|
+
# end # <-- end is automatically added
|
17
|
+
# ```
|
18
|
+
class OnTypeFormatting < BaseRequest
|
19
|
+
extend T::Sig
|
20
|
+
|
21
|
+
END_REGEXES = T.let([
|
22
|
+
/(if|unless|for|while|class|module|until|def|case).*/,
|
23
|
+
/.*\sdo/,
|
24
|
+
], T::Array[Regexp])
|
25
|
+
|
26
|
+
sig { params(document: Document, position: Document::PositionShape, trigger_character: String).void }
|
27
|
+
def initialize(document, position, trigger_character)
|
28
|
+
super(document)
|
29
|
+
|
30
|
+
scanner = Document::Scanner.new(document.source)
|
31
|
+
line_begin = position[:line] == 0 ? 0 : scanner.find_position({ line: position[:line] - 1, character: 0 })
|
32
|
+
line_end = scanner.find_position(position)
|
33
|
+
line = T.must(@document.source[line_begin..line_end])
|
34
|
+
|
35
|
+
@indentation = T.let(find_indentation(line), Integer)
|
36
|
+
@previous_line = T.let(line.strip.chomp, String)
|
37
|
+
@position = position
|
38
|
+
@edits = T.let([], T::Array[Interface::TextEdit])
|
39
|
+
@trigger_character = trigger_character
|
40
|
+
end
|
41
|
+
|
42
|
+
sig { override.returns(T.nilable(T.all(T::Array[Interface::TextEdit], Object))) }
|
43
|
+
def run
|
44
|
+
handle_comment_line
|
45
|
+
|
46
|
+
return @edits unless @document.syntax_errors?
|
47
|
+
|
48
|
+
case @trigger_character
|
49
|
+
when "{"
|
50
|
+
handle_curly_brace
|
51
|
+
when "|"
|
52
|
+
handle_pipe
|
53
|
+
when "\n"
|
54
|
+
handle_statement_end
|
55
|
+
end
|
56
|
+
|
57
|
+
@edits
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
sig { void }
|
63
|
+
def handle_pipe
|
64
|
+
return unless /((?<=do)|(?<={))\s+\|/.match?(@previous_line)
|
65
|
+
|
66
|
+
add_edit_with_text("|")
|
67
|
+
move_cursor_to(@position[:line], @position[:character])
|
68
|
+
end
|
69
|
+
|
70
|
+
sig { void }
|
71
|
+
def handle_curly_brace
|
72
|
+
return unless /".*#\{/.match?(@previous_line)
|
73
|
+
|
74
|
+
add_edit_with_text("}")
|
75
|
+
move_cursor_to(@position[:line], @position[:character])
|
76
|
+
end
|
77
|
+
|
78
|
+
sig { void }
|
79
|
+
def handle_statement_end
|
80
|
+
return unless END_REGEXES.any? { |regex| regex.match?(@previous_line) }
|
81
|
+
|
82
|
+
indents = " " * @indentation
|
83
|
+
|
84
|
+
add_edit_with_text(" \n#{indents}end")
|
85
|
+
move_cursor_to(@position[:line], @indentation + 2)
|
86
|
+
end
|
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
|
+
|
100
|
+
sig { params(text: String).void }
|
101
|
+
def add_edit_with_text(text)
|
102
|
+
position = Interface::Position.new(
|
103
|
+
line: @position[:line],
|
104
|
+
character: @position[:character]
|
105
|
+
)
|
106
|
+
|
107
|
+
@edits << Interface::TextEdit.new(
|
108
|
+
range: Interface::Range.new(
|
109
|
+
start: position,
|
110
|
+
end: position
|
111
|
+
),
|
112
|
+
new_text: text
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
sig { params(line: Integer, character: Integer).void }
|
117
|
+
def move_cursor_to(line, character)
|
118
|
+
position = Interface::Position.new(
|
119
|
+
line: line,
|
120
|
+
character: character
|
121
|
+
)
|
122
|
+
|
123
|
+
# The $0 is a special snippet anchor that moves the cursor to that given position. See the snippets
|
124
|
+
# documentation for more information:
|
125
|
+
# https://code.visualstudio.com/docs/editor/userdefinedsnippets#_create-your-own-snippets
|
126
|
+
@edits << Interface::TextEdit.new(
|
127
|
+
range: Interface::Range.new(
|
128
|
+
start: position,
|
129
|
+
end: position
|
130
|
+
),
|
131
|
+
new_text: "$0"
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
sig { params(line: String).returns(Integer) }
|
136
|
+
def find_indentation(line)
|
137
|
+
count = 0
|
138
|
+
|
139
|
+
line.chars.each do |c|
|
140
|
+
break unless c == " "
|
141
|
+
|
142
|
+
count += 1
|
143
|
+
end
|
144
|
+
|
145
|
+
count
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
@@ -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,73 @@
|
|
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
|
+
class ConfigurationError < StandardError; end
|
18
|
+
|
19
|
+
sig { returns(T::Array[RuboCop::Cop::Offense]) }
|
20
|
+
attr_reader :offenses
|
21
|
+
|
22
|
+
DEFAULT_ARGS = T.let([
|
23
|
+
"--stderr", # Print any output to stderr so that our stdout does not get polluted
|
24
|
+
"--force-exclusion",
|
25
|
+
"--format",
|
26
|
+
"RuboCop::Formatter::BaseFormatter", # Suppress any output by using the base formatter
|
27
|
+
].freeze, T::Array[String])
|
28
|
+
|
29
|
+
sig { params(args: String).void }
|
30
|
+
def initialize(*args)
|
31
|
+
@options = T.let({}, T::Hash[Symbol, T.untyped])
|
32
|
+
@offenses = T.let([], T::Array[RuboCop::Cop::Offense])
|
33
|
+
@errors = T.let([], T::Array[String])
|
34
|
+
@warnings = T.let([], T::Array[String])
|
35
|
+
|
36
|
+
args += DEFAULT_ARGS
|
37
|
+
rubocop_options = ::RuboCop::Options.new.parse(args).first
|
38
|
+
config_store = ::RuboCop::ConfigStore.new
|
39
|
+
|
40
|
+
super(rubocop_options, config_store)
|
41
|
+
end
|
42
|
+
|
43
|
+
sig { params(path: String, contents: String).void }
|
44
|
+
def run(path, contents)
|
45
|
+
# Clear Runner state between runs since we get a single instance of this class
|
46
|
+
# on every use site.
|
47
|
+
@errors = []
|
48
|
+
@warnings = []
|
49
|
+
@offenses = []
|
50
|
+
@options[:stdin] = contents
|
51
|
+
|
52
|
+
super([path])
|
53
|
+
rescue RuboCop::Runner::InfiniteCorrectionLoop => error
|
54
|
+
raise Formatting::Error, error.message
|
55
|
+
rescue RuboCop::ValidationError => error
|
56
|
+
raise ConfigurationError, error.message
|
57
|
+
end
|
58
|
+
|
59
|
+
sig { returns(String) }
|
60
|
+
def formatted_source
|
61
|
+
@options[:stdin]
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
sig { params(_file: String, offenses: T::Array[RuboCop::Cop::Offense]).void }
|
67
|
+
def file_finished(_file, offenses)
|
68
|
+
@offenses = offenses
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/ruby_lsp/requests.rb
CHANGED
@@ -10,6 +10,7 @@ module RubyLsp
|
|
10
10
|
# - {RubyLsp::Requests::SelectionRanges}
|
11
11
|
# - {RubyLsp::Requests::SemanticHighlighting}
|
12
12
|
# - {RubyLsp::Requests::Formatting}
|
13
|
+
# - {RubyLsp::Requests::OnTypeFormatting}
|
13
14
|
# - {RubyLsp::Requests::Diagnostics}
|
14
15
|
# - {RubyLsp::Requests::CodeActions}
|
15
16
|
# - {RubyLsp::Requests::DocumentHighlight}
|
@@ -21,6 +22,7 @@ module RubyLsp
|
|
21
22
|
autoload :SelectionRanges, "ruby_lsp/requests/selection_ranges"
|
22
23
|
autoload :SemanticHighlighting, "ruby_lsp/requests/semantic_highlighting"
|
23
24
|
autoload :Formatting, "ruby_lsp/requests/formatting"
|
25
|
+
autoload :OnTypeFormatting, "ruby_lsp/requests/on_type_formatting"
|
24
26
|
autoload :Diagnostics, "ruby_lsp/requests/diagnostics"
|
25
27
|
autoload :CodeActions, "ruby_lsp/requests/code_actions"
|
26
28
|
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -48,23 +48,30 @@ module RubyLsp
|
|
48
48
|
}
|
49
49
|
end
|
50
50
|
|
51
|
-
|
51
|
+
on_type_formatting_provider = if enabled_features.include?("onTypeFormatting")
|
52
|
+
Interface::DocumentOnTypeFormattingOptions.new(
|
53
|
+
first_trigger_character: "{",
|
54
|
+
more_trigger_character: ["\n", "|"]
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
52
58
|
Interface::InitializeResult.new(
|
53
|
-
capabilities:
|
54
|
-
|
59
|
+
capabilities: Interface::ServerCapabilities.new(
|
60
|
+
text_document_sync: Interface::TextDocumentSyncOptions.new(
|
55
61
|
change: Constant::TextDocumentSyncKind::INCREMENTAL,
|
56
62
|
open_close: true,
|
57
63
|
),
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
+
)
|
68
75
|
)
|
69
76
|
end
|
70
77
|
|
@@ -91,26 +98,26 @@ module RubyLsp
|
|
91
98
|
Handler::VOID
|
92
99
|
end
|
93
100
|
|
94
|
-
on("textDocument/documentSymbol") do |request|
|
101
|
+
on("textDocument/documentSymbol", parallel: true) do |request|
|
95
102
|
store.cache_fetch(request.dig(:params, :textDocument, :uri), :document_symbol) do |document|
|
96
103
|
Requests::DocumentSymbol.new(document).run
|
97
104
|
end
|
98
105
|
end
|
99
106
|
|
100
|
-
on("textDocument/documentLink") do |request|
|
107
|
+
on("textDocument/documentLink", parallel: true) do |request|
|
101
108
|
uri = request.dig(:params, :textDocument, :uri)
|
102
109
|
store.cache_fetch(uri, :document_link) do |document|
|
103
110
|
RubyLsp::Requests::DocumentLink.new(uri, document).run
|
104
111
|
end
|
105
112
|
end
|
106
113
|
|
107
|
-
on("textDocument/foldingRange") do |request|
|
114
|
+
on("textDocument/foldingRange", parallel: true) do |request|
|
108
115
|
store.cache_fetch(request.dig(:params, :textDocument, :uri), :folding_ranges) do |document|
|
109
116
|
Requests::FoldingRanges.new(document).run
|
110
117
|
end
|
111
118
|
end
|
112
119
|
|
113
|
-
on("textDocument/selectionRange") do |request|
|
120
|
+
on("textDocument/selectionRange", parallel: true) do |request|
|
114
121
|
uri = request.dig(:params, :textDocument, :uri)
|
115
122
|
positions = request.dig(:params, :positions)
|
116
123
|
|
@@ -132,7 +139,7 @@ module RubyLsp
|
|
132
139
|
end
|
133
140
|
end
|
134
141
|
|
135
|
-
on("textDocument/semanticTokens/full") do |request|
|
142
|
+
on("textDocument/semanticTokens/full", parallel: true) do |request|
|
136
143
|
store.cache_fetch(request.dig(:params, :textDocument, :uri), :semantic_highlighting) do |document|
|
137
144
|
T.cast(
|
138
145
|
Requests::SemanticHighlighting.new(
|
@@ -144,13 +151,23 @@ module RubyLsp
|
|
144
151
|
end
|
145
152
|
end
|
146
153
|
|
147
|
-
on("textDocument/formatting") do |request|
|
154
|
+
on("textDocument/formatting", parallel: true) do |request|
|
148
155
|
uri = request.dig(:params, :textDocument, :uri)
|
149
156
|
|
150
157
|
Requests::Formatting.new(uri, store.get(uri)).run
|
158
|
+
end.on_error do |error|
|
159
|
+
show_message(Constant::MessageType::ERROR, "Formatting error: #{error.message}")
|
151
160
|
end
|
152
161
|
|
153
|
-
on("textDocument/
|
162
|
+
on("textDocument/onTypeFormatting", parallel: true) do |request|
|
163
|
+
uri = request.dig(:params, :textDocument, :uri)
|
164
|
+
position = request.dig(:params, :position)
|
165
|
+
character = request.dig(:params, :ch)
|
166
|
+
|
167
|
+
Requests::OnTypeFormatting.new(store.get(uri), position, character).run
|
168
|
+
end
|
169
|
+
|
170
|
+
on("textDocument/documentHighlight", parallel: true) do |request|
|
154
171
|
document = store.get(request.dig(:params, :textDocument, :uri))
|
155
172
|
|
156
173
|
if document.parsed?
|
@@ -158,7 +175,7 @@ module RubyLsp
|
|
158
175
|
end
|
159
176
|
end
|
160
177
|
|
161
|
-
on("textDocument/codeAction") do |request|
|
178
|
+
on("textDocument/codeAction", parallel: true) do |request|
|
162
179
|
uri = request.dig(:params, :textDocument, :uri)
|
163
180
|
range = request.dig(:params, :range)
|
164
181
|
start_line = range.dig(:start, :line)
|
@@ -169,16 +186,20 @@ module RubyLsp
|
|
169
186
|
end
|
170
187
|
end
|
171
188
|
|
172
|
-
on("
|
189
|
+
on("$/cancelRequest") do |request|
|
190
|
+
cancel_request(request[:params][:id])
|
191
|
+
Handler::VOID
|
192
|
+
end
|
193
|
+
|
194
|
+
on("textDocument/diagnostic", parallel: true) do |request|
|
173
195
|
uri = request.dig(:params, :textDocument, :uri)
|
174
196
|
response = store.cache_fetch(uri, :diagnostics) do |document|
|
175
197
|
Requests::Diagnostics.new(uri, document).run
|
176
198
|
end
|
177
199
|
|
178
200
|
{ kind: "full", items: response.map(&:to_lsp_diagnostic) } if response
|
179
|
-
|
180
|
-
show_message(Constant::MessageType::ERROR, "Error
|
181
|
-
nil
|
201
|
+
end.on_error do |error|
|
202
|
+
show_message(Constant::MessageType::ERROR, "Error running diagnostics: #{error.message}")
|
182
203
|
end
|
183
204
|
|
184
205
|
on("shutdown") { shutdown }
|
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.2
|
4
|
+
version: 0.3.2
|
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-07 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
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '3.4'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '3.4'
|
55
55
|
description: An opinionated language server for Ruby
|
56
56
|
email:
|
57
57
|
- ruby@shopify.com
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/ruby_lsp/document.rb
|
70
70
|
- lib/ruby_lsp/handler.rb
|
71
71
|
- lib/ruby_lsp/internal.rb
|
72
|
+
- lib/ruby_lsp/queue.rb
|
72
73
|
- lib/ruby_lsp/requests.rb
|
73
74
|
- lib/ruby_lsp/requests/base_request.rb
|
74
75
|
- lib/ruby_lsp/requests/code_actions.rb
|
@@ -78,12 +79,14 @@ files:
|
|
78
79
|
- lib/ruby_lsp/requests/document_symbol.rb
|
79
80
|
- lib/ruby_lsp/requests/folding_ranges.rb
|
80
81
|
- lib/ruby_lsp/requests/formatting.rb
|
82
|
+
- lib/ruby_lsp/requests/on_type_formatting.rb
|
81
83
|
- lib/ruby_lsp/requests/selection_ranges.rb
|
82
84
|
- lib/ruby_lsp/requests/semantic_highlighting.rb
|
83
85
|
- lib/ruby_lsp/requests/support/highlight_target.rb
|
84
86
|
- lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
|
85
87
|
- lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
|
86
88
|
- lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb
|
89
|
+
- lib/ruby_lsp/requests/support/rubocop_runner.rb
|
87
90
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
88
91
|
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
89
92
|
- lib/ruby_lsp/requests/support/source_uri.rb
|