https://github.com/srdjan/zigcli
Advent Of Code 2025: Exploring the "Safe DSL Surface with an Unsafe Engine Under the Hood" Pattern in CLI Parsing
https://github.com/srdjan/zigcli
experimental fun zig
Last synced: about 1 month ago
JSON representation
Advent Of Code 2025: Exploring the "Safe DSL Surface with an Unsafe Engine Under the Hood" Pattern in CLI Parsing
- Host: GitHub
- URL: https://github.com/srdjan/zigcli
- Owner: srdjan
- Created: 2025-12-13T14:01:30.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2025-12-13T14:16:04.000Z (6 months ago)
- Last Synced: 2026-04-08T12:35:30.686Z (3 months ago)
- Topics: experimental, fun, zig
- Language: Zig
- Homepage:
- Size: 13.7 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# zigcli — a tiny type-safe Zig embedded DSL for CLI parsing
This repo is a prototype showing the **"safe DSL surface / unsafe engine under the hood"** pattern applied to CLI parsing.
## What you get
- **Typed results**: `parseOutcome()` returns a tagged union of subcommands with strongly typed structs.
- **No help drift**: help output is derived from the same compile-time spec as parsing.
- **Good diagnostics**: errors carry token index + token + optional suggestion.
- **Lists**: repeatable flags like `--tag a --tag b` become slices (`[]const T`).
- **Arena-owned list storage**: list memory is freed automatically by `Owned.deinit()`.
## Quick start
```bash
zig build run -- serve --host 127.0.0.1 --port 8080 -vv --tag a --tag b
zig build run -- gen outdir --force
zig build run -- serve --help
```
## Example spec
See `examples/mytool.zig`.
```zig
const cli = @import("zigcli");
const Mode = enum { fast, slow };
const App = cli.App(cli.app(.{
.name = "mytool",
.commands = .{
cli.cmd("serve", .{
.about = "Run server",
.opts = .{
cli.opt.str("host", .{ .long="--host", .default="127.0.0.1" }),
cli.opt.u16("port", .{ .long="--port", .short='p', .default=8080 }),
cli.opt.count("verbose", .{ .long="--verbose", .short='v' }),
cli.opt.listStr("tag", .{ .long="--tag", .short='t' }),
cli.opt.enumT("mode", Mode, .{ .long="--mode", .default=.fast }),
},
.rest = cli.rest.capture("extra"),
}),
},
}));
```
## Notes / limitations (MVP)
- List values preserve order and are backed by an arena.
- String list elements (`listStr`) store slices pointing into `argv` (owned by `Owned.args`), so they are safe for the lifetime of `Owned`.
- Suggestions use a small bounded edit-distance with threshold ≤ 2.
## License
MIT (feel free to use/modify).