Gleam-inspired typed configuration language (POC)
0

Configure Feed

Select the types of activity you want to include in your feed.

3 1 0

Clone this repository

https://git.vm.fail/nandi.uk/glint https://git.vm.fail/did:plc:pb2o34bq3h6ocksxfuulunx2
ssh://git@knot1.tangled.sh:2222/nandi.uk/glint ssh://git@knot1.tangled.sh:2222/did:plc:pb2o34bq3h6ocksxfuulunx2

For self-hosted knots, clone URLs may differ based on your setup.


README.md

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 let bindings
  • 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#

  1. Extensions → Install Dev Extension…
  2. Select: /home/nandi/code/glint/editors/zed
  3. Open a *.glint file — the guest starts glint 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:

# 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