Files
ghostty-rs/docs/rewrite/ARCHITECTURE.md
T
ddidderr 85489a164e feat-deviant(os): embed a configurable resource directory
Relocating a Cargo-installed binary loses executable-relative resource
lookup even when themes and shell integration exist under /usr/share.
Allow packagers to set GHOSTTY_BUILD_RESOURCES_DIR when compiling.

Absolute paths are used directly; relative paths resolve against the
running executable's directory for relocatable installations. Explicit
paths do not require terminfo sentinels. A nonempty runtime override wins
in every profile when the build option is configured. Unset or empty
build options preserve existing discovery, including debug precedence.
Cargo watches the build option so changing or unsetting it recompiles
lookup. Resource files still need to be installed separately.

Document this requested upstream deviation and the build option in the
README, architecture overview, and deviation register.

Test Plan:
- Eight resource lookup unit tests pass.
- Nightly formatting and ghostty-os Clippy with -D warnings pass.
- Production build with /usr/share/ghostty succeeds; a copied executable
  lists all 463 themes with no runtime override.
- Compiled probes verify absolute, relative, unset, and empty options,
  Cargo rebuilds, relocation, runtime overrides, and unrelated cwd.

Deviation-Register: docs/rewrite/DEVIANT_FIXES.md
2026-10-13 00:07:15 +02:00

