ruby-lsp 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -0
- data/VERSION +1 -1
- data/lib/ruby_lsp/document.rb +44 -11
- data/lib/ruby_lsp/requests/base_request.rb +9 -0
- data/lib/ruby_lsp/requests/code_actions.rb +1 -1
- data/lib/ruby_lsp/requests/document_highlight.rb +1 -2
- data/lib/ruby_lsp/requests/document_link.rb +2 -3
- data/lib/ruby_lsp/requests/hover.rb +1 -1
- data/lib/ruby_lsp/requests/inlay_hints.rb +1 -1
- data/lib/ruby_lsp/requests/on_type_formatting.rb +3 -3
- data/lib/ruby_lsp/requests/semantic_highlighting.rb +41 -2
- data/lib/ruby_lsp/server.rb +19 -7
- data/lib/ruby_lsp/store.rb +5 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cddece941249b188843957c1c026e6e1e10f875c26a7c2f14f556a53556cc94f
|
4
|
+
data.tar.gz: cdc7368658e3de269033b41bceb831becb68320cd1444ec9792380408ee2a4f2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d28c2f96939d517cacae6b86407e5990ca1587f99848bc14ff98ea24b5421e2ad38ba0ee39a7040c2a4694623e349c907c6f2a764737e0cc9316d302804687b2
|
7
|
+
data.tar.gz: a5e118206994b0e58ff9568043eb534360e591f931c0c8f078579283ab0519057a236606728c230e4be86f7405035a6e2bea1e52959af280f2067f0e52127278
|
data/README.md
CHANGED
@@ -28,6 +28,14 @@ are expected to adhere to the
|
|
28
28
|
[Contributor Covenant](https://github.com/Shopify/ruby-lsp/blob/main/CODE_OF_CONDUCT.md)
|
29
29
|
code of conduct.
|
30
30
|
|
31
|
+
### Running the test suite
|
32
|
+
|
33
|
+
Run the test suite with `bin/test`.
|
34
|
+
|
35
|
+
For more visibility into which tests are running, use the `SpecReporter`:
|
36
|
+
|
37
|
+
`SPEC_REPORTER=1 bin/test`
|
38
|
+
|
31
39
|
### Expectation testing
|
32
40
|
|
33
41
|
To simplify the way we run tests over different pieces of Ruby code, we use a custom expectations test framework against a set of Ruby fixtures.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.7
|
data/lib/ruby_lsp/document.rb
CHANGED
@@ -18,10 +18,11 @@ module RubyLsp
|
|
18
18
|
sig { returns(T::Array[EditShape]) }
|
19
19
|
attr_reader :syntax_error_edits
|
20
20
|
|
21
|
-
sig { params(source: String).void }
|
22
|
-
def initialize(source)
|
21
|
+
sig { params(source: String, encoding: String).void }
|
22
|
+
def initialize(source, encoding = "utf-8")
|
23
23
|
@cache = T.let({}, T::Hash[Symbol, T.untyped])
|
24
24
|
@syntax_error_edits = T.let([], T::Array[EditShape])
|
25
|
+
@encoding = T.let(encoding, String)
|
25
26
|
@source = T.let(source, String)
|
26
27
|
@parsable_source = T.let(source.dup, String)
|
27
28
|
@unparsed_edits = T.let([], T::Array[EditShape])
|
@@ -83,6 +84,11 @@ module RubyLsp
|
|
83
84
|
!@tree.nil?
|
84
85
|
end
|
85
86
|
|
87
|
+
sig { returns(Scanner) }
|
88
|
+
def create_scanner
|
89
|
+
Scanner.new(@source, @encoding)
|
90
|
+
end
|
91
|
+
|
86
92
|
private
|
87
93
|
|
88
94
|
sig { params(edits: T::Array[EditShape]).void }
|
@@ -103,9 +109,9 @@ module RubyLsp
|
|
103
109
|
|
104
110
|
sig { params(source: String, range: RangeShape, text: String).void }
|
105
111
|
def apply_edit(source, range, text)
|
106
|
-
scanner = Scanner.new(source)
|
107
|
-
start_position = scanner.
|
108
|
-
end_position = scanner.
|
112
|
+
scanner = Scanner.new(source, @encoding)
|
113
|
+
start_position = scanner.find_char_position(range[:start])
|
114
|
+
end_position = scanner.find_char_position(range[:end])
|
109
115
|
|
110
116
|
source[start_position...end_position] = text
|
111
117
|
end
|
@@ -113,22 +119,49 @@ module RubyLsp
|
|
113
119
|
class Scanner
|
114
120
|
extend T::Sig
|
115
121
|
|
116
|
-
|
117
|
-
|
122
|
+
LINE_BREAK = T.let(0x0A, Integer)
|
123
|
+
# After character 0xFFFF, UTF-16 considers characters to have length 2 and we have to account for that
|
124
|
+
SURROGATE_PAIR_START = T.let(0xFFFF, Integer)
|
125
|
+
|
126
|
+
sig { params(source: String, encoding: String).void }
|
127
|
+
def initialize(source, encoding)
|
118
128
|
@current_line = T.let(0, Integer)
|
119
129
|
@pos = T.let(0, Integer)
|
120
|
-
@source = source
|
130
|
+
@source = T.let(source.codepoints, T::Array[Integer])
|
131
|
+
@encoding = encoding
|
121
132
|
end
|
122
133
|
|
134
|
+
# Finds the character index inside the source string for a given line and column
|
123
135
|
sig { params(position: PositionShape).returns(Integer) }
|
124
|
-
def
|
136
|
+
def find_char_position(position)
|
137
|
+
# Find the character index for the beginning of the requested line
|
125
138
|
until @current_line == position[:line]
|
126
|
-
@pos += 1 until
|
139
|
+
@pos += 1 until LINE_BREAK == @source[@pos]
|
127
140
|
@pos += 1
|
128
141
|
@current_line += 1
|
129
142
|
end
|
130
143
|
|
131
|
-
|
144
|
+
# The final position is the beginning of the line plus the requested column. If the encoding is UTF-16, we also
|
145
|
+
# need to adjust for surrogate pairs
|
146
|
+
requested_position = @pos + position[:character]
|
147
|
+
requested_position -= utf_16_character_position_correction(@pos, requested_position) if @encoding == "utf-16"
|
148
|
+
requested_position
|
149
|
+
end
|
150
|
+
|
151
|
+
# Subtract 1 for each character after 0xFFFF in the current line from the column position, so that we hit the
|
152
|
+
# right character in the UTF-8 representation
|
153
|
+
sig { params(current_position: Integer, requested_position: Integer).returns(Integer) }
|
154
|
+
def utf_16_character_position_correction(current_position, requested_position)
|
155
|
+
utf16_unicode_correction = 0
|
156
|
+
|
157
|
+
until current_position == requested_position
|
158
|
+
codepoint = @source[current_position]
|
159
|
+
utf16_unicode_correction += 1 if codepoint && codepoint > SURROGATE_PAIR_START
|
160
|
+
|
161
|
+
current_position += 1
|
162
|
+
end
|
163
|
+
|
164
|
+
utf16_unicode_correction
|
132
165
|
end
|
133
166
|
end
|
134
167
|
end
|
@@ -79,6 +79,15 @@ module RubyLsp
|
|
79
79
|
[]
|
80
80
|
end
|
81
81
|
end
|
82
|
+
|
83
|
+
sig { params(node: T.nilable(SyntaxTree::Node), range: T.nilable(T::Range[Integer])).returns(T::Boolean) }
|
84
|
+
def visible?(node, range)
|
85
|
+
return true if range.nil?
|
86
|
+
return false if node.nil?
|
87
|
+
|
88
|
+
loc = node.location
|
89
|
+
range.cover?(loc.start_line - 1) && range.cover?(loc.end_line - 1)
|
90
|
+
end
|
82
91
|
end
|
83
92
|
end
|
84
93
|
end
|
@@ -35,7 +35,7 @@ module RubyLsp
|
|
35
35
|
|
36
36
|
sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::CodeAction], Object)) }
|
37
37
|
def run
|
38
|
-
diagnostics = Diagnostics.new(@uri, @document).run
|
38
|
+
diagnostics = @document.cache_fetch(:diagnostics) { Diagnostics.new(@uri, @document).run }
|
39
39
|
corrections = diagnostics.select do |diagnostic|
|
40
40
|
diagnostic.correctable? && T.cast(diagnostic, Support::RuboCopDiagnostic).in_range?(@range)
|
41
41
|
end
|
@@ -30,10 +30,9 @@ module RubyLsp
|
|
30
30
|
super(document)
|
31
31
|
|
32
32
|
@highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
|
33
|
-
position = Document::Scanner.new(document.source).find_position(position)
|
34
|
-
|
35
33
|
return unless document.parsed?
|
36
34
|
|
35
|
+
position = document.create_scanner.find_char_position(position)
|
37
36
|
@target = T.let(find(T.must(document.tree), position), T.nilable(Support::HighlightTarget))
|
38
37
|
end
|
39
38
|
|
@@ -50,9 +50,8 @@ module RubyLsp
|
|
50
50
|
spec = stub.to_spec
|
51
51
|
lookup[spec.name] = {}
|
52
52
|
lookup[spec.name][spec.version.to_s] = {}
|
53
|
-
prefix_matchers =
|
54
|
-
|
55
|
-
prefix_matcher = Regexp.union(prefix_matchers)
|
53
|
+
prefix_matchers = Regexp.union(spec.require_paths.map { |rp| Regexp.new("^#{rp}/") })
|
54
|
+
prefix_matcher = Regexp.union(prefix_matchers, //)
|
56
55
|
|
57
56
|
spec.files.each do |file|
|
58
57
|
path = file.sub(prefix_matcher, "")
|
@@ -24,7 +24,7 @@ module RubyLsp
|
|
24
24
|
def initialize(document, position)
|
25
25
|
super(document)
|
26
26
|
|
27
|
-
@position = T.let(
|
27
|
+
@position = T.let(document.create_scanner.find_char_position(position), Integer)
|
28
28
|
end
|
29
29
|
|
30
30
|
sig { override.returns(T.nilable(LanguageServer::Protocol::Interface::Hover)) }
|
@@ -40,7 +40,7 @@ module RubyLsp
|
|
40
40
|
return unless node.exception.nil?
|
41
41
|
|
42
42
|
loc = node.location
|
43
|
-
return unless
|
43
|
+
return unless visible?(node, @range)
|
44
44
|
|
45
45
|
@hints << LanguageServer::Protocol::Interface::InlayHint.new(
|
46
46
|
position: { line: loc.start_line - 1, character: loc.start_column + RESCUE_STRING_LENGTH },
|
@@ -27,9 +27,9 @@ module RubyLsp
|
|
27
27
|
def initialize(document, position, trigger_character)
|
28
28
|
super(document)
|
29
29
|
|
30
|
-
scanner =
|
31
|
-
line_begin = position[:line] == 0 ? 0 : scanner.
|
32
|
-
line_end = scanner.
|
30
|
+
scanner = document.create_scanner
|
31
|
+
line_begin = position[:line] == 0 ? 0 : scanner.find_char_position({ line: position[:line] - 1, character: 0 })
|
32
|
+
line_end = scanner.find_char_position(position)
|
33
33
|
line = T.must(@document.source[line_begin..line_end])
|
34
34
|
|
35
35
|
@indentation = T.let(find_indentation(line), Integer)
|
@@ -76,13 +76,20 @@ module RubyLsp
|
|
76
76
|
const :modifier, T::Array[Integer]
|
77
77
|
end
|
78
78
|
|
79
|
-
sig
|
80
|
-
|
79
|
+
sig do
|
80
|
+
params(
|
81
|
+
document: Document,
|
82
|
+
range: T.nilable(T::Range[Integer]),
|
83
|
+
encoder: T.nilable(Support::SemanticTokenEncoder),
|
84
|
+
).void
|
85
|
+
end
|
86
|
+
def initialize(document, range: nil, encoder: nil)
|
81
87
|
super(document)
|
82
88
|
|
83
89
|
@encoder = encoder
|
84
90
|
@tokens = T.let([], T::Array[SemanticToken])
|
85
91
|
@tree = T.let(T.must(document.tree), SyntaxTree::Node)
|
92
|
+
@range = range
|
86
93
|
@special_methods = T.let(nil, T.nilable(T::Array[String]))
|
87
94
|
end
|
88
95
|
|
@@ -105,6 +112,8 @@ module RubyLsp
|
|
105
112
|
|
106
113
|
sig { override.params(node: SyntaxTree::Call).void }
|
107
114
|
def visit_call(node)
|
115
|
+
return super unless visible?(node, @range)
|
116
|
+
|
108
117
|
visit(node.receiver)
|
109
118
|
|
110
119
|
message = node.message
|
@@ -115,12 +124,16 @@ module RubyLsp
|
|
115
124
|
|
116
125
|
sig { override.params(node: SyntaxTree::Command).void }
|
117
126
|
def visit_command(node)
|
127
|
+
return super unless visible?(node, @range)
|
128
|
+
|
118
129
|
add_token(node.message.location, :method) unless special_method?(node.message.value)
|
119
130
|
visit(node.arguments)
|
120
131
|
end
|
121
132
|
|
122
133
|
sig { override.params(node: SyntaxTree::CommandCall).void }
|
123
134
|
def visit_command_call(node)
|
135
|
+
return super unless visible?(node, @range)
|
136
|
+
|
124
137
|
visit(node.receiver)
|
125
138
|
add_token(node.message.location, :method)
|
126
139
|
visit(node.arguments)
|
@@ -128,11 +141,15 @@ module RubyLsp
|
|
128
141
|
|
129
142
|
sig { override.params(node: SyntaxTree::Const).void }
|
130
143
|
def visit_const(node)
|
144
|
+
return super unless visible?(node, @range)
|
145
|
+
|
131
146
|
add_token(node.location, :namespace)
|
132
147
|
end
|
133
148
|
|
134
149
|
sig { override.params(node: SyntaxTree::Def).void }
|
135
150
|
def visit_def(node)
|
151
|
+
return super unless visible?(node, @range)
|
152
|
+
|
136
153
|
add_token(node.name.location, :method, [:declaration])
|
137
154
|
visit(node.params)
|
138
155
|
visit(node.bodystmt)
|
@@ -140,6 +157,8 @@ module RubyLsp
|
|
140
157
|
|
141
158
|
sig { override.params(node: SyntaxTree::DefEndless).void }
|
142
159
|
def visit_def_endless(node)
|
160
|
+
return super unless visible?(node, @range)
|
161
|
+
|
143
162
|
add_token(node.name.location, :method, [:declaration])
|
144
163
|
visit(node.paren)
|
145
164
|
visit(node.operator)
|
@@ -148,6 +167,8 @@ module RubyLsp
|
|
148
167
|
|
149
168
|
sig { override.params(node: SyntaxTree::Defs).void }
|
150
169
|
def visit_defs(node)
|
170
|
+
return super unless visible?(node, @range)
|
171
|
+
|
151
172
|
visit(node.target)
|
152
173
|
visit(node.operator)
|
153
174
|
add_token(node.name.location, :method, [:declaration])
|
@@ -157,12 +178,16 @@ module RubyLsp
|
|
157
178
|
|
158
179
|
sig { override.params(node: SyntaxTree::FCall).void }
|
159
180
|
def visit_fcall(node)
|
181
|
+
return super unless visible?(node, @range)
|
182
|
+
|
160
183
|
add_token(node.value.location, :method) unless special_method?(node.value.value)
|
161
184
|
visit(node.arguments)
|
162
185
|
end
|
163
186
|
|
164
187
|
sig { override.params(node: SyntaxTree::Kw).void }
|
165
188
|
def visit_kw(node)
|
189
|
+
return super unless visible?(node, @range)
|
190
|
+
|
166
191
|
case node.value
|
167
192
|
when "self"
|
168
193
|
add_token(node.location, :variable, [:default_library])
|
@@ -171,6 +196,8 @@ module RubyLsp
|
|
171
196
|
|
172
197
|
sig { override.params(node: SyntaxTree::Params).void }
|
173
198
|
def visit_params(node)
|
199
|
+
return super unless visible?(node, @range)
|
200
|
+
|
174
201
|
node.keywords.each do |keyword,|
|
175
202
|
location = keyword.location
|
176
203
|
add_token(location_without_colon(location), :parameter)
|
@@ -191,6 +218,8 @@ module RubyLsp
|
|
191
218
|
|
192
219
|
sig { override.params(node: SyntaxTree::Field).void }
|
193
220
|
def visit_field(node)
|
221
|
+
return super unless visible?(node, @range)
|
222
|
+
|
194
223
|
add_token(node.name.location, :method)
|
195
224
|
|
196
225
|
super
|
@@ -198,6 +227,8 @@ module RubyLsp
|
|
198
227
|
|
199
228
|
sig { override.params(node: SyntaxTree::VarField).void }
|
200
229
|
def visit_var_field(node)
|
230
|
+
return super unless visible?(node, @range)
|
231
|
+
|
201
232
|
value = node.value
|
202
233
|
|
203
234
|
case value
|
@@ -211,6 +242,8 @@ module RubyLsp
|
|
211
242
|
|
212
243
|
sig { override.params(node: SyntaxTree::VarRef).void }
|
213
244
|
def visit_var_ref(node)
|
245
|
+
return super unless visible?(node, @range)
|
246
|
+
|
214
247
|
value = node.value
|
215
248
|
|
216
249
|
case value
|
@@ -224,11 +257,15 @@ module RubyLsp
|
|
224
257
|
|
225
258
|
sig { override.params(node: SyntaxTree::VCall).void }
|
226
259
|
def visit_vcall(node)
|
260
|
+
return super unless visible?(node, @range)
|
261
|
+
|
227
262
|
add_token(node.value.location, :method) unless special_method?(node.value.value)
|
228
263
|
end
|
229
264
|
|
230
265
|
sig { override.params(node: SyntaxTree::ClassDeclaration).void }
|
231
266
|
def visit_class(node)
|
267
|
+
return super unless visible?(node, @range)
|
268
|
+
|
232
269
|
add_token(node.constant.location, :class, [:declaration])
|
233
270
|
add_token(node.superclass.location, :class) if node.superclass
|
234
271
|
visit(node.bodystmt)
|
@@ -236,6 +273,8 @@ module RubyLsp
|
|
236
273
|
|
237
274
|
sig { override.params(node: SyntaxTree::ModuleDeclaration).void }
|
238
275
|
def visit_module(node)
|
276
|
+
return super unless visible?(node, @range)
|
277
|
+
|
239
278
|
add_token(node.constant.location, :class, [:declaration])
|
240
279
|
visit(node.bodystmt)
|
241
280
|
end
|
data/lib/ruby_lsp/server.rb
CHANGED
@@ -7,6 +7,8 @@ module RubyLsp
|
|
7
7
|
Handler.start do
|
8
8
|
on("initialize") do |request|
|
9
9
|
store.clear
|
10
|
+
store.encoding = request.dig(:params, :capabilities, :general, :positionEncodings)
|
11
|
+
|
10
12
|
initialization_options = request.dig(:params, :initializationOptions)
|
11
13
|
enabled_features = initialization_options.fetch(:enabledFeatures, [])
|
12
14
|
|
@@ -38,10 +40,8 @@ module RubyLsp
|
|
38
40
|
token_types: Requests::SemanticHighlighting::TOKEN_TYPES.keys,
|
39
41
|
token_modifiers: Requests::SemanticHighlighting::TOKEN_MODIFIERS.keys,
|
40
42
|
),
|
41
|
-
range:
|
42
|
-
full: {
|
43
|
-
delta: true,
|
44
|
-
},
|
43
|
+
range: true,
|
44
|
+
full: { delta: false },
|
45
45
|
)
|
46
46
|
end
|
47
47
|
|
@@ -168,6 +168,19 @@ module RubyLsp
|
|
168
168
|
end
|
169
169
|
end
|
170
170
|
|
171
|
+
on("textDocument/semanticTokens/range", parallel: true) do |request|
|
172
|
+
document = store.get(request.dig(:params, :textDocument, :uri))
|
173
|
+
range = request.dig(:params, :range)
|
174
|
+
start_line = range.dig(:start, :line)
|
175
|
+
end_line = range.dig(:end, :line)
|
176
|
+
|
177
|
+
Requests::SemanticHighlighting.new(
|
178
|
+
document,
|
179
|
+
range: start_line..end_line,
|
180
|
+
encoder: Requests::Support::SemanticTokenEncoder.new,
|
181
|
+
).run
|
182
|
+
end
|
183
|
+
|
171
184
|
on("textDocument/formatting", parallel: true) do |request|
|
172
185
|
uri = request.dig(:params, :textDocument, :uri)
|
173
186
|
|
@@ -192,13 +205,12 @@ module RubyLsp
|
|
192
205
|
|
193
206
|
on("textDocument/codeAction", parallel: true) do |request|
|
194
207
|
uri = request.dig(:params, :textDocument, :uri)
|
208
|
+
document = store.get(uri)
|
195
209
|
range = request.dig(:params, :range)
|
196
210
|
start_line = range.dig(:start, :line)
|
197
211
|
end_line = range.dig(:end, :line)
|
198
212
|
|
199
|
-
|
200
|
-
Requests::CodeActions.new(uri, document, start_line..end_line).run
|
201
|
-
end
|
213
|
+
Requests::CodeActions.new(uri, document, start_line..end_line).run
|
202
214
|
end
|
203
215
|
|
204
216
|
on("textDocument/inlayHint", parallel: true) do |request|
|
data/lib/ruby_lsp/store.rb
CHANGED
@@ -9,9 +9,13 @@ module RubyLsp
|
|
9
9
|
class Store
|
10
10
|
extend T::Sig
|
11
11
|
|
12
|
+
sig { params(encoding: String).void }
|
13
|
+
attr_writer :encoding
|
14
|
+
|
12
15
|
sig { void }
|
13
16
|
def initialize
|
14
17
|
@state = T.let({}, T::Hash[String, Document])
|
18
|
+
@encoding = T.let("utf-8", String)
|
15
19
|
end
|
16
20
|
|
17
21
|
sig { params(uri: String).returns(Document) }
|
@@ -25,7 +29,7 @@ module RubyLsp
|
|
25
29
|
|
26
30
|
sig { params(uri: String, content: String).void }
|
27
31
|
def set(uri, content)
|
28
|
-
document = Document.new(content)
|
32
|
+
document = Document.new(content, @encoding)
|
29
33
|
@state[uri] = document
|
30
34
|
end
|
31
35
|
|
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.3.
|
4
|
+
version: 0.3.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: language_server-protocol
|