rucoa 0.11.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -3
  3. data/Gemfile.lock +3 -3
  4. data/README.md +6 -1
  5. data/images/document-highlight.gif +0 -0
  6. data/lib/rucoa/configuration.rb +22 -12
  7. data/lib/rucoa/definition_store.rb +131 -131
  8. data/lib/rucoa/definitions/method_definition.rb +11 -11
  9. data/lib/rucoa/handler_concerns/configuration_requestable.rb +7 -7
  10. data/lib/rucoa/handler_concerns/diagnostics_publishable.rb +11 -11
  11. data/lib/rucoa/handler_concerns/text_document_position_parameters.rb +29 -0
  12. data/lib/rucoa/handler_concerns/text_document_uri_parameters.rb +21 -0
  13. data/lib/rucoa/handler_concerns.rb +2 -0
  14. data/lib/rucoa/handlers/base.rb +9 -9
  15. data/lib/rucoa/handlers/initialize_handler.rb +1 -0
  16. data/lib/rucoa/handlers/initialized_handler.rb +16 -16
  17. data/lib/rucoa/handlers/text_document_code_action_handler.rb +12 -12
  18. data/lib/rucoa/handlers/text_document_completion_handler.rb +85 -99
  19. data/lib/rucoa/handlers/text_document_definition_handler.rb +11 -30
  20. data/lib/rucoa/handlers/text_document_did_close_handler.rb +2 -8
  21. data/lib/rucoa/handlers/text_document_did_open_handler.rb +3 -7
  22. data/lib/rucoa/handlers/text_document_document_highlight_handler.rb +531 -0
  23. data/lib/rucoa/handlers/text_document_document_symbol_handler.rb +47 -76
  24. data/lib/rucoa/handlers/text_document_formatting_handler.rb +16 -24
  25. data/lib/rucoa/handlers/text_document_hover_handler.rb +24 -43
  26. data/lib/rucoa/handlers/text_document_range_formatting_handler.rb +17 -25
  27. data/lib/rucoa/handlers/text_document_selection_range_handler.rb +11 -19
  28. data/lib/rucoa/handlers/text_document_signature_help_handler.rb +17 -36
  29. data/lib/rucoa/handlers.rb +1 -0
  30. data/lib/rucoa/node_concerns/body.rb +1 -1
  31. data/lib/rucoa/node_concerns/modifier.rb +35 -0
  32. data/lib/rucoa/node_concerns/qualified_name.rb +5 -5
  33. data/lib/rucoa/node_concerns/rescue.rb +21 -0
  34. data/lib/rucoa/node_concerns/variable.rb +26 -0
  35. data/lib/rucoa/node_concerns.rb +3 -0
  36. data/lib/rucoa/node_inspector.rb +5 -5
  37. data/lib/rucoa/nodes/arg_node.rb +26 -0
  38. data/lib/rucoa/nodes/args_node.rb +14 -0
  39. data/lib/rucoa/nodes/base.rb +111 -47
  40. data/lib/rucoa/nodes/begin_node.rb +2 -0
  41. data/lib/rucoa/nodes/block_node.rb +38 -0
  42. data/lib/rucoa/nodes/case_node.rb +24 -0
  43. data/lib/rucoa/nodes/const_node.rb +26 -26
  44. data/lib/rucoa/nodes/cvar_node.rb +9 -0
  45. data/lib/rucoa/nodes/cvasgn_node.rb +9 -0
  46. data/lib/rucoa/nodes/def_node.rb +28 -13
  47. data/lib/rucoa/nodes/ensure_node.rb +19 -0
  48. data/lib/rucoa/nodes/for_node.rb +8 -0
  49. data/lib/rucoa/nodes/gvar_node.rb +9 -0
  50. data/lib/rucoa/nodes/gvasgn_node.rb +9 -0
  51. data/lib/rucoa/nodes/if_node.rb +34 -0
  52. data/lib/rucoa/nodes/ivar_node.rb +9 -0
  53. data/lib/rucoa/nodes/ivasgn_node.rb +9 -0
  54. data/lib/rucoa/nodes/lvar_node.rb +1 -18
  55. data/lib/rucoa/nodes/lvasgn_node.rb +9 -0
  56. data/lib/rucoa/nodes/resbody_node.rb +8 -0
  57. data/lib/rucoa/nodes/rescue_node.rb +17 -0
  58. data/lib/rucoa/nodes/send_node.rb +40 -0
  59. data/lib/rucoa/nodes/until_node.rb +9 -0
  60. data/lib/rucoa/nodes/when_node.rb +8 -0
  61. data/lib/rucoa/nodes/while_node.rb +9 -0
  62. data/lib/rucoa/nodes.rb +19 -1
  63. data/lib/rucoa/parser_builder.rb +26 -2
  64. data/lib/rucoa/range.rb +9 -3
  65. data/lib/rucoa/rbs/constant_definition_mapper.rb +5 -5
  66. data/lib/rucoa/rbs/method_definition_mapper.rb +18 -18
  67. data/lib/rucoa/rbs/module_definition_mapper.rb +13 -13
  68. data/lib/rucoa/rbs/ruby_definitions_loader.rb +5 -5
  69. data/lib/rucoa/rubocop/configuration_checker.rb +7 -7
  70. data/lib/rucoa/server.rb +24 -23
  71. data/lib/rucoa/source.rb +6 -6
  72. data/lib/rucoa/source_store.rb +8 -8
  73. data/lib/rucoa/version.rb +1 -1
  74. data/lib/rucoa/yard/definition_generators/method_definition_generator.rb +1 -1
  75. data/lib/rucoa/yard/definitions_loader.rb +1 -1
  76. data/rucoa.gemspec +0 -1
  77. metadata +28 -4
  78. data/lib/rucoa/nodes/defs_node.rb +0 -33
