rucoa 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +2 -2
- data/README.md +6 -4
- data/images/document-highlight.gif +0 -0
- data/lib/rucoa/handlers/text_document_document_highlight_handler.rb +318 -43
- data/lib/rucoa/handlers/text_document_formatting_handler.rb +1 -1
- data/lib/rucoa/node_concerns/modifier.rb +35 -0
- data/lib/rucoa/node_concerns/variable.rb +26 -0
- data/lib/rucoa/node_concerns.rb +2 -0
- data/lib/rucoa/nodes/arg_node.rb +26 -0
- data/lib/rucoa/nodes/args_node.rb +14 -0
- data/lib/rucoa/nodes/base.rb +71 -7
- data/lib/rucoa/nodes/block_node.rb +14 -0
- data/lib/rucoa/nodes/cvar_node.rb +9 -0
- data/lib/rucoa/nodes/cvasgn_node.rb +9 -0
- data/lib/rucoa/nodes/def_node.rb +14 -0
- data/lib/rucoa/nodes/gvar_node.rb +9 -0
- data/lib/rucoa/nodes/gvasgn_node.rb +9 -0
- data/lib/rucoa/nodes/if_node.rb +3 -1
- data/lib/rucoa/nodes/ivar_node.rb +9 -0
- data/lib/rucoa/nodes/ivasgn_node.rb +9 -0
- data/lib/rucoa/nodes/lvar_node.rb +1 -18
- data/lib/rucoa/nodes/lvasgn_node.rb +9 -0
- data/lib/rucoa/nodes/send_node.rb +1 -1
- data/lib/rucoa/nodes/until_node.rb +1 -0
- data/lib/rucoa/nodes/while_node.rb +1 -0
- data/lib/rucoa/nodes.rb +9 -0
- data/lib/rucoa/parser_builder.rb +10 -0
- data/lib/rucoa/source.rb +1 -1
- data/lib/rucoa/version.rb +1 -1
- data/lib/rucoa/yard/definitions_loader.rb +1 -1
- data/rucoa.gemspec +0 -1
- metadata +14 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3829019e74a6fedcb5548ce3630b3c145c12ab40c0df99b63fd9747975f0a71d
|
4
|
+
data.tar.gz: 4cd7373ed7239adeb955caf7c373fe5da6d90ca0d92dc34801d2179db0387bbf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a3bbe0f9cb45652ab45706b3afa87853ba3e4d8e33b5894080772a054463bc3828db454da0a0af292982f4de9b8fa18a0353d1cf527e6961455d08c68eeeae63
|
7
|
+
data.tar.gz: 3b23e8f98a5a57a7f236f22ba7e8e606a43f477e789646740a99cdbb30f0bf5adb21779c1ea2e0f828112e32e4dd242eae28fde14120870d8163f0bc1adbc769
|
data/.rubocop.yml
CHANGED
@@ -8,6 +8,9 @@ AllCops:
|
|
8
8
|
NewCops: enable
|
9
9
|
TargetRubyVersion: 2.7
|
10
10
|
|
11
|
+
Gemspec/RequireMFA:
|
12
|
+
Enabled: false
|
13
|
+
|
11
14
|
Layout/LineLength:
|
12
15
|
Enabled: false
|
13
16
|
|
@@ -47,6 +50,9 @@ Sevencop/MethodDefinitionArgumentsMultiline:
|
|
47
50
|
Sevencop/MethodDefinitionKeywordArgumentOrdered:
|
48
51
|
Enabled: true
|
49
52
|
|
53
|
+
Sevencop/RequireOrdered:
|
54
|
+
Enabled: true
|
55
|
+
|
50
56
|
Style/Documentation:
|
51
57
|
Enabled: false
|
52
58
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rucoa (0.
|
4
|
+
rucoa (0.13.0)
|
5
5
|
parser
|
6
6
|
rbs
|
7
7
|
rubocop
|
@@ -54,7 +54,7 @@ GEM
|
|
54
54
|
rubocop-rspec (2.13.2)
|
55
55
|
rubocop (~> 1.33)
|
56
56
|
ruby-progressbar (1.11.0)
|
57
|
-
sevencop (0.
|
57
|
+
sevencop (0.16.0)
|
58
58
|
rubocop
|
59
59
|
unicode-display_width (2.3.0)
|
60
60
|
webrick (1.7.0)
|
data/README.md
CHANGED
@@ -35,6 +35,12 @@ Run "Format Document" command or enable "Format On Save" in the settings to auto
|
|
35
35
|
|
36
36
|
![demo](images/document-formatting.gif)
|
37
37
|
|
38
|
+
### Highlight
|
39
|
+
|
40
|
+
Highlights corresponding keywords.
|
41
|
+
|
42
|
+
![demo](images/document-highlight.gif)
|
43
|
+
|
38
44
|
### Selection
|
39
45
|
|
40
46
|
Run "Expand Selection" command to select appropriate ranges.
|
@@ -66,10 +72,6 @@ Provides completion items for constant names and method names.
|
|
66
72
|
|
67
73
|
Provides "Go to Definition" command to jump to the definition.
|
68
74
|
|
69
|
-
### Highlight
|
70
|
-
|
71
|
-
Highlights corresponding keywords.
|
72
|
-
|
73
75
|
### Hover
|
74
76
|
|
75
77
|
Shows documentation for the symbol under the cursor.
|
Binary file
|
@@ -1,15 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
|
3
5
|
module Rucoa
|
4
6
|
module Handlers
|
5
7
|
class TextDocumentDocumentHighlightHandler < Base
|
6
8
|
include HandlerConcerns::TextDocumentPositionParameters
|
7
9
|
include HandlerConcerns::TextDocumentUriParameters
|
8
10
|
|
9
|
-
DOCUMENT_HIGHLIGHT_KIND_READ = 2
|
10
|
-
DOCUMENT_HIGHLIGHT_KIND_TEXT = 1
|
11
|
-
DOCUMENT_HIGHLIGHT_KIND_WRITE = 3
|
12
|
-
|
13
11
|
# @return [void]
|
14
12
|
def call
|
15
13
|
respond(document_highlights)
|
@@ -17,21 +15,11 @@ module Rucoa
|
|
17
15
|
|
18
16
|
private
|
19
17
|
|
20
|
-
# @return [Array
|
18
|
+
# @return [Array]
|
21
19
|
def document_highlights
|
22
|
-
parser_ranges.map do |parser_range|
|
23
|
-
{
|
24
|
-
'kind' => DOCUMENT_HIGHLIGHT_KIND_TEXT,
|
25
|
-
'range' => Range.from_parser_range(parser_range).to_vscode_range
|
26
|
-
}
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
# @return [Array<Parser::Source::Range>]
|
31
|
-
def parser_ranges
|
32
20
|
return [] unless reponsible?
|
33
21
|
|
34
|
-
|
22
|
+
NodeToHighlightsMappers::AnyMapper.call(node).map(&:to_vscode_highlight)
|
35
23
|
end
|
36
24
|
|
37
25
|
# @return [Boolean]
|
@@ -39,11 +27,57 @@ module Rucoa
|
|
39
27
|
configuration.enables_highlight?
|
40
28
|
end
|
41
29
|
|
42
|
-
module
|
30
|
+
module Highlights
|
31
|
+
class Base
|
32
|
+
# @param parser_range [Parser::Source::Range]
|
33
|
+
def initialize(parser_range:)
|
34
|
+
@parser_range = parser_range
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# @return [Hash]
|
40
|
+
def vscode_range
|
41
|
+
Range.from_parser_range(@parser_range).to_vscode_range
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class TextHighlight < Base
|
46
|
+
# @return [Hash]
|
47
|
+
def to_vscode_highlight
|
48
|
+
{
|
49
|
+
kind: 1,
|
50
|
+
range: vscode_range
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class ReadHighlight < Base
|
56
|
+
# @return [Hash]
|
57
|
+
def to_vscode_highlight
|
58
|
+
{
|
59
|
+
kind: 2,
|
60
|
+
range: vscode_range
|
61
|
+
}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class WriteHighlight < Base
|
66
|
+
# @return [Hash]
|
67
|
+
def to_vscode_highlight
|
68
|
+
{
|
69
|
+
kind: 3,
|
70
|
+
range: vscode_range
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module NodeToHighlightsMappers
|
43
77
|
class Base
|
44
78
|
class << self
|
45
79
|
# @param node [Rucoa::Nodes::Base]
|
46
|
-
# @return [Array
|
80
|
+
# @return [Array]
|
47
81
|
def call(node)
|
48
82
|
new(node).call
|
49
83
|
end
|
@@ -54,14 +88,14 @@ module Rucoa
|
|
54
88
|
@node = node
|
55
89
|
end
|
56
90
|
|
57
|
-
# @return [Array
|
91
|
+
# @return [Array]
|
58
92
|
def call
|
59
93
|
raise ::NotImplementedError
|
60
94
|
end
|
61
95
|
end
|
62
96
|
|
63
97
|
class AnyMapper < Base
|
64
|
-
# @return [Array
|
98
|
+
# @return [Array]
|
65
99
|
def call
|
66
100
|
case @node
|
67
101
|
when Nodes::BeginNode, Nodes::BlockNode
|
@@ -70,14 +104,22 @@ module Rucoa
|
|
70
104
|
CaseMapper.call(@node)
|
71
105
|
when Nodes::ClassNode, Nodes::ModuleNode
|
72
106
|
ModuleMapper.call(@node)
|
107
|
+
when Nodes::CvarNode, Nodes::CvasgnNode
|
108
|
+
ClassVariableMapper.call(@node)
|
73
109
|
when Nodes::DefNode
|
74
110
|
DefMapper.call(@node)
|
75
111
|
when Nodes::EnsureNode, Nodes::ResbodyNode, Nodes::RescueNode, Nodes::WhenNode
|
76
112
|
AnyMapper.call(@node.parent)
|
77
113
|
when Nodes::ForNode
|
78
114
|
ForMapper.call(@node)
|
115
|
+
when Nodes::GvarNode, Nodes::GvasgnNode
|
116
|
+
GlobalVariableMapper.call(@node)
|
79
117
|
when Nodes::IfNode
|
80
118
|
IfMapper.call(@node)
|
119
|
+
when Nodes::IvarNode, Nodes::IvasgnNode
|
120
|
+
InstanceVariableMapper.call(@node)
|
121
|
+
when Nodes::ArgNode, Nodes::LvarNode, Nodes::LvasgnNode
|
122
|
+
LocalVariableMapper.call(@node)
|
81
123
|
when Nodes::SendNode
|
82
124
|
SendMapper.call(@node)
|
83
125
|
when Nodes::UntilNode, Nodes::WhileNode
|
@@ -89,7 +131,7 @@ module Rucoa
|
|
89
131
|
end
|
90
132
|
|
91
133
|
class BeginMapper < Base
|
92
|
-
# @return [Array
|
134
|
+
# @return [Array]
|
93
135
|
def call
|
94
136
|
[
|
95
137
|
range_begin,
|
@@ -97,7 +139,9 @@ module Rucoa
|
|
97
139
|
range_else,
|
98
140
|
range_ensure,
|
99
141
|
range_end
|
100
|
-
].compact
|
142
|
+
].compact.map do |parser_range|
|
143
|
+
Highlights::TextHighlight.new(parser_range: parser_range)
|
144
|
+
end
|
101
145
|
end
|
102
146
|
|
103
147
|
private
|
@@ -126,7 +170,7 @@ module Rucoa
|
|
126
170
|
@node.ensure.location.keyword
|
127
171
|
end
|
128
172
|
|
129
|
-
# @return [Array
|
173
|
+
# @return [Array]
|
130
174
|
def ranges_resbody
|
131
175
|
return [] unless rescue_node
|
132
176
|
|
@@ -151,19 +195,21 @@ module Rucoa
|
|
151
195
|
end
|
152
196
|
|
153
197
|
class CaseMapper < Base
|
154
|
-
# @return [Array
|
198
|
+
# @return [Array]
|
155
199
|
def call
|
156
200
|
[
|
157
201
|
@node.location.keyword,
|
158
202
|
*ranges_when,
|
159
203
|
@node.location.else,
|
160
204
|
@node.location.end
|
161
|
-
].compact
|
205
|
+
].compact.map do |parser_range|
|
206
|
+
Highlights::TextHighlight.new(parser_range: parser_range)
|
207
|
+
end
|
162
208
|
end
|
163
209
|
|
164
210
|
private
|
165
211
|
|
166
|
-
# @return [Array
|
212
|
+
# @return [Array]
|
167
213
|
def ranges_when
|
168
214
|
@node.whens.map do |when_node|
|
169
215
|
when_node.location.keyword
|
@@ -172,22 +218,35 @@ module Rucoa
|
|
172
218
|
end
|
173
219
|
|
174
220
|
class IfMapper < Base
|
175
|
-
# @return [Array
|
221
|
+
# @return [Array]
|
176
222
|
def call
|
177
223
|
return AnyMapper.call(@node.parent) if @node.elsif?
|
224
|
+
return [] if @node.modifier?
|
178
225
|
|
179
226
|
[
|
180
|
-
|
181
|
-
*
|
182
|
-
|
183
|
-
|
227
|
+
highlight_keyword,
|
228
|
+
*highlights_elsif,
|
229
|
+
highlight_else,
|
230
|
+
highlight_end
|
184
231
|
].compact
|
185
232
|
end
|
186
233
|
|
187
234
|
private
|
188
235
|
|
189
|
-
|
190
|
-
|
236
|
+
def highlight_else
|
237
|
+
Highlights::TextHighlight.new(parser_range: @node.location.else) if @node.location.else
|
238
|
+
end
|
239
|
+
|
240
|
+
def highlight_end
|
241
|
+
Highlights::TextHighlight.new(parser_range: @node.location.end)
|
242
|
+
end
|
243
|
+
|
244
|
+
def highlight_keyword
|
245
|
+
Highlights::TextHighlight.new(parser_range: @node.location.keyword)
|
246
|
+
end
|
247
|
+
|
248
|
+
# @return [Array]
|
249
|
+
def highlights_elsif
|
191
250
|
return [] unless @node.elsif
|
192
251
|
|
193
252
|
ElsifMapper.call(@node.elsif)
|
@@ -195,38 +254,250 @@ module Rucoa
|
|
195
254
|
end
|
196
255
|
|
197
256
|
class ElsifMapper < IfMapper
|
198
|
-
# @return [Array
|
257
|
+
# @return [Array]
|
199
258
|
def call
|
200
259
|
[
|
201
|
-
*
|
202
|
-
|
260
|
+
*highlights_elsif,
|
261
|
+
highlight_else
|
203
262
|
].compact
|
204
263
|
end
|
205
264
|
end
|
206
265
|
|
207
266
|
class ForMapper < Base
|
208
|
-
# @return [Array
|
267
|
+
# @return [Array]
|
209
268
|
def call
|
210
269
|
[
|
211
270
|
@node.location.keyword,
|
212
271
|
@node.location.in,
|
213
272
|
@node.location.end
|
273
|
+
].compact.map do |parser_range|
|
274
|
+
Highlights::TextHighlight.new(parser_range: parser_range)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
class GlobalVariableMapper < Base
|
280
|
+
# @return [Array]
|
281
|
+
def call
|
282
|
+
nodes.map do |node|
|
283
|
+
case node
|
284
|
+
when Nodes::GvarNode
|
285
|
+
Highlights::ReadHighlight
|
286
|
+
when Nodes::GvasgnNode
|
287
|
+
Highlights::WriteHighlight
|
288
|
+
end.new(parser_range: node.location.name)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
private
|
293
|
+
|
294
|
+
# @return [Rucoa::Nodes::Base, nil]
|
295
|
+
def global_variable_scopable_node
|
296
|
+
@node.ancestors.last
|
297
|
+
end
|
298
|
+
|
299
|
+
# @return [Enumerable<Rucoa::Nodes::Base>]
|
300
|
+
def nodes
|
301
|
+
return [] unless global_variable_scopable_node
|
302
|
+
|
303
|
+
global_variable_scopable_node.each_descendant_node(:gvar, :gvasgn).select do |node|
|
304
|
+
node.name == @node.name
|
305
|
+
end
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
class InstanceVariableMapper < Base
|
310
|
+
# @return [Array]
|
311
|
+
def call
|
312
|
+
nodes.map do |node|
|
313
|
+
case node
|
314
|
+
when Nodes::IvarNode
|
315
|
+
Highlights::ReadHighlight
|
316
|
+
when Nodes::IvasgnNode
|
317
|
+
Highlights::WriteHighlight
|
318
|
+
end.new(parser_range: node.location.name)
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
private
|
323
|
+
|
324
|
+
# @return [Rucoa::Nodes::Base, nil]
|
325
|
+
def instance_variable_scopable_node
|
326
|
+
@instance_variable_scopable_node ||= @node.each_ancestor(:class, :module).first
|
327
|
+
end
|
328
|
+
|
329
|
+
# @todo Stop descendant searching if scope boundary node is found (e.g. class, def, etc.).
|
330
|
+
# @return [Enumerable<Rucoa::Nodes::Base>]
|
331
|
+
def nodes
|
332
|
+
return [] unless instance_variable_scopable_node
|
333
|
+
|
334
|
+
instance_variable_scopable_node.each_descendant_node(:ivar, :ivasgn).select do |node|
|
335
|
+
node.name == @node.name
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
class ClassVariableMapper < Base
|
341
|
+
# @return [Array]
|
342
|
+
def call
|
343
|
+
nodes.map do |node|
|
344
|
+
case node
|
345
|
+
when Nodes::CvarNode
|
346
|
+
Highlights::ReadHighlight
|
347
|
+
when Nodes::CvasgnNode
|
348
|
+
Highlights::WriteHighlight
|
349
|
+
end.new(parser_range: node.location.name)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
private
|
354
|
+
|
355
|
+
# @return [Rucoa::Nodes::Base, nil]
|
356
|
+
def instance_variable_scopable_node
|
357
|
+
@node.each_ancestor(:class, :module).first
|
358
|
+
end
|
359
|
+
|
360
|
+
# @return [Enumerable<Rucoa::Nodes::Base>]
|
361
|
+
def nodes
|
362
|
+
return [] unless instance_variable_scopable_node
|
363
|
+
|
364
|
+
instance_variable_scopable_node.each_descendant_node(:cvar, :cvasgn).select do |node|
|
365
|
+
node.name == @node.name
|
366
|
+
end
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
class LocalVariableMapper < Base
|
371
|
+
SCOPE_BOUNDARY_NODE_TYPES = ::Set[
|
372
|
+
:class,
|
373
|
+
:def,
|
374
|
+
:defs,
|
375
|
+
:module,
|
376
|
+
]
|
377
|
+
|
378
|
+
# @return [Array]
|
379
|
+
def call
|
380
|
+
nodes.map do |node|
|
381
|
+
case node
|
382
|
+
when Nodes::LvarNode
|
383
|
+
Highlights::ReadHighlight
|
384
|
+
when Nodes::ArgNode, Nodes::LvasgnNode
|
385
|
+
Highlights::WriteHighlight
|
386
|
+
end.new(parser_range: node.location.name)
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
private
|
391
|
+
|
392
|
+
# @return [Rucoa::Nodes::ArgNode, Rucoa::Nodes::LvasgnNode, nil]
|
393
|
+
def assignment_node
|
394
|
+
@assignment_node ||=
|
395
|
+
case @node
|
396
|
+
when Nodes::ArgNode, Nodes::LvasgnNode
|
397
|
+
@node
|
398
|
+
when Nodes::LvarNode
|
399
|
+
(
|
400
|
+
[@node] + @node.ancestors.take_while do |node|
|
401
|
+
!SCOPE_BOUNDARY_NODE_TYPES.include?(node.type)
|
402
|
+
end
|
403
|
+
).find do |node|
|
404
|
+
case node
|
405
|
+
when Nodes::ArgNode, Nodes::LvasgnNode
|
406
|
+
node.name == @node.name
|
407
|
+
when Nodes::BlockNode, Nodes::DefNode
|
408
|
+
target = node.arguments.find do |argument|
|
409
|
+
argument.name == @node.name
|
410
|
+
end
|
411
|
+
break target if target
|
412
|
+
else
|
413
|
+
target = node.previous_sibling_nodes.reverse.find do |sibling_node|
|
414
|
+
lvasgn_node = [
|
415
|
+
sibling_node,
|
416
|
+
*sibling_node.descendant_nodes
|
417
|
+
].reverse.find do |sibling_or_sibling_descendant|
|
418
|
+
case sibling_or_sibling_descendant
|
419
|
+
when Nodes::LvasgnNode
|
420
|
+
break sibling_or_sibling_descendant if sibling_or_sibling_descendant.name == @node.name
|
421
|
+
end
|
422
|
+
end
|
423
|
+
break lvasgn_node if lvasgn_node
|
424
|
+
end
|
425
|
+
break target if target
|
426
|
+
end
|
427
|
+
end || @node.each_ancestor(:def, :defs).first&.then do |node|
|
428
|
+
break node.arguments.find do |argument|
|
429
|
+
argument.name == @node.name
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
# @return [Enumerable<Rucoa::Nodes::ArgNode, Rucoa::Nodes::LvarNode, Rucoa::Nodes::LvasgnNode>]
|
436
|
+
def nodes
|
437
|
+
[
|
438
|
+
assignment_node,
|
439
|
+
*reference_nodes
|
214
440
|
].compact
|
215
441
|
end
|
442
|
+
|
443
|
+
# @return [Enumerable<Rucoa::Nodes::LvarNode>]
|
444
|
+
def reference_nodes
|
445
|
+
return [] unless assignment_node
|
446
|
+
|
447
|
+
case assignment_node
|
448
|
+
when Nodes::ArgNode
|
449
|
+
assignment_node.each_ancestor(:block, :def, :defs).first.body_children
|
450
|
+
when Nodes::LvasgnNode
|
451
|
+
(
|
452
|
+
[assignment_node] + assignment_node.ancestors.take_while do |node|
|
453
|
+
!SCOPE_BOUNDARY_NODE_TYPES.include?(node.type)
|
454
|
+
end
|
455
|
+
).flat_map(&:next_sibling_nodes)
|
456
|
+
end.flat_map do |node|
|
457
|
+
[
|
458
|
+
node,
|
459
|
+
*node.descendant_nodes
|
460
|
+
]
|
461
|
+
end.take_while do |node| # FIXME: flat_map and take_while are not correct solution for shadowing.
|
462
|
+
case node
|
463
|
+
when Nodes::ArgNode, Nodes::LvasgnNode
|
464
|
+
node.equal?(assignment_node) || node.name != assignment_node.name
|
465
|
+
else
|
466
|
+
true
|
467
|
+
end
|
468
|
+
end.select do |node|
|
469
|
+
case node
|
470
|
+
when Nodes::LvarNode
|
471
|
+
node.name == @node.name
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
class UnshadowedNodeVisitor
|
477
|
+
def initialize(
|
478
|
+
node:,
|
479
|
+
&block
|
480
|
+
)
|
481
|
+
@block = block
|
482
|
+
@node = node
|
483
|
+
end
|
484
|
+
end
|
216
485
|
end
|
217
486
|
|
218
487
|
class ModuleMapper < Base
|
219
|
-
# @return [Array
|
488
|
+
# @return [Array]
|
220
489
|
def call
|
221
490
|
[
|
222
491
|
@node.location.keyword,
|
223
492
|
@node.location.end
|
224
|
-
]
|
493
|
+
].map do |parser_range|
|
494
|
+
Highlights::TextHighlight.new(parser_range: parser_range)
|
495
|
+
end
|
225
496
|
end
|
226
497
|
end
|
227
498
|
|
228
499
|
class SendMapper < Base
|
229
|
-
# @return [Array
|
500
|
+
# @return [Array]
|
230
501
|
def call
|
231
502
|
return [] unless @node.block
|
232
503
|
|
@@ -235,19 +506,23 @@ module Rucoa
|
|
235
506
|
end
|
236
507
|
|
237
508
|
class WhenMapper < Base
|
238
|
-
# @return [Array
|
509
|
+
# @return [Array]
|
239
510
|
def call
|
240
511
|
CaseMapper.call(@node.parent)
|
241
512
|
end
|
242
513
|
end
|
243
514
|
|
244
515
|
class WhileMapper < Base
|
245
|
-
# @return [Array
|
516
|
+
# @return [Array]
|
246
517
|
def call
|
518
|
+
return [] if @node.modifier?
|
519
|
+
|
247
520
|
[
|
248
521
|
@node.location.keyword,
|
249
522
|
@node.location.end
|
250
|
-
]
|
523
|
+
].map do |parser_range|
|
524
|
+
Highlights::TextHighlight.new(parser_range: parser_range)
|
525
|
+
end
|
251
526
|
end
|
252
527
|
end
|
253
528
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module NodeConcerns
|
5
|
+
module Modifier
|
6
|
+
# @return [Boolean]
|
7
|
+
# @example returns true on modifier if node
|
8
|
+
# node = Rucoa::Source.new(
|
9
|
+
# content: <<~RUBY,
|
10
|
+
# 1 if true
|
11
|
+
# RUBY
|
12
|
+
# uri: 'file:///path/to/example.rb'
|
13
|
+
# ).node_at(
|
14
|
+
# Rucoa::Position.new(
|
15
|
+
# column: 2,
|
16
|
+
# line: 1
|
17
|
+
# )
|
18
|
+
# )
|
19
|
+
# expect(node).to be_modifier
|
20
|
+
# @example returns false on non-modifier if node
|
21
|
+
# node = Rucoa::Source.new(
|
22
|
+
# content: <<~RUBY,
|
23
|
+
# if true
|
24
|
+
# 1
|
25
|
+
# end
|
26
|
+
# RUBY
|
27
|
+
# uri: 'file:///path/to/example.rb'
|
28
|
+
# ).root_node
|
29
|
+
# expect(node).not_to be_modifier
|
30
|
+
def modifier?
|
31
|
+
location.end.nil?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module NodeConcerns
|
5
|
+
module Variable
|
6
|
+
# @return [String]
|
7
|
+
# @example returns variable name
|
8
|
+
# node = Rucoa::Source.new(
|
9
|
+
# content: <<~RUBY,
|
10
|
+
# foo = 1
|
11
|
+
# foo
|
12
|
+
# RUBY
|
13
|
+
# uri: 'file:///path/to/example.rb'
|
14
|
+
# ).node_at(
|
15
|
+
# Rucoa::Position.new(
|
16
|
+
# column: 0,
|
17
|
+
# line: 2
|
18
|
+
# )
|
19
|
+
# )
|
20
|
+
# expect(node.name).to eq('foo')
|
21
|
+
def name
|
22
|
+
children[0].to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rucoa/node_concerns.rb
CHANGED
@@ -3,7 +3,9 @@
|
|
3
3
|
module Rucoa
|
4
4
|
module NodeConcerns
|
5
5
|
autoload :Body, 'rucoa/node_concerns/body'
|
6
|
+
autoload :Modifier, 'rucoa/node_concerns/modifier'
|
6
7
|
autoload :QualifiedName, 'rucoa/node_concerns/qualified_name'
|
7
8
|
autoload :Rescue, 'rucoa/node_concerns/rescue'
|
9
|
+
autoload :Variable, 'rucoa/node_concerns/variable'
|
8
10
|
end
|
9
11
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rucoa
|
4
|
+
module Nodes
|
5
|
+
class ArgNode < Base
|
6
|
+
# @return [String]
|
7
|
+
# @example returns variable name
|
8
|
+
# node = Rucoa::Source.new(
|
9
|
+
# content: <<~RUBY,
|
10
|
+
# def foo(bar)
|
11
|
+
# end
|
12
|
+
# RUBY
|
13
|
+
# uri: 'file:///path/to/example.rb'
|
14
|
+
# ).node_at(
|
15
|
+
# Rucoa::Position.new(
|
16
|
+
# column: 8,
|
17
|
+
# line: 1
|
18
|
+
# )
|
19
|
+
# )
|
20
|
+
# expect(node.name).to eq('bar')
|
21
|
+
def name
|
22
|
+
children[0].to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rucoa/nodes/base.rb
CHANGED
@@ -20,8 +20,13 @@ module Rucoa
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# @return [Array<Rucoa::Nodes::Base>]
|
23
|
-
def
|
24
|
-
|
23
|
+
def child_nodes
|
24
|
+
each_child_node.to_a
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [Array<Rucoa::Nodes::Base>]
|
28
|
+
def descendant_nodes
|
29
|
+
each_descendant_node.to_a
|
25
30
|
end
|
26
31
|
|
27
32
|
# @param types [Array<Symbol>]
|
@@ -53,13 +58,13 @@ module Rucoa
|
|
53
58
|
# @param types [Array<Symbol>]
|
54
59
|
# @return [Rucoa::Nodes::Base] if a block is given
|
55
60
|
# @return [Enumerator] if no block is given
|
56
|
-
def
|
61
|
+
def each_descendant_node(
|
57
62
|
*types,
|
58
63
|
&block
|
59
64
|
)
|
60
65
|
return to_enum(__method__, *types) unless block
|
61
66
|
|
62
|
-
|
67
|
+
visit_descendant_nodes(types, &block)
|
63
68
|
self
|
64
69
|
end
|
65
70
|
|
@@ -126,6 +131,32 @@ module Rucoa
|
|
126
131
|
module_nesting.first || 'Object'
|
127
132
|
end
|
128
133
|
|
134
|
+
# @return [Array<Rucoa::Nodes::Base>]
|
135
|
+
# @example returns next siblings
|
136
|
+
# node = Rucoa::Source.new(
|
137
|
+
# content: <<~RUBY,
|
138
|
+
# def foo
|
139
|
+
# a
|
140
|
+
# b
|
141
|
+
# c
|
142
|
+
# d
|
143
|
+
# e
|
144
|
+
# end
|
145
|
+
# RUBY
|
146
|
+
# uri: 'file:///path/to/example.rb'
|
147
|
+
# ).node_at(
|
148
|
+
# Rucoa::Position.new(
|
149
|
+
# column: 2,
|
150
|
+
# line: 4
|
151
|
+
# )
|
152
|
+
# )
|
153
|
+
# expect(node.next_sibling_nodes.map(&:name)).to eq(%w[d e])
|
154
|
+
def next_sibling_nodes
|
155
|
+
return [] unless parent
|
156
|
+
|
157
|
+
parent.child_nodes[(sibling_node_index + 1)..]
|
158
|
+
end
|
159
|
+
|
129
160
|
# @return [Rucoa::Nodes::Base, nil]
|
130
161
|
def parent
|
131
162
|
@mutable_attributes[:parent]
|
@@ -136,6 +167,32 @@ module Rucoa
|
|
136
167
|
@mutable_attributes[:parent] = node
|
137
168
|
end
|
138
169
|
|
170
|
+
# @return [Array<Rucoa::Nodes::Base>]
|
171
|
+
# @example returns previous siblings
|
172
|
+
# node = Rucoa::Source.new(
|
173
|
+
# content: <<~RUBY,
|
174
|
+
# def foo
|
175
|
+
# a
|
176
|
+
# b
|
177
|
+
# c
|
178
|
+
# d
|
179
|
+
# e
|
180
|
+
# end
|
181
|
+
# RUBY
|
182
|
+
# uri: 'file:///path/to/example.rb'
|
183
|
+
# ).node_at(
|
184
|
+
# Rucoa::Position.new(
|
185
|
+
# column: 2,
|
186
|
+
# line: 4
|
187
|
+
# )
|
188
|
+
# )
|
189
|
+
# expect(node.previous_sibling_nodes.map(&:name)).to eq(%w[a b])
|
190
|
+
def previous_sibling_nodes
|
191
|
+
return [] unless parent
|
192
|
+
|
193
|
+
parent.child_nodes[0...sibling_node_index]
|
194
|
+
end
|
195
|
+
|
139
196
|
# @note Override.
|
140
197
|
# Some nodes change their type depending on the context.
|
141
198
|
# For example, `const` node can be `casgn` node.
|
@@ -155,21 +212,28 @@ module Rucoa
|
|
155
212
|
|
156
213
|
protected
|
157
214
|
|
158
|
-
# Visit all
|
215
|
+
# Visit all descendant_nodes.
|
159
216
|
# @param types [Array<Symbol>]
|
160
217
|
# @return [void]
|
161
|
-
def
|
218
|
+
def visit_descendant_nodes(
|
162
219
|
types,
|
163
220
|
&block
|
164
221
|
)
|
165
222
|
each_child_node do |child|
|
166
223
|
yield(child) if types.empty? || types.include?(child.type)
|
167
|
-
child.
|
224
|
+
child.visit_descendant_nodes(types, &block)
|
168
225
|
end
|
169
226
|
end
|
170
227
|
|
171
228
|
private
|
172
229
|
|
230
|
+
# @return [Integer, nil]
|
231
|
+
def sibling_node_index
|
232
|
+
parent&.child_nodes&.index do |child|
|
233
|
+
child.equal?(self)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
173
237
|
# Visits all ancestors.
|
174
238
|
# @param types [Array<Symbol>]
|
175
239
|
# @return [void]
|
@@ -6,6 +6,20 @@ module Rucoa
|
|
6
6
|
include NodeConcerns::Body
|
7
7
|
include NodeConcerns::Rescue
|
8
8
|
|
9
|
+
# @return [Array<Rucoa::Nodes::ArgNode>]
|
10
|
+
# @example returns arguments
|
11
|
+
# node = Rucoa::Source.new(
|
12
|
+
# content: <<~RUBY,
|
13
|
+
# foo do |bar, baz|
|
14
|
+
# end
|
15
|
+
# RUBY
|
16
|
+
# uri: 'file:///path/to/example.rb'
|
17
|
+
# ).root_node
|
18
|
+
# expect(node.arguments.map(&:name)).to eq(%w[bar baz])
|
19
|
+
def arguments
|
20
|
+
children[-2]
|
21
|
+
end
|
22
|
+
|
9
23
|
# @return [Rucoa::Nodes::SendNode]
|
10
24
|
# @example returns send node
|
11
25
|
# node = Rucoa::Source.new(
|
data/lib/rucoa/nodes/def_node.rb
CHANGED
@@ -6,6 +6,20 @@ module Rucoa
|
|
6
6
|
include NodeConcerns::Body
|
7
7
|
include NodeConcerns::Rescue
|
8
8
|
|
9
|
+
# @return [Array<Rucoa::Nodes::ArgNode>]
|
10
|
+
# @example returns arguments
|
11
|
+
# node = Rucoa::Source.new(
|
12
|
+
# content: <<~RUBY,
|
13
|
+
# def foo(bar, baz)
|
14
|
+
# end
|
15
|
+
# RUBY
|
16
|
+
# uri: 'file:///path/to/example.rb'
|
17
|
+
# ).root_node
|
18
|
+
# expect(node.arguments.map(&:name)).to eq(%w[bar baz])
|
19
|
+
def arguments
|
20
|
+
children[-2]
|
21
|
+
end
|
22
|
+
|
9
23
|
# @return [String]
|
10
24
|
def method_marker
|
11
25
|
if singleton?
|
data/lib/rucoa/nodes/if_node.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
module Rucoa
|
4
4
|
module Nodes
|
5
5
|
class IfNode < Base
|
6
|
+
include NodeConcerns::Modifier
|
7
|
+
|
6
8
|
# @return [Rucoa::Nodes::Base, nil]
|
7
9
|
def branch_else
|
8
10
|
children[2]
|
@@ -25,7 +27,7 @@ module Rucoa
|
|
25
27
|
|
26
28
|
# @return [Boolean]
|
27
29
|
def elsif?
|
28
|
-
parent.is_a?(Nodes::IfNode) &&
|
30
|
+
parent.is_a?(Nodes::IfNode) && equal?(parent.elsif)
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
@@ -3,24 +3,7 @@
|
|
3
3
|
module Rucoa
|
4
4
|
module Nodes
|
5
5
|
class LvarNode < Base
|
6
|
-
|
7
|
-
# @example returns local variable name
|
8
|
-
# node = Rucoa::Source.new(
|
9
|
-
# content: <<~RUBY,
|
10
|
-
# foo = 1
|
11
|
-
# foo
|
12
|
-
# RUBY
|
13
|
-
# uri: 'file:///path/to/example.rb'
|
14
|
-
# ).node_at(
|
15
|
-
# Rucoa::Position.new(
|
16
|
-
# column: 2,
|
17
|
-
# line: 2
|
18
|
-
# )
|
19
|
-
# )
|
20
|
-
# expect(node.name).to eq('foo')
|
21
|
-
def name
|
22
|
-
children[0].to_s
|
23
|
-
end
|
6
|
+
include NodeConcerns::Variable
|
24
7
|
end
|
25
8
|
end
|
26
9
|
end
|
data/lib/rucoa/nodes.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
module Rucoa
|
4
4
|
module Nodes
|
5
|
+
autoload :ArgNode, 'rucoa/nodes/arg_node'
|
6
|
+
autoload :ArgsNode, 'rucoa/nodes/args_node'
|
5
7
|
autoload :Base, 'rucoa/nodes/base'
|
6
8
|
autoload :BeginNode, 'rucoa/nodes/begin_node'
|
7
9
|
autoload :BlockNode, 'rucoa/nodes/block_node'
|
@@ -10,11 +12,18 @@ module Rucoa
|
|
10
12
|
autoload :CbaseNode, 'rucoa/nodes/cbase_node'
|
11
13
|
autoload :ClassNode, 'rucoa/nodes/class_node'
|
12
14
|
autoload :ConstNode, 'rucoa/nodes/const_node'
|
15
|
+
autoload :CvarNode, 'rucoa/nodes/cvar_node'
|
16
|
+
autoload :CvasgnNode, 'rucoa/nodes/cvasgn_node'
|
13
17
|
autoload :DefNode, 'rucoa/nodes/def_node'
|
14
18
|
autoload :EnsureNode, 'rucoa/nodes/ensure_node'
|
15
19
|
autoload :ForNode, 'rucoa/nodes/for_node'
|
20
|
+
autoload :GvarNode, 'rucoa/nodes/gvar_node'
|
21
|
+
autoload :GvasgnNode, 'rucoa/nodes/gvasgn_node'
|
16
22
|
autoload :IfNode, 'rucoa/nodes/if_node'
|
23
|
+
autoload :IvarNode, 'rucoa/nodes/ivar_node'
|
24
|
+
autoload :IvasgnNode, 'rucoa/nodes/ivasgn_node'
|
17
25
|
autoload :LvarNode, 'rucoa/nodes/lvar_node'
|
26
|
+
autoload :LvasgnNode, 'rucoa/nodes/lvasgn_node'
|
18
27
|
autoload :ModuleNode, 'rucoa/nodes/module_node'
|
19
28
|
autoload :ResbodyNode, 'rucoa/nodes/resbody_node'
|
20
29
|
autoload :RescueNode, 'rucoa/nodes/rescue_node'
|
data/lib/rucoa/parser_builder.rb
CHANGED
@@ -5,6 +5,8 @@ require 'parser/current'
|
|
5
5
|
module Rucoa
|
6
6
|
class ParserBuilder < ::Parser::Builders::Default
|
7
7
|
NODE_CLASS_BY_TYPE = {
|
8
|
+
arg: Nodes::ArgNode,
|
9
|
+
args: Nodes::ArgsNode,
|
8
10
|
begin: Nodes::BeginNode,
|
9
11
|
block: Nodes::BlockNode,
|
10
12
|
case: Nodes::CaseNode,
|
@@ -13,13 +15,21 @@ module Rucoa
|
|
13
15
|
class: Nodes::ClassNode,
|
14
16
|
const: Nodes::ConstNode,
|
15
17
|
csend: Nodes::SendNode,
|
18
|
+
cvar: Nodes::CvarNode,
|
19
|
+
cvasgn: Nodes::CvasgnNode,
|
16
20
|
def: Nodes::DefNode,
|
17
21
|
defs: Nodes::DefNode,
|
18
22
|
ensure: Nodes::EnsureNode,
|
19
23
|
for: Nodes::ForNode,
|
24
|
+
gvar: Nodes::GvarNode,
|
25
|
+
gvasgn: Nodes::GvasgnNode,
|
20
26
|
if: Nodes::IfNode,
|
27
|
+
ivar: Nodes::IvarNode,
|
28
|
+
ivasgn: Nodes::IvasgnNode,
|
29
|
+
kwarg: Nodes::ArgNode,
|
21
30
|
kwbegin: Nodes::BeginNode,
|
22
31
|
lvar: Nodes::LvarNode,
|
32
|
+
lvasgn: Nodes::LvasgnNode,
|
23
33
|
module: Nodes::ModuleNode,
|
24
34
|
resbody: Nodes::ResbodyNode,
|
25
35
|
rescue: Nodes::RescueNode,
|
data/lib/rucoa/source.rb
CHANGED
data/lib/rucoa/version.rb
CHANGED
data/rucoa.gemspec
CHANGED
@@ -16,7 +16,6 @@ Gem::Specification.new do |spec|
|
|
16
16
|
spec.metadata['homepage_uri'] = spec.homepage
|
17
17
|
spec.metadata['source_code_uri'] = spec.homepage
|
18
18
|
spec.metadata['changelog_uri'] = "#{spec.homepage}/releases"
|
19
|
-
spec.metadata['rubygems_mfa_required'] = 'true'
|
20
19
|
|
21
20
|
spec.files = Dir.chdir(__dir__) do
|
22
21
|
`git ls-files -z`.split("\x0").reject do |f|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rucoa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryo Nakamura
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-10-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -86,6 +86,7 @@ files:
|
|
86
86
|
- exe/rucoa
|
87
87
|
- images/diagnostics.gif
|
88
88
|
- images/document-formatting.gif
|
89
|
+
- images/document-highlight.gif
|
89
90
|
- images/document-symbol.gif
|
90
91
|
- images/selection-ranges.gif
|
91
92
|
- lib/rucoa.rb
|
@@ -131,10 +132,14 @@ files:
|
|
131
132
|
- lib/rucoa/message_writer.rb
|
132
133
|
- lib/rucoa/node_concerns.rb
|
133
134
|
- lib/rucoa/node_concerns/body.rb
|
135
|
+
- lib/rucoa/node_concerns/modifier.rb
|
134
136
|
- lib/rucoa/node_concerns/qualified_name.rb
|
135
137
|
- lib/rucoa/node_concerns/rescue.rb
|
138
|
+
- lib/rucoa/node_concerns/variable.rb
|
136
139
|
- lib/rucoa/node_inspector.rb
|
137
140
|
- lib/rucoa/nodes.rb
|
141
|
+
- lib/rucoa/nodes/arg_node.rb
|
142
|
+
- lib/rucoa/nodes/args_node.rb
|
138
143
|
- lib/rucoa/nodes/base.rb
|
139
144
|
- lib/rucoa/nodes/begin_node.rb
|
140
145
|
- lib/rucoa/nodes/block_node.rb
|
@@ -143,11 +148,18 @@ files:
|
|
143
148
|
- lib/rucoa/nodes/cbase_node.rb
|
144
149
|
- lib/rucoa/nodes/class_node.rb
|
145
150
|
- lib/rucoa/nodes/const_node.rb
|
151
|
+
- lib/rucoa/nodes/cvar_node.rb
|
152
|
+
- lib/rucoa/nodes/cvasgn_node.rb
|
146
153
|
- lib/rucoa/nodes/def_node.rb
|
147
154
|
- lib/rucoa/nodes/ensure_node.rb
|
148
155
|
- lib/rucoa/nodes/for_node.rb
|
156
|
+
- lib/rucoa/nodes/gvar_node.rb
|
157
|
+
- lib/rucoa/nodes/gvasgn_node.rb
|
149
158
|
- lib/rucoa/nodes/if_node.rb
|
159
|
+
- lib/rucoa/nodes/ivar_node.rb
|
160
|
+
- lib/rucoa/nodes/ivasgn_node.rb
|
150
161
|
- lib/rucoa/nodes/lvar_node.rb
|
162
|
+
- lib/rucoa/nodes/lvasgn_node.rb
|
151
163
|
- lib/rucoa/nodes/module_node.rb
|
152
164
|
- lib/rucoa/nodes/resbody_node.rb
|
153
165
|
- lib/rucoa/nodes/rescue_node.rb
|
@@ -199,7 +211,6 @@ metadata:
|
|
199
211
|
homepage_uri: https://github.com/r7kamura/rucoa
|
200
212
|
source_code_uri: https://github.com/r7kamura/rucoa
|
201
213
|
changelog_uri: https://github.com/r7kamura/rucoa/releases
|
202
|
-
rubygems_mfa_required: 'true'
|
203
214
|
post_install_message:
|
204
215
|
rdoc_options: []
|
205
216
|
require_paths:
|