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
6.2 KiB
6.2 KiB
Ghostty-rs Architecture
Rust rewrite of Ghostty 1.3.1. Reference source: ../ghostty/ (Zig), referred
to below as ZIG/ (= /pantheon/pfs/git/rust/ghostty-rewrite/ghostty).
Target platform: Linux (GTK4 + libadwaita, OpenGL). macOS/Metal/CoreText,
WASM, Windows and the embedded C API (libghostty) are out of scope.
Crate map (workspace crates/)
| Crate | Ports (ZIG/src/...) | Depends on |
|---|---|---|
ghostty-vt |
terminal/Parser, parse_table, UTF8Decoder, osc.zig + osc/*, csi, dcs, apc, sgr, color, x11_color, charsets, modes, ansi, device_status, mouse_shape, kitty/key, kitty/color, kitty/graphics_command, stream.zig | – |
ghostty-unicode |
unicode/* (width, grapheme break, props) | – |
ghostty-datastruct |
datastruct/* (split_tree, lru, circ_buf, blocking_queue, cache_table, ...) | – |
ghostty-os |
os/* (xdg, homedir, shell, locale, passwd, env, open, desktop, resourcesdir, hostname, TempDir, uri, ...) | – |
ghostty-input |
input/* (key, key_mods, keycodes, function_keys, key_encode, Binding, command, mouse, paste, kitty, Link) | vt |
ghostty-config |
config/*, cli/args.zig, cli/CommaSplitter.zig, cli/diagnostics.zig | input, os, vt |
ghostty-terminal |
terminal/ page, PageList, Screen, ScreenSet, Terminal, style, hyperlink, Tabstops, size, point, Selection, formatter, render, highlight, search/, kitty/graphics_{image,storage,exec,unicode,render}, tmux/, stream_readonly, StringMap, ref_counted_set, bitmap_allocator semantics | vt, unicode, datastruct |
ghostty-font |
font/* (Metrics, sprite/, Atlas, discovery via fontconfig, face via freetype, shaper via harfbuzz, Collection, CodepointResolver, SharedGrid(Set), opentype/, nerd_font_attributes) | config, unicode, terminal |
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 |
root ghostty-rs (bin ghostty) |
main_ghostty.zig, build_config.zig | core, config, apprt-gtk |
Key design decisions
- Safe Rust by default. Workspace lint
unsafe_code = "forbid". Crates that must do FFI/syscalls (renderer GL loader, termio pty/fork, apprt-gtk) may override withunsafe_code = "deny"and#[allow(unsafe_code)]on minimal,// SAFETY:-commented items. Prefer safe wrapper crates (rustix, glow, gtk4-rs) over raw FFI. - Pages without raw memory. Ghostty's
page.zigpacks a page into one mmap'd buffer with offsets. In Rust aPageownsVec<Row>+Vec<Cell>(row-major,colsper row) plus per-pageRefCountedSet<Style>, grapheme mapHashMap<cell_index, Vec<u32>>, hyperlink set/map, string storage. Capacity accounting is preserved logically (styles, grapheme bytes, hyperlink bytes, string bytes, rows/cols), including Ghostty's byte-size layout formula (Page::layout(cap).total_size), because PageList pruning (scrollback-limitis in bytes), page splitting and capacity-adjust behaviour — and the tests for them — depend on it. - PageList as an index-based linked list. Nodes live in a slab
(
Vec<Option<Node>>+ free list);NodeIdis an index (+ generation for debug checks).Pin { node: NodeId, y, x, garbage }isCopy. Tracked pins live in a PageList-owned slab; holders keep aTrackedPinhandle (index) and read/write through the PageList. All operations that move rows update tracked pins exactly like the Zig code. - Cell is a compact
Copyvalue (target 8 bytes, bit-packed u64 with accessor methods mirroring Zig field names), so memory accounting and copying behaviour stay close to Ghostty. - Parser → Stream → Handler.
ghostty-vt::Parseryields actions;ghostty-vt::stream::Stream<H: Handler>decodes CSI/ESC/OSC/DCS/APC into high-level actions and callsHandler. Terminal state changes live inghostty-terminal(stream_readonlyhandler applies toTerminal), andghostty-termio::StreamHandlerhandles side-effecting actions. - Rendering: OpenGL 4.3 via
glow, inside agtk::GLArea. Shaders are copied verbatim fromZIG/src/renderer/shaders/glsl. Renderer logic followsrenderer/generic.zig(cell contents rebuilt fromterminal::render::RenderState). - Fonts: fontconfig (discovery), freetype (rasterization), harfbuzz (shaping). Sprite font (box drawing etc.) is pure Rust, ported 1:1.
- Threads: like Ghostty — per surface: IO thread (termio), renderer
thread, plus a pty read thread. Mailboxes are
crossbeam-channel/std::sync::mpsc; the GTK main thread is woken viaglibchannels. TheTerminalis shared behindArc<Mutex<..>>(Ghostty's renderer mutex). - Config: same file format, same keys, same defaults, same CLI flags,
same docs text (used by
+show-config --docsand--help). - Tests: every Zig
test "..."block in a ported file is ported to a Rust#[test]with the same name (snake_cased) in the same module.scripts/test-progress.shtracks counts.
Out of scope / deferred
- macOS (Swift app, Metal, CoreText), Windows, WASM, libghostty C API.
- (The ImGui inspector was deferred and is now ported:
docs/rewrite/notes/ghostty-inspector.md.)
Intentional omissions (decided by the orchestrator)
- Sentry crash reporting (
crash/*): optional and disabled by default in upstream Linux builds;+crash-reportlisting 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.