Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions vt/scrollback.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,12 +115,24 @@ func (s *Scrollback) CellAt(x, y int) *uv.Cell {
func trimTrailingEmptyCells(line uv.Line) uv.Line {
lastNonEmpty := -1
for i := len(line) - 1; i >= 0; i-- {
c := &line[i]
if !c.IsZero() && !c.Equal(&uv.EmptyCell) {
if !isTrailingScrollbackBlank(&line[i]) {
lastNonEmpty = i
break
}
}

return line[:lastNonEmpty+1]
}

func isTrailingScrollbackBlank(cell *uv.Cell) bool {
if cell == nil {
return true
}
if cell.IsZero() || cell.Equal(&uv.EmptyCell) {
Comment on lines +127 to +131

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

Suggested 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) {

return true
}
Comment on lines +126 to +133

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 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.

if cell.Width == 0 {
return false
}
return cell.Content == "" || cell.Content == " "
}
27 changes: 27 additions & 0 deletions vt/scrollback_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package vt

import (
"image/color"
"testing"

uv "github.com/charmbracelet/ultraviolet"
)

func TestScrollback(t *testing.T) {
Expand Down Expand Up @@ -68,6 +71,30 @@ func TestScrollback(t *testing.T) {
}
})

t.Run("trims trailing styled blanks", func(t *testing.T) {
sb := NewScrollback(1)
line := make(uv.Line, 12)
for i := range line {
line[i] = uv.Cell{
Content: " ",
Style: uv.Style{Bg: color.RGBA{R: 24, G: 28, B: 36, A: 255}},
Width: 1,
}
}
for i, r := range "prompt" {
line[i] = uv.Cell{Content: string(r), Width: 1}
}

sb.Push(line)

if got := len(sb.Line(0)); got != len("prompt") {
t.Fatalf("stored line length = %d, want %d", got, len("prompt"))
}
if got := sb.Line(0).String(); got != "prompt" {
t.Fatalf("stored line text = %q, want %q", got, "prompt")
}
})

t.Run("clear scrollback", func(t *testing.T) {
e := NewEmulator(20, 5)

Expand Down
Loading