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

Editor Setup

Fatou includes a language server (fatou lsp, stdio JSON-RPC) that any LSP client can drive. It provides formatting (whole document and range), lint and parse diagnostics with quick fixes, completion, hover, signature help, go-to definition, references, rename (of symbols, and of files and folders — moving a file rewrites the include paths that name it), document and workspace symbols, call and type hierarchy, folding ranges, document links, selection ranges, and semantic tokens. It also checks your Project.toml and Manifest.toml themselves, navigates an open Project.toml’s dependency names with inlay hints for their resolved versions, and links an open Manifest.toml’s path entries to the packages they pin.

Renaming a package entry from src/MyPkg.jl to src/NewPkg.jl also updates name in its Project.toml or JuliaProject.toml and matching top-level module MyPkg declarations. The project edit uses unsaved buffer text and preserves the UUID, comments, and other fields. The destination must remain in the package’s src/ directory and have a valid Julia identifier as its name. Imports and references to the package name elsewhere require separate updates.

Static docstrings are decoded before the server presents them, so unsaved local documentation and harvested package documentation render the same way. Their Markdown headings appear in the document outline and fold as sections; external links, fragments, footnotes, and explicit Documenter @ref targets navigate in place. An explicit @ref also completes Julia symbols and documentation anchors. Fences that declare Julia code—including julia, julia-repl, jldoctest, and Julia-bearing Documenter directives—receive completion, hover, signature help, go-to-definition, selection ranges, nested folding, and semantic highlighting. Dynamic or custom @doc metadata remains opaque.

Prerequisites

Install Fatou (see Getting Started) and make sure the fatou binary is on your PATH, or note its absolute path. The VS Code family is an exception, since the extension bundles a binary, and so is Zed, whose extension downloads one when it finds nothing on the PATH.

VS Code

Install the Fatou extension (jolars.fatou) from the Marketplace, or from the command line:

code --install-extension jolars.fatou

The extension activates on Julia files, starts fatou lsp for you, and registers itself as the default formatter for [julia]. Each platform-specific build bundles a matching fatou binary, so nothing else is needed; on a platform without one, it downloads a binary from GitHub releases.

To format on save, add to settings.json:

{
  "[julia]": {
    "editor.defaultFormatter": "jolars.fatou",
    "editor.formatOnSave": true
  }
}

To use a fatou you installed yourself instead of the bundled one:

{
  "fatou.executableStrategy": "environment"
}

or point at an exact binary:

{
  "fatou.executableStrategy": "path",
  "fatou.executablePath": "/usr/local/bin/fatou"
}

The extension’s README documents the available settings and their defaults.

Shared User Config

To use a shared fatou.toml outside your projects, add this to your user settings.json:

{
  "fatou.serverEnv": {
    "FATOU_CONFIG": "P:/Softwares/fatou.toml"
  }
}

Run Fatou: Restart Server after changing this setting or editing the shared file. Project configs take precedence, and the files are never merged. Use an absolute path; an unset or empty value uses the normal user config location. See User-Wide Defaults for the full resolution order and error behavior.

Using Only Some Features

The formatter, linter, and language features share one server but can be turned off independently, so you can adopt just the parts you want:

  • fatou.formatting.enable — use Fatou as a formatter.
  • fatou.diagnostics.enable — show Fatou diagnostics (the linter).
  • fatou.languageFeatures.enable — hover, completion, navigation, symbols, rename, code actions, and the rest.

All three default to true. They are client-side gates, so the server keeps running and the toggles take effect without a restart. For a formatter-only setup, turn off the other two:

{
  "fatou.diagnostics.enable": false,
  "fatou.languageFeatures.enable": false
}

Turning off fatou.diagnostics.enable suppresses every diagnostic, including the parse errors that a fatou.toml [lint] selection cannot silence. The fatou.toml route stays the right tool when you want to keep parse errors but mute specific lint rules across every editor and the CLI.

VSCodium and Other Code OSS Editors

The same extension is published to the Open VSX Registry, which VSCodium and most Code OSS builds use by default:

codium --install-extension jolars.fatou

If your build ships a different registry, download the VSIX matching your OS and architecture from the Open VSX page and install it with Extensions: Install from VSIX…, or from the command line:

codium --install-extension fatou-linux-x64.vsix

Settings are identical to VS Code’s.

Cursor

