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.
@@ -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