@@ -0,0 +1,531 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Rucoa
6
+ module Handlers
7
+ class TextDocumentDocumentHighlightHandler < Base
8
+ include HandlerConcerns::TextDocumentPositionParameters
9
+ include HandlerConcerns::TextDocumentUriParameters
10
+
11
+ # @return [void]
12
+ def call
13
+ respond(document_highlights)
14
+ end
15
+
16
+ private
17
+
18
+ # @return [Array]
19
+ def document_highlights
20
+ return [] unless reponsible?
21
+
22
+ NodeToHighlightsMappers::AnyMapper.call(node).map(&:to_vscode_highlight)
23
+ end
24
+
25
+ # @return [Boolean]
26
+ def reponsible?
27
+ configuration.enables_highlight?
28
+ end
29
+
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
77
+ class Base
78
+ class << self
79
+ # @param node [Rucoa::Nodes::Base]
80
+ # @return [Array]
81
+ def call(node)
82
+ new(node).call
83
+ end
84
+ end
85
+
86
+ # @param node [Rucoa::Nodes::Base]
87
+ def initialize(node)
88
+ @node = node
89
+ end
90
+
91
+ # @return [Array]
92
+ def call
93
+ raise ::NotImplementedError
94
+ end
95
+ end
96
+
97
+ class AnyMapper < Base
98
+ # @return [Array]
99
+ def call
100
+ case @node
101
+ when Nodes::BeginNode, Nodes::BlockNode
102
+ BeginMapper.call(@node)
103
+ when Nodes::CaseNode
104
+ CaseMapper.call(@node)
105
+ when Nodes::ClassNode, Nodes::ModuleNode
106
+ ModuleMapper.call(@node)
107
+ when Nodes::CvarNode, Nodes::CvasgnNode
108
+ ClassVariableMapper.call(@node)
109
+ when Nodes::DefNode
110
+ DefMapper.call(@node)
111
+ when Nodes::EnsureNode, Nodes::ResbodyNode, Nodes::RescueNode, Nodes::WhenNode
112
+ AnyMapper.call(@node.parent)
113
+ when Nodes::ForNode
114
+ ForMapper.call(@node)
115
+ when Nodes::GvarNode, Nodes::GvasgnNode
116
+ GlobalVariableMapper.call(@node)
117
+ when Nodes::IfNode
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)
123
+ when Nodes::SendNode
124
+ SendMapper.call(@node)
125
+ when Nodes::UntilNode, Nodes::WhileNode
126
+ WhileMapper.call(@node)
127
+ else
128
+ []
129
+ end
130
+ end
131
+ end
132
+
133
+ class BeginMapper < Base
134
+ # @return [Array]
135
+ def call
136
+ [
137
+ range_begin,
138
+ *ranges_resbody,
139
+ range_else,
140
+ range_ensure,
141
+ range_end
142
+ ].compact.map do |parser_range|
143
+ Highlights::TextHighlight.new(parser_range: parser_range)
144
+ end
145
+ end
146
+
147
+ private
148
+
149
+ # @return [Parser::Source::Range]
150
+ def range_begin
151
+ @node.location.begin
152
+ end
153
+
154
+ # @return [Parser::Source::Range, nil]
155
+ def range_else
156
+ return unless rescue_node
157
+
158
+ rescue_node.location.else
159
+ end
160
+
161
+ # @return [Parser::Source::Range]
162
+ def range_end
163
+ @node.location.end
164
+ end
165
+
166
+ # @return [Parser::Source::Range]
167
+ def range_ensure
168
+ return unless @node.ensure
169
+
170
+ @node.ensure.location.keyword
171
+ end
172
+
173
+ # @return [Array]
174
+ def ranges_resbody
175
+ return [] unless rescue_node
176
+
177
+ rescue_node.resbodies.map do |resbody|
178
+ resbody.location.keyword
179
+ end
180
+ end
181
+
182
+ # @return [Rucoa::Nodes::RescueNode, nil]
183
+ def rescue_node
184
+ @rescue_node ||= @node.rescue || @node.ensure&.rescue
185
+ end
186
+ end
187
+
188
+ class DefMapper < BeginMapper
189
+ private
190
+
191
+ # @return [Parser::Source::Range]
192
+ def range_begin
193
+ @node.location.keyword
194
+ end
195
+ end
196
+
197
+ class CaseMapper < Base
198
+ # @return [Array]
199
+ def call
200
+ [
201
+ @node.location.keyword,
202
+ *ranges_when,
203
+ @node.location.else,
204
+ @node.location.end
205
+ ].compact.map do |parser_range|
206
+ Highlights::TextHighlight.new(parser_range: parser_range)
207
+ end
208
+ end
209
+
210
+ private
211
+
212
+ # @return [Array]
213
+ def ranges_when
214
+ @node.whens.map do |when_node|
215
+ when_node.location.keyword
216
+ end
217
+ end
218
+ end
219
+
220
+ class IfMapper < Base
221
+ # @return [Array]
222
+ def call
223
+ return AnyMapper.call(@node.parent) if @node.elsif?
224
+ return [] if @node.modifier?
225
+
226
+ [
227
+ highlight_keyword,
228
+ *highlights_elsif,
229
+ highlight_else,
230
+ highlight_end
231
+ ].compact
232
+ end
233
+
234
+ private
235
+
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
250
+ return [] unless @node.elsif
251
+
252
+ ElsifMapper.call(@node.elsif)
253
+ end
254
+ end
255
+
256
+ class ElsifMapper < IfMapper
257
+ # @return [Array]
258
+ def call
259
+ [
260
+ *highlights_elsif,
261
+ highlight_else
262
+ ].compact
263
+ end
264
+ end
265
+
266
+ class ForMapper < Base
267
+ # @return [Array]
268
+ def call
269
+ [
270
+ @node.location.keyword,
271
+ @node.location.in,
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
440
+ ].compact
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
485
+ end
486
+
487
+ class ModuleMapper < Base
488
+ # @return [Array]
489
+ def call
490
+ [
491
+ @node.location.keyword,
492
+ @node.location.end
493
+ ].map do |parser_range|
494
+ Highlights::TextHighlight.new(parser_range: parser_range)
495
+ end
496
+ end
497
+ end
498
+
499
+ class SendMapper < Base
500
+ # @return [Array]
501
+ def call
502
+ return [] unless @node.block
503
+
504
+ BeginMapper.call(@node.block)
505
+ end
506
+ end
507
+
508
+ class WhenMapper < Base
509
+ # @return [Array]
510
+ def call
511
+ CaseMapper.call(@node.parent)
512
+ end
513
+ end
514
+
515
+ class WhileMapper < Base
516
+ # @return [Array]
517
+ def call
518
+ return [] if @node.modifier?
519
+
520
+ [
521
+ @node.location.keyword,
522
+ @node.location.end
523
+ ].map do |parser_range|
524
+ Highlights::TextHighlight.new(parser_range: parser_range)
525
+ end
526
+ end
527
+ end
528
+ end
529
+ end
530
+ end
531
+ end
@@ -5,6 +5,8 @@ require 'set'
5
5
  module Rucoa
