Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Language Server

Flint ships a built-in language server that editors can use for real-time feedback while you write code. It runs as a subprocess of your editor, communicating over standard input and output using the Language Server Protocol (LSP).

Starting the Server

flint lsp

This launches the language server with stdio transport. You do not normally run this command yourself; your editor starts it automatically when you open a Flint file. The sections below explain how to configure that for each supported editor.

Supported Features

The language server provides the following capabilities:

  • Completion. Context-aware completions including use path completion, keywords, top-level items, imported names, local variables (let bindings, parameters, for-loop variables), enum variants after ::, struct fields inside constructors, and member/method completion after . with type inference from construct expressions, function return types, and self inside impl blocks.
  • Diagnostics. Syntax errors appear instantly as you type. Semantic diagnostics (unresolved symbols, missing entry points) and deep type-level diagnostics (mutability violations, ownership errors, use-after-move, missing returns, non-exhaustive match) update after each change via the full in-process compiler pipeline.
  • Hover. Hovering over a function or item shows its signature and doc comments.
  • Go-to-definition. Jump to the definition of any symbol, including across open files.
  • Document symbols. Browse the structure of the current file (functions, types, constants).
  • Workspace symbols. Search for symbols across the entire project.
  • Signature help. See parameter names and types while filling in a function call.
  • Find references. Locate every use of a symbol across all open files.
  • Rename. Rename a symbol and update all references across open files.
  • Code actions. Quick fixes from diagnostic suggestions, automatic “add missing import” for unresolved symbols, and “remove unused import” for dead imports.
  • Formatting. Format the current file through textDocument/formatting, using the same rules as flint fmt.
  • Semantic tokens. Rich, context-aware syntax highlighting that distinguishes functions, types, enums, traits, constants, parameters, and more.
  • Inlay hints. Inline type annotations on let bindings with inferred types, and parameter name hints at call sites.
  • Document highlights. All occurrences of the symbol under the cursor are highlighted.
  • Folding ranges. Collapse function bodies, struct/enum/trait/impl blocks, and nested control flow.

The Self-Contained Part is Real

Most language servers talk to the compiler at arm’s length. They run a separate process, parse its text output, and hope the error messages land on the right line. Some languages have a compiler that was never designed for interactive use, so the LSP has to maintain its own parallel understanding of the code and reconcile it with the real compiler after the fact.

Flint does not work this way. The language server runs the actual compiler frontend in-process: the same lexer, the same parser, the same semantic checker, the same lowerer, and the same type checker that flint check and flint build use. There is no separate analysis engine. There is no second opinion that might disagree with the real compiler. When the language server underlines something in red, it is because the compiler itself rejected it, not because a heuristic guessed something might be wrong.

This means every diagnostic the compiler can produce is available in your editor the moment you stop typing:

  • Mutability. Assigning to a non-mut binding is an error. The fix suggestion tells you to add mut.
  • Ownership. Using a value after it has been moved is an error. The diagnostic points at the move and the use.
  • Definite initialization. Reading a variable before it has been assigned is caught.
  • Return completeness. A function that promises a return value but has a code path that falls through is an error.
  • Exhaustive match. A match that does not cover all variants is caught at the point of the match.
  • Closure captures. Capturing a moved value in a closure is flagged.
  • MCU recursion policy. On MCU targets, recursive call cycles are reported unless explicitly opted in.

These are not lint suggestions. They are the same errors that would stop flint build from producing a binary. Seeing them live while writing code, with explanations and fix suggestions, is a fundamentally different experience from discovering them after a failed build.

This is only possible because Flint owns its entire pipeline. There is no GCC or LLVM in the loop. The compiler is a set of Rust library crates, and the language server calls directly into them. Adding a new diagnostic to the compiler means it automatically appears in every editor. There is no protocol translation layer, no output parser to update, no version skew between the compiler and the editor tooling.

The self-contained toolchain is not just about installation convenience. It is about making the editor and the compiler the same thing.

Editor Setup

VS Code and Cursor

A dedicated VS Code extension with TextMate highlighting and automatic LSP launch is planned. Until it ships, you can configure VS Code (or Cursor, which uses the same extension model) manually:

  1. Install a generic LSP client extension such as vscode-languageclient or configure the built-in language client if your extension supports it.
  2. Point the server command at flint lsp.
  3. Associate .fl files with the Flint language ID.

A minimal settings.json snippet:

{
  "flint.server.path": "flint",
  "flint.server.args": ["lsp"]
}

The exact keys depend on which LSP client extension you use. Refer to that extension’s documentation for the precise configuration format.

Zed

A Zed extension with Tree-sitter grammar and LSP launch is planned. In the meantime, you can add a custom language server entry in your Zed settings:

{
  "lsp": {
    "flint": {
      "binary": {
        "path": "flint",
        "arguments": ["lsp"]
      }
    }
  }
}

Then associate .fl files with the flint language server in your Zed language configuration.

Other Editors

Any editor that supports LSP can use the Flint language server. Configure it to run flint lsp as a stdio-based language server and associate it with .fl files. Neovim (via nvim-lspconfig), Helix, and Sublime Text all support custom LSP server definitions.