fix: close remaining gaps found by the completeness audit

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
This commit is contained in:
ddidderr committed 2026-10-12 04:39:24 +02:00
1 parent 90ad602969
commit f4c020101c
61 files changed
+4210 -298

No files matched your search

+2 -1
View File
@@ -21,6 +21,7 @@ WASM, Windows and the embedded C API (`libghostty`) are out of scope.
| `ghostty-renderer` | renderer/ generic, OpenGL (+ opengl/*), cell, cursor, image, link, size, State, Thread, Overlay, shadertoy, row, shaders/glsl | config, font, terminal |
| `ghostty-termio` | termio/*, pty.zig, Command.zig, shell-integration resources | config, terminal, os |
| `ghostty-cli` | cli/* actions (+list-themes, +show-config, +list-keybinds, ...) | config, input, os, font |
| `ghostty-inspector` | inspector/* (Dear ImGui terminal inspector: widgets, key + VT event recording) | input, renderer, terminal, vt, font, `dear-imgui-rs` |
| `ghostty-core` | App.zig, Surface.zig, surface_mouse.zig, apprt/action.zig, apprt/structs.zig, apprt/surface.zig, global.zig | everything below |
| `ghostty-apprt` | apprt/action.zig, structs.zig, surface.zig, ipc.zig (core↔runtime contract types) | vt, input, config, datastruct |
| `ghostty-apprt-gtk` | apprt/gtk/* | core, config, input |
@@ -75,7 +76,7 @@ WASM, Windows and the embedded C API (`libghostty`) are out of scope.
## Out of scope / deferred
- macOS (Swift app, Metal, CoreText), Windows, WASM, libghostty C API.
- The ImGui inspector is deferred until everything else works (Phase 7).
- (The ImGui inspector was deferred and is now ported: `docs/rewrite/notes/ghostty-inspector.md`.)
## Intentional omissions (decided by the orchestrator)
+16
View File
@@ -0,0 +1,16 @@
# Gap fixes X2 (partial ports)
| # | Item | Status |
|---|------|--------|
| 1 | Flatpak exit watcher consumed the command | Fixed. `ghostty_os::flatpak::FlatpakSignalHandle` (`FlatpakHostCommand::signal_handle()`, shares the `Arc<Shared>` state); `termio/exec.rs` keeps it so `stop()` still SIGHUPs the host process group after `wait_callback` takes the command. Test: `signal_handle_survives_wait_callback` (real DBus path not testable here). |
| 2 | Child env byte-preserving + `filterSnapPaths` | Fixed. New `ghostty_os::EnvMap` (OsString keys/values); `get_env_map()`, `RtSurface::default_termio_env`, core `rt_surface_env`, `shell_integration::EnvMap`, `Command.env`/`Subprocess.env`, `append_env_os`/`prepend_env_os` are all byte-preserving; GTK `default_termio_env` no longer uses `std::env::vars()`. `ghostty_os::filter_snap_paths` ported; applied when `SNAP` is set (Zig gates on the compile-time `snap` option). Flatpak `HostCommand` (`a{ss}`) can only carry UTF-8, so env is lossily converted at that DBus boundary only. `config.env` (RepeatableStringMap) remains String (config values). |
| 3 | Root `main.rs` argv | Fixed. `ghostty_os::args::collect_lossy()` (args_os based) used by `src/main.rs`, `ghostty_config::cli_args::args_iterator`, `ghostty_cli::action::detect_args`. Downstream CLI/config parsing is String based, so a non-UTF-8 arg becomes U+FFFD instead of panicking (not byte-exact end-to-end). |
| 4 | `os/uri.rs` percent-decoding | Fixed. `Component::to_raw_bytes()` (lossless), `to_raw()` is a lossy text view, new `uri::parse_bytes` (handles non-UTF-8 input incl. `raw_path`). OSC 7 (`termio/stream_handler.rs`) uses bytes for `set_pwd` and the pwd surface message; only the window-title fallback is lossy. |
| 5 | Keybinding Unicode case folding | Fixed. `ucd/CaseFolding.txt` (17.0.0, from uucode-0.2.0) vendored; `build.rs` generates `CASE_FOLDING_FULL` (status C+F); API `ghostty_unicode::case_folding::{lookup, fold_full}`; `input/binding::folded_codepoint` uses it (hash and `folded_equal`). |
| 6 | StringMap whole-search retry limit | Fixed. `onig` 6.5.3 only wraps retry-limit-in-match; `onig_sys` exposes `onig_set_retry_limit_in_search_of_match_param`. New crate `crates/ghostty-onig` (`unsafe_code = "deny"`, one SAFETY-commented call) provides `set_retry_limit_in_search`; `string_map.rs` now sets only that limit, like Zig. Tests in both crates (catastrophic regex aborts). |
| 7 | osc9 NUL reservation order | Fixed. `Parser::reserve_nul()`; osc9 uses `buffered()` and reserves only in branches where Zig calls `writeByte(0)` (11, 2, 3, 6, 7, 8, 9 and the notification fallback). Tests for full-buffer behaviour. |
| 8 | Wayland registry add/remove | Fixed in `winproto/wayland.rs` only: the registry `Dispatch` now binds newly advertised supported globals (blur, decoration manager, slide, xdg-activation; `xdg_wm_dialog_v1` flag) and clears/destroys removed ones, tracked by registry name (`bound_names`; Zig compares object id to name, which looks like an upstream quirk). Binds version 1 as the existing init does. No unit test (needs a compositor). |
| 9 | shadertoy sampler2D helpers | Fixed. `renderer/src/shadertoy_sampler.rs` token-level rewrite: `sampler2D` params -> `texture2D x_tex, sampler x_smp`, uses in bodies -> `sampler2D(x_tex, x_smp)`, call args `x`/`iChannel0` -> pairs, forwarding and prototypes work, `texture2D(` -> `texture(` (the prefix macro would clash with the type). Prefix-only rewrites no longer touch user text. Tests incl. textureSize/texelFetch/textureLod. Remaining limits: sampler args must be plain identifiers (no ternary/struct member), no sampler locals/arrays/struct fields, only `sampler2D` (iChannel1-3 are unused upstream). |
| 10 | `+list-themes` preview | Fixed. OSC 8 file:// hyperlinks (list entries, header name/path, error path) and double/dashed/dotted/curly underlines are recorded during draw and re-emitted as raw escapes after each ratatui flush (`Overlay`, `render_overlays`); popups drop covered overlays. Input moved from crossterm to `termina` (drawing still ratatui+crossterm backend) so `CSI ? 997 ; 1|2 n` color-scheme reports are seen; the driver sends `CSI ? 996 n` + `CSI ? 2031 h` unconditionally (vaxis gates on DECRQM 2031, which termina cannot parse). Verified with a pty smoke run; unit tests for overlays, key conversion and theme reports. |
Gate: build/test/clippy/fmt pass for ghostty-{os,termio,input,unicode,vt,terminal,onig,renderer,cli,config,core,apprt}. `ghostty-inspector` (another agent) currently fails clippy and blocks workspace-wide `clippy -D warnings`; it also makes clippy of crates depending on it unreliable (checked with warnings visible: none in X2 files).