Class: RubyLsp::Requests::Completion

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

Overview

![Completion demo](../../completion.gif)

The [completion](microsoft.github.io/language-server-protocol/specification#textDocument_completion) suggests possible completions according to what the developer is typing.

Currently supported targets:

  • Classes

  • Modules

  • Constants

  • Require paths

  • Methods invoked on self only

# Example

“‘ruby require “ruby_lsp/requests” # –> completion: suggests `base_request`, `code_actions`, …

RubyLsp::Requests

# –> completion: suggests ‘Completion`, `Hover`, …

“‘

Constant Summary collapse

ResponseType =
type_member { { fixed: T::Array[Interface::CompletionItem] } }

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document, index, position, typechecker_enabled, dispatcher) ⇒ Completion

Returns a new instance of Completion.



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
# File 'lib/ruby_lsp/requests/completion.rb', line 57

def initialize(document, index, position, typechecker_enabled, dispatcher)
  super()
  @target = T.let(nil, T.nilable(Prism::Node))
  @dispatcher = dispatcher
  # Completion always receives the position immediately after the character that was just typed. Here we adjust it
  # back by 1, so that we find the right node
  char_position = document.create_scanner.find_char_position(position) - 1
  matched, parent, nesting = document.locate(
    document.tree,
    char_position,
    node_types: [Prism::CallNode, Prism::ConstantReadNode, Prism::ConstantPathNode],
  )

  @listener = T.let(
    Listeners::Completion.new(index, nesting, typechecker_enabled, dispatcher),
    Listener[ResponseType],
  )

  return unless matched && parent

  @target = case matched
  when Prism::CallNode
    message = matched.message

    if message == "require"
      args = matched.arguments&.arguments
      return if args.nil? || args.is_a?(Prism::ForwardingArgumentsNode)

      argument = args.first
      return unless argument.is_a?(Prism::StringNode)
      return unless (argument.location.start_offset..argument.location.end_offset).cover?(char_position)

      argument
    else
      matched
    end
  when Prism::ConstantReadNode, Prism::ConstantPathNode
    if parent.is_a?(Prism::ConstantPathNode) && matched.is_a?(Prism::ConstantReadNode)
      parent
    else
      matched
    end
  end
end

Class Method Details

.providerObject



35
36
37
38
39
40
41
42
43
# File 'lib/ruby_lsp/requests/completion.rb', line 35

def provider
  Interface::CompletionOptions.new(
    resolve_provider: false,
    trigger_characters: ["/"],
    completion_item: {
      labelDetailsSupport: true,
    },
  )
end

Instance Method Details

#performObject



103
104
105
106
107
108
# File 'lib/ruby_lsp/requests/completion.rb', line 103

def perform
  return [] unless @target

  @dispatcher.dispatch_once(@target)
  @listener.response
end