A Spacemacs layer for the Flix programming language.
This layer wires up flix-mode as the
major mode and drives the official Flix compiler as an LSP server, as the
official VS Code and
Neovim clients do, giving you completion,
type/effect hovers, go to definition, find references, rename, signature
help, code actions, code lenses, and server-provided semantic highlighting —
inside the Spacemacs key-binding system.
flix-layer-highlights.mp4
Semantic highlighting, the "Run" code lens on an entry point, and an LSP rename propagating across the project.
- LSP integration via the official Flix compiler (jar), started through
flix-mode's public API. - Automatic compiler management:
flix-modedownloads the jar on demand and resolves its version fromflix.toml. - Whole-project analysis: the Flix LSP server loads every project file on initialize, so cross-file module resolution works out of the box.
- Semantic highlighting provided by the compiler.
- Run / test commands that invoke the Flix CLI from the project root.
- Formatting by Flix's own formatter — the one
flix formatruns — served by the LSP server: format the buffer on demand, or on every save. - REPL integration: start a project-scoped Flix REPL, and run entry points
directly from the "Run" code lens. The REPL buffer has minimal standalone
syntax highlighting (keywords, types, comments, strings) and
C-j/C-khistory navigation.
This layer requires:
- Spacemacs with the
lsplayer enabled. - Java 21+ available on your
PATH(the Flix compiler runs on the JVM). - A Flix project with a
flix.tomlin its root.
Clone this repository into your private layers directory:
git clone https://github.com/flix/spacemacs.git \
~/.emacs.d/private/flixThen add flix to the existing dotspacemacs-configuration-layers list in
your ~/.spacemacs:
dotspacemacs-configuration-layers
'(;; ...
lsp
flix)Restart Spacemacs (or reload the configuration with SPC f e R). The first
time you open a .flix file, flix-mode offers to download the Flix compiler
jar for the version declared in flix.toml.
The layer is intentionally thin: it adds a single variable of its own, and otherwise you customize it through the packages it builds on.
-
flix-format-on-save(defaultnil) — when non-nil, format a Flix buffer before saving it:dotspacemacs-configuration-layers '(;; ... lsp (flix :variables flix-format-on-save t))
SPC m T =toggles it for the running session, in every Flix buffer at once. Formatting is Flix's own, requested from the LSP server, so it matches whatflix formatproduces on the command line. It is skipped silently until the server has finished loading the project, and a failure is reported as a warning rather than being allowed to abort the save. -
Compiler / jar management is handled by
flix-mode. Its customize groupflix-mode(browse it withM-x customize-group RET flix-mode RET) exposes:flix-mode-download-dir— where jars are downloadedflix-mode-jar-name— the jar file nameflix-mode-releases-url— where Flix releases are fetched fromflix-mode-project-file— the project file (flix.tomlby default)
-
LSP behavior (inlay hints, code lenses, semantic tokens, completion, and so on) is controlled by the standard
lsp-modevariables. The layer enableslsp-semantic-tokens-enablein Flix buffers so the compiler's semantic highlighting is on by default; everything else uses your existinglsplayer configuration. -
Key bindings follow the Spacemacs conventions below and can be overridden the usual way, e.g. with
spacemacs/set-leader-keys-for-major-modein yourdotspacemacs/user-config.
The layer is deliberately thin; it delegates as much as possible to
flix-mode and lsp-mode.
flix-modeowns the major mode, jar download, and version resolution. This layer calls its public API (flix-mode-ensure,flix-mode-server-path) to obtain the compiler command.lsp-modereceives anlsp-stdio-connectionclient that launchesjava -jar <jar> lsp.- The Flix LSP server resolves the LSP
workspaceFoldername as a relative path when it scans the project. Becauselsp-modesends the directory's short name rather than a full path, the layer sets the server process's working directory to the parent of the workspace root so that the scan resolves correctly. Without this, only the opened file is compiled and you getOrphaned module/Undefined useerrors. - The server does not implement
workspace/executeCommand, so the "Run" code lens (flix.runMain) is handled on the client side: an action handler sends:eval <symbol>()to a project-scoped REPL, the same approach the official VS Code extension takes. flix.tomlis registered as a Projectile project root marker.
Under the major-mode leader (SPC m or ,):
| Key binding | Description |
|---|---|
SPC m ' |
start / switch to the REPL |
SPC m = = |
format the buffer |
SPC m c c |
run the project (flix run) |
SPC m s i |
start / switch to the REPL |
SPC m s q |
quit the REPL |
SPC m t a |
run all tests (flix test) |
SPC m T = |
toggle flix-format-on-save |
Inside the REPL buffer:
| Key binding | Description |
|---|---|
C-j |
next item in REPL history |
C-k |
previous item in REPL history |
Clicking the Run code lens above an entry point runs it in the REPL. All
other language features come from the lsp layer's standard bindings (e.g.
g d for go to definition, K for hover, SPC m r r for rename). That
includes formatting: SPC m = = above is the major-mode spelling of the
lsp layer's own SPC m = b, which runs the same command.
- Test code lenses are not shown: the Flix compiler (as of v0.79.0) only emits
a "Run" lens for entry points, not for
@Testfunctions, so there is nothing for this layer to wire up. UseSPC m t ato run the whole test suite. - Formatting is whole-file only: the server advertises
documentFormattingProviderbut notdocumentRangeFormattingProvider, so thelsplayer'sSPC m = r(lsp-format-region) has nothing to call. flix testruns the entire suite; the compiler exposes no way to filter by test name from the CLI or REPL, so per-test execution is not available.- Files created or deleted mid-session are not pushed to the server until the file is opened (or LSP is restarted), since there is no file-system watcher.
Apache-2.0. See LICENSE.md.