Skip to content

Commit

Permalink
fix the panic caused by inccorect usage of lines
Browse files Browse the repository at this point in the history
  • Loading branch information
kyu08 committed Aug 25, 2024
1 parent ee20954 commit ba5fe39
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 27 deletions.
31 changes: 20 additions & 11 deletions viewport/viewport.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,17 +111,19 @@ func (m *Model) SetContent(s string) {
// maxYOffset returns the maximum possible value of the y-offset based on the
// viewport's content and set height.
func (m Model) maxYOffset() int {
linesHeight := countHeightBasedOnWidth(m.lines, m.Width)
linesHeight := len(linesToActualDisplayedLines(m.lines, m.Width))
return max(0, linesHeight-m.Height)
}

// visibleLines returns the lines that should currently be visible in the
// viewport.
func (m Model) visibleLines() (lines []string) {
if len(m.lines) > 0 {
actualDisplayedLines := linesToActualDisplayedLines(m.lines, m.Width)
top := max(0, m.YOffset)
bottom := clamp(m.YOffset+m.Height, top, len(m.lines))
lines = m.lines[top:bottom]
bottom := clamp(m.YOffset+m.Height, top, len(actualDisplayedLines))

lines = actualDisplayedLines[top:bottom]
}
return lines
}
Expand Down Expand Up @@ -192,7 +194,7 @@ func (m *Model) LineDown(n int) (lines []string) {
// Gather lines to send off for performance scrolling.
bottom := clamp(m.YOffset+m.Height, 0, len(m.lines))
top := clamp(m.YOffset+m.Height-n, 0, bottom)
return m.lines[top:bottom]
return linesToActualDisplayedLines(m.lines, m.Width)[top:bottom]
}

// LineUp moves the view down by the given number of lines. Returns the new
Expand All @@ -209,7 +211,7 @@ func (m *Model) LineUp(n int) (lines []string) {
// Gather lines to send off for performance scrolling.
top := max(0, m.YOffset)
bottom := clamp(m.YOffset+n, 0, m.maxYOffset())
return m.lines[top:bottom]
return linesToActualDisplayedLines(m.lines, m.Width)[top:bottom]
}

// TotalLineCount returns the total number of lines (both hidden and visible) within the viewport.
Expand Down Expand Up @@ -405,15 +407,22 @@ func max(a, b int) int {
return b
}

func countHeightBasedOnWidth(lines []string, width int) int {
h := 0
// linesToActualDisplayedLines converts lines to the actual lines considering window width.
// If there is a line that is longer than the width, it will be displayed in multiple lines.
// For more details: https://github.com/charmbracelet/bubbles/pull/578
// If you want to know actual behavior of this function, please check out the unit tests.
func linesToActualDisplayedLines(lines []string, width int) []string {
var actual []string
for _, line := range lines {
if len(line) <= width {
h++
actual = append(actual, line)
continue
}
h += int(math.Ceil(float64(len(line)) / float64(width)))
for width < len(line) {
actual = append(actual, line[:width])
line = line[width:]
}
actual = append(actual, line)
}

return h
return actual
}
38 changes: 22 additions & 16 deletions viewport/viewport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,37 +4,43 @@ import (
"testing"
)

func Test_countHeightBasedOnWidth(t *testing.T) {
func Test_linesToActualDisplayedLines(t *testing.T) {
t.Parallel()
tests := map[string]struct {
lines []string
width int
want int
want []string
}{
"Empty lines": {
"empty slice": {
lines: []string{},
width: 0,
want: 0,
width: 3,
want: []string{},
},
"Lines within width": {
lines: []string{"123", "123"},
width: 5,
want: 2,
"all lines are within width": {
lines: []string{"aaa", "bbb", "ccc"},
width: 3,
want: []string{"aaa", "bbb", "ccc"},
},
"Lines over width": {
lines: []string{"1234567890", "123"},
width: 5,
want: 3,
"some lines exceeds width": {
lines: []string{"aaaaaa", "bbbbbbbb", "ccc"},
width: 3,
want: []string{"aaa", "aaa", "bbb", "bbb", "bb", "ccc"},
},
}

for name, tt := range tests {
tt := tt
t.Run(name, func(t *testing.T) {
t.Parallel()
got := countHeightBasedOnWidth(tt.lines, tt.width)
if tt.want != got {
t.Errorf("expected %v, got %v", tt.want, got)
got := linesToActualDisplayedLines(tt.lines, tt.width)

if len(got) != len(tt.want) {
t.Errorf("expected len is %d but got %d", len(tt.want), len(got))
}
for i := range tt.want {
if tt.want[i] != got[i] {
t.Errorf("expected %s but got %s", tt.want[i], got[i])
}
}
})
}
Expand Down

0 comments on commit ba5fe39

Please sign in to comment.