Class: RubyLsp::Requests::DocumentSymbol

Inherits:
Listener
  • Object
show all
Extended by:
T::Generic, T::Sig
Defined in:
lib/ruby_lsp/requests/document_symbol.rb

Overview

![Document symbol demo](../../document_symbol.gif)

The [document symbol](microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol) request informs the editor of all the important symbols, such as classes, variables, and methods, defined in a file. With this information, the editor can populate breadcrumbs, file outline and allow for fuzzy symbol searches.

In VS Code, fuzzy symbol search can be accessed by opening the command palette and inserting an ‘@` symbol.

# Example

“‘ruby class Person # –> document symbol: class

attr_reader :age # --> document symbol: field

def initialize
  @age = 0 # --> document symbol: variable
end

def age # --> document symbol: method
end

end “‘

Defined Under Namespace

Classes: SymbolHierarchyRoot

Constant Summary collapse

ResponseType =
type_member { { fixed: T::Array[Interface::DocumentSymbol] } }
SYMBOL_KIND =
T.let(
  {
    file: 1,
    module: 2,
    namespace: 3,
    package: 4,
    class: 5,
    method: 6,
    property: 7,
    field: 8,
    constructor: 9,
    enum: 10,
    interface: 11,
    function: 12,
    variable: 13,
    constant: 14,
    string: 15,
    number: 16,
    boolean: 17,
    array: 18,
    object: 19,
    key: 20,
    null: 21,
    enummember: 22,
    struct: 23,
    event: 24,
    operator: 25,
    typeparameter: 26,
  }.freeze,
  T::Hash[Symbol, Integer],
)
ATTR_ACCESSORS =
T.let(["attr_reader", "attr_writer", "attr_accessor"].freeze, T::Array[String])

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Listener

add_listener, listeners

Methods included from Support::Common

#create_code_lens, #full_constant_name, #range_from_syntax_tree_node, #visible?

Constructor Details

#initialize(emitter, message_queue) ⇒ DocumentSymbol

Returns a new instance of DocumentSymbol.



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 85

def initialize(emitter, message_queue)
  super

  @root = T.let(SymbolHierarchyRoot.new, SymbolHierarchyRoot)
  @response = T.let(@root.children, T::Array[Interface::DocumentSymbol])
  @stack = T.let(
    [@root],
    T::Array[T.any(SymbolHierarchyRoot, Interface::DocumentSymbol)],
  )

  emitter.register(
    self,
    :on_class,
    :after_class,
    :on_command,
    :on_const_path_field,
    :on_def,
    :after_def,
    :on_module,
    :after_module,
    :on_top_const_field,
    :on_var_field,
  )
end

Instance Attribute Details

#responseObject (readonly)

Returns the value of attribute response.



82
83
84
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 82

def response
  @response
end

Instance Method Details

#after_class(node) ⇒ Object



121
122
123
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 121

def after_class(node)
  @stack.pop
end

#after_def(node) ⇒ Object



174
175
176
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 174

def after_def(node)
  @stack.pop
end

#after_module(node) ⇒ Object



189
190
191
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 189

def after_module(node)
  @stack.pop
end

#on_class(node) ⇒ Object



111
112
113
114
115
116
117
118
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 111

def on_class(node)
  @stack << create_document_symbol(
    name: full_constant_name(node.constant),
    kind: :class,
    range_node: node,
    selection_range_node: node.constant,
  )
end

#on_command(node) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 126

def on_command(node)
  return unless ATTR_ACCESSORS.include?(node.message.value)

  node.arguments.parts.each do |argument|
    next unless argument.is_a?(SyntaxTree::SymbolLiteral)

    create_document_symbol(
      name: argument.value.value,
      kind: :field,
      range_node: argument,
      selection_range_node: argument.value,
    )
  end
end

#on_const_path_field(node) ⇒ Object



142
143
144
145
146
147
148
149
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 142

def on_const_path_field(node)
  create_document_symbol(
    name: node.constant.value,
    kind: :constant,
    range_node: node,
    selection_range_node: node.constant,
  )
end

#on_def(node) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 152

def on_def(node)
  target = node.target

  if target.is_a?(SyntaxTree::VarRef) && target.value.is_a?(SyntaxTree::Kw) && target.value.value == "self"
    name = "self.#{node.name.value}"
    kind = :method
  else
    name = node.name.value
    kind = name == "initialize" ? :constructor : :method
  end

  symbol = create_document_symbol(
    name: name,
    kind: kind,
    range_node: node,
    selection_range_node: node.name,
  )

  @stack << symbol
end

#on_module(node) ⇒ Object



179
180
181
182
183
184
185
186
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 179

def on_module(node)
  @stack << create_document_symbol(
    name: full_constant_name(node.constant),
    kind: :module,
    range_node: node,
    selection_range_node: node.constant,
  )
end

#on_top_const_field(node) ⇒ Object



194
195
196
197
198
199
200
201
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 194

def on_top_const_field(node)
  create_document_symbol(
    name: node.constant.value,
    kind: :constant,
    range_node: node,
    selection_range_node: node.constant,
  )
end

#on_var_field(node) ⇒ Object



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/ruby_lsp/requests/document_symbol.rb', line 204

def on_var_field(node)
  value = node.value
  kind = case value
  when SyntaxTree::Const
    :constant
  when SyntaxTree::CVar, SyntaxTree::IVar
    :variable
  else
    return
  end

  create_document_symbol(
    name: value.value,
    kind: kind,
    range_node: node,
    selection_range_node: value,
  )
end