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
"\ndoes not offer\nabla. A second character brings the sequences back, so\nuand\alphastill 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" }tovim.lsp.buf.format(); in Helix, stripformatfrom the other server as shown above; in VS Code, seteditor.defaultFormatterfor[julia]. undefined-nameandcall-arityneed project context, so the language server enables them for workspace member files even though the command line leaves them opt-in. Anignoreentry still turns them off.