ruby-lsp 0.4.2 → 0.5.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +29 -116
  3. data/VERSION +1 -1
  4. data/exe/ruby-lsp +10 -1
  5. data/lib/rubocop/cop/ruby_lsp/use_language_server_aliases.rb +62 -0
  6. data/lib/ruby_lsp/check_docs.rb +112 -0
  7. data/lib/ruby_lsp/document.rb +87 -8
  8. data/lib/ruby_lsp/event_emitter.rb +120 -0
  9. data/lib/ruby_lsp/executor.rb +191 -44
  10. data/lib/ruby_lsp/extension.rb +104 -0
  11. data/lib/ruby_lsp/internal.rb +4 -0
  12. data/lib/ruby_lsp/listener.rb +42 -0
  13. data/lib/ruby_lsp/requests/base_request.rb +2 -90
  14. data/lib/ruby_lsp/requests/code_action_resolve.rb +47 -20
  15. data/lib/ruby_lsp/requests/code_actions.rb +6 -5
  16. data/lib/ruby_lsp/requests/code_lens.rb +151 -0
  17. data/lib/ruby_lsp/requests/diagnostics.rb +5 -5
  18. data/lib/ruby_lsp/requests/document_highlight.rb +8 -10
  19. data/lib/ruby_lsp/requests/document_link.rb +17 -15
  20. data/lib/ruby_lsp/requests/document_symbol.rb +63 -40
  21. data/lib/ruby_lsp/requests/folding_ranges.rb +14 -10
  22. data/lib/ruby_lsp/requests/formatting.rb +15 -15
  23. data/lib/ruby_lsp/requests/hover.rb +45 -34
  24. data/lib/ruby_lsp/requests/inlay_hints.rb +6 -5
  25. data/lib/ruby_lsp/requests/on_type_formatting.rb +5 -1
  26. data/lib/ruby_lsp/requests/path_completion.rb +21 -51
  27. data/lib/ruby_lsp/requests/selection_ranges.rb +4 -4
  28. data/lib/ruby_lsp/requests/semantic_highlighting.rb +30 -16
  29. data/lib/ruby_lsp/requests/support/common.rb +91 -0
  30. data/lib/ruby_lsp/requests/support/highlight_target.rb +5 -4
  31. data/lib/ruby_lsp/requests/support/rails_document_client.rb +7 -6
  32. data/lib/ruby_lsp/requests/support/rubocop_diagnostics_runner.rb +0 -1
  33. data/lib/ruby_lsp/requests/support/rubocop_formatting_runner.rb +0 -1
  34. data/lib/ruby_lsp/requests/support/selection_range.rb +1 -1
  35. data/lib/ruby_lsp/requests/support/semantic_token_encoder.rb +2 -2
  36. data/lib/ruby_lsp/requests/support/sorbet.rb +5 -15
  37. data/lib/ruby_lsp/requests/support/syntax_tree_formatting_runner.rb +42 -0
  38. data/lib/ruby_lsp/requests.rb +17 -14
  39. data/lib/ruby_lsp/server.rb +45 -9
  40. data/lib/ruby_lsp/store.rb +11 -11
  41. data/lib/ruby_lsp/utils.rb +9 -8
  42. metadata +13 -5
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Code action resolve demo](../../misc/code_action_resolve.gif)
6
+ # ![Code action resolve demo](../../code_action_resolve.gif)
7
7
  #
8
8
  # The [code action resolve](https://microsoft.github.io/language-server-protocol/specification#codeAction_resolve)
9
9
  # request is used to to resolve the edit field for a given code action, if it is not already provided in the
@@ -54,7 +54,8 @@ module RubyLsp
54
54
  extracted_source = T.must(@document.source[start_index...end_index])
55
55
 
56
56
  # Find the closest statements node, so that we place the refactor in a valid position
57
- closest_statements = locate(T.must(@document.tree), start_index, node_types: [SyntaxTree::Statements]).first
57
+ closest_statements, parent_statements = @document
58
+ .locate(T.must(@document.tree), start_index, node_types: [SyntaxTree::Statements])
58
59
  return Error::InvalidTargetRange if closest_statements.nil?
59
60
 
