ruby-lsp 0.3.8 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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