Class: Rigor::LanguageServer::HoverProvider

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

Overview

Answers textDocument/hover requests by running the same NodeLocator + ScopeIndexer + Scope#type_of chain that rigor type-of already drives. The LSP wraps the result in a Hover payload with markdown contents.

Per LSP spec § "Position":

  • line and character are 0-based.
  • character counts UTF-16 code units; v1 emits byte counts for ASCII source (UTF-16 conversion is queued, see design doc § "Open questions").

Instance Method Summary collapse

Constructor Details

#initialize(buffer_table:, project_context:, renderer: HoverRenderer.new) ⇒ HoverProvider

Returns a new instance of HoverProvider.



26
27
28
29
30
# File 'lib/rigor/language_server/hover_provider.rb', line 26

def initialize(buffer_table:, project_context:, renderer: HoverRenderer.new)
  @buffer_table = buffer_table
  @project_context = project_context
  @renderer = renderer
end

Instance Method Details

#provide(uri:, line:, character:) ⇒ Hash?

Returns an LSP Hover payload or nil when no expression sits at the queried position. Returning nil maps to result: null per the LSP spec — clients suppress the hover popup in that case.

Returns:

  • (Hash, nil)

    an LSP Hover payload or nil when no expression sits at the queried position. Returning nil maps to result: null per the LSP spec — clients suppress the hover popup in that case.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/rigor/language_server/hover_provider.rb', line 36

def provide(uri:, line:, character:)
  path, entry = buffer_for(uri)
  return nil if entry.nil?

  parse_result = Prism.parse(entry.bytes, 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. Translate at the boundary.
  node = locate_node(source: entry.bytes, root: parse_result.value, line: line + 1, character: character + 1)
  return nil if node.nil?

  scope = base_scope(path)
  index = Inference::ScopeIndexer.index(parse_result.value, default_scope: scope)
  node_scope = index[node]
  type = node_scope.type_of(node)

  @renderer.render(node: node, type: type, node_scope_lookup: index)
end