ruby-lsp 0.0.3 → 0.2.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/.github/workflows/ci.yml +6 -0
- data/.rubocop.yml +25 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +10 -6
- data/Gemfile.lock +63 -16
- data/README.md +41 -0
- data/Rakefile +8 -1
- data/VERSION +1 -1
- data/bin/console +19 -0
- data/bin/tapioca +29 -0
- data/dev.yml +3 -0
- data/exe/ruby-lsp +19 -4
- data/lib/ruby-lsp.rb +2 -1
- data/lib/ruby_lsp/cli.rb +13 -5
- data/lib/ruby_lsp/document.rb +43 -14
- data/lib/ruby_lsp/handler.rb +107 -37
- data/lib/ruby_lsp/internal.rb +7 -0
- data/lib/ruby_lsp/requests/base_request.rb +18 -5
- data/lib/ruby_lsp/requests/code_actions.rb +20 -8
- data/lib/ruby_lsp/requests/diagnostics.rb +25 -7
- data/lib/ruby_lsp/requests/document_highlight.rb +113 -0
- data/lib/ruby_lsp/requests/document_symbol.rb +56 -16
- data/lib/ruby_lsp/requests/folding_ranges.rb +70 -34
- data/lib/ruby_lsp/requests/formatting.rb +24 -14
- data/lib/ruby_lsp/requests/selection_ranges.rb +18 -4
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +187 -34
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +16 -3
- data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +61 -0
- data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +50 -0
- data/lib/ruby_lsp/requests/support/selection_range.rb +4 -0
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +24 -3
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +6 -0
- data/lib/ruby_lsp/requests.rb +13 -1
- data/lib/ruby_lsp/store.rb +20 -3
- data/rakelib/check_docs.rake +34 -6
- data/ruby-lsp.gemspec +7 -5
- data/sorbet/config +4 -0
- data/sorbet/rbi/.rubocop.yml +8 -0
- data/sorbet/rbi/gems/ansi@1.5.0.rbi +338 -0
- data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
- data/sorbet/rbi/gems/builder@3.2.4.rbi +418 -0
- data/sorbet/rbi/gems/coderay@1.1.3.rbi +8 -0
- data/sorbet/rbi/gems/debug@1.5.0.rbi +1273 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +867 -0
- data/sorbet/rbi/gems/io-console@0.5.11.rbi +8 -0
- data/sorbet/rbi/gems/irb@1.4.1.rbi +376 -0
- data/sorbet/rbi/gems/language_server-protocol@3.16.0.3.rbi +7325 -0
- data/sorbet/rbi/gems/method_source@1.0.0.rbi +8 -0
- data/sorbet/rbi/gems/minitest-reporters@1.5.0.rbi +612 -0
- data/sorbet/rbi/gems/minitest@5.15.0.rbi +994 -0
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
- data/sorbet/rbi/gems/parser@3.1.2.0.rbi +3968 -0
- data/sorbet/rbi/gems/prettier_print@0.1.0.rbi +734 -0
- data/sorbet/rbi/gems/pry@0.14.1.rbi +8 -0
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
- data/sorbet/rbi/gems/rake@13.0.6.rbi +1853 -0
- data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
- data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1854 -0
- data/sorbet/rbi/gems/reline@0.3.1.rbi +1274 -0
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
- data/sorbet/rbi/gems/rubocop-ast@1.18.0.rbi +4180 -0
- data/sorbet/rbi/gems/rubocop-minitest@0.20.0.rbi +1369 -0
- data/sorbet/rbi/gems/rubocop-rake@0.6.0.rbi +246 -0
- data/sorbet/rbi/gems/rubocop-shopify@2.6.0.rbi +8 -0
- data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +652 -0
- data/sorbet/rbi/gems/rubocop@1.30.0.rbi +36729 -0
- data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
- data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
- data/sorbet/rbi/gems/syntax_tree@2.7.1.rbi +6777 -0
- data/sorbet/rbi/gems/tapioca@0.8.1.rbi +1972 -0
- data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
- data/sorbet/rbi/gems/unicode-display_width@2.1.0.rbi +27 -0
- data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +1779 -0
- data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +289 -0
- data/sorbet/rbi/gems/yard@0.9.27.rbi +13048 -0
- data/sorbet/rbi/shims/fiddle.rbi +4 -0
- data/sorbet/rbi/shims/hash.rbi +6 -0
- data/sorbet/rbi/shims/rdoc.rbi +4 -0
- data/sorbet/tapioca/config.yml +13 -0
- data/sorbet/tapioca/require.rb +7 -0
- metadata +62 -13
- data/lib/ruby_lsp/requests/rubocop_request.rb +0 -49
- data/shipit.production.yml +0 -1
data/lib/ruby_lsp/handler.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "ruby_lsp/requests"
|
|
@@ -6,51 +7,84 @@ require "benchmark"
|
|
|
6
7
|
|
|
7
8
|
module RubyLsp
|
|
8
9
|
class Handler
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"$/cancelRequest",
|
|
12
|
-
].freeze
|
|
10
|
+
extend T::Sig
|
|
11
|
+
VOID = T.let(Object.new.freeze, Object)
|
|
13
12
|
|
|
13
|
+
sig { returns(Store) }
|
|
14
14
|
attr_reader :store
|
|
15
15
|
|
|
16
16
|
Interface = LanguageServer::Protocol::Interface
|
|
17
17
|
Constant = LanguageServer::Protocol::Constant
|
|
18
18
|
Transport = LanguageServer::Protocol::Transport
|
|
19
19
|
|
|
20
|
+
sig { void }
|
|
20
21
|
def initialize
|
|
21
|
-
@writer = Transport::Stdio::Writer.new
|
|
22
|
-
@reader = Transport::Stdio::Reader.new
|
|
23
|
-
@handlers = {}
|
|
24
|
-
@store = Store.new
|
|
22
|
+
@writer = T.let(Transport::Stdio::Writer.new, Transport::Stdio::Writer)
|
|
23
|
+
@reader = T.let(Transport::Stdio::Reader.new, Transport::Stdio::Reader)
|
|
24
|
+
@handlers = T.let({}, T::Hash[String, T.proc.params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)])
|
|
25
|
+
@store = T.let(Store.new, Store)
|
|
25
26
|
end
|
|
26
27
|
|
|
28
|
+
sig { void }
|
|
27
29
|
def start
|
|
28
30
|
$stderr.puts "Starting Ruby LSP..."
|
|
29
|
-
@reader.read
|
|
30
|
-
with_telemetry(request) { handle(request) }
|
|
31
|
-
end
|
|
31
|
+
@reader.read { |request| handle(request) }
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
+
sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
|
|
34
35
|
def config(&blk)
|
|
35
36
|
instance_exec(&blk)
|
|
36
37
|
end
|
|
37
38
|
|
|
38
39
|
private
|
|
39
40
|
|
|
41
|
+
sig do
|
|
42
|
+
params(
|
|
43
|
+
msg: String,
|
|
44
|
+
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
|
45
|
+
).void
|
|
46
|
+
end
|
|
40
47
|
def on(msg, &blk)
|
|
41
|
-
@handlers[msg
|
|
48
|
+
@handlers[msg] = blk
|
|
42
49
|
end
|
|
43
50
|
|
|
51
|
+
sig { params(request: T::Hash[Symbol, T.untyped]).void }
|
|
44
52
|
def handle(request)
|
|
45
|
-
result =
|
|
46
|
-
|
|
53
|
+
result = T.let(nil, T.untyped)
|
|
54
|
+
error = T.let(nil, T.nilable(StandardError))
|
|
55
|
+
handler = @handlers[request[:method]]
|
|
56
|
+
|
|
57
|
+
request_time = Benchmark.realtime do
|
|
58
|
+
if handler
|
|
59
|
+
begin
|
|
60
|
+
result = handler.call(request)
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
error = e
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
if error
|
|
66
|
+
@writer.write(
|
|
67
|
+
{
|
|
68
|
+
id: request[:id],
|
|
69
|
+
error: { code: Constant::ErrorCodes::INTERNAL_ERROR, message: error.inspect, data: request.to_json },
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
elsif result != VOID
|
|
73
|
+
@writer.write(id: request[:id], result: result)
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
|
|
47
79
|
end
|
|
48
80
|
|
|
81
|
+
sig { void }
|
|
49
82
|
def shutdown
|
|
50
83
|
$stderr.puts "Shutting down Ruby LSP..."
|
|
51
84
|
store.clear
|
|
52
85
|
end
|
|
53
86
|
|
|
87
|
+
sig { params(enabled_features: T::Array[String]).returns(Interface::InitializeResult) }
|
|
54
88
|
def respond_with_capabilities(enabled_features)
|
|
55
89
|
document_symbol_provider = if enabled_features.include?("documentSymbols")
|
|
56
90
|
Interface::DocumentSymbolClientCapabilities.new(
|
|
@@ -69,8 +103,8 @@ module RubyLsp
|
|
|
69
103
|
Interface::SemanticTokensRegistrationOptions.new(
|
|
70
104
|
document_selector: { scheme: "file", language: "ruby" },
|
|
71
105
|
legend: Interface::SemanticTokensLegend.new(
|
|
72
|
-
token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
|
|
73
|
-
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS
|
|
106
|
+
token_types: Requests::SemanticHighlighting::TOKEN_TYPES.keys,
|
|
107
|
+
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys
|
|
74
108
|
),
|
|
75
109
|
range: false,
|
|
76
110
|
full: {
|
|
@@ -90,26 +124,35 @@ module RubyLsp
|
|
|
90
124
|
folding_range_provider: folding_ranges_provider,
|
|
91
125
|
semantic_tokens_provider: semantic_tokens_provider,
|
|
92
126
|
document_formatting_provider: enabled_features.include?("formatting"),
|
|
127
|
+
document_highlight_provider: enabled_features.include?("documentHighlights"),
|
|
93
128
|
code_action_provider: enabled_features.include?("codeActions")
|
|
94
129
|
)
|
|
95
130
|
)
|
|
96
131
|
end
|
|
97
132
|
|
|
133
|
+
sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
|
|
98
134
|
def respond_with_document_symbol(uri)
|
|
99
135
|
store.cache_fetch(uri, :document_symbol) do |document|
|
|
100
|
-
RubyLsp::Requests::DocumentSymbol.
|
|
136
|
+
RubyLsp::Requests::DocumentSymbol.new(document).run
|
|
101
137
|
end
|
|
102
138
|
end
|
|
103
139
|
|
|
140
|
+
sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
|
|
104
141
|
def respond_with_folding_ranges(uri)
|
|
105
142
|
store.cache_fetch(uri, :folding_ranges) do |document|
|
|
106
|
-
Requests::FoldingRanges.
|
|
143
|
+
Requests::FoldingRanges.new(document).run
|
|
107
144
|
end
|
|
108
145
|
end
|
|
109
146
|
|
|
147
|
+
sig do
|
|
148
|
+
params(
|
|
149
|
+
uri: String,
|
|
150
|
+
positions: T::Array[Document::PositionShape]
|
|
151
|
+
).returns(T::Array[T.nilable(RubyLsp::Requests::Support::SelectionRange)])
|
|
152
|
+
end
|
|
110
153
|
def respond_with_selection_ranges(uri, positions)
|
|
111
154
|
ranges = store.cache_fetch(uri, :selection_ranges) do |document|
|
|
112
|
-
Requests::SelectionRanges.
|
|
155
|
+
Requests::SelectionRanges.new(document).run
|
|
113
156
|
end
|
|
114
157
|
|
|
115
158
|
# Per the selection range request spec (https://microsoft.github.io/language-server-protocol/specification#textDocument_selectionRange),
|
|
@@ -123,19 +166,25 @@ module RubyLsp
|
|
|
123
166
|
end
|
|
124
167
|
end
|
|
125
168
|
|
|
169
|
+
sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
|
|
126
170
|
def respond_with_semantic_highlighting(uri)
|
|
127
171
|
store.cache_fetch(uri, :semantic_highlighting) do |document|
|
|
128
|
-
|
|
172
|
+
T.cast(
|
|
173
|
+
Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run,
|
|
174
|
+
LanguageServer::Protocol::Interface::SemanticTokens
|
|
175
|
+
)
|
|
129
176
|
end
|
|
130
177
|
end
|
|
131
178
|
|
|
179
|
+
sig { params(uri: String).returns(T.nilable(T::Array[LanguageServer::Protocol::Interface::TextEdit])) }
|
|
132
180
|
def respond_with_formatting(uri)
|
|
133
|
-
Requests::Formatting.
|
|
181
|
+
Requests::Formatting.new(uri, store.get(uri)).run
|
|
134
182
|
end
|
|
135
183
|
|
|
184
|
+
sig { params(uri: String).void }
|
|
136
185
|
def send_diagnostics(uri)
|
|
137
186
|
response = store.cache_fetch(uri, :diagnostics) do |document|
|
|
138
|
-
Requests::Diagnostics.
|
|
187
|
+
Requests::Diagnostics.new(uri, document).run
|
|
139
188
|
end
|
|
140
189
|
|
|
141
190
|
@writer.write(
|
|
@@ -147,35 +196,56 @@ module RubyLsp
|
|
|
147
196
|
)
|
|
148
197
|
end
|
|
149
198
|
|
|
199
|
+
sig { params(uri: String).void }
|
|
200
|
+
def clear_diagnostics(uri)
|
|
201
|
+
@writer.write(
|
|
202
|
+
method: "textDocument/publishDiagnostics",
|
|
203
|
+
params: Interface::PublishDiagnosticsParams.new(uri: uri, diagnostics: [])
|
|
204
|
+
)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
sig do
|
|
208
|
+
params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::CodeAction])
|
|
209
|
+
end
|
|
150
210
|
def respond_with_code_actions(uri, range)
|
|
151
211
|
store.cache_fetch(uri, :code_actions) do |document|
|
|
152
|
-
Requests::CodeActions.
|
|
212
|
+
Requests::CodeActions.new(uri, document, range).run
|
|
153
213
|
end
|
|
154
214
|
end
|
|
155
215
|
|
|
156
|
-
|
|
157
|
-
|
|
216
|
+
sig do
|
|
217
|
+
params(
|
|
218
|
+
uri: String,
|
|
219
|
+
position: Document::PositionShape
|
|
220
|
+
).returns(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
|
|
221
|
+
end
|
|
222
|
+
def respond_with_document_highlight(uri, position)
|
|
223
|
+
Requests::DocumentHighlight.new(store.get(uri), position).run
|
|
158
224
|
end
|
|
159
225
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
226
|
+
sig do
|
|
227
|
+
params(
|
|
228
|
+
request: T::Hash[Symbol, T.untyped],
|
|
229
|
+
request_time: Float,
|
|
230
|
+
error: T.nilable(StandardError)
|
|
231
|
+
).returns(T::Hash[Symbol, T.any(String, Float)])
|
|
232
|
+
end
|
|
233
|
+
def telemetry_params(request, request_time, error)
|
|
234
|
+
uri = request.dig(:params, :textDocument, :uri)
|
|
167
235
|
|
|
168
236
|
params = {
|
|
169
237
|
request: request[:method],
|
|
170
|
-
requestTime: request_time,
|
|
171
238
|
lspVersion: RubyLsp::VERSION,
|
|
239
|
+
requestTime: request_time,
|
|
172
240
|
}
|
|
173
241
|
|
|
174
|
-
|
|
175
|
-
|
|
242
|
+
if error
|
|
243
|
+
params[:errorClass] = error.class.name
|
|
244
|
+
params[:errorMessage] = error.message
|
|
245
|
+
end
|
|
176
246
|
|
|
177
|
-
|
|
178
|
-
|
|
247
|
+
params[:uri] = uri.sub(%r{.*://#{Dir.home}}, "~") if uri
|
|
248
|
+
params
|
|
179
249
|
end
|
|
180
250
|
end
|
|
181
251
|
end
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
4
5
|
module Requests
|
|
5
6
|
# :nodoc:
|
|
6
7
|
class BaseRequest < SyntaxTree::Visitor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
extend T::Sig
|
|
9
|
+
extend T::Helpers
|
|
10
|
+
|
|
11
|
+
abstract!
|
|
10
12
|
|
|
13
|
+
sig { params(document: Document).void }
|
|
11
14
|
def initialize(document)
|
|
12
15
|
@document = document
|
|
13
16
|
|
|
14
17
|
super()
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
sig { abstract.returns(Object) }
|
|
21
|
+
def run; end
|
|
22
|
+
|
|
23
|
+
sig { params(node: SyntaxTree::Node).returns(LanguageServer::Protocol::Interface::Range) }
|
|
24
|
+
def range_from_syntax_tree_node(node)
|
|
25
|
+
loc = node.location
|
|
26
|
+
|
|
27
|
+
LanguageServer::Protocol::Interface::Range.new(
|
|
28
|
+
start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
|
|
29
|
+
character: loc.start_column),
|
|
30
|
+
end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
|
31
|
+
)
|
|
19
32
|
end
|
|
20
33
|
end
|
|
21
34
|
end
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
4
5
|
module Requests
|
|
6
|
+
# 
|
|
7
|
+
#
|
|
5
8
|
# The [code actions](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction)
|
|
6
9
|
# request informs the editor of RuboCop quick fixes that can be applied. These are accesible by hovering over a
|
|
7
10
|
# specific diagnostic.
|
|
@@ -13,23 +16,32 @@ module RubyLsp
|
|
|
13
16
|
# puts "Hello" # --> code action: quick fix indentation
|
|
14
17
|
# end
|
|
15
18
|
# ```
|
|
16
|
-
class CodeActions
|
|
17
|
-
|
|
18
|
-
new(uri, document, range).run
|
|
19
|
-
end
|
|
19
|
+
class CodeActions < BaseRequest
|
|
20
|
+
extend T::Sig
|
|
20
21
|
|
|
22
|
+
sig do
|
|
23
|
+
params(
|
|
24
|
+
uri: String,
|
|
25
|
+
document: Document,
|
|
26
|
+
range: T::Range[Integer]
|
|
27
|
+
).void
|
|
28
|
+
end
|
|
21
29
|
def initialize(uri, document, range)
|
|
22
|
-
|
|
30
|
+
super(document)
|
|
31
|
+
|
|
23
32
|
@uri = uri
|
|
24
33
|
@range = range
|
|
25
34
|
end
|
|
26
35
|
|
|
36
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::CodeAction], Object)) }
|
|
27
37
|
def run
|
|
28
|
-
diagnostics = Diagnostics.
|
|
29
|
-
corrections = diagnostics.select
|
|
38
|
+
diagnostics = Diagnostics.new(@uri, @document).run
|
|
39
|
+
corrections = diagnostics.select do |diagnostic|
|
|
40
|
+
diagnostic.correctable? && T.cast(diagnostic, Support::RuboCopDiagnostic).in_range?(@range)
|
|
41
|
+
end
|
|
30
42
|
return [] if corrections.empty?
|
|
31
43
|
|
|
32
|
-
corrections.map!(&:to_lsp_code_action)
|
|
44
|
+
T.cast(corrections, T::Array[Support::RuboCopDiagnostic]).map!(&:to_lsp_code_action)
|
|
33
45
|
end
|
|
34
46
|
end
|
|
35
47
|
end
|
|
@@ -1,7 +1,12 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
4
|
+
require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
|
|
5
|
+
|
|
3
6
|
module RubyLsp
|
|
4
7
|
module Requests
|
|
8
|
+
# 
|
|
9
|
+
#
|
|
5
10
|
# The
|
|
6
11
|
# [diagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics)
|
|
7
12
|
# request informs the editor of RuboCop offenses for a given file.
|
|
@@ -13,21 +18,34 @@ module RubyLsp
|
|
|
13
18
|
# puts "Hello" # --> diagnostics: incorrect indentantion
|
|
14
19
|
# end
|
|
15
20
|
# ```
|
|
16
|
-
class Diagnostics <
|
|
17
|
-
|
|
18
|
-
return syntax_error_diagnostics if @document.syntax_errors?
|
|
21
|
+
class Diagnostics < BaseRequest
|
|
22
|
+
extend T::Sig
|
|
19
23
|
|
|
20
|
-
|
|
24
|
+
sig { params(uri: String, document: Document).void }
|
|
25
|
+
def initialize(uri, document)
|
|
26
|
+
super(document)
|
|
21
27
|
|
|
22
|
-
@
|
|
28
|
+
@uri = uri
|
|
23
29
|
end
|
|
24
30
|
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
sig do
|
|
32
|
+
override.returns(
|
|
33
|
+
T.any(
|
|
34
|
+
T.all(T::Array[Support::RuboCopDiagnostic], Object),
|
|
35
|
+
T.all(T::Array[Support::SyntaxErrorDiagnostic], Object),
|
|
36
|
+
)
|
|
37
|
+
)
|
|
38
|
+
end
|
|
39
|
+
def run
|
|
40
|
+
return syntax_error_diagnostics if @document.syntax_errors?
|
|
41
|
+
return [] unless defined?(Support::RuboCopDiagnosticsRunner)
|
|
42
|
+
|
|
43
|
+
Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
|
|
27
44
|
end
|
|
28
45
|
|
|
29
46
|
private
|
|
30
47
|
|
|
48
|
+
sig { returns(T::Array[Support::SyntaxErrorDiagnostic]) }
|
|
31
49
|
def syntax_error_diagnostics
|
|
32
50
|
@document.syntax_error_edits.map { |e| Support::SyntaxErrorDiagnostic.new(e) }
|
|
33
51
|
end
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
# 
|
|
7
|
+
#
|
|
8
|
+
# The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
|
|
9
|
+
# informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
|
|
10
|
+
# the cursor is on the `F` of the constant `FOO`, the editor should identify other occurences of `FOO`
|
|
11
|
+
# and highlight them.
|
|
12
|
+
#
|
|
13
|
+
# For writable elements like constants or variables, their read/write occurrences should be highlighted differently.
|
|
14
|
+
# This is achieved by sending different "kind" attributes to the editor (2 for read and 3 for write).
|
|
15
|
+
#
|
|
16
|
+
# # Example
|
|
17
|
+
#
|
|
18
|
+
# ```ruby
|
|
19
|
+
# FOO = 1 # should be highlighted as "write"
|
|
20
|
+
#
|
|
21
|
+
# def foo
|
|
22
|
+
# FOO # should be highlighted as "read"
|
|
23
|
+
# end
|
|
24
|
+
# ```
|
|
25
|
+
class DocumentHighlight < BaseRequest
|
|
26
|
+
extend T::Sig
|
|
27
|
+
|
|
28
|
+
VarNodes = T.type_alias do
|
|
29
|
+
T.any(
|
|
30
|
+
SyntaxTree::GVar,
|
|
31
|
+
SyntaxTree::Ident,
|
|
32
|
+
SyntaxTree::IVar,
|
|
33
|
+
SyntaxTree::Const,
|
|
34
|
+
SyntaxTree::CVar
|
|
35
|
+
)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
sig { params(document: Document, position: Document::PositionShape).void }
|
|
39
|
+
def initialize(document, position)
|
|
40
|
+
@highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
|
|
41
|
+
position = Document::Scanner.new(document.source).find_position(position)
|
|
42
|
+
@target = T.let(find(document.tree, position), T.nilable(VarNodes))
|
|
43
|
+
|
|
44
|
+
super(document)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight], Object)) }
|
|
48
|
+
def run
|
|
49
|
+
# no @target means the target is not highlightable
|
|
50
|
+
return [] unless @target
|
|
51
|
+
|
|
52
|
+
visit(@document.tree)
|
|
53
|
+
@highlights
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
sig { params(node: SyntaxTree::VarField).void }
|
|
57
|
+
def visit_var_field(node)
|
|
58
|
+
if matches_target?(node.value)
|
|
59
|
+
add_highlight(
|
|
60
|
+
node.value,
|
|
61
|
+
LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
|
|
62
|
+
)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
super
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
sig { params(node: SyntaxTree::VarRef).void }
|
|
69
|
+
def visit_var_ref(node)
|
|
70
|
+
if matches_target?(node.value)
|
|
71
|
+
add_highlight(
|
|
72
|
+
node.value,
|
|
73
|
+
LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
|
|
74
|
+
)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
super
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
sig { params(node: SyntaxTree::Node, position: Integer).returns(T.nilable(VarNodes)) }
|
|
83
|
+
def find(node, position)
|
|
84
|
+
matched =
|
|
85
|
+
node.child_nodes.compact.bsearch do |child|
|
|
86
|
+
if (child.location.start_char...child.location.end_char).cover?(position)
|
|
87
|
+
0
|
|
88
|
+
else
|
|
89
|
+
position <=> child.location.start_char
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
case matched
|
|
94
|
+
when SyntaxTree::GVar, SyntaxTree::Ident, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar
|
|
95
|
+
matched
|
|
96
|
+
when SyntaxTree::Node
|
|
97
|
+
find(matched, position)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
sig { params(node: SyntaxTree::Node).returns(T::Boolean) }
|
|
102
|
+
def matches_target?(node)
|
|
103
|
+
node.is_a?(@target.class) && T.cast(node, VarNodes).value == T.must(@target).value
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
sig { params(node: SyntaxTree::Node, kind: Integer).void }
|
|
107
|
+
def add_highlight(node, kind)
|
|
108
|
+
range = range_from_syntax_tree_node(node)
|
|
109
|
+
@highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|