rucoa 0.11.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
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