Gleam-inspired typed configuration language (POC)
4.6 kB
179 lines
1# Glint
2
3A **Gleam-inspired configuration language** (proof of concept).
4
5Configs are typed values — you declare shapes, then construct one root `pub let config`.
6
7```glint
8type Mode {
9 Dev
10 Prod
11}
12
13type Config {
14 Config(
15 name: String,
16 mode: Mode,
17 port: Int,
18 )
19}
20
21pub let config = Config(
22 name: "hello",
23 mode: Dev,
24 port: 3000,
25)
26```
27
28## Features (POC)
29
30- Custom types: unit variants and labeled records
31- `let` / `pub let` bindings
32- Built-ins: `String`, `Int`, `Float`, `Bool`, `List(a)`, `Option(a)`
33- `True` / `False`, `None` / `Some(x)`
34- `//` comments, trailing commas, numeric underscores (`1_000`)
35- Typecheck + evaluate → dump as Glint syntax or JSON
36
37**Not yet:** imports, env helpers, floats in all edge cases, anonymous maps.
38
39## CLI
40
41```bash
42cd glint
43
44# Erlang target (default) if you have the BEAM installed:
45gleam run -- check examples/hello.glint
46gleam run -- dump examples/hello.glint
47gleam run -- dump examples/hello.glint --json
48
49# Language server (stdio JSON-RPC; Erlang target):
50gleam run -- lsp
51
52# Or JavaScript target (check/dump/library; LSP stdio needs Erlang):
53gleam run --target javascript -- check examples/hello.glint
54gleam test --target javascript
55```
56
57## Language server
58
59`glint lsp` speaks the Language Server Protocol over **stdio** (Content-Length framing).
60
61| Capability | Support |
62|------------|---------|
63| `initialize` / `shutdown` / `exit` | yes |
64| Full document sync (`textDocumentSync: 1`) | yes |
65| `textDocument/didOpen` / `didChange` / `didClose` | yes |
66| `textDocument/publishDiagnostics` | yes (lex / parse / type errors) |
67| `textDocument/hover` | yes (types, constructors, lets, builtins) |
68
69### Editor config (generic)
70
71Point your editor at the `glint` binary with the `lsp` argument, and associate `*.glint` files.
72
73**Neovim** (`nvim-lspconfig` style):
74
75```lua
76vim.api.nvim_create_autocmd("FileType", {
77 pattern = "glint",
78 callback = function()
79 vim.lsp.start({
80 name = "glint",
81 cmd = { "glint", "lsp" }, -- or: { "gleam", "run", "--", "lsp" } from the repo
82 root_dir = vim.fn.getcwd(),
83 })
84 end,
85})
86```
87
88**VS Code** (any generic LSP client extension): command `glint`, args `["lsp"]`, language id / file glob `*.glint`.
89
90
91**Zed** (extension in [`editors/zed/`](editors/zed/) — see that README for full detail):
92
93The extension is **Gleam** (`editors/zed/src/zed_glint.gleam`). Zed Install Dev
94Extension only knows how to run `cargo build --target wasm32-wasip2`, so that
95directory includes a small cargo **build driver** (`build.rs` + linker script)
96that runs `gleam export zed-extension` and installs the Gleam component as the
97crate’s `.wasm`. There is no separate Rust implementation of the guest.
98
99```sh
100# glint LSP
101cd /home/nandi/code/glint && nix build
102
103# wasm-capable gleam: https://tangled.org/nandi.uk/gleam (branch wasm)
104export GLEAM=/home/nandi/code/gleam/target/debug/gleam
105
106# build driver (same command Zed runs)
107cd /home/nandi/code/glint/editors/zed
108rustup target add wasm32-wasip2 # once
109cargo build --release --target wasm32-wasip2
110```
111
112Preferred (flake, prebuilt Gleam guest):
113
114```sh
115nix build .#zed-extension
116nix run .#install-zed-extension -- ~/glint-zed-dev
117# Zed → Install Dev Extension → ~/glint-zed-dev
118```
119
120Or point Install Dev at `editors/zed` after `nix develop` (sets `GLEAM`).
121
122Optional LSP path:
123
124```json
125{
126 "lsp": {
127 "glint": {
128 "binary": {
129 "path": "/home/nandi/code/glint/result/bin/glint",
130 "arguments": ["lsp"]
131 }
132 }
133 }
134}
135```
136
137
138## Library
139
140```gleam
141import glint
142import glint/value
143
144pub fn example() {
145 let assert Ok(checked) = glint.load(source)
146 value.to_json(checked.config)
147}
148```
149
150## Design
151
152| Idea | In Glint |
153|------|----------|
154| Named types first | `type Config { Config(...) }` |
155| One root export | `pub let config = ...` |
156| No null | `Option(a)` with `None` / `Some` |
157| Variants over string enums | `Dev` / `Prod` |
158| Labeled fields | `host: "localhost"` |
159
160## Layout
161
162```
163src/glint.gleam CLI + library entry
164src/glint/
165 token.gleam tokens
166 lexer.gleam lexer (spanned tokens)
167 position.gleam LSP-style positions / ranges
168 ast.gleam AST
169 parser.gleam parser
170 check.gleam typecheck + evaluate
171 value.gleam runtime values + printers
172 pipeline.gleam source → checked config
173 lsp.gleam language server entry
174 lsp/ JSON-RPC, protocol, handlers, diagnostics
175src/glint_lsp_ffi.erl stdio FFI (Erlang)
176examples/
177 hello.glint
178 app.glint
179```