feat(config): port the configuration system and CLI argument parser
Ports ZIG/src/config (minus C/WASM APIs) and cli/{args,CommaSplitter,
diagnostics}.zig into ghostty-config:
- all 202 options with exact names, types, defaults and verbatim docs,
declared through one config_struct! macro; Zig's comptime reflection is
replaced by the ConfigField/CliTarget traits
- loading: default XDG files, -e, config-file includes (optional '?',
cycle detection), themes incl. light:/dark: pairs, conditional config,
replay, finalize() derived defaults, clone/changed diffing for reload
- Linux/GTK default keybinds built on ghostty_input::binding::Set
- formatter producing +show-config output
Verified against the installed Ghostty 1.3.1: `+show-config --default`
and `--default --docs` match byte for byte (except gtk-opengl-debug,
which differs between debug/release builds), as do two complex loaded
configs.
Open items (docs/rewrite/notes/ghostty-config.md): url regex needs an
Oniguruma-compatible engine (onig) in the renderer; some font/terminal
types are local copies awaiting integration; KeyRemapSet equality is
order sensitive unlike Zig.
Test Plan:
- cargo test -p ghostty-config (255 tests)
- compare `ghostty +show-config --default --docs` with our formatter
This commit is contained in:
1 parent
800fe5be5e
commit
33d15a2dc2
34 files changed
+14894
-1
No files matched your search
@@ -0,0 +1,79 @@
|
||||
# ghostty-config port notes (W6)
|
||||
|
||||
Sub-notes from the parallel forks live in `ghostty-config/` (`files-a.md`,
|
||||
`types-a.md`, `types-b.md`, `keybinds.md`).
|
||||
|
||||
## What was ported (Zig -> Rust, all in `crates/ghostty-config/src/`)
|
||||
|
||||
| Zig | Rust |
|
||||
|---|---|
|
||||
| cli/args.zig | `cli_args.rs` (`ConfigField` + `CliTarget` traits, `parse`, `LineIterator`, `ArgsIterator`, `parse_auto_struct_with`, `parse_packed_struct_with`, `split_tagged_union`, `compatibility_renamed`) |
|
||||
| cli/CommaSplitter.zig | `comma_splitter.rs` |
|
||||
| cli/diagnostics.zig | `diagnostics.rs` |
|
||||
| config/Config.zig (fields + methods) | `config.rs` (fields declared in a single `config_struct!` invocation: name, type, default, verbatim doc comment), `keys.rs` (one `Key` const per option) |
|
||||
| Config.zig nested types | `types_a.rs`, `types_b.rs`, `keybinds.rs`, `font_types.rs`, `metric_modifier.rs`, `input_fields.rs` (ConfigField impls for ghostty-input types) |
|
||||
| conditional.zig, key.zig, ErrorList.zig | `conditional.rs`, `key.rs`, `error_list.rs` |
|
||||
| formatter.zig | `formatter.rs` (EntryFormatter) + `file_formatter.rs` (FileFormatter) |
|
||||
| command/path/url/string/io/theme/edit/file_load/RepeatableStringMap/ClipboardCodepointMap | same names, snake_case |
|
||||
| config/config-template, config/testdata | `src/config-template`, `src/testdata/` |
|
||||
| helpgen.zig (config part) | `macros::help_string` (computed at runtime from the doc attributes) |
|
||||
|
||||
Skipped: CApi.zig, c_get.zig, Wasm.zig, all `cval`/`*_c` members, `enum(c_int)`
|
||||
discriminants, `getGObjectType`.
|
||||
|
||||
## Design
|
||||
|
||||
* No comptime reflection: `config_struct!` (macros.rs) generates the struct,
|
||||
`parse_field` (== `parseIntoField`, incl. "empty value resets to default"),
|
||||
per-field `FieldInfo` (name, doc lines, deep-eq fn, format fn) used by
|
||||
`FileFormatter`, `Config::changed`, `ChangeIterator`.
|
||||
* `config_enum!` / `config_packed!` define Zig-style enums / packed bool structs.
|
||||
* Memory: all values are owned (`String`, `Vec`); there is no arena. `clone` is
|
||||
`#[derive(Clone)]`; Zig `equal` == `PartialEq` (custom where Zig's differs).
|
||||
* Replay (theme / conditional state): `Config::load_replay` replaces the Zig
|
||||
`Replay.Iterator` (which aliased the config); behaviour is the same.
|
||||
* `Config::default()` == Zig `Config.default` (default keybinds, command palette
|
||||
entries and the URL link are installed). `Config::raw_default()` == bare `.{}`.
|
||||
* `Config::load()` == Zig `Config.load` (default files, CLI, recursive files,
|
||||
finalize). `finalize` skips the shell/passwd lookup under `cfg(test)` like Zig's
|
||||
`builtin.is_test`.
|
||||
* Linux values are baked in for `builtin.os.tag` switches (e.g. `font-size = 12`,
|
||||
`copy-on-select = true`, `quit-after-last-window-closed = true`,
|
||||
`linux-cgroup = single-instance`, `alpha-blending = linear-corrected`).
|
||||
`gtk-opengl-debug` follows `cfg!(debug_assertions)` (Zig: `mode == .Debug`).
|
||||
`auto-update-channel` finalizes to `stable` (upstream release build value).
|
||||
* macOS-only options (`macos-*`) are parsed and stored but otherwise ignored.
|
||||
|
||||
## Verification against the real binary
|
||||
|
||||
`ghostty +show-config --default` and `--default --docs` (Ghostty 1.3.1 installed
|
||||
at /usr/bin/ghostty) were diffed against `FileFormatter` output of
|
||||
`Config::default()`: identical except `gtk-opengl-debug` (debug vs release build).
|
||||
A loaded config (themes light/dark, config-file includes incl. `?` optional
|
||||
and missing, keybinds, palette, font-codepoint-map, errors/diagnostics) was also
|
||||
diffed against `ghostty +show-config`; identical except `auto-update-channel`.
|
||||
|
||||
## Tests
|
||||
|
||||
Every Zig `test` in the ported files is ported (names snake_cased), except:
|
||||
* args.zig: none skipped (36 Zig tests -> 40+ Rust tests incl. extras)
|
||||
* Config.zig: C-API tests ("RepeatableCommand cval", "cval cleared") skipped
|
||||
* key.zig `Value` (comptime type check) replaced by `value_key_types`
|
||||
* Allocator-failure tests: none existed.
|
||||
Extra tests added for config-file cycles / optional includes, docs formatting.
|
||||
|
||||
## Deviations / notes for integration
|
||||
|
||||
* `ArgError::Other(name)` renders as `unknown error error.<name>` like Zig's `{}` of an error.
|
||||
* Error text for IO failures in `config-file` diagnostics uses Rust wording except
|
||||
`FileNotFound`/`AccessDenied`.
|
||||
* `theme::open` takes the resources dir explicitly (`ghostty_os::resources_dir().app()`).
|
||||
* URL regex (`url::REGEX`) needs Oniguruma-style lookbehind: consumers (renderer
|
||||
link matching) must use the `onig` crate (added as dev-dependency only here).
|
||||
* `font_types.rs` holds local `Variation`, `Descriptor`, `CodepointMap`;
|
||||
`clipboard_codepoint_map::Entry` mirrors terminal/formatter's CodepointMap
|
||||
(TODO(integration): ghostty-font / ghostty-terminal should re-use these).
|
||||
* `metric_modifier::MetricModifier` is the font `Metrics.Modifier` (font crate depends on config).
|
||||
* `CursorStyle` is defined in `types_a.rs` (cannot depend on ghostty-terminal).
|
||||
* macOS app-support config paths are not implemented (Linux only).
|
||||
* `KeyRemapSet::PartialEq` is input's derived equality (Zig `equal` is order independent).
|
||||
Reference in new issue
Block a user