Files
oh-my-pi/packages
Leo Kimandcan1357 767cff9313 fix(tui): bound viewportRefresh to visible window + preserve scrollback
The `viewportRefresh()` helper (added by 498e9c2cc, kept across the
erase-after-content refactor in cdbf07a24) claimed to repaint only the
visible viewport but actually wrote every line in `newLines` from the top
of the screen. On terminals without alt-screen — which is OMP's default
on the main screen — that pushed `newLines.length - height` rows into
scrollback on every refresh.

With `PI_DEBUG_REDRAW=1` on a 24-row terminal and a 52-line transcript
the path fired roughly every 30 ms while streaming markdown:

  [..] fullRender: firstChanged < viewportTop (5 < 28) — viewport
  refresh (prev=52, new=52, height=24)
  [..] same, 33 ms later
  [..] same, 35 ms later
  ...

Users saw historical prompt frames (`╰ ㅁㄴ`, `╰ 바ㅇㄱㅁ`, `╰ 바방금 ...`)
stacking up in scrollback even though the visible viewport rendered
correctly. The Korean IME bracketed-paste / display fix from 37ada6c54
is genuinely independent — the residue was always the viewportRefresh
path quietly pushing whole-transcript snapshots into scrollback.

This change:

  * Anchors the repaint window to the last `height` content rows. The
    `\x1b[H` + line-write loop now never exceeds the visible area, so
    the repaint itself can never scroll.
  * Pre-scrolls only the delta when the bottom-anchored visible window
    slid forward since the last render. The differential-append path
    already does the same — losing scrolled-off content silently would
    break `Ctrl+B [` / mouse-wheel scrollback during streaming.
  * Truncates lines wider than `width` (matching the differential
    path's pattern, including the `LINE_TERMINATOR`/`SEGMENT_RESET`
    re-append). Wrap-around would otherwise push repaint content past
    the bottom row and re-introduce the same unwanted scroll.
  * Enriches the `PI_DEBUG_REDRAW` log line with `visibleStart..end`
    and `visibleCount/newLines.length` so future repeats of this kind
    of regression are obvious in `~/.omp/agent/omp-debug.log`.

Tests:

  * New `render-regressions.test.ts` case (scrollback integrity):
    height-6 terminal, 30-line transcript, 30 above-viewport mutations.
    Asserts (1) scrollback growth stays under 50 rows (pre-fix was
    ~720), and (2) above-viewport marker values that only ever existed
    above the visible window never appear in scrollback.
  * Tightened the existing `viewportRefresh` case in
    `render-no-2k-flash.test.ts`: now also asserts the captured frames
    do NOT contain the above-viewport mutation token and DO contain
    the visible-window's bottom line.
  * Re-passes the pre-existing `retains append history when offscreen
    header changes during overflow growth` test which had been failing
    against both the broken viewportRefresh (received 17 lines per
    marker) and a naive non-scrolling fix (received 0). The new
    pre-scroll branch puts it back at exactly 1.

Full TUI suite: 393/393 pass (was 392/393 before, with the one failure
being the offscreen-header test described above).
2026-05-25 12:08:36 +02:00
..
2026-05-22 17:48:11 +09:00
2026-05-22 17:48:11 +09:00
2026-05-22 17:48:11 +09:00