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/queue.rb
DELETED
@@ -1,182 +0,0 @@
|
|
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: 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, 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
|
-
|
171
|
-
log_params = request[:params]&.reject { |k, _| k == :textDocument }
|
172
|
-
params[:params] = log_params.to_json if log_params&.any?
|
173
|
-
|
174
|
-
backtrace = error.backtrace
|
175
|
-
params[:backtrace] = backtrace.map { |bt| bt.sub(/^#{Dir.home}/, "~") }.join("\n") if backtrace
|
176
|
-
end
|
177
|
-
|
178
|
-
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
179
|
-
params
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
module Requests
|
6
|
-
module Support
|
7
|
-
class SyntaxErrorDiagnostic
|
8
|
-
extend T::Sig
|
9
|
-
|
10
|
-
sig { params(edit: Document::EditShape).void }
|
11
|
-
def initialize(edit)
|
12
|
-
@edit = edit
|
13
|
-
end
|
14
|
-
|
15
|
-
sig { returns(FalseClass) }
|
16
|
-
def correctable?
|
17
|
-
false
|
18
|
-
end
|
19
|
-
|
20
|
-
sig { returns(LanguageServer::Protocol::Interface::Diagnostic) }
|
21
|
-
def to_lsp_diagnostic
|
22
|
-
LanguageServer::Protocol::Interface::Diagnostic.new(
|
23
|
-
message: "Syntax error",
|
24
|
-
source: "SyntaxTree",
|
25
|
-
severity: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
|
26
|
-
range: @edit[:range],
|
27
|
-
)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|