Search for Fatou in the Extensions view and install it. If your Cursor build does not list it, download the VSIX for your platform from Open VSX and install it with Extensions: Install from VSIX… from the command palette.

Cursor reads the same settings.json keys as VS Code, so the format-on-save and binary-selection snippets above apply unchanged.

Zed

Fatou attaches to Zed’s Julia language, which the Julia extension provides. Install that one first, then install Fatou from the extensions view (zed: extensions in the command palette).

Zed uses the fatou on your PATH when there is one, and otherwise downloads the release binary matching your platform. Keeping Fatou on the PATH is the better option on distributions that cannot run the generic release build, NixOS above all.

To run Fatou as the only Julia language server and use it for formatting, add this to settings.json:

{
  "languages": {
    "Julia": {
      "language_servers": ["fatou-language-server"],
      "formatter": {
        "language_server": {
          "name": "fatou-language-server"
        }
      }
    }
  }
}

To format on save, also add "format_on_save": "on" under languages.Julia.

Settings go under the server’s id, using the schema described in Configuration below:

{
  "lsp": {
    "fatou-language-server": {
      "settings": {
        "format": { "line-width": 100 },
        "lint": { "ignore": ["unused-binding"] }
      }
    }
  }
}

A fatou.toml in the project shadows these entirely, so prefer the file when the whole team should share the behavior.

To point Zed at a particular binary, set binary.path:

{
  "lsp": {
    "fatou-language-server": {
      "binary": { "path": "/opt/fatou/bin/fatou", "arguments": ["lsp"] }
    }
  }
}

arguments replaces the command line rather than extending it, so it has to keep naming a subcommand that speaks LSP.

Neovim

Neovim 0.11+ (built-in vim.lsp.config)

Add to your config (e.g. init.lua or a file under lua/):

vim.lsp.config("fatou", {
  cmd = { "fatou", "lsp" },              -- or the absolute path to the binary
  filetypes = { "julia" },
  root_markers = { "Project.toml", "JuliaProject.toml", ".git" },
})
vim.lsp.enable("fatou")

Format on save:

vim.api.nvim_create_autocmd("BufWritePre", {
  pattern = "*.jl",
  callback = function() vim.lsp.buf.format({ name = "fatou" }) end,
})

Older Neovim (autocmd + vim.lsp.start)

vim.api.nvim_create_autocmd("FileType", {
  pattern = "julia",
  callback = function(args)
    vim.lsp.start({
      name = "fatou",
      cmd = { "fatou", "lsp" },
      root_dir = vim.fs.root(args.buf, { "Project.toml", "JuliaProject.toml", ".git" }),
    })
  end,
})

ALE (Vim and Neovim)

ALE includes a Fatou linter and fixer for Julia. Install ALE and make sure fatou is on your PATH, then add to your .vimrc or init.vim:

let g:ale_linters = {'julia': ['fatou']}
let g:ale_fixers = {'julia': ['fatou']}

If you already configure these dictionaries for other languages, add the julia entries to them.

The linter starts fatou lsp to provide diagnostics and language features. The fixer runs fatou format; use :ALEFix to format the current buffer. To run configured fixers automatically on save, add:

let g:ale_fix_on_save = 1

To select a particular Fatou binary, set:

let g:ale_julia_fatou_executable = '/opt/fatou/bin/fatou'

This applies to both the linter and fixer. Configure project behavior through fatou.toml. See :help ale-julia-fatou for ALE’s Fatou-specific options.

Helix

Add to ~/.config/helix/languages.toml:

[language-server.fatou]
command = "fatou"
args = ["lsp"]

[[language]]
name = "julia"
language-servers = ["fatou"]
auto-format = true

Listing language-servers replaces Helix’s default for Julia, which is LanguageServer.jl. To keep it for the features Fatou does not cover yet while Fatou handles formatting, list both and take formatting away from the other server:

[[language]]
name = "julia"
language-servers = [{ name = "julia", except-features = ["format"] }, "fatou"]
auto-format = true

hx --health julia shows which servers Helix resolved for the language.

Other LSP clients

Any client that speaks LSP over stdio works: launch fatou lsp with no arguments for *.jl files, rooted at Project.toml, JuliaProject.toml, or .git. Nothing else is required, because Fatou discovers its own configuration from the file’s directory upward.

