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:
ddidderr committed 2026-10-11 22:00:12 +02:00
1 parent 47b479dcfb
commit 67367dcaf5
34 files changed
+14894 -1

No files matched your search

@@ -0,0 +1,63 @@
//! ClipboardCodepointMap is a map of codepoints to replacement values
//! for clipboard operations. When copying text to clipboard, matching
//! codepoints will be replaced with their mapped values.
/// Replacement value for a codepoint range.
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Replacement {
/// A single replacement codepoint.
Codepoint(u32),
/// A UTF-8 encoded string to replace with.
String(String),
}
/// One entry of the map.
///
/// TODO(integration): this mirrors `terminal/formatter.zig` `CodepointMap`;
/// replace with `ghostty_terminal::formatter::CodepointMap` once available.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Entry {
/// Unicode codepoint range to replace.
/// Asserts: range[0] <= range[1]
pub range: [u32; 2],
/// Replacement value for this range.
pub replacement: Replacement,
}
/// The list of entries.
///
/// Note: we do a linear search because we expect to always have very
/// few entries, so the overhead of a binary search is not worth it.
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ClipboardCodepointMap {
pub list: Vec<Entry>,
}
impl ClipboardCodepointMap {
/// Add an entry to the map.
///
/// For conflicting codepoints, entries added later take priority over
/// entries added earlier.
pub fn add(&mut self, entry: Entry) {
assert!(entry.range[0] <= entry.range[1]);
self.list.push(entry);
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn add_and_clone() {
let mut m = ClipboardCodepointMap::default();
m.add(Entry {
range: [1, 2],
replacement: Replacement::String("x".into()),
});
let c = m.clone();
assert_eq!(m, c);
assert_eq!(c.list.len(), 1);
}
}