rucoa 0.12.0 → 0.13.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/.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
|

|
37
37
|
|
38
|
+
### Highlight
|
39
|
+
|
40
|
+
Highlights corresponding keywords.
|
41
|
+
|
42
|
+

|
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:
|