60
61
  # Find the node with the end line closest to the requested position, so that we can place the refactor
@@ -64,25 +65,51 @@ module RubyLsp
64
65
  distance <= 0 ? Float::INFINITY : distance
65
66
  end
66
67
 
67
- # When trying to extract the first node inside of a statements block, then we can just select one line above it
68
- target_line = if closest_node == closest_statements.child_nodes.first
69
- closest_node.location.start_line - 1
68
+ # Find the parent expression of the closest node
69
+ parent_expression = parent_statements.child_nodes.compact.find do |node|
70
+ loc = node.location
71
+ loc.start_line - 1 <= source_range.dig(:start, :line) && loc.end_line - 1 >= source_range.dig(:end, :line)
72
+ end if parent_statements
73
+
74
+ closest_node_loc = closest_node.location
75
+ # If the parent expression is a single line block, then we have to extract it inside of the oneline block
76
+ if parent_expression.is_a?(SyntaxTree::MethodAddBlock) &&
77
+ parent_expression.location.start_line == parent_expression.location.end_line
78
+
79
+ variable_source = " #{NEW_VARIABLE_NAME} = #{extracted_source};"
80
+ character = source_range.dig(:start, :character) - 1
81
+ target_range = {
82
+ start: { line: closest_node_loc.end_line - 1, character: character },
83
+ end: { line: closest_node_loc.end_line - 1, character: character },
84
+ }
70
85
  else
71
- closest_node.location.end_line
72
- end
73
-
74
- lines = @document.source.lines
75
- indentation = T.must(T.must(lines[target_line - 1])[/\A */]).size
76
-
77
- target_range = {
78
- start: { line: target_line, character: indentation },
79
- end: { line: target_line, character: indentation },
80
- }
81
-
82
- variable_source = if T.must(lines[target_line]).strip.empty?
83
- "\n#{" " * indentation}#{NEW_VARIABLE_NAME} = #{extracted_source}"
84
- else
85
- "#{NEW_VARIABLE_NAME} = #{extracted_source}\n#{" " * indentation}"
86
+ # If the closest node covers the requested location, then we're extracting a statement nested inside of it. In
87
+ # that case, we want to place the extraction at the start of the closest node (one line above). Otherwise, we
88
+ # want to place the extract right below the closest node
89
+ if closest_node_loc.start_line - 1 <= source_range.dig(
90
+ :start,
91
+ :line,
92
+ ) && closest_node_loc.end_line - 1 >= source_range.dig(:end, :line)
93
+ indentation_line = closest_node_loc.start_line - 1
94
+ target_line = indentation_line
95
+ else
96
+ target_line = closest_node_loc.end_line
97
+ indentation_line = closest_node_loc.end_line - 1
98
+ end
99
+
100
+ lines = @document.source.lines
101
+ indentation = T.must(T.must(lines[indentation_line])[/\A */]).size
102
+
103
+ target_range = {
104
+ start: { line: target_line, character: indentation },
105
+ end: { line: target_line, character: indentation },
106
+ }
107
+
108
+ variable_source = if T.must(lines[target_line]).strip.empty?
109
+ "\n#{" " * indentation}#{NEW_VARIABLE_NAME} = #{extracted_source}"
110
+ else
111
+ "#{NEW_VARIABLE_NAME} = #{extracted_source}\n#{" " * indentation}"
112
+ end
86
113
  end
87
114
 
88
115
  Interface::CodeAction.new(
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Code actions demo](../../misc/code_actions.gif)
6
+ # ![Code actions demo](../../code_actions.gif)
7
7
  #
8
8
  # The [code actions](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeAction)
9
9
  # request informs the editor of RuboCop quick fixes that can be applied. These are accessible by hovering over a
@@ -21,16 +21,15 @@ module RubyLsp
21
21
 
22
22
  sig do
23
23
  params(
24
- uri: String,
25
24
  document: Document,
26
25
  range: Document::RangeShape,
27
26
  context: T::Hash[Symbol, T.untyped],
28
27
  ).void
29
28
  end
30
- def initialize(uri, document, range, context)
29
+ def initialize(document, range, context)
31
30
  super(document)
32
31
 
