Class: Pikuri::Lsp::Navigator
- Inherits:
-
Object
- Object
- Pikuri::Lsp::Navigator
- Defined in:
- lib/pikuri/lsp/navigator.rb
Overview
One lsp call, end to end: route to a server, wait for its index, re-open
the document, ask, render. LspTool holds the schema and the legs; this holds
the behaviour, so a spec can drive it with no tool in sight.
navigator = Navigator.new(servers: servers, filesystem: filesystem,
on_progress: ->(progress) { ctx.emit_event(progress) })
navigator.navigate(operation: 'goToDefinition', symbol: 'resolve_for_read',
file: 'read.rb', line: 165)
The order of the five steps is the design
- Route on the file, or fan out when there is none — the model names no server, and a registry keyed by language would fail in exactly the mixed-language repo that makes a registry worth having.
- Gate on what that server advertised, per workspace and at dispatch.
Extension routing without this is how a shipped client leaks
Method not found: textDocument/implementationat the model. - Wait for the index — the one place waiting beats relaying, because a
mid-index server answers
[]with a success code and there is nothing in[]to reason about. No timeout: a cold Java import measured 78 seconds, no number separates that from a hang, and progress events pluscancellablemake the human the timeout. - Re-open the document (ClientWrapper#open_document), and hand it back once every reply is in (#release_documents) — the pair is per call, because one call can ask several questions about one document.
- Ask and render, running the
preparehop and the per-level walk here so the model issues one call and never holds an opaque protocol item.
Errors are relayed, never worked around
Every server is broken in its own way and the ways do not generalize — one
advertises a type hierarchy whose downward half is a # TODO, another indexes
no methods, a third crashes on a notification the spec allows. So there is no
per-server workaround and no known-stub list here: what the server said and
what it was asked go back, and the model decides. That includes a reply pikuri
cannot parse (#relaying) — the server's bug, and dying on it would be the
one failure mode this stance exists to prevent.
Constant Summary collapse
- MAX_PREPARED =
Items a
preparehop may produce before the rest are dropped with a note.preparecan legitimately answer several — Java overloads, one name declared in several classes — and the model has no more idea which is meant than this does, so each is queried and the results are labelled. 3
Instance Method Summary collapse
-
#initialize(servers:, filesystem:, on_progress: nil, cancellable: nil) ⇒ Navigator
constructor
A new instance of Navigator.
-
#navigate(operation:, symbol:, file: nil, line: nil) ⇒ String
Answer one call.
Constructor Details
#initialize(servers:, filesystem:, on_progress: nil, cancellable: nil) ⇒ Navigator
Returns a new instance of Navigator.
57 58 59 60 61 62 63 64 65 |
# File 'lib/pikuri/lsp/navigator.rb', line 57 def initialize(servers:, filesystem:, on_progress: nil, cancellable: nil) @servers = servers @filesystem = filesystem @on_progress = on_progress || ->(_progress) {} @cancellable = cancellable @ready = [] @texts = {} @opened = [] end |
Instance Method Details
#navigate(operation:, symbol:, file: nil, line: nil) ⇒ String
Answer one call.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/pikuri/lsp/navigator.rb', line 79 def navigate(operation:, symbol:, file: nil, line: nil) op = Operation[operation] raise ArgumentError, "unknown lsp operation #{operation.inspect}" if op.nil? renderer = Renderer.new(sources: Sources.new(filesystem: @filesystem)) @ready = [] @texts = {} @opened = [] raise Refusal, 'no language server is configured' if @servers.empty? dispatch(op, symbol, file, line, renderer) rescue Refusal, Pikuri::Workspace::Filesystem::Error, ClientWrapper::ServerDied => e "Error: #{e.}" rescue Connection::ServerError => e "Error: the language server refused #{operation}: #{e.}" ensure release_documents end |