feat(os): port Ghostty's Linux OS helpers
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
This commit is contained in:
1 parent
04a6b7c97a
commit
b681241359
30 files changed
+3736
-1
No files matched your search
@@ -0,0 +1,70 @@
|
||||
# ghostty-os notes
|
||||
|
||||
Port of `ZIG/src/os/*` (Linux only) and `ZIG/src/file_type.zig`. `unsafe` is
|
||||
forbidden; deps: rustix, nix (user), zbus, gettext-rs (`gettextrs`), thiserror,
|
||||
log; dev: temp-env.
|
||||
|
||||
## File -> module
|
||||
xdg, homedir, hostname, env, file, flatpak, i18n, i18n_locales, locale, open,
|
||||
passwd, path, pipe, resourcesdir, shell, string_encoding, systemd,
|
||||
TempDir (`temp_dir`), uri, desktop, kernel_info, cgroup, dbus, mouse, args,
|
||||
main (re-exports in `lib.rs`), `file_type` (from `src/file_type.zig`).
|
||||
|
||||
## Skipped files
|
||||
macos.zig, mach.zig, cf_release_thread.zig, windows.zig, wasm.zig, wasm/*
|
||||
(macOS/Windows/WASM are out of scope). Windows/macOS branches inside ported
|
||||
files are dropped. `main.zig` exports `OpenType` (stale, nonexistent in
|
||||
open.zig) - not ported.
|
||||
|
||||
## API shape deviations (buffers/allocators -> owned values)
|
||||
- Zig allocator/fixed-buffer APIs return `String`/`Option<String>`. Fixed
|
||||
buffer overflow semantics kept only where tested: `homedir::home_with_capacity`
|
||||
/ `expand_home_with_capacity` (BufferTooSmall).
|
||||
- `env::getenv` returns `Option<String>` (no `GetEnvResult`); `setenv`/`unsetenv`
|
||||
are NOT provided (unsafe in Rust 2024). Tests use `temp_env` (dev-dep).
|
||||
- `ShellEscapeWriter<W: io::Write>`, `ShellCommandBuilder::to_owned_slice` -> `CString`.
|
||||
- `string_encoding` take `impl io::Write`; error enum `{DecodeError, Io}`.
|
||||
- `uri`: own `Uri`/`Component` types replicating `std.Uri.parse` (Zig std not
|
||||
available in Rust); `parse(text, ParseOptions)` as in Zig.
|
||||
- `cgroup::current(pid)` reads at most 4096 bytes (caller buffer in Zig).
|
||||
- `resourcesdir`: Zig `builtin.mode == .Debug` mapped to `cfg!(debug_assertions)`
|
||||
(note: workspace `release` profile has debug-assertions on; `production` off).
|
||||
- `TempDir`: path-based (parent + name) rather than Dir handles; deletes on Drop;
|
||||
`deinit(self)` provided. Dir created mode 0o755.
|
||||
- `file::fix_max_files` uses rustix rlimit; `None` == RLIM_INFINITY.
|
||||
- `systemd::notify`: a leading `@` in NOTIFY_SOCKET is now treated as an abstract
|
||||
socket (Zig copied it literally, which can't work). Port otherwise 1:1.
|
||||
- `i18n::canonicalize_locale`: gnulib's `_libintl_locale_name_canonicalize` is
|
||||
not available; pure-Rust approximation (zh fixes + `-` -> `_`). `tr()` ==
|
||||
`_()` (dgettext on bundle id domain). `static_locale` is a `const fn` that
|
||||
panics at compile time for unsupported locales. i18n always enabled.
|
||||
- `open::open(kind, url)`: local `OpenUrlKind` enum
|
||||
(TODO(integration): apprt action kind). Snap handling keyed on `SNAP` env
|
||||
instead of build flag.
|
||||
|
||||
## Deferred / incomplete
|
||||
- **locale::ensure_locale is a no-op.** `setlocale` and `setenv` are unsafe;
|
||||
no safe crate wraps them (`gettextrs::setlocale` is `unsafe fn`). gtk_init
|
||||
calls `setlocale(LC_ALL, "")` on Linux. TODO(integration): if needed, perform
|
||||
the libc call in an unsafe-allowed crate (steps documented in locale.rs).
|
||||
- **passwd Flatpak branch**: Zig shells out to host `getent passwd` via
|
||||
FlatpakHostCommand + Pty. Needs ghostty-termio Pty -> TODO(integration);
|
||||
currently warns and uses sandbox entry.
|
||||
- **FlatpakHostCommand**: implemented with `zbus` blocking API (HostCommand,
|
||||
HostCommandSignal, HostCommandExited signal, fd passing) in a helper thread;
|
||||
`waitXev` replaced by `wait_callback`. Compiles and the state machine/error
|
||||
paths are tested, but the D-Bus path is UNTESTED (no Flatpak portal here).
|
||||
Constructor `FlatpakHostCommand::new(argv, stdin, stdout, stderr)`; fds are
|
||||
`OwnedFd` and dup'd on spawn.
|
||||
- `mouse::click_interval` is `None` on Linux (macOS only).
|
||||
|
||||
## Tests
|
||||
Ported Linux-applicable Zig tests (all passing, 88 total incl. extras):
|
||||
xdg(5), homedir(2: expandHomeUnix, home), hostname(4), env(4), path(3),
|
||||
shell(1 builder + 7 escape), string_encoding(10 printf_q + singles_percent +
|
||||
7 percent), uri(3), desktop(1), kernel_info(1), args(1), passwd(1), TempDir(1),
|
||||
i18n canonicalize (darwin-only in Zig, run here against the approximation).
|
||||
Skipped: none of the Linux tests. Extras: path_join, file_type, systemd notify
|
||||
(real unix datagram socket), resourcesdir, pipe, uri/std parse, etc.
|
||||
Zig tests that mutate env were rewritten with `temp_env::with_vars`; tests that
|
||||
read PATH/HOME take the same lock via `testutil::with_env_lock`.
|
||||
Reference in new issue
Block a user