Symptoms
When the sticky zone (status line + attachment line + preview + editor) exceeds the terminal height, the rendering corrupts the scrollback history. The sticky content duplicates on screen with empty gaps between copies, and history lines get permanently destroyed.
Reproduction:
- Shrink the terminal height (or zoom in significantly)
- Have enough sticky content to exceed the viewport -- e.g. multi-line editor input, attachment line with preview, status line
- Observe: sticky zone renders past the top of the viewport, cursor positioning breaks, history corrupts
Also reproducible by dragging the VS Code terminal slider to minimum height (bottoms out at 2 rows).
Expected Behaviour
The sticky zone should never render more lines than the terminal height. When the editor content exceeds the viewport, only the visible portion around the cursor should be rendered -- like a scrollable window:
If cursor is near the bottom: If cursor moves to the top:
--------------------- ---------------------
| | | [cursor] |
| Not rendered | | |
| | | |
|-------------------| | |
| | | |
| | |-------------------|
| | | |
| | | Not rendered |
| [cursor] | | |
--------------------- ---------------------
The scroll offset follows the cursor. Content above or below the viewport simply isn't rendered.
Edge Case: Minimum terminal size
Tested VS Code terminal resize behaviour:
cols=235 rows=7
cols=235 rows=5
cols=235 rows=4
cols=235 rows=3
cols=235 rows=2 <- VS Code minimum
cols=235 rows=3
cols=235 rows=7
VS Code bottoms out at 2 rows (doesn't reach 0), but 0 and 1 should still be guarded:
- 0 rows -- freeze rendering entirely (pause). Don't write anything. Resume when rows >= minimum.
- 1 row -- same, not enough space for status + editor.
- 2 rows -- minimum viable: status line + editor line. No attachments, no preview.
If rows < 2, pause rendering. Otherwise, render what fits using the height budget.
Guidance
The hard parts are already solved (#136 width math, #139 string-width, #144 wrap-aware cursor). The viewport is one scroll offset number:
- Track a
scrollOffset (terminal row index of the top of the visible portion)
- When cursor row < scrollOffset: scroll up (
scrollOffset = cursorRow)
- When cursor row >= scrollOffset + viewportHeight: scroll down (
scrollOffset = cursorRow - viewportHeight + 1)
- In
buildSticky(), only render editor lines within [scrollOffset, scrollOffset + availableRows)
availableRows = process.stdout.rows minus the non-editor sticky components (status line, attachment line, preview).
The minimum terminal size guard is the degenerate case of this: when availableRows <= 0, don't render the editor (or anything below the guard threshold).
Key locations
terminal.ts buildSticky() -- needs scroll offset, viewport slicing of editor lines, and minimum size guard
terminal.ts clearStickyZone() -- cursor math currently breaks when stickyLineCount > rows; viewport cap prevents this entirely
Symptoms
When the sticky zone (status line + attachment line + preview + editor) exceeds the terminal height, the rendering corrupts the scrollback history. The sticky content duplicates on screen with empty gaps between copies, and history lines get permanently destroyed.
Reproduction:
Also reproducible by dragging the VS Code terminal slider to minimum height (bottoms out at 2 rows).
Expected Behaviour
The sticky zone should never render more lines than the terminal height. When the editor content exceeds the viewport, only the visible portion around the cursor should be rendered -- like a scrollable window:
The scroll offset follows the cursor. Content above or below the viewport simply isn't rendered.
Edge Case: Minimum terminal size
Tested VS Code terminal resize behaviour:
VS Code bottoms out at 2 rows (doesn't reach 0), but 0 and 1 should still be guarded:
If
rows < 2, pause rendering. Otherwise, render what fits using the height budget.Guidance
The hard parts are already solved (#136 width math, #139 string-width, #144 wrap-aware cursor). The viewport is one scroll offset number:
scrollOffset(terminal row index of the top of the visible portion)scrollOffset = cursorRow)scrollOffset = cursorRow - viewportHeight + 1)buildSticky(), only render editor lines within[scrollOffset, scrollOffset + availableRows)availableRows=process.stdout.rowsminus the non-editor sticky components (status line, attachment line, preview).The minimum terminal size guard is the degenerate case of this: when
availableRows <= 0, don't render the editor (or anything below the guard threshold).Key locations
terminal.tsbuildSticky()-- needs scroll offset, viewport slicing of editor lines, and minimum size guardterminal.tsclearStickyZone()-- cursor math currently breaks whenstickyLineCount > rows; viewport cap prevents this entirely