ultraviolet.Buffer.Resize (buffer.go) truncates/drops cells on shrink with no reflow and nothing preserved:
func (b *Buffer) Resize(width int, height int) {
...
} else if width < curWidth {
for i := range b.Lines {
b.Lines[i] = b.Lines[i][:width] // cells beyond width: gone
}
}
...
} else if height < len(b.Lines) {
b.Lines = b.Lines[:height] // rows beyond height: gone
}
}
Consequences downstream in charmbracelet/x/vt's Emulator.Resize (which calls straight into this for both the main and alt screens):
- Shrinking width truncates every row to the new width; the trailing cells are discarded, not wrapped onto a new row and not pushed to scrollback.
- Shrinking height keeps rows
[0, newHeight) and drops [newHeight, oldHeight), i.e. it drops the bottom rows, not the top ones a terminal would normally scroll into history.
- Growing back afterwards only appends blank cells / blank rows, there's nothing left to restore from, so previously-visible content never comes back even though there's room for it again.
Repro
Using vt.NewEmulator directly (no PTY needed):
term := vt.NewEmulator(10, 1)
term.WriteString("0123456789")
term.Resize(5, 1) // "56789" is now gone
term.Resize(10, 1) // still gone, row is "01234 "
Expected
At minimum, don't silently discard already-rendered content, e.g. push truncated/dropped cells to the emulator's scrollback (same as Screen.ClearWithScrollback already does on erase) so it's recoverable via scrollback even if live reflow is out of scope. Ideally, real reflow: recompute line wrapping from a logical-line model in both directions, the way terminals like Windows Terminal/iTerm2/kitty do.
Where I hit this
Building an SSH-in-a-TUI pane on top of x/vt (https://github.com/muhamm-ad/bubble-ssh), resizing the pane (e.g. resizing the host terminal window) permanently loses on-screen content that falls outside the new size, and growing back doesn't recover it.
Versions
github.com/charmbracelet/ultraviolet, confirmed present in v0.0.0-20260703014108-f5a850f9c2b7 and still present in the latest available commit as of 2026-09-07, v0.0.0-20260906173415-0277a179edd9.
github.com/charmbracelet/x/vt, same, v0.0.0-20260730164118-7e2d3e6c5238 through v0.0.0-20260906004030-3986e9119cf9.
ultraviolet.Buffer.Resize(buffer.go) truncates/drops cells on shrink with no reflow and nothing preserved:Consequences downstream in
charmbracelet/x/vt'sEmulator.Resize(which calls straight into this for both the main and alt screens):[0, newHeight)and drops[newHeight, oldHeight), i.e. it drops the bottom rows, not the top ones a terminal would normally scroll into history.Repro
Using
vt.NewEmulatordirectly (no PTY needed):Expected
At minimum, don't silently discard already-rendered content, e.g. push truncated/dropped cells to the emulator's scrollback (same as
Screen.ClearWithScrollbackalready does on erase) so it's recoverable via scrollback even if live reflow is out of scope. Ideally, real reflow: recompute line wrapping from a logical-line model in both directions, the way terminals like Windows Terminal/iTerm2/kitty do.Where I hit this
Building an SSH-in-a-TUI pane on top of
x/vt(https://github.com/muhamm-ad/bubble-ssh), resizing the pane (e.g. resizing the host terminal window) permanently loses on-screen content that falls outside the new size, and growing back doesn't recover it.Versions
github.com/charmbracelet/ultraviolet, confirmed present inv0.0.0-20260703014108-f5a850f9c2b7and still present in the latest available commit as of 2026-09-07,v0.0.0-20260906173415-0277a179edd9.github.com/charmbracelet/x/vt, same,v0.0.0-20260730164118-7e2d3e6c5238throughv0.0.0-20260906004030-3986e9119cf9.