Fix bug where performance rendering could render one line too many

This commit is contained in:
Christian Rocha 2021-09-16 11:56:56 -04:00
parent 8c03905dbe
commit 0ac5ecdf81

View File

@ -21,7 +21,7 @@ type Model struct {
YOffset int YOffset int
// YPosition is the position of the viewport in relation to the terminal // YPosition is the position of the viewport in relation to the terminal
// window. It's used in high performance rendering. // window. It's used in high performance rendering only.
YPosition int YPosition int
// HighPerformanceRendering bypasses the normal Bubble Tea renderer to // HighPerformanceRendering bypasses the normal Bubble Tea renderer to
@ -69,7 +69,7 @@ func (m Model) ScrollPercent() float64 {
// SetContent set the pager's text content. For high performance rendering the // SetContent set the pager's text content. For high performance rendering the
// Sync command should also be called. // Sync command should also be called.
func (m *Model) SetContent(s string) { func (m *Model) SetContent(s string) {
s = strings.Replace(s, "\r\n", "\n", -1) // normalize line endings s = strings.ReplaceAll(s, "\r\n", "\n") // normalize line endings
m.lines = strings.Split(s, "\n") m.lines = strings.Split(s, "\n")
if m.YOffset > len(m.lines)-1 { if m.YOffset > len(m.lines)-1 {
@ -77,7 +77,8 @@ func (m *Model) SetContent(s string) {
} }
} }
// Return the lines that should currently be visible in the viewport. // visibleLines returns the lines that should currently be visible in the
// viewport.
func (m Model) visibleLines() (lines []string) { func (m Model) visibleLines() (lines []string) {
if len(m.lines) > 0 { if len(m.lines) > 0 {
top := max(0, m.YOffset) top := max(0, m.YOffset)
@ -87,6 +88,16 @@ func (m Model) visibleLines() (lines []string) {
return lines return lines
} }
// scrollArea returns the scrollable boundaries for high performance rendering.
func (m Model) scrollArea() (top, bottom int) {
top = max(0, m.YPosition)
bottom = max(top, top+m.Height)
if top > 0 && bottom > top {
bottom--
}
return top, bottom
}
// SetYOffset sets the Y offset. // SetYOffset sets the Y offset.
func (m *Model) SetYOffset(n int) { func (m *Model) SetYOffset(n int) {
m.YOffset = clamp(n, 0, len(m.lines)-m.Height) m.YOffset = clamp(n, 0, len(m.lines)-m.Height)
@ -186,17 +197,8 @@ func Sync(m Model) tea.Cmd {
if len(m.lines) == 0 { if len(m.lines) == 0 {
return nil return nil
} }
top, bottom := m.scrollArea()
// TODO: we should probably use m.visibleLines() rather than these two return tea.SyncScrollArea(m.visibleLines(), top, bottom)
// expressions.
top := max(m.YOffset, 0)
bottom := clamp(m.YOffset+m.Height, 0, len(m.lines)-1)
return tea.SyncScrollArea(
m.lines[top:bottom],
m.YPosition,
m.YPosition+m.Height,
)
} }
// ViewDown is a high performance command that moves the viewport up by a given // ViewDown is a high performance command that moves the viewport up by a given
@ -210,7 +212,8 @@ func ViewDown(m Model, lines []string) tea.Cmd {
if len(lines) == 0 { if len(lines) == 0 {
return nil return nil
} }
return tea.ScrollDown(lines, m.YPosition, m.YPosition+m.Height) top, bottom := m.scrollArea()
return tea.ScrollDown(lines, top, bottom)
} }
// ViewUp is a high performance command the moves the viewport down by a given // ViewUp is a high performance command the moves the viewport down by a given
@ -220,7 +223,8 @@ func ViewUp(m Model, lines []string) tea.Cmd {
if len(lines) == 0 { if len(lines) == 0 {
return nil return nil
} }
return tea.ScrollUp(lines, m.YPosition, m.YPosition+m.Height) top, bottom := m.scrollArea()
return tea.ScrollUp(lines, top, bottom)
} }
// UPDATE // UPDATE