fix: preserve non-UTF-8 bytes in OS, config and CLI layers
Zig treats paths, arguments and environment values as byte slices; the port converted them lossily in many places. Now (final-Z1.md): - argv, env (incl. present non-UTF-8 values), HOME, PATH lookup, passwd, resources dir, TMPDIR, cgroup, config path canonicalization, +validate-config, +list-themes and Zig-string escapes (\xFF) keep raw bytes. String-based config values carry bytes via ghostty_os::osbytes, a bijective escape (noncharacter U+FDD0 + byte) that leaves all valid UTF-8 - including Nerd Font private-use icons - unchanged. - os/file rlimit fallbacks exist on all targets. - i18n locale canonicalization is an exact port of libintl's tables (e.g. pa-Guru -> pa_IN). - New ghostty-build-info crate is the single source of version, channel, commit and build mode for all consumers. Test Plan: - cargo test -p ghostty-os -p ghostty-config -p ghostty-cli (incl. randomized osbytes round-trip property tests)
This commit is contained in:
1 parent
3f3f6680a5
commit
8519f1ba1b
32 files changed
+1464
-333
No files matched your search
@@ -243,6 +243,28 @@ pub fn detect(args: &[String]) -> Result<Option<Action>, DetectError> {
|
||||
detect_iter::<Action, _, _>(args.iter())
|
||||
}
|
||||
|
||||
/// Convert raw OS arguments (Zig `[]const u8` argv) into the argument strings
|
||||
/// used by the CLI layers. No bytes are lost: invalid UTF-8 bytes use the
|
||||
/// reversible escape encoding of `ghostty_os::osbytes`, which the config
|
||||
/// layer (`cli_args`) decodes back to the original bytes.
|
||||
#[must_use]
|
||||
pub fn os_args_to_strings(args: &[std::ffi::OsString]) -> Vec<String> {
|
||||
args.iter()
|
||||
.map(|a| ghostty_os::osbytes::os_to_config_string(a))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// [`detect`] over raw OS arguments.
|
||||
pub fn detect_os(args: &[std::ffi::OsString]) -> Result<Option<Action>, DetectError> {
|
||||
detect(&os_args_to_strings(args))
|
||||
}
|
||||
|
||||
/// [`run_from_args`] over raw OS arguments (byte-preserving).
|
||||
#[must_use]
|
||||
pub fn run_from_os_args(args: &[std::ffi::OsString]) -> Option<u8> {
|
||||
run_from_args(&os_args_to_strings(args))
|
||||
}
|
||||
|
||||
/// The CLI entrypoint logic of `main_ghostty.zig` for actions: detect the
|
||||
/// action from `args` (the full argv), print the errors Ghostty prints for
|
||||
/// invalid invocations and run the action.
|
||||
@@ -338,6 +360,23 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn os_args_keep_non_utf8_bytes_and_still_dispatch() {
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
let args = vec![
|
||||
std::ffi::OsString::from("ghostty"),
|
||||
std::ffi::OsString::from_vec(b"--title=\xff".to_vec()),
|
||||
std::ffi::OsString::from("+version"),
|
||||
];
|
||||
assert_eq!(Some(Action::Version), detect_os(&args).unwrap());
|
||||
let strings = os_args_to_strings(&args);
|
||||
assert_eq!(
|
||||
ghostty_os::osbytes::config_str_to_bytes(&strings[1]),
|
||||
b"--title=\xff"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn names_round_trip() {
|
||||
for a in Action::ALL {
|
||||
|
||||
Reference in new issue
Block a user