Fatou also checks your Project.toml and Manifest.toml themselves, and publishes those findings on the file at fault whether or not it is open. If you additionally attach the server to those files (the VS Code extension does), an open one reports its TOML errors as you type, before you save.

An open Project.toml also answers on its dependency names: go-to-definition and a document link take you to the package’s entry file, hovering reports the version, kind, and resolved path the environment gave it, and an inlay hint puts each resolved version beside its UUID, so you can read off what you are actually on without opening the Manifest.toml. In an open Manifest.toml, each path entry — a package you have dev’d — is a link to that package’s Project.toml.

Dependency updates follow the update/upgrade distinction used by crates.nvim, adapted to Julia’s Pkg compatibility grammar. On a dependency declaration or its existing [compat] entry, Fatou offers:

  • Update to adjust the bound to the newest stable release it already allows.
  • Upgrade to allow the newest stable release outside the current bound.

Actions appear only when they change the bound. Edits retain version precision, operators, quotes, surrounding comments, and whitespace: given releases 1.9.3 and 2.3.4, a bound of "1.2" offers Update to "1.9" and Upgrade to "2.3". A bound of "1" offers only Upgrade to "2". Julia’s comma-separated ranges form a union; updates change the matching arm, and upgrades outside a union append a new arm so earlier support ranges survive.

With LSP inlay hints enabled, each [compat] value shows the newest matching release and any available upgrade, such as v1.9.3 → v2.3.4. The matching release stays visible when the bound is current. These registry hints complement the resolved versions beside [deps] UUIDs; their tooltips explain the distinction.

This works in Project.toml and JuliaProject.toml, including [weakdeps], [extras], and unsaved edits. Fatou reads installed directory and compressed registries in the background, caching compressed results until the archive changes. It skips yanked releases, prereleases, and dependencies overridden in [sources]. Missing or malformed registry data produces fewer suggestions.

Suggestions use local registry data; unlike crates.nvim’s crates.io requests, Fatou does not fetch published releases over the network. Update your registries through Pkg when you need fresher suggestions. Applying an action edits only Project.toml: it does not resolve the environment, update Manifest.toml, download packages, invoke Julia, or check compatibility with the project’s Julia version and other dependencies. Formatting remains unavailable for TOML files.

Configuration

Fatou reads its settings from a fatou.toml next to your project (see the Configuration guide), which is the recommended way to configure it in any editor, since the whole team gets the same behavior.

A client can also push settings over LSP, as initializationOptions or workspace/didChangeConfiguration, using the same schema as the file, either bare or wrapped in a "fatou" key the way VS Code namespaces settings. In Helix, for example:

[language-server.fatou.config.format]
line-width = 100

[language-server.fatou.config.lint]
ignore = ["unused-binding"]

A discovered fatou.toml shadows editor-pushed settings entirely rather than merging with them, so a project file always wins.

Unicode Symbol Input

Completion also offers the LaTeX and emoji sequences the Julia REPL substitutes on tab, so \alpha inserts α, \_1 inserts ₁, and \:smile: inserts 😄. Type the backslash to open the list, keep typing to narrow it, and accepting an entry replaces the whole sequence, backslash included. As in the REPL, a bare \ lists the LaTeX sequences and \: opens the emoji. The table comes from the running Julia’s REPL.REPLCompletions, so it matches what your REPL does.

Two places stay quiet, so the list does not get in the way:

  • inside a string macro or command literal (r"\d", raw"\n", `ls \d`), where every backslash belongs to the literal itself;
  • on a lone escape in a plain string, so typing "\n does not offer \nabla. A second character brings the sequences back, so \nu and \alpha still work in strings and docstrings.

Check It Works

Open a .jl file containing x=1 and format the buffer: it becomes x = 1. In Neovim that is :lua vim.lsp.buf.format(), in Helix :format, and in the VS Code family Format Document. Diagnostics appear inline, and a lint finding with a fix offers it as a quick fix (:lua vim.lsp.buf.code_action(), <space>a in Helix, or the lightbulb in VS Code).

Notes

  • Document sync is incremental, and both whole-document and range formatting are supported.
  • Multiple formatters attached? In Neovim, pass { name = "fatou" } to vim.lsp.buf.format(); in Helix, strip format from the other server as shown above; in VS Code, set editor.defaultFormatter for [julia].
  • undefined-name and call-arity need project context, so the language server enables them for workspace member files even though the command line leaves them opt-in. An ignore entry still turns them off.