ruby-lsp 0.0.3 → 0.0.4
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 +16 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +8 -5
- data/Gemfile.lock +55 -10
- data/README.md +40 -0
- data/VERSION +1 -1
- data/bin/tapioca +29 -0
- data/dev.yml +3 -0
- data/exe/ruby-lsp +19 -4
- data/lib/internal.rb +7 -0
- data/lib/ruby-lsp.rb +1 -0
- data/lib/ruby_lsp/cli.rb +12 -5
- data/lib/ruby_lsp/document.rb +37 -14
- data/lib/ruby_lsp/handler.rb +78 -23
- data/lib/ruby_lsp/requests/base_request.rb +11 -0
- data/lib/ruby_lsp/requests/code_actions.rb +1 -0
- data/lib/ruby_lsp/requests/diagnostics.rb +1 -0
- data/lib/ruby_lsp/requests/document_highlight.rb +96 -0
- data/lib/ruby_lsp/requests/document_symbol.rb +1 -10
- data/lib/ruby_lsp/requests/folding_ranges.rb +3 -2
- data/lib/ruby_lsp/requests/formatting.rb +2 -1
- data/lib/ruby_lsp/requests/rubocop_request.rb +1 -0
- data/lib/ruby_lsp/requests/selection_ranges.rb +1 -0
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +17 -3
- data/lib/ruby_lsp/requests/support/rubocop_diagnostic.rb +1 -0
- data/lib/ruby_lsp/requests/support/selection_range.rb +1 -0
- data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +12 -1
- data/lib/ruby_lsp/requests/support/syntax_error_diagnostic.rb +1 -0
- data/lib/ruby_lsp/requests.rb +2 -0
- data/lib/ruby_lsp/store.rb +19 -3
- data/rakelib/check_docs.rake +4 -1
- data/ruby-lsp.gemspec +1 -0
- 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 +64 -2
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,24 +7,25 @@ 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
31
|
@reader.read do |request|
|
|
@@ -31,26 +33,39 @@ module RubyLsp
|
|
|
31
33
|
end
|
|
32
34
|
end
|
|
33
35
|
|
|
36
|
+
sig { params(blk: T.proc.bind(Handler).params(arg0: T.untyped).void).void }
|
|
34
37
|
def config(&blk)
|
|
35
38
|
instance_exec(&blk)
|
|
36
39
|
end
|
|
37
40
|
|
|
38
41
|
private
|
|
39
42
|
|
|
43
|
+
sig do
|
|
44
|
+
params(
|
|
45
|
+
msg: String,
|
|
46
|
+
blk: T.proc.bind(Handler).params(request: T::Hash[Symbol, T.untyped]).returns(T.untyped)
|
|
47
|
+
).void
|
|
48
|
+
end
|
|
40
49
|
def on(msg, &blk)
|
|
41
|
-
@handlers[msg
|
|
50
|
+
@handlers[msg] = blk
|
|
42
51
|
end
|
|
43
52
|
|
|
53
|
+
sig { params(request: T::Hash[Symbol, T.untyped]).void }
|
|
44
54
|
def handle(request)
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
handler = @handlers[request[:method]]
|
|
56
|
+
return unless handler
|
|
57
|
+
|
|
58
|
+
result = handler.call(request)
|
|
59
|
+
@writer.write(id: request[:id], result: result) unless result == VOID
|
|
47
60
|
end
|
|
48
61
|
|
|
62
|
+
sig { void }
|
|
49
63
|
def shutdown
|
|
50
64
|
$stderr.puts "Shutting down Ruby LSP..."
|
|
51
65
|
store.clear
|
|
52
66
|
end
|
|
53
67
|
|
|
68
|
+
sig { params(enabled_features: T::Array[String]).returns(Interface::InitializeResult) }
|
|
54
69
|
def respond_with_capabilities(enabled_features)
|
|
55
70
|
document_symbol_provider = if enabled_features.include?("documentSymbols")
|
|
56
71
|
Interface::DocumentSymbolClientCapabilities.new(
|
|
@@ -70,7 +85,7 @@ module RubyLsp
|
|
|
70
85
|
document_selector: { scheme: "file", language: "ruby" },
|
|
71
86
|
legend: Interface::SemanticTokensLegend.new(
|
|
72
87
|
token_types: Requests::SemanticHighlighting::TOKEN_TYPES,
|
|
73
|
-
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS
|
|
88
|
+
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys
|
|
74
89
|
),
|
|
75
90
|
range: false,
|
|
76
91
|
full: {
|
|
@@ -90,23 +105,32 @@ module RubyLsp
|
|
|
90
105
|
folding_range_provider: folding_ranges_provider,
|
|
91
106
|
semantic_tokens_provider: semantic_tokens_provider,
|
|
92
107
|
document_formatting_provider: enabled_features.include?("formatting"),
|
|
108
|
+
document_highlight_provider: enabled_features.include?("documentHighlights"),
|
|
93
109
|
code_action_provider: enabled_features.include?("codeActions")
|
|
94
110
|
)
|
|
95
111
|
)
|
|
96
112
|
end
|
|
97
113
|
|
|
114
|
+
sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
|
|
98
115
|
def respond_with_document_symbol(uri)
|
|
99
116
|
store.cache_fetch(uri, :document_symbol) do |document|
|
|
100
117
|
RubyLsp::Requests::DocumentSymbol.run(document)
|
|
101
118
|
end
|
|
102
119
|
end
|
|
103
120
|
|
|
121
|
+
sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::FoldingRange]) }
|
|
104
122
|
def respond_with_folding_ranges(uri)
|
|
105
123
|
store.cache_fetch(uri, :folding_ranges) do |document|
|
|
106
124
|
Requests::FoldingRanges.run(document)
|
|
107
125
|
end
|
|
108
126
|
end
|
|
109
127
|
|
|
128
|
+
sig do
|
|
129
|
+
params(
|
|
130
|
+
uri: String,
|
|
131
|
+
positions: T::Array[Document::PositionShape]
|
|
132
|
+
).returns(T::Array[RubyLsp::Requests::Support::SelectionRange])
|
|
133
|
+
end
|
|
110
134
|
def respond_with_selection_ranges(uri, positions)
|
|
111
135
|
ranges = store.cache_fetch(uri, :selection_ranges) do |document|
|
|
112
136
|
Requests::SelectionRanges.run(document)
|
|
@@ -123,16 +147,19 @@ module RubyLsp
|
|
|
123
147
|
end
|
|
124
148
|
end
|
|
125
149
|
|
|
150
|
+
sig { params(uri: String).returns(LanguageServer::Protocol::Interface::SemanticTokens) }
|
|
126
151
|
def respond_with_semantic_highlighting(uri)
|
|
127
152
|
store.cache_fetch(uri, :semantic_highlighting) do |document|
|
|
128
153
|
Requests::SemanticHighlighting.new(document, encoder: Requests::Support::SemanticTokenEncoder.new).run
|
|
129
154
|
end
|
|
130
155
|
end
|
|
131
156
|
|
|
157
|
+
sig { params(uri: String).returns(T::Array[LanguageServer::Protocol::Interface::TextEdit]) }
|
|
132
158
|
def respond_with_formatting(uri)
|
|
133
159
|
Requests::Formatting.run(uri, store.get(uri))
|
|
134
160
|
end
|
|
135
161
|
|
|
162
|
+
sig { params(uri: String).void }
|
|
136
163
|
def send_diagnostics(uri)
|
|
137
164
|
response = store.cache_fetch(uri, :diagnostics) do |document|
|
|
138
165
|
Requests::Diagnostics.run(uri, document)
|
|
@@ -147,35 +174,63 @@ module RubyLsp
|
|
|
147
174
|
)
|
|
148
175
|
end
|
|
149
176
|
|
|
177
|
+
sig do
|
|
178
|
+
params(uri: String, range: T::Range[Integer]).returns(T::Array[LanguageServer::Protocol::Interface::Diagnostic])
|
|
179
|
+
end
|
|
150
180
|
def respond_with_code_actions(uri, range)
|
|
151
181
|
store.cache_fetch(uri, :code_actions) do |document|
|
|
152
182
|
Requests::CodeActions.run(uri, document, range)
|
|
153
183
|
end
|
|
154
184
|
end
|
|
155
185
|
|
|
156
|
-
|
|
157
|
-
|
|
186
|
+
sig do
|
|
187
|
+
params(
|
|
188
|
+
uri: String,
|
|
189
|
+
position: Document::PositionShape
|
|
190
|
+
).returns(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
|
|
191
|
+
end
|
|
192
|
+
def respond_with_document_highlight(uri, position)
|
|
193
|
+
Requests::DocumentHighlight.run(store.get(uri), position)
|
|
158
194
|
end
|
|
159
195
|
|
|
160
|
-
|
|
161
|
-
|
|
196
|
+
sig { params(request: T::Hash[Symbol, T.untyped], block: T.proc.void).returns(T.untyped) }
|
|
197
|
+
def with_telemetry(request, &block)
|
|
198
|
+
result = T.let(nil, T.untyped)
|
|
199
|
+
error = T.let(nil, T.nilable(StandardError))
|
|
162
200
|
|
|
163
|
-
result = nil
|
|
164
201
|
request_time = Benchmark.realtime do
|
|
165
|
-
result =
|
|
202
|
+
result = block.call
|
|
203
|
+
rescue StandardError => e
|
|
204
|
+
error = e
|
|
166
205
|
end
|
|
167
206
|
|
|
207
|
+
@writer.write(method: "telemetry/event", params: telemetry_params(request, request_time, error))
|
|
208
|
+
result
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
sig do
|
|
212
|
+
params(
|
|
213
|
+
request: T::Hash[Symbol, T.untyped],
|
|
214
|
+
request_time: Float,
|
|
215
|
+
error: T.nilable(StandardError)
|
|
216
|
+
).returns(T::Hash[Symbol, T.any(String, Float)])
|
|
217
|
+
end
|
|
218
|
+
def telemetry_params(request, request_time, error)
|
|
219
|
+
uri = request.dig(:params, :textDocument, :uri)
|
|
220
|
+
|
|
168
221
|
params = {
|
|
169
222
|
request: request[:method],
|
|
170
|
-
requestTime: request_time,
|
|
171
223
|
lspVersion: RubyLsp::VERSION,
|
|
224
|
+
requestTime: request_time,
|
|
172
225
|
}
|
|
173
226
|
|
|
174
|
-
|
|
175
|
-
|
|
227
|
+
if error
|
|
228
|
+
params[:errorClass] = error.class.name
|
|
229
|
+
params[:errorMessage] = error.message
|
|
230
|
+
end
|
|
176
231
|
|
|
177
|
-
|
|
178
|
-
|
|
232
|
+
params[:uri] = uri if uri
|
|
233
|
+
params
|
|
179
234
|
end
|
|
180
235
|
end
|
|
181
236
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -17,6 +18,16 @@ module RubyLsp
|
|
|
17
18
|
def run
|
|
18
19
|
raise NotImplementedError, "#{self.class}#run must be implemented"
|
|
19
20
|
end
|
|
21
|
+
|
|
22
|
+
def range_from_syntax_tree_node(node)
|
|
23
|
+
loc = node.location
|
|
24
|
+
|
|
25
|
+
LanguageServer::Protocol::Interface::Range.new(
|
|
26
|
+
start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
|
|
27
|
+
character: loc.start_column),
|
|
28
|
+
end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
|
29
|
+
)
|
|
30
|
+
end
|
|
20
31
|
end
|
|
21
32
|
end
|
|
22
33
|
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# typed: true
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module RubyLsp
|
|
5
|
+
module Requests
|
|
6
|
+
# The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
|
|
7
|
+
# informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
|
|
8
|
+
# the cursor is on the `F` of the constant `FOO`, the editor should identify other occurences of `FOO`
|
|
9
|
+
# and highlight them.
|
|
10
|
+
#
|
|
11
|
+
# For writable elements like constants or variables, their read/write occurrences should be highlighted differently.
|
|
12
|
+
# This is achieved by sending different "kind" attributes to the editor (2 for read and 3 for write).
|
|
13
|
+
#
|
|
14
|
+
# # Example
|
|
15
|
+
#
|
|
16
|
+
# ```ruby
|
|
17
|
+
# FOO = 1 # should be highlighted as "write"
|
|
18
|
+
#
|
|
19
|
+
# def foo
|
|
20
|
+
# FOO # should be highlighted as "read"
|
|
21
|
+
# end
|
|
22
|
+
# ```
|
|
23
|
+
class DocumentHighlight < BaseRequest
|
|
24
|
+
def self.run(document, position)
|
|
25
|
+
new(document, position).run
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def initialize(document, position)
|
|
29
|
+
@highlights = []
|
|
30
|
+
position = Document::Scanner.new(document.source).find_position(position)
|
|
31
|
+
@target = find(document.tree, position)
|
|
32
|
+
|
|
33
|
+
super(document)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def run
|
|
37
|
+
# no @target means the target is not highlightable
|
|
38
|
+
return [] unless @target
|
|
39
|
+
|
|
40
|
+
visit(@document.tree)
|
|
41
|
+
@highlights
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def visit_var_field(node)
|
|
45
|
+
if matches_target?(node.value)
|
|
46
|
+
add_highlight(
|
|
47
|
+
node.value,
|
|
48
|
+
LanguageServer::Protocol::Constant::DocumentHighlightKind::WRITE
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
super
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def visit_var_ref(node)
|
|
56
|
+
if matches_target?(node.value)
|
|
57
|
+
add_highlight(
|
|
58
|
+
node.value,
|
|
59
|
+
LanguageServer::Protocol::Constant::DocumentHighlightKind::READ
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
super
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
def find(node, position)
|
|
69
|
+
matched =
|
|
70
|
+
node.child_nodes.compact.bsearch do |child|
|
|
71
|
+
if (child.location.start_char...child.location.end_char).cover?(position)
|
|
72
|
+
0
|
|
73
|
+
else
|
|
74
|
+
position <=> child.location.start_char
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
case matched
|
|
79
|
+
when SyntaxTree::GVar, SyntaxTree::Ident, SyntaxTree::IVar, SyntaxTree::Const, SyntaxTree::CVar
|
|
80
|
+
matched
|
|
81
|
+
when SyntaxTree::Node
|
|
82
|
+
find(matched, position)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def matches_target?(node)
|
|
87
|
+
node.is_a?(@target.class) && node.value == @target.value
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def add_highlight(node, kind)
|
|
91
|
+
range = range_from_syntax_tree_node(node)
|
|
92
|
+
@highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: kind)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -210,16 +211,6 @@ module RubyLsp
|
|
|
210
211
|
|
|
211
212
|
symbol
|
|
212
213
|
end
|
|
213
|
-
|
|
214
|
-
def range_from_syntax_tree_node(node)
|
|
215
|
-
loc = node.location
|
|
216
|
-
|
|
217
|
-
LanguageServer::Protocol::Interface::Range.new(
|
|
218
|
-
start: LanguageServer::Protocol::Interface::Position.new(line: loc.start_line - 1,
|
|
219
|
-
character: loc.start_column),
|
|
220
|
-
end: LanguageServer::Protocol::Interface::Position.new(line: loc.end_line - 1, character: loc.end_column),
|
|
221
|
-
)
|
|
222
|
-
end
|
|
223
214
|
end
|
|
224
215
|
end
|
|
225
216
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -148,7 +149,7 @@ module RubyLsp
|
|
|
148
149
|
end
|
|
149
150
|
|
|
150
151
|
def add_call_range(node)
|
|
151
|
-
receiver = node.receiver
|
|
152
|
+
receiver = T.let(node.receiver, SyntaxTree::Node)
|
|
152
153
|
loop do
|
|
153
154
|
case receiver
|
|
154
155
|
when SyntaxTree::Call
|
|
@@ -184,7 +185,7 @@ module RubyLsp
|
|
|
184
185
|
end
|
|
185
186
|
|
|
186
187
|
def add_string_concat(node)
|
|
187
|
-
left = node.left
|
|
188
|
+
left = T.let(node.left, SyntaxTree::Node)
|
|
188
189
|
left = left.left while left.is_a?(SyntaxTree::StringConcat)
|
|
189
190
|
|
|
190
191
|
add_lines_range(left.location.start_line, node.right.location.end_line)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -14,7 +15,7 @@ module RubyLsp
|
|
|
14
15
|
# end
|
|
15
16
|
# ```
|
|
16
17
|
class Formatting < RuboCopRequest
|
|
17
|
-
RUBOCOP_FLAGS = (COMMON_RUBOCOP_FLAGS + ["--
|
|
18
|
+
RUBOCOP_FLAGS = (COMMON_RUBOCOP_FLAGS + ["--autocorrect"]).freeze
|
|
18
19
|
|
|
19
20
|
def initialize(uri, document)
|
|
20
21
|
super
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -20,7 +21,19 @@ module RubyLsp
|
|
|
20
21
|
:variable,
|
|
21
22
|
:method,
|
|
22
23
|
].freeze
|
|
23
|
-
|
|
24
|
+
|
|
25
|
+
TOKEN_MODIFIERS = {
|
|
26
|
+
declaration: 0,
|
|
27
|
+
definition: 1,
|
|
28
|
+
readonly: 2,
|
|
29
|
+
static: 3,
|
|
30
|
+
deprecated: 4,
|
|
31
|
+
abstract: 5,
|
|
32
|
+
async: 6,
|
|
33
|
+
modification: 7,
|
|
34
|
+
documentation: 8,
|
|
35
|
+
default_library: 9,
|
|
36
|
+
}.freeze
|
|
24
37
|
|
|
25
38
|
SemanticToken = Struct.new(:location, :length, :type, :modifier)
|
|
26
39
|
|
|
@@ -89,9 +102,10 @@ module RubyLsp
|
|
|
89
102
|
add_token(node.value.location, :method)
|
|
90
103
|
end
|
|
91
104
|
|
|
92
|
-
def add_token(location, type)
|
|
105
|
+
def add_token(location, type, modifiers = [])
|
|
93
106
|
length = location.end_char - location.start_char
|
|
94
|
-
|
|
107
|
+
modifiers_indices = modifiers.filter_map { |modifier| TOKEN_MODIFIERS[modifier] }
|
|
108
|
+
@tokens.push(SemanticToken.new(location, length, TOKEN_TYPES.index(type), modifiers_indices))
|
|
95
109
|
end
|
|
96
110
|
end
|
|
97
111
|
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -38,11 +39,21 @@ module RubyLsp
|
|
|
38
39
|
delta_column = column
|
|
39
40
|
delta_column -= @current_column if delta_line == 0
|
|
40
41
|
|
|
41
|
-
[delta_line, delta_column, token.length, token.type, token.modifier]
|
|
42
|
+
[delta_line, delta_column, token.length, token.type, encode_modifiers(token.modifier)]
|
|
42
43
|
ensure
|
|
43
44
|
@current_row = row
|
|
44
45
|
@current_column = column
|
|
45
46
|
end
|
|
47
|
+
|
|
48
|
+
# Encode an array of modifiers to positions onto a bit flag
|
|
49
|
+
# For example, [:default_library] will be encoded as
|
|
50
|
+
# 0b1000000000, as :default_library is the 10th bit according
|
|
51
|
+
# to the token modifiers index map.
|
|
52
|
+
def encode_modifiers(modifiers)
|
|
53
|
+
modifiers.inject(0) do |encoded_modifiers, modifier|
|
|
54
|
+
encoded_modifiers | (1 << modifier)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
46
57
|
end
|
|
47
58
|
end
|
|
48
59
|
end
|
data/lib/ruby_lsp/requests.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: true
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
module RubyLsp
|
|
@@ -11,6 +12,7 @@ module RubyLsp
|
|
|
11
12
|
autoload :Formatting, "ruby_lsp/requests/formatting"
|
|
12
13
|
autoload :Diagnostics, "ruby_lsp/requests/diagnostics"
|
|
13
14
|
autoload :CodeActions, "ruby_lsp/requests/code_actions"
|
|
15
|
+
autoload :DocumentHighlight, "ruby_lsp/requests/document_highlight"
|
|
14
16
|
|
|
15
17
|
module Support
|
|
16
18
|
autoload :RuboCopDiagnostic, "ruby_lsp/requests/support/rubocop_diagnostic"
|
data/lib/ruby_lsp/store.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: strict
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
require "cgi"
|
|
@@ -6,36 +7,51 @@ require "ruby_lsp/document"
|
|
|
6
7
|
|
|
7
8
|
module RubyLsp
|
|
8
9
|
class Store
|
|
10
|
+
extend T::Sig
|
|
11
|
+
|
|
12
|
+
sig { void }
|
|
9
13
|
def initialize
|
|
10
|
-
@state = {}
|
|
14
|
+
@state = T.let({}, T::Hash[String, Document])
|
|
11
15
|
end
|
|
12
16
|
|
|
17
|
+
sig { params(uri: String).returns(Document) }
|
|
13
18
|
def get(uri)
|
|
14
19
|
document = @state[uri]
|
|
15
20
|
return document unless document.nil?
|
|
16
21
|
|
|
17
22
|
set(uri, File.binread(CGI.unescape(URI.parse(uri).path)))
|
|
18
|
-
@state[uri]
|
|
23
|
+
T.must(@state[uri])
|
|
19
24
|
end
|
|
20
25
|
|
|
26
|
+
sig { params(uri: String, content: String).void }
|
|
21
27
|
def set(uri, content)
|
|
22
28
|
@state[uri] = Document.new(content)
|
|
23
29
|
rescue SyntaxTree::Parser::ParseError
|
|
24
30
|
# Do not update the store if there are syntax errors
|
|
25
31
|
end
|
|
26
32
|
|
|
33
|
+
sig { params(uri: String, edits: T::Array[Document::EditShape]).void }
|
|
27
34
|
def push_edits(uri, edits)
|
|
28
|
-
@state[uri].push_edits(edits)
|
|
35
|
+
T.must(@state[uri]).push_edits(edits)
|
|
29
36
|
end
|
|
30
37
|
|
|
38
|
+
sig { void }
|
|
31
39
|
def clear
|
|
32
40
|
@state.clear
|
|
33
41
|
end
|
|
34
42
|
|
|
43
|
+
sig { params(uri: String).void }
|
|
35
44
|
def delete(uri)
|
|
36
45
|
@state.delete(uri)
|
|
37
46
|
end
|
|
38
47
|
|
|
48
|
+
sig do
|
|
49
|
+
params(
|
|
50
|
+
uri: String,
|
|
51
|
+
request_name: Symbol,
|
|
52
|
+
block: T.proc.params(document: Document).returns(T.untyped)
|
|
53
|
+
).returns(T.untyped)
|
|
54
|
+
end
|
|
39
55
|
def cache_fetch(uri, request_name, &block)
|
|
40
56
|
get(uri).cache_fetch(request_name, &block)
|
|
41
57
|
end
|
data/rakelib/check_docs.rake
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# typed: false
|
|
1
2
|
# frozen_string_literal: true
|
|
2
3
|
|
|
3
4
|
desc "Check if all LSP requests are documented"
|
|
@@ -14,7 +15,9 @@ task :check_docs do
|
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
spec_matcher = %r{\(https://microsoft.github.io/language-server-protocol/specification#.*\)}
|
|
17
|
-
error_messages = RubyLsp::Requests
|
|
18
|
+
error_messages = RubyLsp::Requests
|
|
19
|
+
.constants # rubocop:disable Sorbet/ConstantsFromStrings
|
|
20
|
+
.each_with_object(Hash.new { |h, k| h[k] = [] }) do |request, errors|
|
|
18
21
|
full_name = "RubyLsp::Requests::#{request}"
|
|
19
22
|
docs = YARD::Registry.at(full_name).docstring
|
|
20
23
|
next if /:nodoc:/.match?(docs)
|
data/ruby-lsp.gemspec
CHANGED
data/sorbet/config
ADDED