Glint#
A Gleam-inspired configuration language (proof of concept).
Configs are typed values — you declare shapes, then construct one root pub let config.
type Mode {
Dev
Prod
}
type Config {
Config(
name: String,
mode: Mode,
port: Int,
)
}
pub let config = Config(
name: "hello",
mode: Dev,
port: 3000,
)
Features (POC)#
- Custom types: unit variants and labeled records
let/pub letbindings- Built-ins:
String,Int,Float,Bool,List(a),Option(a) True/False,None/Some(x)//comments, trailing commas, numeric underscores (1_000)- Typecheck + evaluate → dump as Glint syntax or JSON
Not yet: imports, env helpers, floats in all edge cases, anonymous maps.
CLI#
cd glint
# Erlang target (default) if you have the BEAM installed:
gleam run -- check examples/hello.glint
gleam run -- dump examples/hello.glint
gleam run -- dump examples/hello.glint --json
# Language server (stdio JSON-RPC; Erlang target):
gleam run -- lsp
# Or JavaScript target (check/dump/library; LSP stdio needs Erlang):
gleam run --target javascript -- check examples/hello.glint
gleam test --target javascript
Language server#
glint lsp speaks the Language Server Protocol over stdio (Content-Length framing).
| Capability | Support |
|---|---|
initialize / shutdown / exit |
yes |
Full document sync (textDocumentSync: 1) |
yes |
textDocument/didOpen / didChange / didClose |
yes |
textDocument/publishDiagnostics |
yes (lex / parse / type errors) |
Editor config (generic)#
Point your editor at the glint binary with the lsp argument, and associate *.glint files.
Neovim (nvim-lspconfig style):
vim.api.nvim_create_autocmd("FileType", {
pattern = "glint",
callback = function()
vim.lsp.start({
name = "glint",
cmd = { "glint", "lsp" }, -- or: { "gleam", "run", "--", "lsp" } from the repo
root_dir = vim.fn.getcwd(),
})
end,
})
VS Code (any generic LSP client extension): command glint, args ["lsp"], language id / file glob *.glint.
Zed (dev extension in this repo — see also editors/zed/README.md):
Why is there Rust under editors/zed/?#
Not because we want the extension authored in Rust. Zed forces it today.
On Install Dev Extension, when extension.toml has [lib] kind = "Rust"
(the only allowed kind), Zed always runs roughly:
cargo build --target wasm32-wasip2
and writes extension.wasm from that crate. There is no install path that
only loads a prebuilt component from gleam export zed-extension. Without
Cargo.toml + src/*.rs you get failed to compile Rust extension.
So editors/zed/src/glint.rs is a thin temporary guest (same behaviour as
zed_glint.gleam: resolve glint, start LSP). Direction of travel is pure
Gleam via our wasm fork; the .rs crate
can go once Zed accepts prebuilt guests (or we use another install path).
| Path | Role |
|---|---|
editors/zed/src/glint.rs |
What Zed can compile and install now |
editors/zed/src/zed_glint.gleam |
Target authoring surface (pure Gleam) |
nandi.uk/gleam wasm |
Compiler that builds a real zed:extension component |
1. Build the glint binary#
cd /home/nandi/code/glint
nix build # → result/bin/glint
2. Compile the Zed guest (Rust)#
Zed Install Dev Extension always runs cargo build --target wasm32-wasip2.
Build yourself first if you want to check the toolchain:
cd /home/nandi/code/glint/editors/zed
rustup target add wasm32-wasip2 # once
cargo build --release --target wasm32-wasip2
cp target/wasm32-wasip2/release/zed_glint.wasm extension.wasm
file extension.wasm # WebAssembly component
3. Install in Zed#
- Extensions → Install Dev Extension…
- Select:
/home/nandi/code/glint/editors/zed - Open a
*.glintfile — the guest startsglint lsp
Optional settings override:
{
"lsp": {
"glint": {
"binary": {
"path": "/home/nandi/code/glint/result/bin/glint",
"arguments": ["lsp"]
}
}
}
}
Pure Gleam guest (experimental)#
Compiler work lives on our Gleam wasm fork:
- https://tangled.org/nandi.uk/gleam (
wasmbranch)
# build the forked compiler
git clone https://tangled.org/nandi.uk/gleam
cd gleam && git checkout wasm
cargo build -p gleam
# from this extension (optional; Install Dev still uses Rust today)
cd /home/nandi/code/glint/editors/zed
/path/to/gleam/target/debug/gleam export zed-extension
Notes: grammar id is gleam (exports tree_sitter_gleam). Zed does not yet
install a prebuilt Gleam extension.wasm without cargo — see
docs on the fork /
docs/compiler/wasm-zed-extensions.md.
Library#
import glint
import glint/value
pub fn example() {
let assert Ok(checked) = glint.load(source)
value.to_json(checked.config)
}
Design#
| Idea | In Glint |
|---|---|
| Named types first | type Config { Config(...) } |
| One root export | pub let config = ... |
| No null | Option(a) with None / Some |
| Variants over string enums | Dev / Prod |
| Labeled fields | host: "localhost" |
Layout#
src/glint.gleam CLI + library entry
src/glint/
token.gleam tokens
lexer.gleam lexer (spanned tokens)
position.gleam LSP-style positions / ranges
ast.gleam AST
parser.gleam parser
check.gleam typecheck + evaluate
value.gleam runtime values + printers
pipeline.gleam source → checked config
lsp.gleam language server entry
lsp/ JSON-RPC, protocol, handlers, diagnostics
src/glint_lsp_ffi.erl stdio FFI (Erlang)
examples/
hello.glint
app.glint