ruby-lsp 0.3.8 → 0.4.1
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/document.rb +5 -3
- data/lib/ruby_lsp/executor.rb +390 -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_action_resolve.rb +100 -0
- data/lib/ruby_lsp/requests/code_actions.rb +38 -8
- data/lib/ruby_lsp/requests/diagnostics.rb +7 -11
- data/lib/ruby_lsp/requests/formatting.rb +10 -5
- data/lib/ruby_lsp/requests/on_type_formatting.rb +33 -14
- data/lib/ruby_lsp/requests/path_completion.rb +95 -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 +7 -1
- data/lib/ruby_lsp/server.rb +129 -221
- data/lib/ruby_lsp/utils.rb +78 -0
- metadata +13 -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
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.1
|
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-22 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,11 +72,11 @@ 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
|
79
|
+
- lib/ruby_lsp/requests/code_action_resolve.rb
|
80
80
|
- lib/ruby_lsp/requests/code_actions.rb
|
81
81
|
- lib/ruby_lsp/requests/diagnostics.rb
|
82
82
|
- lib/ruby_lsp/requests/document_highlight.rb
|
@@ -87,9 +87,12 @@ files:
|
|
87
87
|
- lib/ruby_lsp/requests/hover.rb
|
88
88
|
- lib/ruby_lsp/requests/inlay_hints.rb
|
89
89
|
- lib/ruby_lsp/requests/on_type_formatting.rb
|
90
|
+
- lib/ruby_lsp/requests/path_completion.rb
|
90
91
|
- lib/ruby_lsp/requests/selection_ranges.rb
|
91
92
|
- lib/ruby_lsp/requests/semantic_highlighting.rb
|
93
|
+
- lib/ruby_lsp/requests/support/annotation.rb
|
92
94
|
- lib/ruby_lsp/requests/support/highlight_target.rb
|
95
|
+
- lib/ruby_lsp/requests/support/prefix_tree.rb
|
93
96
|
- lib/ruby_lsp/requests/support/rails_document_client.rb
|
94
97
|
- lib/ruby_lsp/requests/support/rubocop_diagnostic.rb
|
95
98
|
- lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb
|
@@ -97,10 +100,11 @@ files:
|
|
97
100
|
- lib/ruby_lsp/requests/support/rubocop_runner.rb
|
98
101
|
- lib/ruby_lsp/requests/support/selection_range.rb
|
99
102
|
- lib/ruby_lsp/requests/support/semantic_token_encoder.rb
|
103
|
+
- lib/ruby_lsp/requests/support/sorbet.rb
|
100
104
|
- lib/ruby_lsp/requests/support/source_uri.rb
|
101
|
-
- lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb
|
102
105
|
- lib/ruby_lsp/server.rb
|
103
106
|
- lib/ruby_lsp/store.rb
|
107
|
+
- lib/ruby_lsp/utils.rb
|
104
108
|
homepage: https://github.com/Shopify/ruby-lsp
|
105
109
|
licenses:
|
106
110
|
- 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
|
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
|