feat(vt): add Scrollback.Render() for retired-line snapshots#852
Open
manusa wants to merge 2 commits into
Open
feat(vt): add Scrollback.Render() for retired-line snapshots#852manusa wants to merge 2 commits into
manusa wants to merge 2 commits into
Conversation
The visible-grid Render() omits scrolled-off lines by definition, which forces consumers (terminal multiplexers, late-attach rehydrators, byte- stream snapshotters) to reach into the cell-walk APIs and re-derive the SGR pen-diff / hyperlink reset rules that renderLine already encodes. Add Scrollback.Render() mirroring (*Buffer).Render(): delegates to uv.Lines(s.lines).Render() so the encoding stays in lock-step with the live grid. Lines are LF-separated with no trailing LF, matching the output of Emulator.Render(). Signed-off-by: Marc Nuri <marc@marcnuri.com>
Callers (terminal multiplexers) substitute LF -> CRLF when targeting receivers without an onlcr translation. Asserting absence of CR in the render output makes a future change that emits CR fail loudly instead of silently double-CR'ing downstream. Signed-off-by: Marc Nuri <marc@marcnuri.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
(*Scrollback).Render() string— a new method onvt.Scrollbackthat renders the retired-line buffer as a styled string with all the required attributes and styles, mirroring(*Buffer).Render()(inultraviolet) and(*Emulator).Render()on the live grid.Implementation is a one-line delegation to the existing public renderer:
Why
vt.ScrollbackexposesPush,Len,Lines,Line,CellAtbut noRender(). Consumers that want to snapshot retired lines as a styled byte stream (terminal multiplexers, late-attach rehydrators, debug tools) currently have to walk cells viaCellAt(x, y)and re-implement vt's internalrenderLineSGR-pen-diff / hyperlink reset logic outside the package. That's fragile — every future fix to pen-reset edge cases, wide-char placeholder handling, hyperlink escape rules, or new cell attributes silently bypasses the external implementation.This patch closes that gap by reusing
Lines.Render()fromultraviolet, the same rendererBuffer.Render()already delegates to. Lines stay LF-separated with no trailing LF — same shape as the live grid'sRender().The motivating consumer is ai-beacon, a terminal multiplexer that needs to deliver retired-line content to late-attaching browser clients so xterm.js's scrollback shows what the agent emitted before attach. Without
Scrollback.Render()the multiplexer either re-implementsrenderLine(the maintenance hazard above) or ships a vendored fork of vt — neither great.Steps to showcase
Before — the only way to render retired lines was to walk cells:
After — one call, encoding stays in lock-step with
Buffer.Render():Tests
Five subtests added under
TestScrollback:Render returns empty string when scrollback is empty— emptyScrollback, returns"".Render returns empty string on nil receiver— nil-safe.Render emits content from scrolled-off lines— content is preserved through retirement → render.Render preserves order from oldest to newest— earliest line appears before latest in the output.Render separates lines with newline and no trailing newline— pins the LF-only contract (no CR, no trailing LF), matchingLines.RenderandBuffer.Renderupstream.All existing
vttests continue to pass.Notes for maintainers
CONTRIBUTING.md.I'd usually open a Discussion first per the new-feature workflow, but the patch is minimal (~6 LOC of production code, all delegating to existing public API) and addresses an obvious gap relative to
Buffer.Render(). Happy to convert this into a Discussion thread instead if you'd prefer — just let me know.Confirmed.