feat(terminal): port page memory model (partial PageList)

First cut of the terminal core memory model from ZIG/src/terminal:
size, point, style, hyperlink, ref_counted_set, page and PageList.

Design (see docs/rewrite/ARCHITECTURE.md decisions 2-4):
- Cell/Row are 8-byte u64 wrappers with Zig's exact bit offsets.
- Page owns row/cell Vecs plus style set, grapheme and hyperlink maps;
  Page::layout reproduces Ghostty's byte-size formula on 64-bit Linux so
  scrollback-limit pruning matches.
- PageList keeps nodes in a generation-checked slab with a free list and
  list-owned tracked pins addressed by handles.

This is explicitly partial (docs/rewrite/notes/ghostty-terminal-
pagelist.md): 151/202 PageList tests ported; reflow rebuilds a snapshot
instead of Zig's incremental ReflowCursor; point<->pin conversion walks
from the list head (no active/viewport caches); RefCountedSet doesn't
reproduce probe-dependent ID reuse. A follow-up pass finishes parity.

Test Plan:
- cargo test -p ghostty-terminal (239 tests)
This commit is contained in:
ddidderr committed 2026-10-11 22:12:31 +02:00
1 parent 09cbe3bc97
commit 6cf16ed2e6
11 files changed
+8817 -3

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
//! Owned OSC 8 hyperlinks and per-page identifiers.
/// Nonzero page-local hyperlink identifier.
pub type Id = u16;
/// Mapping from a cell index to its hyperlink.
pub type Map = std::collections::HashMap<usize, Id>;
/// An explicit OSC 8 ID or an automatically generated screen-local ID.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum HyperlinkId {
/// Application-provided byte string.
Explicit(Vec<u8>),
/// Screen-generated identifier.
Implicit(u32),
}
/// A decoded hyperlink owning its ID and URI.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Hyperlink {
/// Hyperlink identity.
pub id: HyperlinkId,
/// URI bytes, which need not be UTF-8.
pub uri: Vec<u8>,
}
impl Hyperlink {
/// Duplicate the owned strings.
pub fn dupe(&self) -> Self {
self.clone()
}
/// Compare identity and URI.
pub fn eql(&self, other: &Self) -> bool {
self == other
}
/// Logical string allocation including 32-byte chunk rounding.
pub fn string_bytes(&self) -> usize {
self.uri.len().next_multiple_of(32)
+ match &self.id {
HyperlinkId::Explicit(v) => v.len().next_multiple_of(32),
HyperlinkId::Implicit(_) => 0,
}
}
}
/// Owned page entry; unlike Zig it needs no base address for decoding.
pub type PageEntry = Hyperlink;
/// Reference-counted set of page entries.
pub type Set = crate::ref_counted_set::RefCountedSet<PageEntry>;