33
- @uri = uri
32
+ @uri = T.let(document.uri, String)
34
33
  @range = range
35
34
  @context = context
36
35
  end
@@ -49,7 +48,9 @@ module RubyLsp
49
48
  code_action if diagnostic.dig(:data, :correctable) && cover?(range)
50
49
  end
51
50
 
52
- code_actions << refactor_code_action(@range, @uri)
51
+ # Only add refactor actions if there's a non empty selection in the editor
52
+ code_actions << refactor_code_action(@range, @uri) unless @range.dig(:start) == @range.dig(:end)
53
+ code_actions
53
54
  end
54
55
 
55
56
  private
@@ -0,0 +1,151 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Requests
6
+ # ![Code lens demo](../../code_lens.gif)
7
+ #
8
+ # This feature is currently experimental. Clients will need to pass `experimentalFeaturesEnabled`
9
+ # in the initialization options to enable it.
10
+ #
11
+ # The
12
+ # [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
13
+ # request informs the editor of runnable commands such as tests
14
+ #
15
+ # # Example
16
+ #
17
+ # ```ruby
18
+ # # Run
19
+ # class Test < Minitest::Test
20
+ # end
21
+ # ```
22
+ class CodeLens < Listener
23
+ extend T::Sig
24
+ extend T::Generic
25
+
26
+ ResponseType = type_member { { fixed: T::Array[Interface::CodeLens] } }
27
+
28
+ BASE_COMMAND = T.let((File.exist?("Gemfile.lock") ? "bundle exec ruby" : "ruby") + " -Itest ", String)
29
+ ACCESS_MODIFIERS = T.let(["public", "private", "protected"], T::Array[String])
30
+
31
+ sig { override.returns(ResponseType) }
32
+ attr_reader :response
33
+
34
+ sig { params(uri: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
35
+ def initialize(uri, emitter, message_queue)
36
+ super(emitter, message_queue)
37
+
38
+ @response = T.let([], ResponseType)
39
+ @path = T.let(T.must(URI(uri).path), String)
40
+ @visibility = T.let("public", String)
41
+ @prev_visibility = T.let("public", String)
42
+
43
+ emitter.register(self, :on_class, :on_def, :on_command, :after_command, :on_call, :after_call, :on_vcall)
44
+ end
45
+
46
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
47
+ def on_class(node)
48
+ class_name = node.constant.constant.value
49
+ if class_name.end_with?("Test")
50
+ add_code_lens(node, name: class_name, command: BASE_COMMAND + @path)
51
+ end
52
+ end
53
+
54
+ sig { params(node: SyntaxTree::DefNode).void }
55
+ def on_def(node)
56
+ if @visibility == "public"
57
+ method_name = node.name.value
58
+ if method_name.start_with?("test_")
59
+ add_code_lens(
60
+ node,
61
+ name: method_name,
62
+ command: BASE_COMMAND + @path + " --name " + method_name,
63
+ )
64
+ end
65
+ end
66
+ end
67
+
68
+ sig { params(node: SyntaxTree::Command).void }
69
+ def on_command(node)
70
+ if ACCESS_MODIFIERS.include?(node.message.value) && node.arguments.parts.any?
71
+ @prev_visibility = @visibility
72
+ @visibility = node.message.value
73
+ end
74
+ end
75
+
76
+ sig { params(node: SyntaxTree::Command).void }
77
+ def after_command(node)
78
+ @visibility = @prev_visibility
79
+ end
80
+
81
+ sig { params(node: SyntaxTree::CallNode).void }
82
+ def on_call(node)
83
+ ident = node.message if node.message.is_a?(SyntaxTree::Ident)
84
+
85
+ if ident
86
+ ident_value = T.cast(ident, SyntaxTree::Ident).value
87
+ if ACCESS_MODIFIERS.include?(ident_value)
88
+ @prev_visibility = @visibility
89
+ @visibility = ident_value
90
+ end
91
+ end
92
+ end
93
+
94
+ sig { params(node: SyntaxTree::CallNode).void }
95
+ def after_call(node)
96
+ @visibility = @prev_visibility
97
+ end
98
+
99
+ sig { params(node: SyntaxTree::VCall).void }
100
+ def on_vcall(node)
101
+ vcall_value = node.value.value
102
+
103
+ if ACCESS_MODIFIERS.include?(vcall_value)
104
+ @prev_visibility = vcall_value
105
+ @visibility = vcall_value
106
+ end
107
+ end
108
+
109
+ sig { params(other: Listener[ResponseType]).returns(T.self_type) }
110
+ def merge_response!(other)
111
+ @response.concat(other.response)
112
+ self
113
+ end
114
+
115
+ private
116
+
117
+ sig { params(node: SyntaxTree::Node, name: String, command: String).void }
118
+ def add_code_lens(node, name:, command:)
119
+ @response << create_code_lens(
120
+ node,
121
+ title: "Run",
122
+ command_name: "rubyLsp.runTest",
123
+ path: @path,
124
+ name: name,
125
+ test_command: command,
126
+ type: "test",
127
+ )
128
+
129
+ @response << create_code_lens(
130
+ node,
131
+ title: "Run In Terminal",
132
+ command_name: "rubyLsp.runTestInTerminal",
133
+ path: @path,
134
+ name: name,
135
+ test_command: command,
136
+ type: "test_in_terminal",
137
+ )
138
+
139
+ @response << create_code_lens(
140
+ node,
141
+ title: "Debug",
142
+ command_name: "rubyLsp.debugTest",
143
+ path: @path,
144
+ name: name,
145
+ test_command: command,
146
+ type: "debug",
147
+ )
148
+ end
149
+ end
150
+ end
151
+ end
@@ -5,7 +5,7 @@ require "ruby_lsp/requests/support/rubocop_diagnostics_runner"
5
5
 
6
6
  module RubyLsp
7
7
  module Requests
8
- # ![Diagnostics demo](../../misc/diagnostics.gif)
8
+ # ![Diagnostics demo](../../diagnostics.gif)
9
9
  #
10
10
  # The
11
11
  # [diagnostics](https://microsoft.github.io/language-server-protocol/specification#textDocument_publishDiagnostics)
@@ -21,11 +21,11 @@ module RubyLsp
21
21
  class Diagnostics < BaseRequest
22
22
  extend T::Sig
23
23
 
24
- sig { params(uri: String, document: Document).void }
25
- def initialize(uri, document)
24
+ sig { params(document: Document).void }
25
+ def initialize(document)
26
26
  super(document)
27
27
 
28
- @uri = uri
28
+ @uri = T.let(document.uri, String)
29
29
  end
30
30
 
31
31
  sig { override.returns(T.nilable(T.all(T::Array[Support::RuboCopDiagnostic], Object))) }
@@ -34,7 +34,7 @@ module RubyLsp
34
34
  return unless defined?(Support::RuboCopDiagnosticsRunner)
35
35
 
36
36
  # Don't try to run RuboCop diagnostics for files outside the current working directory
37
- return unless @uri.start_with?(WORKSPACE_URI)
37
+ return unless URI(@uri).path&.start_with?(T.must(WORKSPACE_URI.path))
38
38
 
39
39
  Support::RuboCopDiagnosticsRunner.instance.run(@uri, @document)
40
40
  end
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Document highlight demo](../../misc/document_highlight.gif)
6
+ # ![Document highlight demo](../../document_highlight.gif)
7
7
  #
8
8
  # The [document highlight](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentHighlight)
9
9
  # informs the editor all relevant elements of the currently pointed item for highlighting. For example, when
@@ -29,14 +29,13 @@ module RubyLsp
29
29
  def initialize(document, position)
30
30
  super(document)
31
31
 
32
- @highlights = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentHighlight])
32
+ @highlights = T.let([], T::Array[Interface::DocumentHighlight])
33
33
  return unless document.parsed?