162 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ghostty-rs Architecture
Rust rewrite of Ghostty 1.3.1. Reference source: `../ghostty/` (Zig), referred
to below as `ZIG/` (= `../../../ghostty`).
Primary platform: **Linux (GTK4 + libadwaita, OpenGL)** — built, tested and
verified at runtime here. Phase 8 extends the port to the rest of Ghostty's
Zig code: the embedded `libghostty` C API (identical `include/ghostty.h` ABI,
so Ghostty's unchanged Swift macOS app can link the Rust library), the
`libghostty-vt` C API (`include/ghostty/vt*.h`), WASM (wasm32), macOS
(Metal renderer, CoreText fonts, Darwin keymap/os) and Windows (ConPTY).
Non-Linux targets are compile-checked (`cargo check --target ...`) on this
machine; they cannot be run here. Phase 9 additionally ports the Swift macOS app (`macos/`) to Rust
(`crates/ghostty-macos`, AppKit via objc2), compile-checked like the rest of
the Apple code; the C ABI stays available for the original Swift app.
## Top-down decomposition
```
ghostty (bin, src/main.rs) CLI `+action` dispatch or GTK app startup
├── ghostty-cli `ghostty +action` commands
├── ghostty-apprt-gtk GTK4/libadwaita runtime: windows, tabs, splits,
│ │ dialogs, GLArea surfaces, IPC, inspector windows
│ └── ghostty-apprt core<->runtime contract (actions, messages, traits)
└── ghostty-core App + Surface: input routing, bindings, mouse,
│ clipboard, config reload, per-surface threads
├── ghostty-termio IO thread, pty, child process, stream handler
│ └── ghostty-terminal terminal state machine
│ ├── Terminal / Screen cursor, modes, scrolling, alt screen, selection
│ ├── PageList / Page scrollback memory model (slab nodes, tracked pins)
│ ├── render / formatter per-frame RenderState, text/VT/HTML export
│ ├── kitty / search / tmux kitty graphics, search thread, tmux control mode
│ └── ghostty-vt byte stream -> Parser -> Stream -> Handler actions
├── ghostty-renderer OpenGL renderer (glow), renderer thread, shaders
│ └── ghostty-font fontconfig/freetype/harfbuzz, sprite font, atlas
├── ghostty-inspector Dear ImGui terminal inspector
└── ghostty-config config file/CLI parsing, themes, keybinds
├── ghostty-input keys, key encoding, binding sets, mouse
└── ghostty-os XDG, env, shell, locale, resources dir, flatpak
Support: ghostty-unicode (width/grapheme/case-fold tables), ghostty-datastruct
(split tree, LRU, queues), ghostty-onig (Oniguruma retry-limit FFI),
ghostty-bench (benchmarks), ghostty-build-data (completions, man pages, syntax).
```
## Crate map (workspace `crates/`)
| Crate | Ports (ZIG/src/...) | Internal deps |
|---|---|---|
| `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,color,graphics_command}, tmux/control, stream.zig, simd (scalar) | – |
| `ghostty-unicode` | unicode/* (width, grapheme break, props, symbols) + case folding, generated from vendored UCD 17.0.0 | – |
| `ghostty-datastruct` | datastruct/* (split_tree, lru, circ_buf, blocking_queue, cache_table, ...) | – |
| `ghostty-onig` | (Oniguruma whole-search retry limit used by StringMap.zig) | – |
| `ghostty-os` | os/* (xdg, homedir, shell, locale, passwd, env, open, desktop, resourcesdir, hostname, TempDir, uri, flatpak, systemd, cgroup, ...) | vt |
| `ghostty-input` | input/* (key, key_mods, keycodes, function_keys, key_encode, Binding, command, mouse, paste, kitty, Link) | vt, unicode |
| `ghostty-terminal` | terminal/ page, PageList, Screen, ScreenSet, Terminal, style, hyperlink, Tabstops, size, point, Selection, formatter, render, highlight, search/*, kitty/graphics_*, tmux/{layout,output,viewer}, stream_readonly, StringMap, ref_counted_set | vt, unicode, datastruct, onig |
| `ghostty-config` | config/*, cli/args.zig, cli/CommaSplitter.zig, cli/diagnostics.zig | input, os, terminal, vt |
| `ghostty-font` | font/* (Metrics, sprite/*, Atlas, discovery (fontconfig), face (freetype), shaper (harfbuzz) + run, Collection, CodepointResolver, SharedGrid(Set), opentype/*, nerd_font_attributes) | config, terminal, unicode, datastruct |
| `ghostty-renderer` | renderer/ generic, OpenGL + opengl/*, cell, cursor, image, link, size, State, Thread, Overlay, shadertoy, row, shaders/glsl | config, font, terminal, input, unicode, vt, datastruct |
| `ghostty-inspector` | inspector/* (Dear ImGui terminal inspector) | font, input, renderer, terminal, vt |
| `ghostty-apprt` | apprt/action.zig, structs.zig, surface.zig, ipc.zig, runtime traits | config, input, inspector, renderer, terminal, vt, datastruct |
| `ghostty-termio` | termio/*, pty.zig, Command.zig, terminfo/*, shell integration | apprt, config, os, renderer, terminal, vt, datastruct |
| `ghostty-core` | App.zig, Surface.zig, surface_mouse.zig, global.zig | apprt, config, font, input, inspector, os, renderer, terminal, termio, ... |
| `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 |
Non-code: `resources/` (shell-integration, themes, terminfo), `dist/` (desktop
integration), `po/` (translations), crate-local `res/`/`shaders/`/`resources/`.
Resource lookup: `ghostty-os::resourcesdir` accepts the optional build-time
`GHOSTTY_BUILD_RESOURCES_DIR` path (watched by `ghostty-os/build.rs`). Runtime
`GHOSTTY_RESOURCES_DIR` overrides a configured build path; otherwise that path
precedes automatic discovery. Relative build paths resolve from the executable's
directory, allowing relocatable installations. Without a build path, upstream's
environment/terminfo lookup and the checkout resource fallback apply. See
`README.md` (Build-time resource directory) and `DEVIANT_FIXES.md`.
Build inputs: `ghostty-build-info/build.rs` derives version metadata from the
workspace manifest and Git HEAD/refs, watching `packed-refs` only when it exists
(packing loose refs also changes the watched `refs` directory). The GTK build
script compiles `resources/` in checkouts and watches the optional
`dist/ghostty.gresource` bundle only when consuming it from a source tarball.
Missing optional files must not be emitted as Cargo `rerun-if-changed` inputs:
they invalidate every subsequent build and rebuild downstream crates.
GTK invokes `glib-compile-resources` directly so generated XML/UI files in
`OUT_DIR` are not watched as inputs; the `resources/` watch covers their sources.
## Key design decisions
1. **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 with `unsafe_code = "deny"` and `#[allow(unsafe_code)]` on
minimal, `// SAFETY:`-commented items. Prefer safe wrapper crates (rustix,
glow, gtk4-rs) over raw FFI.
2. **Pages without raw memory.** Ghostty's `page.zig` packs a page into one
mmap'd buffer with offsets. In Rust a `Page` owns `Vec<Row>` + `Vec<Cell>`
(row-major, `cols` per row) plus per-page `RefCountedSet<Style>`, grapheme
map `HashMap<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-limit` is in bytes), page splitting and capacity-adjust
behaviour — and the tests for them — depend on it.
3. **PageList as an index-based linked list.** Nodes live in a slab
(`Vec<Option<Node>>` + free list); `NodeId` is an index (+ generation for
debug checks). `Pin { node: NodeId, y, x, garbage }` is `Copy`. Tracked pins
live in a PageList-owned slab; holders keep a `TrackedPin` handle
(index) and read/write through the PageList. All operations that move
rows update tracked pins exactly like the Zig code.
4. **Cell is a compact `Copy` value** (target 8 bytes, bit-packed u64 with
accessor methods mirroring Zig field names), so memory accounting and
copying behaviour stay close to Ghostty.
5. **Parser → Stream → Handler.** `ghostty-vt::Parser` yields actions;
`ghostty-vt::stream::Stream<H: Handler>` decodes CSI/ESC/OSC/DCS/APC into
high-level actions and calls `Handler`. Terminal state changes live in
`ghostty-terminal` (`stream_readonly` handler applies to `Terminal`), and
`ghostty-termio::StreamHandler` handles side-effecting actions.
6. **Rendering:** OpenGL 4.3 via `glow`, inside a `gtk::GLArea`. Shaders are
copied verbatim from `ZIG/src/renderer/shaders/glsl`. Renderer logic
follows `renderer/generic.zig` (cell contents rebuilt from
`terminal::render::RenderState`).
7. **Fonts:** fontconfig (discovery), freetype (rasterization), harfbuzz
(shaping). Sprite font (box drawing etc.) is pure Rust, ported 1:1.
8. **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 via `glib` channels.
The `Terminal` is shared behind `Arc<Mutex<..>>` (Ghostty's renderer mutex).
9. **Config:** same file format, same keys, same defaults, same CLI flags,
same docs text (used by `+show-config --docs` and `--help`).
10. **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.sh` tracks 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`.)
## Scope changes
- 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.