6
6
  module Handlers
7
7
  class TextDocumentDocumentSymbolHandler < Base
8
+ include HandlerConcerns::TextDocumentUriParameters
9
+
8
10
  DOCUMENT_SYMBOL_KIND_FOR_FILE = 1
9
11
  DOCUMENT_SYMBOL_KIND_FOR_MODULE = 2
10
12
  DOCUMENT_SYMBOL_KIND_FOR_NAMESPACE = 3
@@ -47,51 +49,6 @@ module Rucoa
47
49
 
48
50
  private
49
51
 
50
- # @return [Array<Hash>]
51
- def document_symbols
52
- visit(source.root_node)
53
- document_symbol_stack.first[:children]
54
- end
55
-
56
- # @param node [Rucoa::Nodes::Base]
57
- # @return [void]
58
- def visit(node)
59
- document_symbols = create_document_symbols_for(node)
60
- document_symbol_stack.last[:children].push(*document_symbols)
61
- with_document_symbol_stack(document_symbols.first) do
62
- with_singleton_class_stack(node) do
63
- node.each_child_node do |child_node|
64
- visit(child_node)
65
- end
66
- end
67
- end
68
- end
69
-
70
- # @param document_symbol [Hash, nil]
71
- # @return [void]
72
- def with_document_symbol_stack(document_symbol)
73
- unless document_symbol
74
- yield
75
- return
76
- end
77
-
78
- document_symbol_stack.push(document_symbol)
79
- yield
80
- document_symbol_stack.pop
81
- end
82
-
83
- # @param node [Rucoa::Nodes::Base]
84
- def with_singleton_class_stack(node)
85
- unless node.is_a?(Rucoa::Nodes::SclassNode)
86
- yield
87
- return
88
- end
89
-
90
- singleton_class_stack.push(node)
91
- yield
92
- singleton_class_stack.pop
93
- end
94
-
95
52
  # @param node [Rucoa::Nodes::Base]
