Class: RubyLsp::Requests::Definition

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

Overview

![Definition demo](../../definition.gif)

The [definition request](microsoft.github.io/language-server-protocol/specification#textDocument_definition) jumps to the definition of the symbol under the cursor.

Currently supported targets:

  • Classes

  • Modules

  • Constants

  • Require paths

  • Methods invoked on self only and on receivers where the type is unknown

  • Instance variables

# Example

“‘ruby require “some_gem/file” # <- Request go to definition on this string will take you to the file Product.new # <- Request go to definition on this class name will take you to its declaration. “`

Constant Summary collapse

SPECIAL_METHOD_CALLS =
[
  :require,
  :require_relative,
  :autoload,
].freeze

Instance Method Summary collapse

Constructor Details

#initialize(document, global_state, position, dispatcher, sorbet_level) ⇒ Definition

Returns a new instance of Definition.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ruby_lsp/requests/definition.rb', line 48

def initialize(document, global_state, position, dispatcher, sorbet_level)
  super()
  @response_builder = T.let(
    ResponseBuilders::CollectionResponseBuilder[T.any(Interface::Location, Interface::LocationLink)].new,
    ResponseBuilders::CollectionResponseBuilder[T.any(Interface::Location, Interface::LocationLink)],
  )
  @dispatcher = dispatcher

  node_context = document.locate_node(
    position,
    node_types: [
      Prism::CallNode,
      Prism::ConstantReadNode,
      Prism::ConstantPathNode,
      Prism::BlockArgumentNode,
      Prism::InstanceVariableReadNode,
      Prism::InstanceVariableAndWriteNode,
      Prism::InstanceVariableOperatorWriteNode,
      Prism::InstanceVariableOrWriteNode,
      Prism::InstanceVariableTargetNode,
      Prism::InstanceVariableWriteNode,
      Prism::SymbolNode,
      Prism::StringNode,
      Prism::SuperNode,
      Prism::ForwardingSuperNode,
    ],
  )

  target = node_context.node
  parent = node_context.parent

  if target.is_a?(Prism::ConstantReadNode) && parent.is_a?(Prism::ConstantPathNode)
    # If the target is part of a constant path node, we need to find the exact portion of the constant that the
    # user is requesting to go to definition for
    target = determine_target(
      target,
      parent,
      position,
    )
  elsif target.is_a?(Prism::CallNode) && !SPECIAL_METHOD_CALLS.include?(target.message) && !covers_position?(
    target.message_loc, position
  )
    # If the target is a method call, we need to ensure that the requested position is exactly on top of the
    # method identifier. Otherwise, we risk showing definitions for unrelated things
    target = nil
  # For methods with block arguments using symbol-to-proc
  elsif target.is_a?(Prism::SymbolNode) && parent.is_a?(Prism::BlockArgumentNode)
    target = parent
  end

  if target
    Listeners::Definition.new(
      @response_builder,
      global_state,
      document.language_id,
      document.uri,
      node_context,
      dispatcher,
      sorbet_level,
    )

    Addon.addons.each do |addon|
      addon.create_definition_listener(@response_builder, document.uri, node_context, dispatcher)
    end
  end

  @target = T.let(target, T.nilable(Prism::Node))
end

Instance Method Details

#performObject



118
119
120
121
# File 'lib/ruby_lsp/requests/definition.rb', line 118

def perform
  @dispatcher.dispatch_once(@target) if @target
  @response_builder.response
end