Skip to content
Merged
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
15 changes: 15 additions & 0 deletions cmd/display/tty.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,21 @@ func (w *ttyWriter) printWithDimensions(terminalWidth, terminalHeight int) {
}
}

// pad timers so they all have the same visible width
for i := range lines {
l := &lines[i]
if l.timer == "" {
continue
}
timerWidth := utf8.RuneCountInString(l.timer)
if timerWidth < timerLen {
// Left-pad so the timer's right edge stays aligned on the terminal.
// This also prevents stale suffix characters from visually “sticking”
// when a previously-rendered timer was wider (e.g. "10.6s" -> "0.0s").
l.timer = strings.Repeat(" ", timerLen-timerWidth) + l.timer
}
}

// shorten details/taskID to fit terminal width
w.adjustLineWidth(lines, timerLen, terminalWidth)

Expand Down
61 changes: 61 additions & 0 deletions cmd/display/tty_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,67 @@ func TestPrintWithDimensions_PulledAndPullingWithLongIDs(t *testing.T) {
}
}

func TestPrintWithDimensions_TimerIsRightAligned(t *testing.T) {
w, buf := newTestWriter()

base := time.Unix(0, 0)

// Long timer: "10.6s" (length 5)
longTask := &task{
ID: "task-long",
parents: make(map[string]struct{}),
startTime: base,
endTime: base.Add(10*time.Second + 600*time.Millisecond),
text: "Pulled",
status: api.Done,
spinner: NewSpinner(),
}
longTask.spinner.Stop()
w.tasks[longTask.ID] = longTask
w.ids = append(w.ids, longTask.ID)

// Short timer: "0.0s" (length 4)
shortTask := &task{
ID: "task-short",
parents: make(map[string]struct{}),
startTime: base,
endTime: base,
text: "Pulled",
status: api.Done,
spinner: NewSpinner(),
}
shortTask.spinner.Stop()
w.tasks[shortTask.ID] = shortTask
w.ids = append(w.ids, shortTask.ID)

terminalWidth := 80
w.printWithDimensions(terminalWidth, 24)

// Strip ANSI codes from output and split by newline
stripped := stripAnsi(buf.String())
lines := strings.Split(stripped, "\n")

var nonEmptyLines []string
for _, line := range lines {
if strings.TrimSpace(line) != "" {
nonEmptyLines = append(nonEmptyLines, line)
}
}

// Find the line containing the shorter timer.
var shortLine string
for _, line := range nonEmptyLines {
if strings.Contains(line, "0.0s") {
shortLine = line
break
}
}
assert.Assert(t, shortLine != "", "expected to find a rendered line containing \"0.0s\"")
assert.Assert(t, strings.HasSuffix(shortLine, "0.0s"),
"short timer should be left-padded (no trailing spaces after the timer); got: %q",
shortLine)
}

func TestLenAnsi(t *testing.T) {
testCases := []struct {
input string
Expand Down
Loading