34
34
 
35
- position = document.create_scanner.find_char_position(position)
36
- @target = T.let(find(T.must(document.tree), position), T.nilable(Support::HighlightTarget))
35
+ @target = T.let(find(position), T.nilable(Support::HighlightTarget))
37
36
  end
38
37
 
39
- sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentHighlight], Object)) }
38
+ sig { override.returns(T.all(T::Array[Interface::DocumentHighlight], Object)) }
40
39
  def run
41
40
  # no @target means the target is not highlightable
42
41
  visit(@document.tree) if @document.parsed? && @target
@@ -68,12 +67,11 @@ module RubyLsp
68
67
 
69
68
  sig do
70
69
  params(
71
- node: SyntaxTree::Node,
72
- position: Integer,
70
+ position: Document::PositionShape,
73
71
  ).returns(T.nilable(Support::HighlightTarget))
74
72
  end
75
- def find(node, position)
76
- matched, parent = locate(node, position)
73
+ def find(position)
74
+ matched, parent = @document.locate_node(position)
77
75
 
78
76
  return unless matched && parent
79
77
  return unless matched.is_a?(SyntaxTree::Ident) || DIRECT_HIGHLIGHTS.include?(matched.class)
@@ -90,7 +88,7 @@ module RubyLsp
90
88
  sig { params(match: Support::HighlightTarget::HighlightMatch).void }
