Stop replaying <Static> output on full-clear frames - #1005
Conversation
7d2c075 to
62339cc
Compare
Since the full-clear path started preserving scrollback (vadimdemedes#994), it still rewrote the accumulated `<Static>` output after every clear. Each overflowing rerender therefore stamped another copy of the whole static history into scrollback and rewrote it to the terminal. Erase only the previous frame instead. When it filled the viewport, home + erase-down already erases exactly that frame. When it did not (a small frame growing past the viewport), erase it relative to the cursor so `<Static>` and console rows still in the viewport survive and scroll into history naturally. `fullStaticOutput` is now only accumulated in debug mode; a boolean keeps the unmount guard from vadimdemedes#397.
Dropping the `fullStaticOutput` replay also dropped the only write of the current frame's `staticOutput` on the full-clear path, so any `<Static>` item added while the live region overflowed the viewport never reached the terminal. Write it once, ahead of the frame, in both erase branches. Test: `<Static>` items added while the frame overflows are written once, for standard and incremental rendering. Fails without the fix.
62339cc to
6c138d5
Compare
|
Could we keep replaying the accumulated This works on the primary screen because previously rendered static lines remain in scrollback. The alternate screen has no scrollback, though. If the live frame overflows and later shrinks, I think the simplest fix is to keep accumulating and replaying the full static output only when the alternate screen is active, while retaining the new write-once behavior for the primary screen. Otherwise we would need to explicitly document |
The alternate screen has no scrollback, so <Static> rows that a full clear erases or an overflowing frame pushes off the top are gone for good. Keep accumulating the static output there and replay it ahead of the frame on every full clear. The primary screen still writes each item once.
|
Yes, that was a regression on the alternate screen. Fixed by keeping the accumulation and replay only when Added two tests for standard and incremental rendering: the frame grows past a 5-row viewport and shrinks back with three static items, asserting the reconstructed screen is One pre-existing gap, not from this PR: resuming from suspend re-enters the alternate screen and redraws only the frame, so static rows are lost until the next full clear. Happy to do that as a follow-up if you want it. |
馃憤 |
Follow-up to #994. Since the full-clear path preserves scrollback, it still rewrites the accumulated
<Static>output (fullStaticOutput) after every clear. Each overflowing rerender therefore stamps another copy of the whole static history into scrollback and rewrites all of it to the terminal. This is the "duplicate stamping" described in #990, and it is not in a release yet (7.1.1 predates #994).Reproduced by running a fixture in a pty and replaying the bytes through xterm.js headless (8 rows, a
<Static>with 3 items, a 12-line live region, 3 rerenders): master leaves 5 copies of the static lines in the terminal buffer; with this change, one.Change
The full clear now erases only the previous live frame and never replays static output:
lastOutputHeight >= viewportRows),homeAndEraseDownalready erases exactly that frame, and it keeps the absolute erase that Windows consoles need (Ink 7 rendering broken on all Windows terminals聽#969).log.clear()instead, so<Static>and console rows that are still in the viewport survive and scroll into history as the new frame is written.fullStaticOutputis only accumulated in debug mode now. A boolean keeps the unmount guard from Static + exit results in broken/mismatched output聽#397.<Static>output from the current frame is still written once, ahead of the frame, in both erase branches. The full clear previously dropped it.Behavior change
When the live region shrinks from fullscreen back to a small frame, the frame is written at the top of an empty viewport; the static log is one page up in scrollback. Before, the replay made the viewport look continuous (static tail + frame) at the cost of duplicating the log. If the continuous look is preferred, replaying only the last
rows - frameHeightstatic lines would keep it without scrolling anything into history, at the cost of one bounded duplicate per shrink. Happy to switch to that.Tests
full clears do not replay <Static> output into scrollbackandgrowing into an overflowing frame keeps <Static> rows that are still in the viewport, plus<Static> items added while the frame overflows are written once, for standard and incremental rendering, usingreconstructTerminalLines. All fail on master. The existing #450, #935 and #969 tests still pass.