Saule for VS Code
Full language support for .sau files: a TextMate grammar for syntax
highlighting plus a Language Server Protocol client that talks to
saule-lsp, the language server of the
Saule programming language.
Features
Powered by the saule-lsp server:
- Diagnostics — lex, parse, semantic, and type errors, live on every
edit.
- Hover — types and signatures for locals, functions, methods,
classes, enums, and stdlib/native members (with generic substitution,
so
Table.remove(table<integer>) shows integer?).
- Go-to-definition and find-all-references.
- Document highlights and document symbols (outline / breadcrumbs).
- Inlay hints — inferred local types and parameter-name labels.
- Signature help — parameter popups while typing call arguments, and
whenever the caret moves back inside a call's parens.
- Formatting — full-document and range formatting.
Provided by the extension itself, so they work with or without the server:
- Indentation while typing — Enter indents the new line, and block-closing
keywords dedent as you finish them:
end, until, else, elseif,
catch and case snap to the right level. Saule closes blocks with words
rather than braces, so there is no } for the usual dedent to hook onto.
Driven by editor.formatOnType, which this extension turns on for .sau
files (along with two-space indentation, matching saule fmt).
- Run commands — run the current file or the whole project in a terminal.
Install
Search for Saule in the Extensions view, install it from the
Marketplace,
or run:
code --install-extension saule.saule
The extension also needs the Saule toolchain, once per machine.
The extension needs the saule-lsp binary. The installer puts it, and the
saule CLI, in ~/.saule/bin (%USERPROFILE%\.saule\bin) and adds that to
your PATH:
irm https://lauriszz123.github.io/saule/install.ps1 | iex
curl -fsSL https://lauriszz123.github.io/saule/install.sh | sh
The extension discovers the binaries in the same order as the IntelliJ plugin
and the Neovim plugin:
SAULE_LSP_PATH / SAULE_PATH environment variables.
saule.server.path / saule.cli.path, or saule.toolchainDir, from your
User settings. A project's .vscode/settings.json cannot set these.
- Only with
saule.allowProjectBuild on: Cargo build output, walking up
from each workspace folder looking for target/release then target/debug.
saule-lsp / saule on your PATH.
~/.saule/bin (or $SAULE_HOME/bin), where the installer puts them.
Step 3 is off by default because a repository can commit a target/debug/saule-lsp
of its own, and opening a folder should not run it. Turn it on if you work on
the language itself. The extension is
also disabled in untrusted workspaces.
Versioning
The extension version tracks the toolchain it targets — <year>.<build>, the
same number saule --version prints, plus a .0 because the Marketplace
validates the manifest as strict semver. It has to be written into
package.json and both places package-lock.json keeps it, so one script
writes all three:
npm run stamp -- 26.8
npm run stamp -- 26.8 --check # verify, change nothing
Run the stamp before vsce package, and --check in CI — it turns "bumped
the manifest and forgot the lockfile" into a failed job rather than an
npm ci that refuses to install.
Settings
| Setting |
Default |
Purpose |
saule.server.path |
"" |
Absolute path to saule-lsp. Empty = auto-detect. |
saule.cli.path |
"" |
Absolute path to saule, used by the run commands. Empty = auto-detect. |
saule.toolchainDir |
"" |
Directory holding both binaries, used when no explicit path is set. |
saule.server.extraArgs |
[] |
Extra CLI args for the server. |
saule.trace.server |
"off" |
LSP message tracing (off / messages / verbose). |
The extension also sets editor.tabSize: 2, editor.insertSpaces: true,
editor.formatOnType: true and editor.wordBasedSuggestions: "off" for
[saule] files. The last one leaves completion to saule-lsp: VS Code's
word-based provider otherwise scrapes identifiers out of the open document
and offers them everywhere, including the declaration positions where the
server deliberately stays quiet — so naming a new fn suggested every
similar-looking word already in the file. These are defaults — your own
settings still win.
Commands
- Saule: Run File —
saule run <file> on the active buffer, saving it
first. Also on the editor context menu.
- Saule: Run Project —
saule run from the workspace root.
- Saule: Restart Language Server — relaunch the server (e.g. after a
fresh
cargo build).
- Saule: Show Language Server Output — open the server's output
channel for logs and traces.
Editor parity
src/indent.ts is a port of the IntelliJ plugin's SauleIndentModel and
shares its test corpus with the Neovim plugin's lua/saule/indent.lua. All
three are derived from the printer in crates/saule-fmt/src/lib.rs in the
language repository. The three clients live in separate repositories now, so
changing one is a change to all three: update
saule-intellij and
saule-nvim alongside it and
re-run every suite.
npm test
Syntax highlighting
syntaxes/saule.tmLanguage.json is a copy. The grammar is written once, in
the language repository at grammar/saule.tmLanguage.json, next to the lexer
it has to agree with, and is read from there by the documentation site as
well. A .vsix has to carry the file it ships, so this repository keeps a copy
and refreshes it after an upstream change:
npm run sync:grammar # from github.com/lauriszz123/saule
npm run sync:grammar -- ../saule # from a local checkout
Colours come from the user's active theme via these scopes:
keyword.control, keyword.declaration, entity.name.type,
entity.name.function, string.quoted.double, comment.line,
constant.numeric, constant.language, variable.language.
Build from source
Only needed to work on the extension itself.
git clone https://github.com/lauriszz123/saule-vscode.git
cd saule-vscode
npm install
npm run compile
# then either press F5 / "Run Extension" from Run & Debug,
# or package and install:
npm install -g @vscode/vsce
vsce package
code --install-extension saule-<version>.vsix
For zero-build syntax-only dev, copy this folder into
%USERPROFILE%\.vscode\extensions\saule\ and reload — but the LSP
features need the compiled out/extension.js (npm run compile).
License
MIT — see LICENSE.