Treat FINISH as the self-delimiting snapshot boundary instead of peeking for end-of-file. Normal decoding now leaves continuation bytes unread, allowing snapshots and live protocol data to share a stream without waiting for closure.
Add decodeExact for bounded files that still require strict exhaustion, and update the Kaitai schema, documentation, and tests for continuation and sequential snapshot decoding.
Stream complete snapshot records to any std.Io.Writer while retaining one reusable payload buffer for length and CRC calculation. Update BLAKE3 incrementally so checkpoints no longer require rehashing an allocating destination.
Wrap decode hashing in StreamReader to enforce exact checkpoint boundaries. Preserve v1 bytes while allowing snapshots to begin at the current writer position and retaining only valid prefixes on failures.
Route HISTORY sequences by their encoded screen key so both keyed sequence groups can arrive in either order. Keep undeclared and duplicate routing strict, separate HISTORY manifest parsing from page restoration, and clear decoder-only generation state before returning the terminal.
Normalize unknown terminal-wide semantic fields during restore while keeping dimensions and screen count structural. Preserve canonical encoding, ignore reserved mode and tab-stop bits, reset invalid color and scrolling state, and clamp finite scrollback policies to the native range.
Treat HISTORY row counts as canonical metadata rather than a reason to reject otherwise usable history. Restore topology from the declared PAGE sequence while keeping record framing, routing keys, and sequence boundaries strict.
Keep the standalone style and hyperlink codecs strict while allowing PAGE and SCREEN decoders to discard invalid optional data at boundaries they own. Normalize invalid styles to defaults, ignore unrepresentable hyperlinks, reuse duplicate entries, and validate hyperlink values before encoding.
Keep SCREEN encoding strict while allowing decoding to recover from unknown or noncanonical semantic state. Cursor positions now clamp to the restored active area, and invalid enum values, reserved bits, and optional state degrade to native defaults.
Keep snapshot grid encoding strict by rejecting malformed wide-cell relationships before they can produce invalid wire data.
Decode untrusted grids liberally while preserving record alignment. Unknown semantic values and content kinds degrade to safe defaults, optional graphemes and hyperlinks are dropped when invalid or over capacity, and malformed wide-cell markers normalize to narrow cells.
Treat Kitty virtual placeholder codepoints as ordinary valid grid content during snapshot restore and derive the native row lookup hint from decoded cells. Image and placement registries remain intentionally omitted.
Cover the behavior with a complete snapshot round trip containing a real virtual placement and its grapheme diacritics.
Describe the complete version 1 snapshot format with a Kaitai schema and make every golden fixture self-describing for automatic discovery. Add a verifier that compiles the schema, parses all fixtures, and checks record checksums, checkpoint digests, and cross-record invariants.
Preserve Kaitai metadata when generating fixture candidates and provide the compiler and Python runtime dependencies through the development shell. Keep the mode registry portable to Kaitai JavaScript targets so the complete fixture also works in the web IDE.
Extracted out the raw `src/terminal` changes needed for the future
snapshot work, 4 separate changes. These are uncontroversial and
relatively simple, summarized below. Tests AI assisted but the rest
including commit messages, this PR message, etc. all organic.
* **Add iterator to ref counted set.** Iterate over live entries and
their IDs. Const, doesn't mutate the set.
* **lib.Enum produces stable enums for Zig.** Basically the same as C
except it uses the smallest fitting integer including the holes.
* **PageList: a couple helpers for manually creating pages.** There is
`PageList.Builder` for creating a new pagelist and
`PageList.allocatePage` for modifying an existing one. This allows
PageList construction from raw pages.
Rename Builder.addPage and PageAllocation.cancel to their consistent allocatePage and deinit forms. Track successful ownership transfers so both builder APIs can use unconditional deferred cleanup without releasing pages transferred to a PageList.
Fixes#13522
Fixes unreachable when reflow dupes a hyperlink into a destination page
whose string allocator is nearly full.
The capacity precondition in ReflowCursor.writeCell performed a single
test allocation of `uri.len + id.len` bytes before duping a hyperlink
into the destination page. But PageEntry.dupe allocates the URI and
the explicit ID as two separate allocations, and the string allocator
rounds every allocation up to its 32-byte chunk size independently, so
the two separate allocations can require one more chunk than the
single combined test allocation.
Write a new helper to make sure we get the right amount of space
using the same allocation pattern of dupe.
Applications cannot infer whether an unfocused terminal remains visible, so
focus reports are insufficient for avoiding expensive rendering while a
view is hidden.
Implement private mode 2033 and the visibility query/report sequences.
Track conservative per-surface visibility, report every effective change
while enabled, and always answer explicit queries and mode enables. Keep
view visibility across terminal resets because it is owned by the host,
not terminal state.
Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019fa965-aa5f-7099-85b4-a9679d2c8bd3
C API callers could configure runtime scrollback limits but could not
read them back. Add terminal data keys for the primary screen byte and
line configurations.
Return GHOSTTY_NO_VALUE for unlimited limits and keep reads stable while
an alternate screen is active. Document the configured-value semantics
and add focused coverage for defaults, updates, and unlimited values.
Terminal construction previously accepted GhosttyTerminalOptions with
dimensions and one scrollback byte limit. Remove the options struct from
the ABI and make ghostty_terminal_new accept columns and rows directly.
Add byte and line limit options to ghostty_terminal_set and forward them
to the runtime Terminal setters. NULL removes a limit, while zero bytes
disables scrollback. Update type metadata, tests, and all API examples.
Scrollback limits were fixed when a terminal screen was initialized.
Move byte and line state and enforcement into a shared Limits type so
PageList can update both constraints after initialization and resize.
Add runtime setters to PageList and Terminal. Lowering a limit prunes
eligible history immediately, while zero bytes switches the primary
screen to no-scrollback behavior and clears retained history. Keep
alternate screens unchanged.
This adds a new config `scrollback-limit-lines` to limit scrollback by
lines instead of bytes. This also renames `scrollback-limit` to
`scrollback-limit-bytes` to make it clear what it does but we have a
compatibility entry so old configurations will continue to work, so its
not breaking.
**This is NOT exclusive to `scrollback-limit-bytes`**. When both are
set, then the _first limit reached_ is used. Since lines is affected by
viewport size and bytes are affected by entries (more styles, more
graphemes, etc.), they serve somewhat different purposes and it might be
useful to set both.
The default remains 50MB of bytes, unlimited lines.
This is not exposed to libghostty yet. I have that coming as a follow up
change.