refactor(terminal): wire kitty graphics and drop PageList workarounds
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
This commit is contained in:
1 parent
88cc13871c
commit
677683b740
12 files changed
+708
-476
No files matched your search
@@ -7,7 +7,7 @@
|
||||
| graphics_storage.zig | `graphics_storage.rs` (`ImageStorage`, `Placement`, `PlacementKey`, `TerminalInfo`) | 19/19 Zig + 3 extra (placement replace releases pin, eviction order + limit, image_by_number newest) |
|
||||
| graphics_unicode.zig | `graphics_unicode.rs` (`placement_iterator`, `Placement`, `render_placement`) | 16/16 Zig + 2 extra |
|
||||
| graphics_render.zig | `graphics_render.rs` (`Placement`) | no tests in Zig |
|
||||
| graphics_exec.zig | `graphics_exec.rs` (`execute`, `ExecTerminal` trait) | 8/8 Zig + 4 extra (run against a harness, see below) |
|
||||
| graphics_exec.zig | `graphics_exec.rs` (`execute`, `ExecTerminal` trait) | 8/8 Zig + 8 extra (real Terminal, including lifecycle integration) |
|
||||
| kitty.zig / graphics.zig | `kitty/mod.rs` (re-exports; the command parser stays in `ghostty_vt::kitty::graphics_command`) | - |
|
||||
|
||||
`pub mod kitty;` added to `lib.rs`. Test data copied to `kitty/testdata/`.
|
||||
@@ -32,39 +32,52 @@ Zig tests skipped: none. (`debugDump` not ported: debug-only helper.)
|
||||
`evicted > req` (strictly); `set_limit(0)` resets storage to defaults (limit then set to 0); screen reset `.{ .dirty = true }` also resets total_limit to default.
|
||||
- `execute(terminal, &cmd)` has no allocator; `Command` stays borrowed (the loading image copies the payload).
|
||||
|
||||
## graphics_exec and Terminal (TODO(integration), needs T3)
|
||||
`Screen.kitty_images` is still the placeholder `KittyImages { dirty }`, so `Terminal` cannot implement `ExecTerminal` yet.
|
||||
`execute` is generic over the `ExecTerminal` trait; the exec tests run against a `Harness { t: Terminal, storage: ImageStorage }`
|
||||
(real `Terminal::index`/`set_cursor_pos`/pages; storage held beside it). No tests are ignored.
|
||||
## graphics_exec and Terminal integration — complete
|
||||
|
||||
### Integration steps
|
||||
1. `screen.rs`: replace `KittyImages` with `pub kitty_images: crate::kitty::graphics_storage::ImageStorage` (`Default` = Zig `.{}`).
|
||||
- `Screen::new`: after constructing, `result.kitty_images.set_limit(&mut result.pages, opts.kitty_image_storage_limit).unwrap()`
|
||||
(infallible there; `set_limit` returns `Result`). Opts default is already 320_000_000.
|
||||
- `Screen::reset` (Zig `self.kitty_images.deinit(self); self.kitty_images = .{ .dirty = true }`):
|
||||
`self.kitty_images.deinit(&mut self.pages); self.kitty_images = ImageStorage { dirty: true, ..Default::default() };`
|
||||
- `Drop`/explicit teardown: `kitty_images.deinit(&mut pages)` must run before pages are dropped (tracked pins). `clone_screen` does not clone images.
|
||||
- the existing `self.kitty_images.dirty = true` sites keep working unchanged.
|
||||
2. `terminal.rs`:
|
||||
- `erase_display` `.complete` and `.scrollback`... (Zig lines ~2495/2552): `let info = TerminalInfo::from_terminal(self); let s = self.screens.active_mut(); s.kitty_images.delete(&mut s.pages, &info, Delete::All(true));`
|
||||
- `switch_screen_mode`/`set_alternate`: new-screen `kitty_image_storage_limit` = primary `kitty_images.total_limit`; then `new.kitty_images.dirty = true`.
|
||||
- add `Terminal::kitty_graphics_command(&mut self, cmd: &Command) -> Option<Response> { kitty::graphics_exec::execute(self, cmd) }`
|
||||
(Zig `Terminal.kittyGraphics`).
|
||||
- `impl ExecTerminal for Terminal`:
|
||||
```rust
|
||||
fn kitty_parts(&mut self) -> (&mut ImageStorage, &mut PageList) { let s = self.screens.active_mut(); (&mut s.kitty_images, &mut s.pages) }
|
||||
fn exec_info(&self) -> TerminalInfo { TerminalInfo::from_terminal(self) }
|
||||
fn exec_cursor_pin(&self) -> Pin { self.screens.active().cursor_pin() }
|
||||
fn exec_index(&mut self) -> Result<(), page::Error> { self.index() }
|
||||
fn exec_set_cursor_pos(&mut self, row: usize, col: usize) { self.set_cursor_pos(row, col) }
|
||||
```
|
||||
- `print`: Zig sets row `kitty_virtual_placeholder` when printing `kitty::graphics_unicode::PLACEHOLDER` (already present in Rust, uses its own constant; can switch to `crate::kitty::unicode::PLACEHOLDER`).
|
||||
3. `stream_readonly`/termio: APC `G` -> `ghostty_vt::apc` already yields a parsed `Command`; termio calls `terminal.kitty_graphics_command(&cmd)` and, if `Some(resp)`, writes `resp.encode(..)` to the pty.
|
||||
Termio config: `screen.kitty_images.set_limit(&mut screen.pages, limit)` (Termio.zig 265/469); clear-screen binding: `Delete::All(true)` as in step 2 (Termio.zig 615).
|
||||
4. Renderer (`renderer/image.zig` equivalent): iterate `storage.placements` / `storage.images`, `Placement::rect`/`grid_size`/`calculated_size`,
|
||||
`graphics_unicode::placement_iterator(&pages, top, Some(bot))` + `Placement::render_placement(storage, img, cell_w, cell_h)`; reset `storage.dirty = false` after upload.
|
||||
Font shaper uses `kitty::unicode::PLACEHOLDER`.
|
||||
5. Once Terminal implements the trait, the exec tests' `Harness` can be replaced by `Terminal` directly.
|
||||
`Screen.kitty_images` is the real `ImageStorage`. Initialization applies the
|
||||
configured limit, reset deinitializes storage and restores default limits with
|
||||
`dirty = true`, and Drop releases placement pins before dropping PageList.
|
||||
`clone_screen` does not copy images. The default is still 320,000,000 bytes.
|
||||
|
||||
## Quality gate (2026-10-11)
|
||||
`cargo build/test/clippy -D warnings -p ghostty-terminal` pass (1243 tests incl. 66 kitty: 54 ported + 12 extra); rustfmt applied to `kitty/*.rs`.
|
||||
`Terminal` implements `ExecTerminal` by splitting active-screen storage/pages,
|
||||
snapshotting `TerminalInfo`, and forwarding cursor/index operations. Both
|
||||
`kitty_graphics(&mut Command)` and the new borrowed
|
||||
`kitty_graphics_command(&Command)` execute commands and return real responses.
|
||||
All graphics_exec tests now use Terminal directly; the separate harness is gone.
|
||||
|
||||
Reference hook audit:
|
||||
- `.complete` and `.scroll_complete` display erasure call `Delete::All(true)`.
|
||||
`.scrollback` only erases history, as in Terminal.zig.
|
||||
- Lazy alternate-screen creation inherits the primary image limit; screen
|
||||
switching marks the new screen's images dirty.
|
||||
- All existing image dirty hooks in Screen and Terminal remain at their Zig
|
||||
locations (scrolling, index, insert/delete lines, screen switching).
|
||||
- Full reset drops alternate storage and resets primary storage. Placeholder
|
||||
printing uses the shared `graphics_unicode::PLACEHOLDER` constant.
|
||||
|
||||
Four additional integration regressions cover screen clone/reset and pin
|
||||
release, erasure hooks, alternate-screen isolation/limit inheritance/full
|
||||
reset, and the legacy command entrypoint plus in-progress transfer reset.
|
||||
|
||||
## API changes and consumer wiring
|
||||
|
||||
Added `Terminal::kitty_graphics_command(&Command)` and `ExecTerminal for
|
||||
Terminal`; retained `Terminal::kitty_graphics(&mut Command)` unchanged.
|
||||
`Screen.kitty_images` now has the required concrete ImageStorage type;
|
||||
existing `.dirty` access remains valid. No downstream callers needed edits.
|
||||
|
||||
Termio can pass APC `G` commands through either terminal entrypoint and encode
|
||||
returned responses to the pty. Storage limits use
|
||||
`screen.kitty_images.set_limit(&mut screen.pages, limit)`; clear-screen bindings
|
||||
use `Delete::All(true)`. Renderer consumers can inspect placements/images and
|
||||
Unicode placements and clear the storage dirty flag after updating graphics.
|
||||
Consumer implementation beyond the public terminal API remains owned by the
|
||||
concurrent renderer/termio agents.
|
||||
|
||||
## Quality gate (2026-10-11 integration pass)
|
||||
|
||||
`cargo test -p ghostty-terminal`: 1252 unit tests (including 70 Kitty tests:
|
||||
54 source cases + 16 extra) and 1 documentation test pass; 0 failed, 0 ignored.
|
||||
Clippy with `--all-targets -- -D warnings`, rustfmt, and the combined build of
|
||||
`ghostty-font`, `ghostty-renderer`, and `ghostty-termio` pass. No commit or version
|
||||
change was made. Existing non-integration deviations above are unchanged.
|
||||
@@ -1,15 +1,62 @@
|
||||
# Requests for page.rs / page_list.rs (from the Screen port)
|
||||
|
||||
1. **Pin-based iterators** (Zig `PageList.zig` ~5100-5170): `Pin::{row_iterator, cell_iterator, page_iterator, prompt_iterator}(direction, limit: Option<Pin>)`.
|
||||
The limit pin is inclusive and applies at row granularity. Screen uses a local copy in `pin_iter.rs`.
|
||||
2. **`PageList::set_tracked_pin` validity**: it rejects pins with `y >= node.size.rows`. Zig writes the pin raw; `Screen::split_for_capacity` temporarily restores the cursor to the pre-split node, which may have shrunk. Worked around with a clamped stand-in.
|
||||
3. **Cross-page row clone**: Zig `Page.cloneRowFrom(other_page, ...)` between two nodes of one list needs two page borrows. Screen implements it with `export_cell`/`import_cell` (`Screen::clone_row_between`). A `PageList::clone_row_between(src_pin, dst_pin)` would be better.
|
||||
4. **String allocator probing**: `Page.string_alloc` is private; Zig `cursorSetHyperlink` probes it before growing. Screen instead re-adds the cursor hyperlink after `increase_capacity`. Also `insert_hyperlink` allocates strings before checking set dedup, so near-full pages can fail needlessly.
|
||||
5. **`fixup_viewport` must handle `Viewport::Top`** after `erase_rows` (Zig PageList.zig ~3043-3070). Worked around in `Screen::erase_rows`.
|
||||
6. **Resize reflow / no-reflow fewer rows** must drop trailing blank rows, including rows holding only bg-color cells (Zig `resizeCols`/`resizeWithoutReflow`). Three Screen tests are `#[ignore = "pagelist: ..."]`:
|
||||
`screen_resize_no_reflow_less_rows_trims_blank_lines`, `screen_resize_less_cols_with_reflow_but_row_space`, `screen_resize_less_cols_to_wrap_wide_char`.
|
||||
7. `PageList::reset` and `erase_rows` return `Result`; `erase_rows` with an empty history start point returns `InvalidCoordinate` (Zig would assert). Screen guards/ignores.
|
||||
- (T3/p4) **`erase_row_bounded` must reset row flags on the blanked row**: after rotating, the final row is cleared with `Page::clear_cells`, which leaves `row.hyperlink`/`styled`/`grapheme` set. Zig's row is left with the flags cleared (test `Terminal: index bottom of scroll region clear hyperlinks` expects `!row.hyperlink`; ignored as `terminal_index_bottom_of_scroll_region_clear_hyperlinks`).
|
||||
- (T3/p8) **Reflow to fewer cols with a pending-wrap cursor**: 4x2 screen printed "0123", `resize(2,2)` with reflow gives screen contents "01\n23" but the active area/viewport dump is only "23" (active top is one row too low; Zig yields "01\n23"). Ignored test: `terminal_resize_with_wraparound_on`.
|
||||
- (T3/p1) **`Page::set_graphemes` / `Page::append_grapheme` must not mark the row dirty** (Zig `Page.appendGrapheme` leaves dirty untouched; callers like `Terminal.print` mark dirty explicitly). Terminal works around it for the zero-width path (test `terminal_ignored_vs16_doesnt_mark_dirty`).
|
||||
- (T3/terminal) `PageList::clone_partial_row_between(src_pin, dst_pin, left, right)`: Terminal `insert_lines`/`delete_lines` need Zig's `Page.clonePartialRowFrom` between two different page nodes of one list (needs two page borrows). `terminal.rs::clone_partial_row_between` re-implements it via `export_cell`/`import_cell` (now `pub(crate)` use) plus the row-metadata merge from `Page::clone_partial_row_from`.
|
||||
All requests resolved and verified in the 2026-10-11 integration pass.
|
||||
|
||||
1. **Resolved — pin-based iterators.** `Pin::{row_iterator, cell_iterator,
|
||||
page_iterator, prompt_iterator}` take the owning `&PageList`, direction, and
|
||||
an inclusive optional limit pin. Limits apply to whole rows; cell iteration
|
||||
begins at the starting column. Construction uses pins directly, without
|
||||
point conversion or a list scan. Screen, Terminal, and Selection use these
|
||||
methods. Public `pin_iter` functions/types remain as compatibility wrappers.
|
||||
2. **Resolved — tracked-pin restoration.** `set_tracked_pin` validates the
|
||||
handle and node lifetime, allowing a temporarily out-of-range row during
|
||||
split recovery. Screen restores the exact old pin, with no clamped stand-in.
|
||||
Cursor dirtying accesses the still-allocated row, matching Zig's cached
|
||||
`page_row`. The maximum-style page-split regression passes.
|
||||
3. **Resolved — cross-page row clone.** `PageList::clone_row_between(src, dst)`
|
||||
borrows the two pages directly and calls `Page::clone_row_from`. Screen's
|
||||
export/import row snapshot helper is removed.
|
||||
4. **Resolved — string allocation and hyperlink deduplication.** Screen probes
|
||||
`Page::can_allocate_string` before capacity growth in `cursor_set_hyperlink`,
|
||||
following Zig's string-growth/hyperlink-growth/retry order. The probe frees
|
||||
its temporary reservation in Rust; the page is then rebuilt. The cursor-link
|
||||
recovery workaround is removed. `insert_hyperlink` retains existing live
|
||||
entries before allocating strings; a full-allocator regression covers this.
|
||||
5. **Resolved — Top viewport after erasure.** `fixup_viewport` handles `Top`
|
||||
inside PageList; Screen has no viewport fixup. Resize still only fixes a
|
||||
pinned viewport, preserving Zig's `Top` behavior (covered by the existing
|
||||
resize-no-reflow-more-rows-contains-viewport test).
|
||||
6. **Verified resolved — trailing blank rows during resize.** All three tests
|
||||
are enabled and pass: `screen_resize_no_reflow_less_rows_trims_blank_lines`,
|
||||
`screen_resize_less_cols_with_reflow_but_row_space`, and
|
||||
`screen_resize_less_cols_to_wrap_wide_char`.
|
||||
7. **Resolved — reset/erase error handling.** Existing public `Result` signatures
|
||||
remain for backwards compatibility. Erasing empty history is a successful
|
||||
no-op. Screen's extra history guard and error swallowing are removed;
|
||||
valid internal erasure/reset calls assert success as in Zig.
|
||||
|
||||
- **Verified resolved (T3/p4):** `erase_row_bounded` clears the blanked row's
|
||||
managed flags; `terminal_index_bottom_of_scroll_region_clear_hyperlinks`
|
||||
is enabled and passes.
|
||||
- **Verified resolved (T3/p8):** pending-wrap reflow retains the correct active
|
||||
rows; `terminal_resize_with_wraparound_on` is enabled and passes.
|
||||
- **Resolved (T3/p1):** `set_graphemes` and `append_grapheme` preserve row dirty
|
||||
state, including allocation growth. Terminal's save/restore workaround is
|
||||
removed; the VS16 test and a direct append regression pass.
|
||||
- **Resolved (T3/terminal):** `PageList::clone_partial_row_between(src, dst,
|
||||
left, right)` directly borrows distinct pages and delegates managed-memory
|
||||
and row-metadata handling to `Page::clone_partial_row_from`. Terminal's
|
||||
export/import implementation is removed. The regression checks graphemes,
|
||||
hyperlinks, untouched columns, dirty/wrap flags, and Kitty placeholder flags.
|
||||
|
||||
## API changes
|
||||
|
||||
Additive methods: the four Pin iterators and both PageList row-copy helpers.
|
||||
Existing iterator wrappers and `Result` signatures are retained. No downstream
|
||||
caller edits were needed.
|
||||
|
||||
## Validation
|
||||
|
||||
`cargo test -p ghostty-terminal`: 1252 unit tests and 1 documentation test pass,
|
||||
0 failed, 0 ignored. Clippy with `-D warnings`, rustfmt, and the combined build
|
||||
of `ghostty-font`, `ghostty-renderer`, and `ghostty-termio` pass.
|
||||
@@ -3,13 +3,13 @@
|
||||
## Ported
|
||||
| Zig | Rust | tests |
|
||||
|---|---|---|
|
||||
| Screen.zig | `screen.rs` (+ `cursor.rs` for cursor.zig `Style`, `pin_iter.rs` helper) | 183 of 184 (`screen/tests/p1..p5.rs`) |
|
||||
| Screen.zig | `screen.rs` (+ `cursor.rs` for cursor.zig `Style`) | 183 of 184 (`screen/tests/p1..p5.rs`) |
|
||||
| ScreenSet.zig | `screen_set.rs` | 1/1 |
|
||||
| Tabstops.zig | `tabstops.rs` | 4/5 |
|
||||
| Selection.zig | `selection.rs` | 18/18 |
|
||||
|
||||
Skipped: `Tabstops: resize alloc failure preserves state` and `selectionString map allocation failure cleanup` (Zig tripwire failure injection).
|
||||
Ignored (pagelist limitations, see `ghostty-terminal-pagelist-requests.md`): 3 resize tests.
|
||||
All three formerly blocked resize tests are enabled and pass. No ignored tests.
|
||||
Deps added: ghostty-unicode (width in `test_write_string`), ghostty-datastruct (unused so far), log.
|
||||
|
||||
## Deviations
|
||||
@@ -19,11 +19,11 @@ Deps added: ghostty-unicode (width in `test_write_string`), ghostty-datastruct (
|
||||
- `clone` is `clone_screen(top, bot)`. `cursor_copy(&Cursor, hyperlink: bool)` copies the hyperlink from the other cursor's heap copy.
|
||||
- `append_grapheme(x, cp)` takes a column of the cursor row. `clear_cells(node, y, x0, x1)` takes a half-open column range.
|
||||
- Selection methods take `&PageList` (`&screen.pages`) since tracked bounds are handles: `sel.start(&pages)`, `top_left`, `order`, `contains`, `contained_row`, `ordered`, `eql(&pages, &other)`, `adjust(&mut pages, adj)`, `track(&mut pages)`, `deinit(&mut pages)`. `Selection` is `Copy`.
|
||||
- `kitty_images` is a placeholder `KittyImages { dirty }` (TODO(integration) until kitty graphics storage lands). `StringMap` is a local struct (TODO(integration)).
|
||||
- Minimal plain-text formatter (`plain_format` in screen.rs) backs `selection_string[_map]`, `dump_string`, `dump_string_alloc[_unwrapped]`; TODO(integration): delegate to formatter.rs.
|
||||
- `kitty_images` owns `kitty::graphics_storage::ImageStorage`: initialization applies the configured limit; reset releases placement pins and restores default storage with `dirty = true`; Drop releases storage before pages. `clone_screen` does not clone images.
|
||||
- `StringMap` re-exports the real `string_map::StringMap`.
|
||||
- Selection/dump strings use the real `formatter::ScreenFormatter`.
|
||||
- Tabstops::unset XORs like Zig (unsetting an unset stop sets it).
|
||||
- `cursor_set_hyperlink` does not probe the string allocator (private); it re-adds the link after growth.
|
||||
- `Screen::erase_rows` carries a `Viewport::Top` workaround (request 5).
|
||||
- `cursor_set_hyperlink` follows the reference allocator probe and capacity-growth order. PageList owns viewport repair and cross-page row copying; Screen uses native Pin iterators and exact cursor restoration after page splitting. No PageList workarounds remain.
|
||||
|
||||
## API overview for Terminal
|
||||
`Screen` fields: `pages, no_scrollback, cursor, saved_cursor, selection, charset, protected_mode, kitty_keyboard, kitty_images, semantic_prompt, dirty`.
|
||||
@@ -32,3 +32,20 @@ Editing: `clear_cells`, `clear_unprotected_cells`, `clear_rows`, `erase_rows`, `
|
||||
Style/links: `set_attribute(sgr::Attribute)`, `manual_style_update()`, `start_hyperlink(uri, id)`, `end_hyperlink()`, `cursor_set_hyperlink()`, `cursor_set_semantic_content(..)`.
|
||||
Selection: `select(Option<Selection>)`, `clear_selection()`, `select_line/all/word/word_between/output`, `line_iterator`, `prompt_click_move`, `selection_string`.
|
||||
Test helper: `test_write_string`.
|
||||
|
||||
## API changes (integration pass)
|
||||
|
||||
`Screen.kitty_images` now exposes the required real `ImageStorage`; its existing
|
||||
`dirty` field access remains valid. The old standalone `KittyImages` value type
|
||||
is retained for compatibility, but is no longer used by Screen. Other public
|
||||
signatures, including `Screen::reset() -> Result`, are unchanged. No renderer,
|
||||
font, or termio callers needed edits.
|
||||
|
||||
## Integration verification (2026-10-11)
|
||||
|
||||
All Screen/Terminal TODO and Zig-reference comments were reviewed against the
|
||||
reference. Remaining TODOs also occur in Zig (capacity-growth recovery and a
|
||||
selection test note); no integration workaround remains. Lifecycle regressions
|
||||
cover real image storage, clone isolation, reset, and placement-pin release.
|
||||
Crate gate: 1252 unit + 1 documentation tests pass, none ignored; clippy with
|
||||
warnings denied, rustfmt, and the combined font/renderer/termio build pass.
|
||||
@@ -3,16 +3,15 @@
|
||||
## Ported
|
||||
| Zig | Rust | tests |
|
||||
|---|---|---|
|
||||
| Terminal.zig | `terminal.rs` (+ `terminal/tests/p1..p8.rs`, helpers in `tests/mod.rs`) | 372 of 372 (370 pass, 2 `#[ignore = "pagelist: ..."]`) |
|
||||
| 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 |
|
||||
|
||||
Ignored tests (PageList gaps, see `ghostty-terminal-pagelist-requests.md`):
|
||||
`terminal_index_bottom_of_scroll_region_clear_hyperlinks` (erase_row_bounded keeps the row hyperlink flag) and
|
||||
`terminal_resize_with_wraparound_on` (reflow to fewer cols loses a row in the active dump).
|
||||
|
||||
Small non-test deviations: `glitch.txt` copied next to the tests (used by the glitch-text test); zero-width attach in
|
||||
`print` restores the row dirty flag because `Page::append_grapheme` marks rows dirty (Zig does not; request in the pagelist file).
|
||||
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)
|
||||
```rust
|
||||
@@ -35,8 +34,38 @@ let text = t.plain_string()?; // viewport as text (p
|
||||
- Termio's own handler can call the same `Terminal` methods; it should handle side-effect actions (queries, title, clipboard, bell, APC/DCS) itself and delegate the rest, mirroring `stream_readonly::Handler::vt`.
|
||||
- Tests: Zig tests that mixed `s.nextSlice` and direct `t.` calls use `feed(&mut t, bytes)` (fresh stream per call) or `t.vt_stream()` + `s.handler.terminal`.
|
||||
|
||||
## TODO(integration)
|
||||
- `Terminal::kitty_graphics(cmd)` is a stub returning `None` (Zig `kitty.graphics.execute`); `kitty_images_delete_all` (erase display complete/scroll complete) only sets `kitty_images.dirty`; kitty image storage limit on lazily-created screens uses `Options::DEFAULT`. `kitty_images.dirty = true` hooks are in place at every Zig location (index, scroll_up, insert/delete lines, switch_screen, Screen::scroll).
|
||||
- tmux control-mode viewer: not required by Terminal/stream_readonly; not ported here.
|
||||
- `clone_partial_row_between` local helper (pagelist request).
|
||||
- Oniguruma: `onig` crate lacks the retry-limit-in-search setter; only retry-limit-in-match is set.
|
||||
## Integration complete (2026-10-11)
|
||||
|
||||
- `Terminal` implements `kitty::graphics_exec::ExecTerminal` using its active
|
||||
screen's storage/pages and real cursor/index operations.
|
||||
- `kitty_graphics` executes commands and returns real responses. Display erasure
|
||||
uses `Delete::All(true)` at exactly the reference `.complete` and
|
||||
`.scroll_complete` hooks (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: `onig` lacks 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.
|
||||
Reference in new issue
Block a user