Integration pass over the terminal core (Codex/gpt-6-astra, reviewed): - Screen now owns the real kitty ImageStorage; new/reset/teardown, erase-display deletes and alternate-screen limit inheritance hook in where Zig does, and Terminal implements ExecTerminal so kitty APC commands execute against it. Exec tests use a real Terminal. - The PageList gains the APIs Screen/Terminal needed (pin iterators, cross-page row/partial-row clone, string allocator probing, dedup before allocating hyperlinks, Top viewport fixup after erase, append_ grapheme no longer marking rows dirty), and the Screen/Terminal workarounds for their absence are removed so the code mirrors Zig. Public signatures are unchanged; downstream crates build as before. Test Plan: - cargo test -p ghostty-terminal (1252 passed, 0 ignored) - cargo clippy -p ghostty-terminal --all-targets -- -D warnings
5.0 KiB
ghostty-terminal: Terminal, stream_readonly, StringMap
Ported
| Zig | Rust | tests |
|---|---|---|
| Terminal.zig | terminal.rs (+ terminal/tests/p1..p8.rs, helpers in tests/mod.rs) |
372 of 372 (all pass) |
| stream_readonly.zig | stream_readonly.rs |
33 of 33 |
| StringMap.zig | string_map.rs (uses the onig crate; ghostty-config is a dev-dependency for the URL regex tests; Screen's stand-in StringMap is now a re-export) |
3 of 3 |
The two formerly blocked tests (terminal_index_bottom_of_scroll_region_clear_hyperlinks
and terminal_resize_with_wraparound_on) are enabled and pass. glitch.txt
remains next to the tests. The zero-width grapheme dirty-state workaround and
local cross-page row snapshot helper have been removed: Page/PageList now own
those semantics.
API overview (for termio / renderer / core)
use ghostty_terminal::terminal::{Terminal, Options};
let mut t = Terminal::new(Options::new(80, 24))?; // Options{cols,rows,max_scrollback=10_000,colors,default_modes}
{
let mut s = t.vt_stream(); // ghostty_vt::stream::Stream<stream_readonly::Handler<'_>> (new_alloc)
s.next_slice(b"hello\r\n\x1b[31mred\x1b[0m")?; // applies every state-changing action; queries are ignored
} // s.handler.terminal gives &mut Terminal while the stream lives
t.resize(100, 30)?; // Zig resize(alloc, cols, rows); primary reflows (if wraparound mode), alt does not
t.print(cp)?; t.print_string("text\n")?; t.full_reset();
let text = t.plain_string()?; // viewport as text (plain_string_unwrapped respects wrap)
t.screensis aScreenSet:t.screen()/t.screen_mut()(=screens.active()/active_mut()),t.screens.active_key,get(Key).- Reading cells:
scr.pages.get_cell(Point::Viewport(Coordinate{x,y}))->Cell(Copy); rows/pages viascr.pages.pin(pt)+pin.row_and_cell(&scr.pages); page datascr.page(node); style of a cellpage.style(cell); graphemespage.lookup_grapheme(page.cell_index(x,y)?). - Cursor:
t.screen().cursor(x, y, pending_wrap, style,cursor_style, hyperlink_id, semantic_content). Selection:screen.select(..),screen.selection_string(..)(Screen API). - State:
t.modes(ModeState),t.flags(mouse_event/format, focused,dirtyrenderer flags, shell_redraws_prompt, ...),t.colors(DynamicRgb fg/bg/cursor + DynamicPalette),t.scrolling_region,t.tabstops,t.pwd/get_pwd(),t.mouse_shape,t.status_display,t.width_px/height_px. - Viewport:
t.scroll_viewport(ScrollViewport::{Top,Bottom,Delta(n)}). Screen switching:switch_screen(Key) -> Option<old Key>,switch_screen_mode(SwitchScreenMode::{M47,M1047,M1049}, enabled). print_attributes()returns aString(DECRQSS SGR reply body) instead of writing into a buffer;set_pwd(&[u8]).- Termio's own handler can call the same
Terminalmethods; it should handle side-effect actions (queries, title, clipboard, bell, APC/DCS) itself and delegate the rest, mirroringstream_readonly::Handler::vt. - Tests: Zig tests that mixed
s.nextSliceand directt.calls usefeed(&mut t, bytes)(fresh stream per call) ort.vt_stream()+s.handler.terminal.
Integration complete (2026-10-11)
Terminalimplementskitty::graphics_exec::ExecTerminalusing its active screen's storage/pages and real cursor/index operations.kitty_graphicsexecutes commands and returns real responses. Display erasure usesDelete::All(true)at exactly the reference.completeand.scroll_completehooks (not.scrollback). Lazy alternate-screen creation inherits the primary image limit. All existing dirty hooks remain at their reference locations, including both branches of shared insert/delete-lines.- Placeholder printing uses the shared Kitty Unicode constant. Full reset tears down alternate-screen images and resets primary-screen storage.
- Pin iteration and partial row copying delegate to PageList. Reset/erase no longer swallow internal errors. Existing public Result APIs are retained.
- Reviewed all workaround/TODO/stand-in/Zig comments. Remaining functional TODO comments are inherited from Terminal.zig, not integration gaps.
API changes
Added kitty_graphics_command(&Command) -> Option<Response> and the
ExecTerminal implementation. Existing kitty_graphics(&mut Command) is
unchanged and delegates to the new entrypoint. No downstream callers changed.
Remaining representation limitations
- Oniguruma:
oniglacks the retry-limit-in-search setter; only retry-limit-in-match is set. - tmux control-mode viewer is implemented separately in
tmux/; it is not part of Terminal/stream_readonly's integration surface.
Quality gate
1252 unit tests and 1 documentation test pass, none failed or ignored.
cargo clippy -p ghostty-terminal --all-targets -- -D warnings, rustfmt, and
cargo build -p ghostty-font -p ghostty-renderer -p ghostty-termio pass.
No version bump or commit was made.