Files
ddidderr 16eb1fba61 fix: use Zig's numeric parsing in protocol and escape-sequence parsers
Rust's str::parse accepts and rejects different inputs than Zig's
std.fmt.parseInt/parseFloat (underscores, base prefixes, signs). The
config layer already used the Zig ports; now the protocol parsers do
too (call site -> Zig reference -> status in final-Z12.md):
- zig_fmt moves into the leaf crate ghostty-zigfmt (ghostty-vt cannot
  depend on ghostty-os); ghostty-os re-exports it unchanged.
- ghostty-vt: kitty graphics keys, kitty text sizing, OSC 4/5/10-19
  color indices, hex color components and intensities, OSC 9 sleep and
  progress, OSC 133 exit codes, OSC 3008 fields, kitty color palette.
- ghostty-terminal: tmux layout, format variables and pane tabs.
- ghostty-os: URI ports and %XX decoding; ghostty-bench CLI arguments.
Expected values were cross-checked against the real Zig toolchain.

Test Plan:
- cargo test --workspace --no-fail-fast
- just check-macos (both), just check-windows, just check-wasm
2026-10-12 12:45:55 +02:00

2.9 KiB

Z12: Zig-exact numeric parsing in protocol / non-config code

zig_fmt moved to the new leaf crate crates/ghostty-zigfmt (no deps); ghostty_os::zig_fmt is now pub use ghostty_zigfmt as zig_fmt, so existing callers are unchanged. ghostty-vt and ghostty-terminal depend on it directly (ghostty-os depends on ghostty-vt, so vt could not use os). Expected values in the new tests were cross-checked with the real zig 0.16 (std.fmt.parseInt/parseUnsigned/parseFloat).

Rust call site Zig reference Status
vt kitty/graphics_command.rs::parse_int graphics_command.zig:262 parseInt(i32/u32, _, 10) fixed (was hand-rolled: no _)
vt osc/parsers/kitty_text_sizing.rs::parse_u4 kitty_text_sizing.zig:52 parseInt(u4,10) fixed
vt osc/parsers/color.rs::parse_u9 parsers/color.zig:176,249 parseInt(u9,10) fixed
vt color.rs::parse_unsigned_hex_u16 color.zig:505 parseUnsigned(u16,16) fixed (Rust wrongly allowed +, -0)
vt color.rs::from_intensity color.zig:483 parseFloat(f64) fixed (str::parse -> parse_float: hex floats, _)
vt osc/parsers/osc9.rs::parse_unsigned osc9.zig:27,195 parseUnsigned(u16/usize,10) fixed (was str::parse, accepted +)
vt osc/parsers/semantic_prompt.rs exit_code semantic_prompt.zig:155 parseInt(i32,10) fixed
vt osc/parsers/context_signal.rs pid/status context_signal.zig:167 (digit pre-check, parseInt(u64)) fixed
vt kitty/color.rs::Kind::parse kitty/color.zig:51 parseUnsigned(u8,10) fixed (no + accepted)
vt tmux/control.rs::digits control.zig regex [0-9]+ then parseInt(usize) unchanged: regex guarantees digits only
terminal tmux/layout.rs::parse_usize layout.zig:99-163 parseInt(usize,10) fixed (_, -0)
terminal tmux/output.rs::parse_int output.zig:200-214 fixed (_)
terminal tmux/viewer.rs pane_tabs viewer.zig:1026 parseInt(usize,10) catch continue fixed
os uri.rs port std.Uri parseInt(u16,10) fixed (_, no behaviour change for +)
os uri.rs::percent_decode std.Uri formatRaw parseInt(u8,"XX",16) fixed (accepts %+A, %-0; rejects nothing new)
bench args.rs::take cli/args.zig:429 parseInt(T,_,0) / parseFloat fixed (base 0 prefixes, _, hex float)
vt parser.rs / stream.rs param_acc Parser.zig:353, stream.zig:673 saturating digit loop already identical
font shaper/feature.rs feature.zig:133-153 digit loop (u32 mul) already identical
config / input binding / cli ssh-cache / os desktop Z11 already using zig_fmt
vt x11_color.rs, build.rs (rgb.txt) x11_color.zig:30 comptime on fixed data n/a (data file)
cli list_themes/preview.rs COLORFGBG, core GHOSTTY_DEBUG_SCREENSHOT_MS, apprt-gtk debug_input, build-info/fake_version, renderer shadertoy no Zig counterpart (Rust-only) left on str::parse