91
89
  def add_highlight(match)
92
90
  range = range_from_syntax_tree_node(match.node)
93
- @highlights << LanguageServer::Protocol::Interface::DocumentHighlight.new(range: range, kind: match.type)
91
+ @highlights << Interface::DocumentHighlight.new(range: range, kind: match.type)
94
92
  end
95
93
  end
96
94
  end
@@ -5,7 +5,7 @@ require "ruby_lsp/requests/support/source_uri"
5
5
 
6
6
  module RubyLsp
7
7
  module Requests
8
- # ![Document link demo](../../misc/document_link.gif)
8
+ # ![Document link demo](../../document_link.gif)
9
9
  #
10
10
  # The [document link](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentLink)
11
11
  # makes `# source://PATH_TO_FILE#line` comments in a Ruby/RBI file clickable if the file exists.
@@ -18,8 +18,11 @@ module RubyLsp
18
18
  # def format(source, maxwidth = T.unsafe(nil))
19
19
  # end
20
20
  # ```
21
- class DocumentLink < BaseRequest
21
+ class DocumentLink < Listener
22
22
  extend T::Sig
23
+ extend T::Generic
24
+
25
+ ResponseType = type_member { { fixed: T::Array[Interface::DocumentLink] } }
23
26
 
24
27
  GEM_TO_VERSION_MAP = T.let(
25
28
  [*::Gem::Specification.default_stubs, *::Gem::Specification.stubs].map! do |s|
@@ -69,34 +72,33 @@ module RubyLsp
69
72
  end
70
73
  end
71
74
 
72
- sig { params(uri: String, document: Document).void }
73
- def initialize(uri, document)
74
- super(document)
75
+ sig { override.returns(ResponseType) }
76
+ attr_reader :response
77
+
78
+ sig { params(uri: String, emitter: EventEmitter, message_queue: Thread::Queue).void }
79
+ def initialize(uri, emitter, message_queue)
80
+ super(emitter, message_queue)
75
81
 
76
82
  # Match the version based on the version in the RBI file name. Notice that the `@` symbol is sanitized to `%40`
77
83
  # in the URI
78
84
  version_match = /(?<=%40)[\d.]+(?=\.rbi$)/.match(uri)
79
85
  @gem_version = T.let(version_match && version_match[0], T.nilable(String))
80
- @links = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentLink])
81
- end
86
+ @response = T.let([], T::Array[Interface::DocumentLink])
82
87
 
83
- sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentLink], Object)) }
84
- def run
85
- visit(@document.tree) if @document.parsed?
86
- @links
88
+ emitter.register(self, :on_comment)
87
89
  end
88
90
 
