LAB-1803: Trim styled blanks in vt scrollback - #15
Conversation
|
Claude finished @cweill's task in 2m 10s —— View job PR Review: LAB-1803: Trim styled blanks in vt scrollback
SummaryThe change extracts The logic is correct. A few observations below, none blocking. Observations1. Continuation cell test is missing (non-blocking) The PR description calls out "Preserve width-0 continuation cells" as a stated invariant, but there is no test exercising it. A line like 2. Nil check in
3. Styled-space trimming is broader than background-only (intentional, non-blocking) The check 4. A full-width space (e.g., LGTM |
Greptile SummaryThis PR narrows the definition of a "trimmable" trailing cell in the scrollback ring: previously only zero-value cells or
Confidence Score: 4/5Safe to merge; the change is tightly scoped to the scrollback trim path and does not touch the live screen buffer or any public API. The core logic is correct and the regression test exercises the new path directly. The dead nil guard and the narrower-than-described Width==0 protection do not affect correctness or introduce regressions. vt/scrollback.go — the ordering of guards in isTrailingScrollbackBlank is worth a second look to confirm zero-value continuation cells at trailing positions are handled as intended. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["trimTrailingEmptyCells(line)"] --> B["Scan from right to left"]
B --> C{"isTrailingScrollbackBlank(cell)"}
C --> D{"cell == nil?"}
D -- yes --> E["return true (blank)"]
D -- no --> F{"IsZero() or Equal(EmptyCell)?"}
F -- yes --> G["return true (blank)"]
F -- no --> H{"cell.Width == 0?"}
H -- yes --> I["return false (preserve continuation)"]
H -- no --> J{"Content == '' or ' '?"}
J -- yes --> K["return true (styled blank — NEW)"]
J -- no --> L["return false (non-blank content)"]
C -- blank --> M["continue scan leftward"]
C -- non-blank --> N["set lastNonEmpty = i, break"]
N --> O["return line[:lastNonEmpty+1]"]
Reviews (1): Last reviewed commit: "LAB-1803: Trim trailing styled blanks in..." | Re-trigger Greptile |
| func isTrailingScrollbackBlank(cell *uv.Cell) bool { | ||
| if cell == nil { | ||
| return true | ||
| } | ||
| if cell.IsZero() || cell.Equal(&uv.EmptyCell) { |
There was a problem hiding this comment.
The
nil check here is dead code. isTrailingScrollbackBlank is only ever called with &line[i] inside trimTrailingEmptyCells, where i is a valid slice index, so the pointer is always non-nil. The branch can be removed without any behavioural change.
| func isTrailingScrollbackBlank(cell *uv.Cell) bool { | |
| if cell == nil { | |
| return true | |
| } | |
| if cell.IsZero() || cell.Equal(&uv.EmptyCell) { | |
| func isTrailingScrollbackBlank(cell *uv.Cell) bool { | |
| if cell.IsZero() || cell.Equal(&uv.EmptyCell) { |
|
|
||
| func isTrailingScrollbackBlank(cell *uv.Cell) bool { | ||
| if cell == nil { | ||
| return true | ||
| } | ||
| if cell.IsZero() || cell.Equal(&uv.EmptyCell) { | ||
| return true | ||
| } |
There was a problem hiding this comment.
Width == 0 guard silently unreachable for zero-value continuation cells
The PR description states "Preserve width-0 continuation cells so wide-character layout state is not discarded," but a zero-value continuation cell (Width: 0, Content: "", Style: {}) satisfies IsZero() and returns true before the Width == 0 guard is ever reached. Only a non-zero continuation cell (e.g. one carrying inherited style) is actually protected. A trailing zero-value continuation cell was already trimmed before this PR, so there is no regression, but the protection is narrower than the PR description implies. Worth a clarifying code comment if zero-value continuations at trailing positions are expected to be preserved too.
## Motivation LAB-1803's live heap profile reproduced the reported post-LAB-1750 shape. During verification on 2026-05-13, a fresh server heap profile for the installed `d266004` build showed 676.69 MB in-use with `vt.cloneLineInto` retaining 411.63 MB / 60.83%; the issue artifact from 2026-05-13 showed the same post-LAB-1750 shape at 507.70 MB with `cloneLineInto` at 298.41 MB / 58.78%. A pre-LAB-1750 heap artifact from 2026-05-12 showed 300.18 MB total with `cloneLineInto` at 91.16 MB / 30.37%. `go tool pprof -peek cloneLineInto` pointed at `vt.(*scrollbackRing).push`, not an amux snapshot cache, so the fix targets the vt scrollback clone input instead of adding amux-side memoization. ## Summary - Add a resize-preservation benchmark that writes full-width styled scrollback rows before shrinking and widening the emulator. - Pin `github.com/charmbracelet/x/vt` to weill-labs/x commit `fc372e8574ca`, which trims trailing styled blank cells before cloning rows into scrollback. - Keep `cloneLineInto`'s API unchanged; the fork-side change is tracked in weill-labs/x#15. - LAB-1794 is already fixed on fork `main` by `6adbf8184605`, so this PR pins a later fork commit rather than cherry-picking the soft-wrap API restoration here. ## Baseline numbers Hardware: AMD EPYC-Milan Processor, Linux amd64. | Measurement | Before | After | | --- | ---: | ---: | | `BenchmarkVTEmulatorResizePreservationStyledScrollback` bytes/op | ~14.00 MB/op | ~10.16 MB/op | | `BenchmarkVTEmulatorResizePreservationStyledScrollback` allocs/op | 1518-1519 | 1506-1507 | | Styled workload heap in-use | 112.13 MB | 48.10 MB | | Styled workload `vt.cloneLineInto` in-use | 67.62 MB / 60.30% | 5.00 MB / 10.41% | ## Testing - `go test ./internal/mux -run '^$' -bench BenchmarkVTEmulatorResizePreservationStyledScrollback -benchmem -count=5` - `go test ./internal/mux -run 'TestRenderWithCursorRoundTripPreserves(SoftWrapForResize|WrappedTrailingSpaces|BlankWrappedSpacesAtCursor|BlankWrappedRowsBeforeHardNewline|PhantomCursorForResize)|TestVTEmulatorResizeShrink' -count=100` - `go test -race ./internal/mux -timeout 120s -count=10` - `go test ./... -timeout 180s` - `go test ./test -run '^TestSwapForward$' -timeout 120s -count=1` after one `go test ./... -timeout 120s` run hit that integration timing flake. - In `weill-labs/x/vt`: `go test -run 'TestScrollback/trims_trailing_styled_blanks' -count=100` - In `weill-labs/x/vt`: `go test -run TestScrollback -count=1` - In `weill-labs/x/vt`: `go test ./...` - `go test -race ./... -timeout 120s -count=10` was attempted and currently fails outside the touched package set in timing-heavy tests/packages (`internal/cli`, `internal/client`, `internal/dialutil`, `internal/remote`, `internal/server`, and `test`). `internal/mux` passed the same race/count loop. ## Review focus - Whether the fork-side scrollback trim semantics are the right layer versus amux memoization; profiles showed retained bytes in vt scrollback ring storage. - Confirming LAB-1750 preserve-output behavior stays intact; the preserve-output regression tests re-pass with `-count=100`. - Whether to merge weill-labs/x#15 first and then update this PR to the merged fork commit. Closes LAB-1803. --------- Co-authored-by: Orca worker-02 <worker-02@orca.local>
Motivation
Amux LAB-1803 heap profiles showed
vt.cloneLineIntoretaining the majority of server heap when scrollback contains full-width styled blank padding. The retained bytes were under the vt scrollback ring push path, so trimming scrollback rows before cloning reduces retained cells without changing the public API.Summary
Testing
go test -run 'TestScrollback/trims_trailing_styled_blanks' -count=100go test -run TestScrollback -count=1go test ./...Review focus
Content == ""orContent == " ".Refs LAB-1803.