Zig parses config values (cli/args.zig, Config.zig field parsers,
config/string.zig) from raw byte slices, and each field type decides
whether it requires UTF-8 (InvalidValue otherwise) or stores bytes. The
port escape-encoded raw bytes into Strings at the line reader and let
fields parse the escaped text, so fields could observe encoding
artifacts; successive audits kept finding such leaks (RV5-RV8).
Field parsers now receive the original bytes: text fields validate UTF-8
where Zig does, byte/path fields store bytes (EncodedOs/OsString). This
resolves all 9 RV8 findings (docs/rewrite/notes/review-rv8-codex.md),
each with a regression test: Windows path conversion fails with
BadPathName instead of substituting U+FFFD; Windows process launch uses
strict UTF-8 like Zig's Command; the WTF-8 decoder accepts paired-
surrogate encodings like Zig; literal U+FDD0 Unicode key triggers;
selection-word-chars and clipboard-codepoint-map reject invalid UTF-8;
font style / codepoint-map family names use original bytes; C title
actions forward bytes; D-Bus new-window/Flatpak conversions match Zig.
Design, sweep and validation: docs/rewrite/notes/final-bytes-refactor.md.
Also moves the bundled iTerm2-Color-Schemes license out of
resources/themes/ so +list-themes no longer lists it as a theme
(output is now byte-identical to Ghostty 1.3.1).
Done by Codex (gpt-6-astra), reviewed and verified by the orchestrator.
Test Plan:
- cargo test --workspace --no-fail-fast (3428 passed, exit 0)
- just check-macos (both), just check-windows, just check-wasm
- +show-config --default --docs, +list-keybinds, +list-actions --docs,
+list-themes --plain compared with /usr/bin/ghostty
Escaped config strings (ghostty_os::osbytes) kept reaching OS
boundaries undecoded, and decoding was occasionally applied to plain
text. The root cause was that both were plain `String`s. Now:
- `EncodedOs` is a newtype (no Display/AsRef<Path>) that decodes only
via to_os/to_path/to_bytes/to_wide; plain text enters via
from_plain_text. OS helpers (env, home, xdg, passwd, resources dir,
path expansion), config::Path, WorkingDirectory, theme/file_load/edit
paths, terminal pwd, OpenUrl/Pwd actions and termio cwd use it, so the
compiler forces decoding at every boundary. os::open takes &OsStr.
Config output is unchanged.
Fixes all rows of docs/rewrite/notes/review-rv5-codex.md (final-Z7.md):
screen-file copy; regex/OSC 8 URLs no longer decoded (regression);
lossless Windows WTF-8/WTF-16 for args, env and CreateProcessW; Windows
resources dir/TERMINFO; color OSC request lists and X11 color lookup no
longer allocate globally (C zero-allocation test extended); macOS Mach
handler resumes all threads before KERN_FAILURE (hang regression) and
SIGABRT minidumps go through the exception thread; plus open-config,
background images, crash dir, ssh cache, exe dir/PATH, fontconfig
filenames, file links, kitty TMPDIR, .hushlogin and benchmark paths.
The typing also surfaced and fixed gtk-custom-css, bell audio, bash
HISTFILE, OSC 52 writes and the C config getters.
Test Plan:
- cargo test --workspace (3376 passed)
- just check-macos (both), just check-windows, just check-wasm
- diff <(ghostty-rs +show-config --default --docs) \
<(ghostty +show-config --default --docs)
Resolves the 13 rows still partial in docs/rewrite/notes/review-rv4-
codex.md (details in final-Z5.md):
- Escaped config strings are decoded to raw bytes at every OS boundary:
Flatpak cwd/argv to D-Bus, screen-file paths, the default config
template, GHOSTTY_RESOURCES_DIR/TERMINFO/shell integration/
bindtextdomain consumers, custom shader loading, list-themes hyperlinks.
- osbytes escapes literal U+FDD0 on non-Unix too (bijective everywhere);
the GTK paste dialog only decodes text that was actually encoded.
- shadertoy: whole-array uses of iChannelTime rebuild a plain float[4]
from the std140-padded members (naga-validated, MSL offsets checked).
- libghostty-vt: the OSC parser holds caller-allocated storage inline
and command payloads borrow from it, so ghostty_osc_end performs no
global allocations (verified from Rust and C).
- crash: aarch64 Linux minidump context fixed; macOS fatal signals record
siginfo, registers and a fault-safe stack walk.
- tripwire: selectionString map allocation-failure cleanup test ported.
- libghostty-vt emits the versioned soname libghostty-vt.so.0 at build
time (no patchelf needed at install).
Test Plan:
- cargo test --workspace (3342 passed)
- just check-macos; just check-macos x86_64-apple-darwin;
just check-windows; just check-wasm
- cargo check --target aarch64-unknown-linux-gnu -p ghostty-crash
Exercises the runtime paths that had never run (details in
docs/rewrite/notes/verification-VR.md):
- IME: replay steps drive the surface's real GtkIMContext handlers with
a real preedit + attributes; preedit renders under the cursor and
commits reach the pty, incl. dead-key and compose orderings.
- Paste and OSC 52 read/write confirmation dialogs: allow, deny and
remember flows.
- Quick terminal on niri via wlr-layer-shell: positions, sizes, toggle
and autohide. Fixes a real bug: link order could put libwayland-client
ahead of libgtk4-layer-shell, silently disabling the quick terminal;
apprt-gtk now loads libwayland-client via wayland-sys dlopen.
- Flatpak host commands against a zbus mock of
org.freedesktop.Flatpak.Development under dbus-run-session: spawn,
exit status, cwd/env/fd forwarding and SIGHUP on stop, both directly
and through termio Exec (flatpak-info path seam added).
- Horizontal-scroll tab switching thresholds and reset.
tests/gtk_replay.rs runs the real binary against the session display
(skips without one).
Test Plan:
- cargo test --test gtk_replay (needs a Wayland/X11 display)
- cargo test -p ghostty-os --test flatpak_mock; -p ghostty-termio
--test flatpak_exec
rustfmt.toml sets group_imports, imports_granularity and imports_layout,
which are nightly-only; agents formatted with stable rustfmt, which
ignored them. This is a formatting-only pass with `cargo +nightly fmt`.
Test Plan:
- cargo clippy --workspace --all-targets -- -D warnings
- cargo test --workspace
Addresses the partial ports listed in
docs/rewrite/notes/review-completeness-codex.md (details in
docs/rewrite/notes/gaps-X2.md):
- Flatpak: the exit watcher no longer consumes the host command; a
shared FlatpakSignalHandle lets closing a surface still SIGHUP the
host process group.
- Child environment is byte-preserving end to end (ghostty_os::EnvMap
of OsStrings) and Snap paths are filtered like filterSnapPaths.
- argv handling no longer panics on non-UTF-8 arguments.
- URI percent-decoding keeps raw bytes; OSC 7 pwd is passed through
without lossy conversion.
- Keybinding comparison/hashing uses full Unicode case folding from a
table generated from CaseFolding.txt (Unicode 17.0.0).
- Link regexes set Oniguruma's whole-search retry limit through the new
minimal ghostty-onig crate (one SAFETY-commented FFI call).
- OSC 9 NUL-capacity check ordering matches Zig.
- Wayland registry binds/clears globals advertised after startup.
- Custom shaders may pass sampler2D to helper functions (naga adapter).
- +list-themes preview renders OSC 8 links, styled underlines and
follows color-scheme reports.
Also includes the inspector's integration edits in shared files
(renderer state hook, termio VT recording, core/apprt-gtk wiring), X1's
config/input/cli additions for completion generation, and a fix for a
race in the termio backpressure test (it wrote before `stty raw`
applied, so the cooked line discipline dropped bytes past MAX_CANON).
Test Plan:
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
Ports ZIG/src/os for Linux into ghostty-os: XDG dirs, home dir, hostname,
env/PATH helpers, passwd lookup (via nix), shell detection, resources
dir discovery, string encodings (printf-q, URL percent), systemd
sd_notify, i18n via gettextrs, xdg-open, desktop/cgroup/kernel info,
temp dirs, URI parsing (port of std.Uri incl. Ghostty's extra options),
and a zbus-based Flatpak HostCommand implementation.
The crate stays free of unsafe. Consequences, all tracked as
TODO(integration) in docs/rewrite/notes/ghostty-os.md:
- locale::ensure_locale is a no-op (setlocale/setenv are unsafe; GTK
calls setlocale itself); setenv/unsetenv are not exposed.
- passwd's Flatpak branch needs the termio pty and falls back to the
sandbox entry for now.
- FlatpakHostCommand's D-Bus path is untested (no portal here).
Intentional fix: a leading '@' in NOTIFY_SOCKET is treated as an
abstract socket.
macOS/Windows/WASM modules are out of scope.
Test Plan:
- cargo test -p ghostty-os (88 tests)
- cargo clippy -p ghostty-os --all-targets -- -D warnings