89
- sig { override.params(node: SyntaxTree::Comment).void }
90
- def visit_comment(node)
91
+ sig { params(node: SyntaxTree::Comment).void }
92
+ def on_comment(node)
91
93
  match = node.value.match(%r{source://.*#\d+$})
92
94
  return unless match
93
95
 
94
- uri = T.cast(URI(match[0]), URI::Source)
96
+ uri = T.cast(URI(T.must(match[0])), URI::Source)
95
97
  gem_version = T.must(resolve_version(uri))
96
98
  file_path = self.class.gem_paths.dig(uri.gem_name, gem_version, uri.path)
97
99
  return if file_path.nil?
98
100
 
99
- @links << LanguageServer::Protocol::Interface::DocumentLink.new(
101
+ @response << Interface::DocumentLink.new(
100
102
  range: range_from_syntax_tree_node(node),
101
103
  target: "file://#{file_path}##{uri.line_number}",
102
104
  tooltip: "Jump to #{file_path}##{uri.line_number}",
@@ -3,7 +3,7 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Requests
6
- # ![Document symbol demo](../../misc/document_symbol.gif)
6
+ # ![Document symbol demo](../../document_symbol.gif)
7
7
  #
8
8
  # The [document
9
9
  # symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request
@@ -26,8 +26,11 @@ module RubyLsp
26
26
  # end
27
27
  # end
28
28
  # ```
29
- class DocumentSymbol < BaseRequest
29
+ class DocumentSymbol < Listener
30
30
  extend T::Sig
31
+ extend T::Generic
32
+
33
+ ResponseType = type_member { { fixed: T::Array[Interface::DocumentSymbol] } }
31
34
 
32
35
  SYMBOL_KIND = T.let(
33
36
  {
@@ -66,49 +69,62 @@ module RubyLsp
66
69
  class SymbolHierarchyRoot
67
70
  extend T::Sig
68
71
 
69
- sig { returns(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol]) }
72
+ sig { returns(T::Array[Interface::DocumentSymbol]) }
70
73
  attr_reader :children
71
74
 
72
75
  sig { void }
73
76
  def initialize
74
- @children = T.let([], T::Array[LanguageServer::Protocol::Interface::DocumentSymbol])
77
+ @children = T.let([], T::Array[Interface::DocumentSymbol])
75
78
  end
76
79
  end
77
80
 
78
- sig { params(document: Document).void }
79
- def initialize(document)
81
+ sig { override.returns(T::Array[Interface::DocumentSymbol]) }
82
+ attr_reader :response
83
+
84
+ sig { params(emitter: EventEmitter, message_queue: Thread::Queue).void }
85
+ def initialize(emitter, message_queue)
80
86
  super
81
87
 
82
88
  @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
89
+ @response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
83
90
  @stack = T.let(
84
91
  [@root],
85
- T::Array[T.any(SymbolHierarchyRoot, LanguageServer::Protocol::Interface::DocumentSymbol)],
92
+ T::Array[T.any(SymbolHierarchyRoot, Interface::DocumentSymbol)],
86
93
  )
87
- end
88
94
 
89
- sig { override.returns(T.all(T::Array[LanguageServer::Protocol::Interface::DocumentSymbol], Object)) }
90
- def run
91
- visit(@document.tree) if @document.parsed?
92
- @root.children
95
+ emitter.register(
96
+ self,
97
+ :on_class,
98
+ :after_class,
99
+ :on_command,
100
+ :on_const_path_field,
101
+ :on_def,
102
+ :after_def,
103
+ :on_module,
104
+ :after_module,
105
+ :on_top_const_field,
106
+ :on_var_field,
107
+ )
93
108
  end
94
109
 
95
- sig { override.params(node: SyntaxTree::ClassDeclaration).void }
96
- def visit_class(node)
97
- symbol = create_document_symbol(
110
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
111
+ def on_class(node)
112
+ @stack << create_document_symbol(
98
113
  name: full_constant_name(node.constant),
99
114
  kind: :class,
100
115
  range_node: node,
101
116
  selection_range_node: node.constant,
102
117
  )
118
+ end
103
119
 
104
- @stack << symbol
105
- visit(node.bodystmt)
120
+ sig { params(node: SyntaxTree::ClassDeclaration).void }
121
+ def after_class(node)
106
122
  @stack.pop
107
123
  end
108
124
 
109
- sig { override.params(node: SyntaxTree::Command).void }
110
- def visit_command(node)
111
- return visit(node.arguments) unless ATTR_ACCESSORS.include?(node.message.value)
125
+ sig { params(node: SyntaxTree::Command).void }
126
+ def on_command(node)
127
+ return unless ATTR_ACCESSORS.include?(node.message.value)
112
128
 
113
129
  node.arguments.parts.each do |argument|
114
130
  next unless argument.is_a?(SyntaxTree::SymbolLiteral)
@@ -122,8 +138,8 @@ module RubyLsp
122
138
  end
123
139
  end
124
140
 
125
- sig { override.params(node: SyntaxTree::ConstPathField).void }
126
- def visit_const_path_field(node)
141
+ sig { params(node: SyntaxTree::ConstPathField).void }
142
+ def on_const_path_field(node)
127
143
  create_document_symbol(
128
144
  name: node.constant.value,
129
145
  kind: :constant,
@@ -132,9 +148,11 @@ module RubyLsp
132
148
  )
133
149
  end
134
150
 
135
- sig { override.params(node: SyntaxTree::DefNode).void }
136
- def visit_def(node)
137
- if node.target&.value&.value == "self"
151
+ sig { params(node: SyntaxTree::DefNode).void }
152
+ def on_def(node)
153
+ target = node.target
154
+
155
+ if target.is_a?(SyntaxTree::VarRef) && target.value.is_a?(SyntaxTree::Kw) && target.value.value == "self"
138
156
  name = "self.#{node.name.value}"
139
157
  kind = :method
140
158
  else
@@ -150,26 +168,30 @@ module RubyLsp
150
168
  )
151
169
 
152
170
  @stack << symbol
153
- visit(node.bodystmt)
171
+ end
172
+
173
+ sig { params(node: SyntaxTree::DefNode).void }
174
+ def after_def(node)
154
175
  @stack.pop
155
176
  end
156
177
 
157
- sig { override.params(node: SyntaxTree::ModuleDeclaration).void }
158
- def visit_module(node)
159
- symbol = create_document_symbol(
178
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
179
+ def on_module(node)
180
+ @stack << create_document_symbol(
160
181
  name: full_constant_name(node.constant),
161
182
  kind: :module,
162
183
  range_node: node,
163
184
  selection_range_node: node.constant,
164
185
  )
186
+ end
165
187
 
166
- @stack << symbol
167
- visit(node.bodystmt)
188
+ sig { params(node: SyntaxTree::ModuleDeclaration).void }
189
+ def after_module(node)
168
190
  @stack.pop
169
191
  end
170
192
 
171
- sig { override.params(node: SyntaxTree::TopConstField).void }
172
- def visit_top_const_field(node)
193
+ sig { params(node: SyntaxTree::TopConstField).void }
194
+ def on_top_const_field(node)
173
195
  create_document_symbol(
174
196
  name: node.constant.value,
175
197
  kind: :constant,
@@ -178,9 +200,10 @@ module RubyLsp
178
200
  )
179
201
  end
180
202
 
181
- sig { override.params(node: SyntaxTree::VarField).void }
182
- def visit_var_field(node)
183
- kind = case node.value
203
+ sig { params(node: SyntaxTree::VarField).void }
204
+ def on_var_field(node)
205
+ value = node.value
206
+ kind = case value
184
207
  when SyntaxTree::Const
185
208
  :constant
186
209
  when SyntaxTree::CVar, SyntaxTree::IVar
@@ -190,10 +213,10 @@ module RubyLsp
190
213
  end
191
214
 
192
215
  create_document_symbol(
193
- name: node.value.value,
216
+ name: value.value,
194
217
  kind: kind,
195
218
  range_node: node,
196
- selection_range_node: node.value,
219
+ selection_range_node: value,
197
220
  )
198
221
  end
199
222
 
@@ -205,10 +228,10 @@ module RubyLsp
205
228
  kind: Symbol,
206
229
  range_node: SyntaxTree::Node,
207
230
  selection_range_node: SyntaxTree::Node,
208
- ).returns(LanguageServer::Protocol::Interface::DocumentSymbol)
231
+ ).returns(Interface::DocumentSymbol)
209
232
  end
210
233
  def create_document_symbol(name:, kind:, range_node:, selection_range_node:)
211
- symbol = LanguageServer::Protocol::Interface::DocumentSymbol.new(
234
+ symbol = Interface::DocumentSymbol.new(
212
235
  name: name,
213
236
  kind: SYMBOL_KIND[kind],
214
237
  range: range_from_syntax_tree_node(range_node),