ruby-lsp 0.3.8 → 0.4.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 +39 -1
- data/VERSION +1 -1
- data/exe/ruby-lsp +2 -1
- data/lib/ruby_lsp/executor.rb +362 -0
- data/lib/ruby_lsp/internal.rb +6 -1
- data/lib/ruby_lsp/requests/base_request.rb +10 -3
- data/lib/ruby_lsp/requests/code_actions.rb +21 -7
- data/lib/ruby_lsp/requests/diagnostics.rb +7 -11
- data/lib/ruby_lsp/requests/formatting.rb +8 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +33 -14
- data/lib/ruby_lsp/requests/path_completion.rb +88 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +35 -11
- data/lib/ruby_lsp/requests/support/annotation.rb +46 -0
- data/lib/ruby_lsp/requests/support/highlight_target.rb +14 -3
- data/lib/ruby_lsp/requests/support/prefix_tree.rb +80 -0
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +29 -44
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +1 -1
- data/lib/ruby_lsp/requests/support/rubocop_runner.rb +27 -1
- data/lib/ruby_lsp/requests/support/sorbet.rb +120 -0
- data/lib/ruby_lsp/requests.rb +5 -1
- data/lib/ruby_lsp/server.rb +128 -221
- data/lib/ruby_lsp/utils.rb +78 -0
- metadata +12 -9
- data/lib/ruby_lsp/handler.rb +0 -118
- data/lib/ruby_lsp/queue.rb +0 -182
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +0 -32
data/lib/ruby_lsp/server.rb
CHANGED
@@ -1,250 +1,157 @@
|
|
1
1
|
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require "ruby_lsp/internal"
|
5
|
-
|
6
4
|
module RubyLsp
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
5
|
+
Interface = LanguageServer::Protocol::Interface
|
6
|
+
Constant = LanguageServer::Protocol::Constant
|
7
|
+
Transport = LanguageServer::Protocol::Transport
|
8
|
+
|
9
|
+
class Server
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { void }
|
13
|
+
def initialize
|
14
|
+
@writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
|
15
|
+
@reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
|
16
|
+
@store = T.let(Store.new, Store)
|
17
|
+
|
18
|
+
# The job queue is the actual list of requests we have to process
|
19
|
+
@job_queue = T.let(Thread::Queue.new, Thread::Queue)
|
20
|
+
# The jobs hash is just a way of keeping a handle to jobs based on the request ID, so we can cancel them
|
21
|
+
@jobs = T.let({}, T::Hash[T.any(String, Integer), Job])
|
22
|
+
@mutex = T.let(Mutex.new, Mutex)
|
23
|
+
@worker = T.let(new_worker, Thread)
|
24
|
+
|
25
|
+
Thread.main.priority = 1
|
26
|
+
end
|
27
|
+
|
28
|
+
sig { void }
|
29
|
+
def start
|
30
|
+
warn("Starting Ruby LSP...")
|
31
|
+
|
32
|
+
# Requests that have to be executed sequentially or in the main process are implemented here. All other requests
|
33
|
+
# fall under the else branch which just pushes requests to the queue
|
34
|
+
@reader.read do |request|
|
35
|
+
case request[:method]
|
36
|
+
when "initialize", "textDocument/didOpen", "textDocument/didClose", "textDocument/didChange"
|
37
|
+
result = Executor.new(@store).execute(request)
|
38
|
+
finalize_request(result, request)
|
39
|
+
when "$/cancelRequest"
|
40
|
+
# Cancel the job if it's still in the queue
|
41
|
+
@mutex.synchronize { @jobs[request[:params][:id]]&.cancel }
|
42
|
+
when "shutdown"
|
43
|
+
warn("Shutting down Ruby LSP...")
|
44
|
+
|
45
|
+
# Close the queue so that we can no longer receive items
|
46
|
+
@job_queue.close
|
47
|
+
# Clear any remaining jobs so that the thread can terminate
|
48
|
+
@job_queue.clear
|
49
|
+
@jobs.clear
|
50
|
+
# Wait until the thread is finished
|
51
|
+
@worker.join
|
52
|
+
@store.clear
|
53
|
+
|
54
|
+
finalize_request(Result.new(response: nil, notifications: []), request)
|
55
|
+
when "exit"
|
56
|
+
# We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
|
57
|
+
# https://microsoft.github.io/language-server-protocol/specification/#exit
|
58
|
+
status = @store.empty? ? 0 : 1
|
59
|
+
exit(status)
|
60
|
+
else
|
61
|
+
# Default case: push the request to the queue to be executed by the worker
|
62
|
+
job = Job.new(request: request, cancelled: false)
|
63
|
+
|
64
|
+
# Remember a handle to the job, so that we can cancel it
|
65
|
+
@mutex.synchronize { @jobs[request[:id]] = job }
|
66
|
+
@job_queue << job
|
67
|
+
end
|
64
68
|
end
|
65
|
-
|
66
|
-
Interface::InitializeResult.new(
|
67
|
-
capabilities: Interface::ServerCapabilities.new(
|
68
|
-
text_document_sync: Interface::TextDocumentSyncOptions.new(
|
69
|
-
change: Constant::TextDocumentSyncKind::INCREMENTAL,
|
70
|
-
open_close: true,
|
71
|
-
),
|
72
|
-
selection_range_provider: enabled_features.include?("selectionRanges"),
|
73
|
-
hover_provider: hover_provider,
|
74
|
-
document_symbol_provider: document_symbol_provider,
|
75
|
-
document_link_provider: document_link_provider,
|
76
|
-
folding_range_provider: folding_ranges_provider,
|
77
|
-
semantic_tokens_provider: semantic_tokens_provider,
|
78
|
-
document_formatting_provider: enabled_features.include?("formatting"),
|
79
|
-
document_highlight_provider: enabled_features.include?("documentHighlights"),
|
80
|
-
code_action_provider: enabled_features.include?("codeActions"),
|
81
|
-
document_on_type_formatting_provider: on_type_formatting_provider,
|
82
|
-
diagnostic_provider: diagnostics_provider,
|
83
|
-
inlay_hint_provider: inlay_hint_provider,
|
84
|
-
),
|
85
|
-
)
|
86
69
|
end
|
87
70
|
|
88
|
-
|
89
|
-
uri = request.dig(:params, :textDocument, :uri)
|
90
|
-
store.push_edits(uri, request.dig(:params, :contentChanges))
|
91
|
-
|
92
|
-
Handler::VOID
|
93
|
-
end
|
94
|
-
|
95
|
-
on("textDocument/didOpen") do |request|
|
96
|
-
uri = request.dig(:params, :textDocument, :uri)
|
97
|
-
text = request.dig(:params, :textDocument, :text)
|
98
|
-
store.set(uri, text)
|
99
|
-
|
100
|
-
Handler::VOID
|
101
|
-
end
|
102
|
-
|
103
|
-
on("textDocument/didClose") do |request|
|
104
|
-
uri = request.dig(:params, :textDocument, :uri)
|
105
|
-
store.delete(uri)
|
106
|
-
clear_diagnostics(uri)
|
71
|
+
private
|
107
72
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
on("textDocument/documentLink", parallel: true) do |request|
|
118
|
-
uri = request.dig(:params, :textDocument, :uri)
|
119
|
-
store.cache_fetch(uri, :document_link) do |document|
|
120
|
-
RubyLsp::Requests::DocumentLink.new(uri, document).run
|
121
|
-
end
|
122
|
-
end
|
73
|
+
sig { returns(Thread) }
|
74
|
+
def new_worker
|
75
|
+
Thread.new do
|
76
|
+
# Thread::Queue#pop is thread safe and will wait until an item is available
|
77
|
+
loop do
|
78
|
+
job = T.let(@job_queue.pop, T.nilable(Job))
|
79
|
+
# The only time when the job is nil is when the queue is closed and we can then terminate the thread
|
80
|
+
break if job.nil?
|
123
81
|
|
124
|
-
|
125
|
-
|
126
|
-
document = store.get(request.dig(:params, :textDocument, :uri))
|
82
|
+
request = job.request
|
83
|
+
@mutex.synchronize { @jobs.delete(request[:id]) }
|
127
84
|
|
128
|
-
|
129
|
-
|
85
|
+
result = if job.cancelled
|
86
|
+
# We need to return nil to the client even if the request was cancelled
|
87
|
+
Result.new(response: nil, notifications: [])
|
88
|
+
else
|
89
|
+
Executor.new(@store).execute(request)
|
90
|
+
end
|
130
91
|
|
131
|
-
|
132
|
-
|
133
|
-
Requests::FoldingRanges.new(document).run
|
92
|
+
finalize_request(result, request)
|
93
|
+
end
|
134
94
|
end
|
135
95
|
end
|
136
96
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
97
|
+
# Finalize a Queue::Result. All IO operations should happen here to avoid any issues with cancelling requests
|
98
|
+
sig { params(result: Result, request: T::Hash[Symbol, T.untyped]).void }
|
99
|
+
def finalize_request(result, request)
|
100
|
+
@mutex.synchronize do
|
101
|
+
error = result.error
|
102
|
+
response = result.response
|
103
|
+
|
104
|
+
# If the response include any notifications, go through them and publish each one
|
105
|
+
result.notifications.each { |n| @writer.write(method: n.message, params: n.params) }
|
106
|
+
|
107
|
+
if error
|
108
|
+
@writer.write(
|
109
|
+
id: request[:id],
|
110
|
+
error: {
|
111
|
+
code: Constant::ErrorCodes::INTERNAL_ERROR,
|
112
|
+
message: error.inspect,
|
113
|
+
data: request.to_json,
|
114
|
+
},
|
115
|
+
)
|
116
|
+
elsif response != VOID
|
117
|
+
@writer.write(id: request[:id], result: response)
|
155
118
|
end
|
156
|
-
end
|
157
|
-
end
|
158
119
|
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
document,
|
164
|
-
encoder: Requests::Support::SemanticTokenEncoder.new,
|
165
|
-
).run,
|
166
|
-
LanguageServer::Protocol::Interface::SemanticTokens,
|
167
|
-
)
|
120
|
+
request_time = result.request_time
|
121
|
+
if request_time
|
122
|
+
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
|
123
|
+
end
|
168
124
|
end
|
169
125
|
end
|
170
126
|
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
Requests::SemanticHighlighting.new(
|
178
|
-
document,
|
179
|
-
range: start_line..end_line,
|
180
|
-
encoder: Requests::Support::SemanticTokenEncoder.new,
|
181
|
-
).run
|
127
|
+
sig do
|
128
|
+
params(
|
129
|
+
request: T::Hash[Symbol, T.untyped],
|
130
|
+
request_time: Float,
|
131
|
+
error: T.nilable(Exception),
|
132
|
+
).returns(T::Hash[Symbol, T.any(String, Float)])
|
182
133
|
end
|
183
|
-
|
184
|
-
on("textDocument/formatting", parallel: true) do |request|
|
134
|
+
def telemetry_params(request, request_time, error)
|
185
135
|
uri = request.dig(:params, :textDocument, :uri)
|
136
|
+
params = {
|
137
|
+
request: request[:method],
|
138
|
+
lspVersion: RubyLsp::VERSION,
|
139
|
+
requestTime: request_time,
|
140
|
+
}
|
186
141
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
end
|
191
|
-
|
192
|
-
on("textDocument/onTypeFormatting", parallel: true) do |request|
|
193
|
-
uri = request.dig(:params, :textDocument, :uri)
|
194
|
-
position = request.dig(:params, :position)
|
195
|
-
character = request.dig(:params, :ch)
|
142
|
+
if error
|
143
|
+
params[:errorClass] = error.class.name
|
144
|
+
params[:errorMessage] = error.message
|
196
145
|
|
197
|
-
|
198
|
-
|
146
|
+
log_params = request[:params]
|
147
|
+
params[:params] = log_params.reject { |k, _| k == :textDocument }.to_json if log_params
|
199
148
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
Requests::DocumentHighlight.new(document, request.dig(:params, :position)).run
|
204
|
-
end
|
205
|
-
|
206
|
-
on("textDocument/codeAction", parallel: true) do |request|
|
207
|
-
uri = request.dig(:params, :textDocument, :uri)
|
208
|
-
document = store.get(uri)
|
209
|
-
range = request.dig(:params, :range)
|
210
|
-
start_line = range.dig(:start, :line)
|
211
|
-
end_line = range.dig(:end, :line)
|
212
|
-
|
213
|
-
Requests::CodeActions.new(uri, document, start_line..end_line).run
|
214
|
-
end
|
215
|
-
|
216
|
-
on("textDocument/inlayHint", parallel: true) do |request|
|
217
|
-
document = store.get(request.dig(:params, :textDocument, :uri))
|
218
|
-
range = request.dig(:params, :range)
|
219
|
-
start_line = range.dig(:start, :line)
|
220
|
-
end_line = range.dig(:end, :line)
|
221
|
-
|
222
|
-
Requests::InlayHints.new(document, start_line..end_line).run
|
223
|
-
end
|
224
|
-
|
225
|
-
on("$/cancelRequest") do |request|
|
226
|
-
cancel_request(request[:params][:id])
|
227
|
-
Handler::VOID
|
228
|
-
end
|
229
|
-
|
230
|
-
on("textDocument/diagnostic", parallel: true) do |request|
|
231
|
-
uri = request.dig(:params, :textDocument, :uri)
|
232
|
-
response = store.cache_fetch(uri, :diagnostics) do |document|
|
233
|
-
Requests::Diagnostics.new(uri, document).run
|
149
|
+
backtrace = error.backtrace
|
150
|
+
params[:backtrace] = backtrace.map { |bt| bt.sub(/^#{Dir.home}/, "~") }.join("\n") if backtrace
|
234
151
|
end
|
235
152
|
|
236
|
-
|
237
|
-
|
238
|
-
show_message(Constant::MessageType::ERROR, "Error running diagnostics: #{error.message}")
|
239
|
-
end
|
240
|
-
|
241
|
-
on("shutdown") { shutdown }
|
242
|
-
|
243
|
-
on("exit") do
|
244
|
-
# We return zero if shutdown has already been received or one otherwise as per the recommendation in the spec
|
245
|
-
# https://microsoft.github.io/language-server-protocol/specification/#exit
|
246
|
-
status = store.empty? ? 0 : 1
|
247
|
-
exit(status)
|
153
|
+
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
154
|
+
params
|
248
155
|
end
|
249
156
|
end
|
250
157
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# typed: strict
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module RubyLsp
|
5
|
+
# Used to indicate that a request shouldn't return a response
|
6
|
+
VOID = T.let(Object.new.freeze, Object)
|
7
|
+
|
8
|
+
# A notification to be sent to the client
|
9
|
+
class Notification
|
10
|
+
extend T::Sig
|
11
|
+
|
12
|
+
sig { returns(String) }
|
13
|
+
attr_reader :message
|
14
|
+
|
15
|
+
sig { returns(Object) }
|
16
|
+
attr_reader :params
|
17
|
+
|
18
|
+
sig { params(message: String, params: Object).void }
|
19
|
+
def initialize(message:, params:)
|
20
|
+
@message = message
|
21
|
+
@params = params
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# The final result of running a request before its IO is finalized
|
26
|
+
class Result
|
27
|
+
extend T::Sig
|
28
|
+
|
29
|
+
sig { returns(T.untyped) }
|
30
|
+
attr_reader :response
|
31
|
+
|
32
|
+
sig { returns(T::Array[Notification]) }
|
33
|
+
attr_reader :notifications
|
34
|
+
|
35
|
+
sig { returns(T.nilable(Exception)) }
|
36
|
+
attr_reader :error
|
37
|
+
|
38
|
+
sig { returns(T.nilable(Float)) }
|
39
|
+
attr_reader :request_time
|
40
|
+
|
41
|
+
sig do
|
42
|
+
params(
|
43
|
+
response: T.untyped,
|
44
|
+
notifications: T::Array[Notification],
|
45
|
+
error: T.nilable(Exception),
|
46
|
+
request_time: T.nilable(Float),
|
47
|
+
).void
|
48
|
+
end
|
49
|
+
def initialize(response:, notifications:, error: nil, request_time: nil)
|
50
|
+
@response = response
|
51
|
+
@notifications = notifications
|
52
|
+
@error = error
|
53
|
+
@request_time = request_time
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# A request that will sit in the queue until it's executed
|
58
|
+
class Job
|
59
|
+
extend T::Sig
|
60
|
+
|
61
|
+
sig { returns(T::Hash[Symbol, T.untyped]) }
|
62
|
+
attr_reader :request
|
63
|
+
|
64
|
+
sig { returns(T::Boolean) }
|
65
|
+
attr_reader :cancelled
|
66
|
+
|
67
|
+
sig { params(request: T::Hash[Symbol, T.untyped], cancelled: T::Boolean).void }
|
68
|
+
def initialize(request:, cancelled:)
|
69
|
+
@request = request
|
70
|
+
@cancelled = cancelled
|
71
|
+
end
|
72
|
+
|
73
|
+
sig { void }
|
74
|
+
def cancel
|
75
|
+
@cancelled = true
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
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.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|
@@ -44,20 +44,20 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '6'
|
48
48
|
- - "<"
|
49
49
|
- !ruby/object:Gem::Version
|
50
|
-
version: '
|
50
|
+
version: '7'
|
51
51
|
type: :runtime
|
52
52
|
prerelease: false
|
53
53
|
version_requirements: !ruby/object:Gem::Requirement
|
54
54
|
requirements:
|
55
55
|
- - ">="
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
57
|
+
version: '6'
|
58
58
|
- - "<"
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '7'
|
61
61
|
description: An opinionated language server for Ruby
|
62
62
|
email:
|
63
63
|
- ruby@shopify.com
|
@@ -72,9 +72,8 @@ files:
|
|
72
72
|
- exe/ruby-lsp
|
73
73
|
- lib/ruby-lsp.rb
|
74
74
|
- lib/ruby_lsp/document.rb
|
75
|
-
- lib/ruby_lsp/
|
75
|
+
- lib/ruby_lsp/executor.rb
|
76
76
|
- lib/ruby_lsp/internal.rb
|
77
|
-
- lib/ruby_lsp/queue.rb
|
78
77
|
- lib/ruby_lsp/requests.rb
|
79
78
|
- lib/ruby_lsp/requests/base_request.rb
|
80
79
|
- lib/ruby_lsp/requests/code_actions.rb
|
@@ -87,9 +86,12 @@ files:
|
|
87
86
|
- lib/ruby_lsp/requests/hover.rb
|
88
87
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
89
88
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
89
|
+
- lib/ruby_lsp/requests/path_completion.rb
|
90
90
|
- lib/ruby_lsp/requests/selection_ranges.rb
|
91
91
|
- lib/ruby_lsp/requests/semantic_highlighting.rb
|
92
|
+
- lib/ruby_lsp/requests/support/annotation.rb
|
92
93
|
- lib/ruby_lsp/requests/support/highlight_target.rb
|
94
|
+
- lib/ruby_lsp/requests/support/prefix_tree.rb
|
93
95
|
- lib/ruby_lsp/requests/support/rails_document_client.rb
|
94
96
|
- lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
|
95
97
|
- lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
|
@@ -97,10 +99,11 @@ files:
|
|
97
99
|
- lib/ruby_lsp/requests/support/rubocop_runner.rb
|
98
100
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
99
101
|
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
102
|
+
- lib/ruby_lsp/requests/support/sorbet.rb
|
100
103
|
- lib/ruby_lsp/requests/support/source_uri.rb
|
101
|
-
- lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb
|
102
104
|
- lib/ruby_lsp/server.rb
|
103
105
|
- lib/ruby_lsp/store.rb
|
106
|
+
- lib/ruby_lsp/utils.rb
|
104
107
|
homepage: https://github.com/Shopify/ruby-lsp
|
105
108
|
licenses:
|
106
109
|
- MIT
|
data/lib/ruby_lsp/handler.rb
DELETED
@@ -1,118 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "ruby_lsp/requests"
|
5
|
-
require "ruby_lsp/store"
|
6
|
-
require "ruby_lsp/queue"
|
7
|
-
|
8
|
-
module RubyLsp
|
9
|
-
Interface = LanguageServer::Protocol::Interface
|
10
|
-
Constant = LanguageServer::Protocol::Constant
|
11
|
-
Transport = LanguageServer::Protocol::Transport
|
12
|
-
|
13
|
-
class Handler
|
14
|
-
extend T::Sig
|
15
|
-
VOID = T.let(Object.new.freeze, Object)
|
16
|
-
|
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
|
46
|
-
end
|
47
|
-
|
48
|
-
sig { returns(Store) }
|
49
|
-
attr_reader :store
|
50
|
-
|
51
|
-
sig { void }
|
52
|
-
def initialize
|
53
|
-
@writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
|
54
|
-
@reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
|
55
|
-
@handlers = T.let({}, T::Hash[String, RequestHandler])
|
56
|
-
@store = T.let(Store.new, Store)
|
57
|
-
@queue = T.let(Queue.new(@writer, @handlers), Queue)
|
58
|
-
end
|
59
|
-
|
60
|
-
sig { void }
|
61
|
-
def start
|
62
|
-
warn("Starting Ruby LSP...")
|
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
|
75
|
-
end
|
76
|
-
|
77
|
-
private
|
78
|
-
|
79
|
-
sig { params(id: T.any(String, Integer)).void }
|
80
|
-
def cancel_request(id)
|
81
|
-
@queue.cancel(id)
|
82
|
-
end
|
83
|
-
|
84
|
-
sig do
|
85
|
-
params(
|
86
|
-
msg: String,
|
87
|
-
parallel: T::Boolean,
|
88
|
-
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped),
|
89
|
-
).returns(RequestHandler)
|
90
|
-
end
|
91
|
-
def on(msg, parallel: false, &blk)
|
92
|
-
@handlers[msg] = RequestHandler.new(action: blk, parallel: parallel)
|
93
|
-
end
|
94
|
-
|
95
|
-
sig { void }
|
96
|
-
def shutdown
|
97
|
-
warn("Shutting down Ruby LSP...")
|
98
|
-
@queue.shutdown
|
99
|
-
store.clear
|
100
|
-
end
|
101
|
-
|
102
|
-
sig { params(uri: String).void }
|
103
|
-
def clear_diagnostics(uri)
|
104
|
-
@writer.write(
|
105
|
-
method: "textDocument/publishDiagnostics",
|
106
|
-
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: []),
|
107
|
-
)
|
108
|
-
end
|
109
|
-
|
110
|
-
sig { params(type: Integer, message: String).void }
|
111
|
-
def show_message(type, message)
|
112
|
-
@writer.write(
|
113
|
-
method: "window/showMessage",
|
114
|
-
params: Interface::ShowMessageParams.new(type: type, message: message),
|
115
|
-
)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|