feat: port GTK version fallbacks, helpgen, bench modes, CLI leftovers
- apprt-gtk: Ghostty's runtime+build-time version gating (at_least) with cargo features adw_1_3/adw_1_4/adw_1_5/gtk_4_16 (default on) and the fallbacks for older libraries: MessageDialog (adw < 1.5), clipboard dialog without SwitchRow, pre-Banner debug warning and child-exited widgets, the old about dialog, GTK 4.16 CSS error source bytes. The minimum stays GTK 4.14 / libadwaita 1.5 (Ghostty's floor). The root build links with -z lazy so version-gated symbols don't keep older libraries from loading. - ghostty-helpgen (port of helpgen.zig) generates CLI action help and keybinding action docs from doc comments at build time, replacing the checked-in help/*.txt; +help and +list-actions --docs stay byte-identical to Ghostty 1.3.1. - ghostty-bench: libc wcwidth mode and separate simd/table and uucode/table code paths like Zig. - ghostty-cli: Windows branches of edit-config, list-colors, list-keybinds and boo; ssh-cache DiskCache flock locking (no-op on Windows, as in Zig) with an exclusivity test. Test Plan: - cargo test --workspace - diff <(cargo run -q -- +list-actions --docs) \ <(ghostty +list-actions --docs)
This commit is contained in:
1 parent
cd86fe92a8
commit
f2252bb165
51 files changed
+2426
-1621
No files matched your search
@@ -62,6 +62,7 @@ ghostty-bench (benchmarks), ghostty-build-data (completions, man pages, syntax).
|
||||
| `ghostty-cli` | cli/* actions, build_config.zig (build info) | apprt, config, font, input, os, vt |
|
||||
| `ghostty-apprt-gtk` | apprt/gtk/* (+ ui/*.blp, css) | apprt, config, input, inspector, os, vt, datastruct |
|
||||
| `ghostty-bench` | benchmark/*, synthetic/* | terminal, unicode, vt |
|
||||
| `ghostty-helpgen` | helpgen.zig (build-time doc-comment extraction for CLI-action and keybind-action help; used from `build.rs` of ghostty-cli / ghostty-input) | – |
|
||||
| `ghostty-build-data` | main_build_data.zig, extra/*, build/mdgen | cli, config, input, os, termio |
|
||||
| root `ghostty-rs` (bin `ghostty`) | main_ghostty.zig | apprt, apprt-gtk, cli, config, core, os |
|
||||
|
||||
@@ -123,11 +124,19 @@ integration), `po/` (translations), crate-local `res/`/`shaders/`/`resources/`.
|
||||
|
||||
- 2026-10-12: Sentry crash handling and GTK<4.14/libadwaita<1.5 fallbacks,
|
||||
previously omitted, are ported in Phase 8 for full parity.
|
||||
- 2026-10-12 (GC): the GTK/libadwaita compatibility fallbacks are ported
|
||||
(MessageDialog, SwitchRow-less clipboard template, pre-Banner debug warning
|
||||
and child-exited, GtkAboutDialog, CSS error source bytes, all blueprint
|
||||
variants in the gresource). Minimum versions: **GTK 4.14, libadwaita 1.5** --
|
||||
Ghostty's own floor (its build compiles every blueprint, incl. the `1.5/`
|
||||
ones, and calls `gtk_css_provider_load_from_bytes` (4.12) and
|
||||
`gtk_im_context_activate_osk` (4.14) unconditionally); the `gnome_44`
|
||||
binding feature was dropped. Version gating mirrors Zig's `atLeast`
|
||||
(build level AND runtime): cargo features `adw_1_3|1_4|1_5` and `gtk_4_16`
|
||||
(all default) are the "header version"; building without them selects the
|
||||
Zig fallbacks at compile time. See `notes/compat-GC.md`.
|
||||
|
||||
## Intentional omissions (decided by the orchestrator)
|
||||
|
||||
- Sentry crash reporting (`crash/*`): optional and disabled by default in
|
||||
upstream Linux builds; `+crash-report` listing is ported.
|
||||
- GTK < 4.14 / libadwaita < 1.5 compatibility fallbacks (MessageDialog,
|
||||
pre-Banner widgets, old about dialog, 1.0–1.3 blueprint variants): the
|
||||
Rust port requires GTK ≥ 4.14 and libadwaita ≥ 1.5.
|
||||
@@ -0,0 +1,18 @@
|
||||
# ghostty-bench: CodepointWidth / IsSymbol (compat-GC)
|
||||
|
||||
- `codepoint-width` modes (CLI as Zig: noop|wcwidth|simd|table):
|
||||
- `wcwidth`: real libc `wcwidth` via a local `extern "C"` (no libc crate), in
|
||||
a module with `#[allow(unsafe_code)]` + SAFETY comment. Zig does not call
|
||||
`setlocale`, so neither do we (C locale). Non-unix: warning no-op like Zig on Windows.
|
||||
- `simd`: new `src/simd_width.rs`, scalar port of `simd/codepoint_width.cpp`
|
||||
(same range tables and precedence; vector lanes replaced by a sequential scan).
|
||||
- `table`: generated two-stage table with the `<= 0xFF => 1` shortcut.
|
||||
- `is-symbol` modes: `uucode` (default) = `is_symbol_computed`, computed from
|
||||
private-use + block ranges (`computeIsSymbol`); `table` = generated symbols table.
|
||||
Test verifies equality with the table over all codepoints.
|
||||
- Cargo.toml: `[lints]` no longer `workspace = true` (workspace `forbid` cannot be
|
||||
locally allowed); `unsafe_code = "deny"` and the clippy set is copied. Keep in sync.
|
||||
- Deviation: Zig's `simd` falls back to uucode when built without SIMD; there is no
|
||||
separate uucode width mode in the CLI (none in Zig), so none added.
|
||||
- Tests: all modes run on a sample file; computed vs table symbols; simd vs table
|
||||
samples; wcwidth ASCII. Zig `test CodepointWidth/IsSymbol` (run once, no data) covered by the run tests.
|
||||
@@ -0,0 +1,13 @@
|
||||
# compat-GC: ghostty-cli Windows branches and DiskCache locking
|
||||
|
||||
Ported (all `cfg(windows)` / cfg-gated, no unsafe, no new deps):
|
||||
* `edit_config.rs`: Windows prints "not supported on Windows ... edit manually at <path>" to stderr and returns 1 (after the path lookup, before the editor lookup, as in Zig). The `exec` path is now `cfg(unix)` (`exec_editor`).
|
||||
* `list_colors.rs` / `list_keybinds.rs`: both use `tui::window_size()`; on Windows it returns the fixed Zig default (120 cols x 24 rows) instead of querying the tty. Pixel size (1024x768) is not modelled (unused).
|
||||
* `boo.rs`: Zig allows windows/macos/linux/freebsd and returns 1 elsewhere; mirrored with a `cfg!` check. Windows needs no other change.
|
||||
* `ssh_cache/disk_cache.rs`: made the module compile on Windows (unix-only `mode`/`PermissionsExt` gated; `fixup_permissions` is a no-op on Windows as in Zig "Windows does not support chmod").
|
||||
|
||||
Locking deviation from the task brief: Zig does NOT lock on Windows (`if (comptime builtin.os.tag != .windows) file.tryLock(.exclusive)` and the matching unlock). So the faithful port is a no-op lock on Windows rather than LockFileEx; hence no windows-sys/unsafe. On unix the existing implementation already matched Zig: `File::try_lock` (flock LOCK_EX|LOCK_NB), WouldBlock is ignored (proceeds unlocked, as Zig ignores the bool), other errors -> CacheIsLocked, unlock on drop.
|
||||
|
||||
Tests: unix `lock_is_exclusive_until_dropped`; windows-only `lock_is_noop_on_windows` (compiled only); permission assertion split into unix-only `disk_cache_file_permissions`.
|
||||
|
||||
Verified: build/test(92)/clippy -D warnings on linux; `cargo check --target x86_64-pc-windows-gnu --tests -p ghostty-cli` and windows clippy clean (stub fontconfig.pc, RUSTC_WRAPPER= as in windows-WIN.md).
|
||||
@@ -0,0 +1,43 @@
|
||||
# compat-GC: helpgen (ZIG/src/helpgen.zig)
|
||||
|
||||
Zig generates help strings at build time from doc comments (`helpgen.zig`,
|
||||
exposed as `help_strings`). The Rust port does the same instead of keeping
|
||||
checked-in tables.
|
||||
|
||||
## Design
|
||||
|
||||
* New crate `crates/ghostty-helpgen` (no dependencies), used as a
|
||||
`[build-dependencies]` of `ghostty-cli` and `ghostty-input`.
|
||||
* `doc_lines`: port of `extractDocComments`/`findCommonPrefix` (strip
|
||||
`///`, remove the common leading-space prefix of non-blank lines, keep
|
||||
blank lines and code fences verbatim).
|
||||
* `run_fn_doc`: doc comment of a module's `run` function (Zig `genActions`).
|
||||
* `enum_variant_docs`: `///` docs per variant of an enum (Zig
|
||||
`genKeybindActions`).
|
||||
* `*_match`: emit Rust `match self { ... }` bodies with escaped literals.
|
||||
* `ghostty-cli/build.rs` reads the variants of `enum Action` in
|
||||
`src/ghostty.rs`, maps `ListFonts` -> `src/list_fonts.rs`, extracts the doc
|
||||
of `pub fn run`, writes `$OUT_DIR/action_help.rs`; `Action::help_text`
|
||||
`include!`s it. A missing doc comment fails the build (as in Zig).
|
||||
The former `src/help/*.txt` files are deleted.
|
||||
* `ghostty-input/build.rs` extracts the docs of every variant of
|
||||
`enum Action` in `src/binding/action.rs` (now `///` instead of `//`),
|
||||
writes `$OUT_DIR/keybind_action_docs.rs`, included by `ActionKey::docs`
|
||||
(docs = lines joined by `\n` plus one trailing `\n`, as before;
|
||||
`help_string` strips one).
|
||||
* Config help already derives from field docs through `config_struct!`
|
||||
(`ghostty-config/src/macros.rs`), so no generation was needed there.
|
||||
* A line-based scanner is used rather than `syn`: it mirrors Zig's token
|
||||
based approach (doc run + following item) and avoids a heavy build dep.
|
||||
|
||||
## Verification
|
||||
|
||||
Outputs of `+help`, `+list-actions [--docs]` and every `+<action> --help`
|
||||
were captured before and after: byte identical. Differences vs
|
||||
`/usr/bin/ghostty` exist only for `+version --help` and `+new-window --help`
|
||||
(unchanged from the baseline).
|
||||
|
||||
## Tests
|
||||
|
||||
`ghostty-helpgen` unit tests (marker stripping, common prefix, blank lines,
|
||||
code fences, `////`, run-doc and enum-variant extraction, escaping).
|
||||
@@ -0,0 +1,76 @@
|
||||
# compat-GC: GTK/libadwaita compat fallbacks, bench modes, helpgen, CLI Windows
|
||||
|
||||
Sub-notes: `compat-GC-bench.md`, `compat-GC-helpgen.md`, `compat-GC-cli.md`.
|
||||
|
||||
## 1. GTK / libadwaita compatibility (crates/ghostty-apprt-gtk)
|
||||
|
||||
### Ghostty's own minimum (finding)
|
||||
`ZIG/src/build/SharedDeps.zig` runs `blueprint.zig` over *every* entry of
|
||||
`gresource.blueprints`, which refuses to compile a `<maj>.<min>/x.blp` if the
|
||||
libadwaita headers are older than that version; the list contains `1.5/` files
|
||||
(window, tab, command palette, ...). So Ghostty 1.3.1 cannot be *built* against
|
||||
libadwaita < 1.5, and the Zig code calls `gtk_css_provider_load_from_bytes`
|
||||
(4.12) and `gtk_im_context_activate_osk` (4.14) unguarded. Ghostty's real
|
||||
minimum is therefore **GTK 4.14 / libadwaita 1.5**, which is what the crate
|
||||
already required; I verified this by compiling with `gtk4` features `v4_8`/`v4_10`
|
||||
(fails on `load_from_bytes`/`activate_osk`) and `v4_14` (compiles). The only
|
||||
change to the requirement is dropping the unneeded `gnome_44` feature. In Zig the
|
||||
fallbacks below are only reachable in a (hypothetical) build against older
|
||||
headers; they are ported with identical selection logic.
|
||||
|
||||
### Version gating (gtk_version.rs, adw_version.rs)
|
||||
Zig's `atLeast` = comptime header version AND runtime library version. Rust:
|
||||
* cargo features are the "header version": `adw_1_3` < `adw_1_4` < `adw_1_5`
|
||||
and `gtk_4_16` (`gtk/v4_16`); all are default. `BUILD_LEVEL` /
|
||||
`const fn comptime_at_least` read them; `at_least` = `comptime_at_least &&
|
||||
runtime_at_least`; `runtime_at_least`/`runtime_until` unchanged.
|
||||
`COMPTIME_VERSION` (pkg-config) is kept for `+version` output.
|
||||
* Types that Zig selects at comptime are selected with `cfg(feature = ...)`.
|
||||
* Debug builds only: `GHOSTTY_DEBUG_FAKE_GTK_VERSION` / `GHOSTTY_DEBUG_FAKE_ADW_VERSION`
|
||||
(e.g. `1.4.0`) override the *runtime* version answers (`fake_version.rs`; no Zig
|
||||
counterpart) so runtime branches can be exercised on new libraries.
|
||||
* Root `build.rs` links the binary with `-z lazy` (Rust defaults to `-z now`) so
|
||||
symbols only used behind a runtime check (GTK 4.16 `gtk_css_section_get_bytes`)
|
||||
don't stop an older library from loading the program, like Zig's lazy binding.
|
||||
|
||||
### Fallbacks ported
|
||||
| Zig | Rust |
|
||||
|---|---|
|
||||
| `class/dialog.zig` `Parent = AlertDialog / MessageDialog`, `present`/`close` | `class/dialog.rs`: `DialogParent` + `present`/`close` per cfg `adw_1_5`; macros `dialog_subclass_wrapper!`/`impl_dialog_parent!` give the three subclasses (close-confirmation, config-errors, clipboard) the right `@extends` chain and `response` override for both parents |
|
||||
| `clipboard_confirmation_dialog.zig` `can_remember`, template 1.4 vs 1.0 | `cfg_attr` template resource `ui/1.4` (adw_1_4) vs `ui/1.0`; `remember_choice` child only with SwitchRow; `CAN_REMEMBER`; `remember=false` without it |
|
||||
| `debug_warning.zig` Parent `adw.Bin`/`gtk.Box`, template 1.3/1.2 | `class/debug_warning.rs` cfg `adw_1_3` |
|
||||
| `surface_child_exited.zig` Banner / `SurfaceChildExitedNoop` | `class/surface_child_exited.rs`: noop widget (no template, `NOOP`, `close-request` emitted from `set_child_exited`); `Surface::child_exited` returns false for the noop, as in Zig. NB: Zig has no `1.2/surface-child-exited.blp` (the task text assumed one); the pre-Banner implementation is the Noop |
|
||||
| `window.zig` `actionAbout` | `adw::AboutDialog` if `supports_dialogs()` else `gtk::show_about_dialog` |
|
||||
| `application.zig` `signalCssParsingError` (GTK >= 4.16 branch) | `css.rs`: `domain code message` + `\n<source bytes>` (`CssSection::bytes`) behind `gtk_4_16` + runtime check, plain line otherwise; tested via `parsing_error_message` |
|
||||
| blueprint variants | `build.rs` already compiles 1.0/1.2/1.3/1.4/1.5 variants (same list as `gresource.zig`) into the gresource; the class selects at build level (as Zig) |
|
||||
|
||||
### Verification
|
||||
* `cargo clippy -p ghostty-apprt-gtk --all-targets -D warnings` clean with default
|
||||
features AND with `default = []` (temporarily edited), i.e. both the new and
|
||||
the fallback code compile.
|
||||
* Default build: GTK app runs with the debug replay hook (paste dialog shows
|
||||
`GhosttyClipboardConfirmationDialog` with the remember switch; no GTK criticals).
|
||||
* Fallback build (`default = []`, run via the replay hook): the paste confirmation
|
||||
and the close confirmation come up as `adw::MessageDialog`-based
|
||||
`GhosttyClipboardConfirmationDialog` / `GhosttyCloseConfirmationDialog`
|
||||
(transient for the window), the binary has no `BIND_NOW`.
|
||||
* Workspace gate (excluding L1's in-progress `ghostty-lib`): `cargo clippy --workspace
|
||||
--all-targets -D warnings`, `cargo test --workspace`, `cargo +nightly fmt --all` pass.
|
||||
`+help`, `+list-actions [--docs]`, `+list-keybinds --help`, `+show-config --help`
|
||||
are byte-identical to `/usr/bin/ghostty`.
|
||||
|
||||
### Deviation found by the runtime check
|
||||
Zig's `GhosttyCloseConfirmationDialog` registers a `close-request` signal; with
|
||||
the `MessageDialog` (a `GtkWindow`) parent that name already exists in the class
|
||||
ancestry and GObject aborts. Zig's fallback has the same latent bug (dead code
|
||||
upstream). The fallback build here names it `dialog-close-request`
|
||||
(`close_confirmation_dialog.rs::CLOSE_REQUEST`); default build unchanged.
|
||||
|
||||
### Not testable here
|
||||
Real old libraries (GTK < 4.16 / libadwaita < 1.5) are not installed; only the
|
||||
compile-time fallback selection and the version arithmetic are exercised.
|
||||
|
||||
## 2-4
|
||||
See the sub-notes. Deviations vs the task text: Zig `CodepointWidth` has no
|
||||
`uucode` mode (bench); Zig does no file locking on Windows, so the faithful
|
||||
port is a no-op there (cli).
|
||||
Reference in new issue
Block a user