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

+61
View File
@@ -0,0 +1,61 @@
//! Oniguruma `MatchParam` extensions missing from the `onig` crate.
//!
//! Ghostty's `StringMap` bounds regex work with
//! `MatchParam.setRetryLimitInSearch` (a *whole-search* retry budget); the
//! `onig` crate only wraps the per-match limit, so the search limit is set
//! here through `onig_sys`.
use onig::MatchParam;
/// Set the retry limit in search (Oniguruma's aggregate backtracking-work
/// budget across the entire search, as opposed to per match attempt).
pub fn set_retry_limit_in_search(param: &mut MatchParam, limit: u32) {
#[allow(unsafe_code)]
// SAFETY: `param.as_raw()` is the live, non-null `OnigMatchParam*` owned
// by `param` (allocated by `onig_new_match_param` in
// `MatchParam::default`) and we hold `&mut` so nothing else uses it for
// the duration of the call; the function only writes an integer field.
unsafe {
onig_sys::onig_set_retry_limit_in_search_of_match_param(
param.as_raw(),
std::os::raw::c_ulong::from(limit),
);
}
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used)]
use super::*;
use onig::{Regex, SearchOptions};
fn search(re: &Regex, text: &str, limit: Option<u32>) -> Result<Option<usize>, onig::Error> {
let mut param = MatchParam::default();
if let Some(l) = limit {
set_retry_limit_in_search(&mut param, l);
}
re.search_with_param(
text,
0,
text.len(),
SearchOptions::SEARCH_OPTION_NONE,
None,
param,
)
}
#[test]
fn small_limit_aborts_catastrophic_search() {
// Classic exponential backtracking pattern.
let re = Regex::new("(a+)+$").unwrap();
let text = format!("{}b", "a".repeat(40));
// With a tiny whole-search budget the search errors out.
assert!(search(&re, &text, Some(1000)).is_err());
}
#[test]
fn generous_limit_allows_normal_search() {
let re = Regex::new("b+").unwrap();
assert_eq!(search(&re, "aaabbb", Some(100_000)).unwrap(), Some(3));
}
}