Hovering on a Pipeline
When you hover over a function call in a typical editor, you get a tooltip with the signature. Useful. When you hover over a *pipeline stage*, you get… the same tooltip. Which is fine, but it leaves you mentally reconstructing what value just flowed in and what value is flowing out. In Lateralus 0.5 we fixed that.
Full implementation: compiler/lsp/hover.ltl.
◉ What hovering a stage shows you
Given:
let report = txns
|> filter(is_recent)
|> group_by(|t| t.category)
|> map_entries(|cat, ts| (cat, ts |> map(.amount) |> sum()))
|> sort_by(|(_, total)| 0 - total)
Hover on group_by:
Pipeline stage
in : [Transaction]
out : Map<Category, [Transaction]>
Hover the call itself for the function signature.
You get the input type and the output type of *this stage*, not the function's generic signature. If your pipeline is wrong, the mismatch jumps out at the hover, not at the diagnostic several stages later.
◉ Why this was trivial
Lateralus' LSP backend has the type environment that produced the program. Pipeline stages are AST nodes (ast::PipeStage). The hover handler has two lookups:
let in_ty = module |> inferred_input(stage)
let out_ty = module |> inferred_output(stage)
Both are already populated by the type checker for diagnostic purposes. The hover provider just re-uses them. The whole render_stage function is 12 lines.
◉ Literal hover does more than you'd expect
A bonus we shipped at the same time: numeric literals show their hex and binary form on hover.
let mask = 0x0F_FF
Hover:
4095: Int
hex: 0xFFF | bin: 0b111111111111
Saves a trip to the REPL every time you're wrangling a bitfield or a Unicode codepoint.
◉ Function-call hover with docstrings and return types
pub fn map(xs: [T], f: fn(T) -> U) -> [U]
Returns: [String]
Apply `f` to each element of `xs`, returning the results.
The mapping is lazy: no work is done until a consumer
requests the first element.
Standard fare, but note the explicit Returns: line showing the *inferred* return type at this call site — [String] rather than [U]. Generics get monomorphized in the tooltip, which matters when you're debugging why the next stage doesn't type-check.
◉ Editor integrations
The LSP ships with the Lateralus compiler. Your editor picks it up if it supports the protocol:
- VS Code — install lateralus-vscode - Neovim — :LspInstall lateralus once the community metadata lands - Helix — add to languages.toml: [language.language-server] command = "lateralus"
All three call the same handle(HoverParams) -> HoverResult entry point.
◉ What's next in the LSP
Signature help, go-to-definition across crates, and a rename refactor that respects pipeline semantics (renaming a pipe stage's callee must update call sites but not inner closures). All small, all in-flight. None of them require new compiler infrastructure — the LSP is a *reader* of the existing type environment, not a second implementation of it.
The lesson repeats: if you put it in the compiler, the editor gets it for free.
Try it in the playground
Every snippet on this page runs in your browser. No install, no signup.
▶ Open Playground Star on GitHub