Class: Rigor::LanguageServer::CompletionProvider

Inherits:
Object
  • Object
show all
Includes:
BufferResolution
Defined in:
lib/rigor/language_server/completion_provider.rb

Overview

Answers textDocument/completion requests. Provides method completion for obj.| (known-type receiver → RBS-known methods), constant-path completion, hash-key completion, Union / Intersection / Refined / Shape receiver handling, and parse-recovery fallback for malformed buffers (sentinel injection).

LSP CompletionItemKind values used:

  • 2 = Method, 5 = Field, 7 = Class, 9 = Module, 21 = Constant.

Constant Summary collapse

KIND_METHOD =
2
KIND_FIELD =
5
KIND_CLASS =
7
KIND_MODULE =
9
KIND_CONSTANT =
21

Instance Method Summary collapse

Constructor Details

#initialize(buffer_table:, project_context:) ⇒ CompletionProvider

Returns a new instance of CompletionProvider.



39
40
41
42
# File 'lib/rigor/language_server/completion_provider.rb', line 39

def initialize(buffer_table:, project_context:)
  @buffer_table = buffer_table
  @project_context = project_context
end

Instance Method Details

#provide(uri:, line:, character:, trigger_character: nil) ⇒ Array<Hash>?

Returns LSP CompletionItem[] or nil when the cursor isn't at a position the provider can enumerate completions for. Returning nil maps to result: null per the LSP spec — clients treat it as "no completions available," distinct from [] which means "we tried and got nothing".

Returns:

  • (Array<Hash>, nil)

    LSP CompletionItem[] or nil when the cursor isn't at a position the provider can enumerate completions for. Returning nil maps to result: null per the LSP spec — clients treat it as "no completions available," distinct from [] which means "we tried and got nothing".



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
# File 'lib/rigor/language_server/completion_provider.rb', line 50

def provide(uri:, line:, character:, trigger_character: nil)
  _ = trigger_character # Trigger info logged-not-routed in v1.
  path, entry = buffer_for(uri)
  return nil if entry.nil?

  # Slice B4 — parse recovery. The common mid-edit buffer (`obj.` / `Foo::`) doesn't parse cleanly; try
  # inserting a sentinel name at the cursor before falling through.
  bytes_to_parse, locate_at = parse_attempt_bytes(entry.bytes, line, character)
  parse_result = Prism.parse(bytes_to_parse, filepath: path,
                                             version: @project_context.configuration.target_ruby)
  return nil unless parse_result.errors.empty?

  # Rigor's NodeLocator uses 1-based line / column; LSP uses 0-based.
  node = locate_node(source: bytes_to_parse, root: parse_result.value,
                     line: locate_at[0] + 1, character: locate_at[1] + 1)
  return nil if node.nil?

  case node
  when Prism::CallNode
    # `hash[:|` patches to `hash[:KEY_SENTINEL]`, an index access call whose argument is the sentinel
    # symbol; NodeLocator at the sentinel returns the inner CallNode for `[]`. Hash-key completion wins
    # when the call is an index access on a HashShape carrier; otherwise fall through to method
    # completion.
    hash_key_completion_for(node, parse_result.value, path) ||
      method_completion_for(node, parse_result.value, path)
  when Prism::SymbolNode
    # The sentinel symbol's NodeLocator hit; walk up via the AST to find the enclosing `[]` call.
    hash_key_completion_for_symbol(node, parse_result.value, path)
  when Prism::ConstantPathNode
    constant_path_completion_for(node, path)
  end
end