96
53
  # @return [Array<Hash>]
97
54
  def create_document_symbols_for(node)
@@ -102,8 +59,6 @@ module Rucoa
102
59
  create_document_symbols_for_class(node)
103
60
  when Nodes::DefNode
104
61
  create_document_symbols_for_def(node)
105
- when Nodes::DefsNode
106
- create_document_symbols_for_defs(node)
107
62
  when Nodes::ModuleNode
108
63
  create_document_symbols_for_module(node)
109
64
  when Nodes::SendNode
@@ -141,14 +96,14 @@ module Rucoa
141
96
  ]
142
97
  end
143
98
 
144
- # @param node [Rucoa::Nodes::ModuleNode]
99
+ # @param node [Rucoa::Nodes::DefNode]
145
100
  # @return [Array<Hash>]
146
- def create_document_symbols_for_module(node)
101
+ def create_document_symbols_for_def(node)
147
102
  [
148
103
  {
149
104
  children: [],
150
- kind: DOCUMENT_SYMBOL_KIND_FOR_MODULE,
151
- name: node.name,
105
+ kind: DOCUMENT_SYMBOL_KIND_FOR_METHOD,
106
+ name: "#{node.method_marker}#{node.name}",
152
107
  range: Range.from_parser_range(node.location.expression).to_vscode_range,
153
108
  selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
154
109
  }
@@ -157,26 +112,26 @@ module Rucoa
157
112
 
158
113
  # @param node [Rucoa::Nodes::DefNode]
159
114
  # @return [Array<Hash>]
160
- def create_document_symbols_for_def(node)
115
+ def create_document_symbols_for_defs(node)
161
116
  [
162
117
  {
163
118
  children: [],
164
119
  kind: DOCUMENT_SYMBOL_KIND_FOR_METHOD,
165
- name: singleton_class_stack.empty? ? "##{node.name}" : ".#{node.name}",
120
+ name: ".#{node.name}",
166
121
  range: Range.from_parser_range(node.location.expression).to_vscode_range,
167
122
  selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
168
123
  }
169
124
  ]
170
125
  end
171
126
 
172
- # @param node [Rucoa::Nodes::DefNode]
127
+ # @param node [Rucoa::Nodes::ModuleNode]
173
128
  # @return [Array<Hash>]
174
- def create_document_symbols_for_defs(node)
129
+ def create_document_symbols_for_module(node)
175
130
  [
176
131
  {
177
132
  children: [],
178
- kind: DOCUMENT_SYMBOL_KIND_FOR_METHOD,
179
- name: ".#{node.name}",
133
+ kind: DOCUMENT_SYMBOL_KIND_FOR_MODULE,
134
+ name: node.name,
180
135
  range: Range.from_parser_range(node.location.expression).to_vscode_range,
181
136
  selectionRange: Range.from_parser_range(node.location.name).to_vscode_range
182
137
  }
@@ -205,27 +160,17 @@ module Rucoa
205
160
  end
206
161
  end
207
162
 
208
- # @return [Boolean]
209
- def responsible?
210
- configuration.enables_document_symbol? &&
211
- !source.nil?
212
- end
213
-
214
- # @return [Rucoa::Source]
215
- def source
216
- @source ||= source_store.get(uri)
217
- end
218
-
219
- # @return [String]
220
- def uri
221
- request.dig('params', 'textDocument', 'uri')
222
- end
223
-
224
163
  # @return [Arrah<Hash>]
225
164
  def document_symbol_stack
226
165
  @document_symbol_stack ||= [dummy_document_symbol]
227
166
  end
228
167
 
168
+ # @return [Array<Hash>]
169
+ def document_symbols
170
+ visit(source.root_node)
171
+ document_symbol_stack.first[:children]
172
+ end
173
+
229
174
  # @return [Hash]
230
175
  def dummy_document_symbol
231
176
  {
@@ -233,9 +178,35 @@ module Rucoa
233
178
  }
234
179
  end
235
180
 
236
- # @return [Array<Rucoa::Nodes::SclassNode>]
237
- def singleton_class_stack
238
- @singleton_class_stack ||= []
181
+ # @return [Boolean]
182
+ def responsible?
183
+ configuration.enables_document_symbol? &&
184
+ !source.nil?
185
+ end
186
+
187
+ # @param node [Rucoa::Nodes::Base]
188
+ # @return [void]
189
+ def visit(node)
190
+ document_symbols = create_document_symbols_for(node)
191
+ document_symbol_stack.last[:children].push(*document_symbols)
192
+ with_document_symbol_stack(document_symbols.first) do
193
+ node.each_child_node do |child_node|
194
+ visit(child_node)
195
+ end
196
+ end
197
+ end
198
+
199
+ # @param document_symbol [Hash, nil]
200
+ # @return [void]
201
+ def with_document_symbol_stack(document_symbol)
202
+ unless document_symbol
203
+ yield
204
+ return
205
+ end
206
+
207
+ document_symbol_stack.push(document_symbol)
208
+ yield
209
+ document_symbol_stack.pop
239
210
  end
240
211
  end
241
212
  end