fix: close the RV6 verification gaps

Resolves the 7 gap groups in docs/rewrite/notes/review-rv6-codex.md
(final-Z8.md):
- crash (macOS): request_abort_dump returns false on mach_msg receive
  timeout/error so the signal-path fallback runs; EXC_SOFT_SIGNAL keeps
  the signal number in the minidump exception info.
- Default SHELL read as an OS string and stored in encoded command form.
- macOS executable search works on raw PATH bytes; the default path is
  used only when PATH is unset.
- Windows: config env overrides are decoded; EnvMap compares keys as
  WTF-16 units with per-unit Unicode simple uppercasing (no lossy
  conversion, distinct lone-surrogate keys stay distinct).
- +show-config writes original bytes for encoded OS data, so export +
  reload round-trips; UTF-8 configs are byte-identical as before.
- Zig's ensureLocale chain lives in ghostty-os for all Unix targets and
  is used by both the GTK app and the C API init.

Also makes the quick-terminal GTK replay test independent of compositor
focus: GTK's is-active is read-only, so when niri actually focuses the
layer surface the simulated focus-out cannot drive autohide and that
assertion is skipped (the production logic is unchanged and matches Zig).

Test Plan:
- cargo test --workspace (3390 passed, incl. tests/gtk_replay.rs)
- just check-macos (both), just check-windows, just check-wasm
This commit is contained in:
ddidderr committed 2026-10-12 10:27:37 +02:00
1 parent e57e54cbf2
commit 5c5d916960
12 files changed
+452 -133

No files matched your search

+35 -2
View File
@@ -59,9 +59,9 @@ pub fn run(args: &[String]) -> Result<u8, Error> {
Config::load()?
};
let text = format_config(&config, &opts)?;
let text = format_config_bytes(&config, &opts)?;
let mut stdout = std::io::stdout().lock();
stdout.write_all(text.as_bytes())?;
stdout.write_all(&text)?;
stdout.flush()?;
Ok(0)
}
@@ -78,6 +78,16 @@ pub fn format_config(config: &Config, opts: &Options) -> Result<String, Error> {
Ok(out)
}
/// Like [`format_config`] but the original bytes: the config layer holds OS
/// data in the reversible escape encoding, and Zig writes the raw bytes, so
/// export + reload reproduces the same value. Plain UTF-8 output is
/// unchanged.
pub fn format_config_bytes(config: &Config, opts: &Options) -> Result<Vec<u8>, Error> {
Ok(ghostty_os::osbytes::config_str_to_bytes(&format_config(
config, opts,
)?))
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
@@ -103,6 +113,29 @@ mod tests {
assert!(s.contains("\nfont-size = 12\n"));
}
#[cfg(unix)]
#[test]
fn show_config_round_trips_non_utf8_and_fdd0_paths() {
use ghostty_os::osbytes::EncodedOs;
let dir = tempfile::tempdir().unwrap();
let first = dir.path().join("a.conf");
let raw: &[u8] = b"custom-shader = /tmp/a\xff\xef\xb7\x90b\n";
std::fs::write(&first, raw).unwrap();
let mut cfg = Config::new_default();
cfg.load_file(&EncodedOs::from_path(&first)).unwrap();
let opts = Options::default();
let out = format_config_bytes(&cfg, &opts).unwrap();
assert_eq!(out, raw);
// Reload the exported bytes: same value.
let second = dir.path().join("b.conf");
std::fs::write(&second, &out).unwrap();
let mut cfg2 = Config::new_default();
cfg2.load_file(&EncodedOs::from_path(&second)).unwrap();
assert_eq!(cfg.custom_shader, cfg2.custom_shader);
assert_eq!(format_config_bytes(&cfg2, &opts).unwrap(), raw);
}
#[test]
fn options_parse() {
let mut opts = Options::default();