Open-Source Wikis

/

Helix

/

Features

/

Language servers

helix-editor/helix

Language servers

Helix has built-in LSP support: per-language servers spawned on demand, multiple servers per language, and async hooks driving completion, signature help, document highlights, and diagnostics. The protocol layer lives in helix-lsp; the user-facing features are spread across helix-term.

Configuration

Servers are declared once at the top of languages.toml:

[language-server.rust-analyzer]
command = "rust-analyzer"
config = { check = { command = "clippy" } }

Then attached to a language:

[[language]]
name = "rust"
language-servers = [ "rust-analyzer" ]

A language can list multiple servers — each gets started independently and their responses are combined for goto, references, completions, and diagnostics. The server config struct is LanguageServerConfiguration in helix-core/src/syntax/config.rs.

Per-server feature flags (only-features, except-features) gate which capabilities Helix uses from that server. The full list lives in LanguageServerFeature in helix-core/src/syntax/config.rs.

Lifecycle

sequenceDiagram
    participant Doc as Document::open
    participant Ed as Editor
    participant Reg as helix_lsp::Registry
    participant Cli as Client
    participant LS as Language Server

    Doc->>Ed: detect language
    Ed->>Reg: get_or_start("rust", "rust-analyzer", root)
    Reg->>Cli: spawn process
    Cli->>LS: initialize
    LS-->>Cli: capabilities (offset_encoding, completion, hover, …)
    Cli->>LS: initialized + workspace/didOpen documents
    Doc->>Cli: textDocument/didOpen
    Note over Doc,Cli: Document::apply now sends didChange on each edit
    Doc->>Cli: textDocument/didClose (on Document drop)

The registry restarts a crashed client transparently. :lsp-restart and :lsp-stop accept an optional language list to scope to specific servers.

Async handlers

Each LSP feature that fires in the background is an AsyncHook in helix-term/src/handlers/:

Handler Trigger Behaviour
completion PostInsertChar, SelectionDidChange Debounced completion request; resolves item details on demand.
signature_help PostInsertChar, mode change to Insert Shows signature popup when in argument context.
document_highlight SelectionDidChange (debounced) Highlights other references to the symbol under the cursor.
diagnostics DocumentDidChange Pull-model: requests diagnostics for servers that don't push.
pull_all_documents_diagnostics Workspace events Workspace-wide pull diagnostics fetcher.
document_colors Document open / change Renders inline color swatches from textDocument/documentColor.
document_links Document open / change Resolves clickable links.

All of these communicate back to the main loop via Jobs and helix_event::request_redraw.

Synchronous commands

LSP-driven user actions live in helix-term/src/commands/lsp.rs:

  • goto_definition, goto_declaration, goto_type_definition, goto_implementation, goto_reference
  • hover — shows server hover content (cycles through multiple servers via A-n/A-p).
  • code_action — opens the Menu of available actions.
  • rename_symbol, format_selections, signature_help (manual trigger).
  • workspace_symbol_picker, document_symbol_picker, diagnostics_picker.
  • lsp_workspace_command_picker — runs server-defined commands via workspace/executeCommand.

These commands are bound by default to keys under the g (goto) and space (workspace) prefixes — see helix-term/src/keymap/default.rs.

Diagnostics

Diagnostics are stored on Editor::diagnostics keyed by Uri and tagged with their DiagnosticProvider. Multiple providers can contribute to the same file (e.g. rust-analyzer plus a separate linter). Rendering happens via:

Completion

The completion pipeline is in helix-term/src/handlers/completion and the rendering popup in helix-term/src/ui/completion.rs. 25.07 added support for "incomplete" completions — when the server says the list isn't exhaustive, Helix re-requests on filter change.

editor.preview-completion-insert causes Helix to optimistically insert the completion text; cancelling reverts via the saved snippet snapshot.

Workspace edits, snippets, and code actions

util::apply_workspace_edit (helix-lsp/src/lib.rs) receives a WorkspaceEdit from a code action or rename and produces a sequence of transactions across documents (and file create/rename/delete operations). Snippet edits are turned into a Transaction plus an ActiveSnippet that drives tab-stop navigation in helix-core/src/snippets/active.rs.

Three "decorative" LSP features all follow the same pattern: an AsyncHook requests data from the server when the document or viewport changes; results are stored on Document (or Editor); a renderer consults the stored data and emits text annotations or virtual text. The decoration engine is in helix-term/src/ui/text_decorations.

Health check

hx --health <lang> (helix-term/src/health.rs) reports whether the configured language servers, formatter, and DAP adapter are on $PATH — the most common debugging step for "completion isn't working".

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Language servers – Helix wiki | Factory