mirror of
https://github.com/zoriya/bubbles.git
synced 2026-08-05 04:36:07 +00:00
fix(viewport): normalize method names (#763)
* Reapply "fix(viewport): normalize method names"
This reverts commit f2434c374b.
* test: fixes
* fix: lint
* fix: disable horizontal scroll on v1
it might be a breaking change.
let's enable it by default on v2, and remove the deprecated methods as
well.
cc/ @meowgorithm
* fix: simplify
This commit is contained in:
@@ -857,9 +857,9 @@ func (m *Model) repositionView() {
|
||||
maximum := minimum + m.viewport.Height - 1
|
||||
|
||||
if row := m.cursorLineNumber(); row < minimum {
|
||||
m.viewport.LineUp(minimum - row)
|
||||
m.viewport.ScrollUp(minimum - row)
|
||||
} else if row > maximum {
|
||||
m.viewport.LineDown(row - maximum)
|
||||
m.viewport.ScrollDown(row - maximum)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestVerticalScrolling(t *testing.T) {
|
||||
"the text area.",
|
||||
}
|
||||
for _, line := range lines {
|
||||
textarea.viewport.LineDown(1)
|
||||
textarea.viewport.ScrollDown(1)
|
||||
view = textarea.View()
|
||||
if !strings.Contains(view, line) {
|
||||
t.Log(view)
|
||||
|
||||
+92
-57
@@ -10,10 +10,6 @@ import (
|
||||
"github.com/charmbracelet/x/ansi"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultHorizontalStep = 6
|
||||
)
|
||||
|
||||
// New returns a new model with the given width and height as well as default
|
||||
// key mappings.
|
||||
func New(width, height int) (m Model) {
|
||||
@@ -76,7 +72,6 @@ func (m *Model) setInitialValues() {
|
||||
m.MouseWheelEnabled = true
|
||||
m.MouseWheelDelta = 3
|
||||
m.initialized = true
|
||||
m.horizontalStep = defaultHorizontalStep
|
||||
}
|
||||
|
||||
// Init exists to satisfy the tea.Model interface for composability purposes.
|
||||
@@ -168,7 +163,7 @@ func (m Model) visibleLines() (lines []string) {
|
||||
|
||||
// scrollArea returns the scrollable boundaries for high performance rendering.
|
||||
//
|
||||
// XXX: high performance rendering is deprecated in Bubble Tea.
|
||||
// Deprecated: high performance rendering is deprecated in Bubble Tea.
|
||||
func (m Model) scrollArea() (top, bottom int) {
|
||||
top = max(0, m.YPosition)
|
||||
bottom = max(top, top+m.Height)
|
||||
@@ -183,45 +178,81 @@ func (m *Model) SetYOffset(n int) {
|
||||
m.YOffset = clamp(n, 0, m.maxYOffset())
|
||||
}
|
||||
|
||||
// ViewDown moves the view down by the number of lines in the viewport.
|
||||
// PageDown moves the view down by the number of lines in the viewport.
|
||||
// Basically, "page down".
|
||||
//
|
||||
// Deprecated: use [Model.PageDown] instead.
|
||||
func (m *Model) ViewDown() []string {
|
||||
return m.PageDown()
|
||||
}
|
||||
|
||||
// PageDown moves the view down by the number of lines in the viewport.
|
||||
func (m *Model) PageDown() []string {
|
||||
if m.AtBottom() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.LineDown(m.Height)
|
||||
return m.ScrollDown(m.Height)
|
||||
}
|
||||
|
||||
// ViewUp moves the view up by one height of the viewport. Basically, "page up".
|
||||
// ViewUp moves the view up by one height of the viewport.
|
||||
// Basically, "page up".
|
||||
//
|
||||
// Deprecated: use [Model.PageUp] instead.
|
||||
func (m *Model) ViewUp() []string {
|
||||
return m.PageUp()
|
||||
}
|
||||
|
||||
// PageUp moves the view up by one height of the viewport.
|
||||
func (m *Model) PageUp() []string {
|
||||
if m.AtTop() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.LineUp(m.Height)
|
||||
return m.ScrollUp(m.Height)
|
||||
}
|
||||
|
||||
// HalfViewDown moves the view down by half the height of the viewport.
|
||||
//
|
||||
// Deprecated: use [Model.HalfPageDown] instead.
|
||||
func (m *Model) HalfViewDown() (lines []string) {
|
||||
return m.HalfPageDown()
|
||||
}
|
||||
|
||||
// HalfPageDown moves the view down by half the height of the viewport.
|
||||
func (m *Model) HalfPageDown() (lines []string) {
|
||||
if m.AtBottom() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.LineDown(m.Height / 2) //nolint:mnd
|
||||
return m.ScrollDown(m.Height / 2) //nolint:mnd
|
||||
}
|
||||
|
||||
// HalfViewUp moves the view up by half the height of the viewport.
|
||||
//
|
||||
// Deprecated: use [Model.HalfPageUp] instead.
|
||||
func (m *Model) HalfViewUp() (lines []string) {
|
||||
return m.HalfPageUp()
|
||||
}
|
||||
|
||||
// HalfPageUp moves the view up by half the height of the viewport.
|
||||
func (m *Model) HalfPageUp() (lines []string) {
|
||||
if m.AtTop() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return m.LineUp(m.Height / 2) //nolint:mnd
|
||||
return m.ScrollUp(m.Height / 2) //nolint:mnd
|
||||
}
|
||||
|
||||
// LineDown moves the view down by the given number of lines.
|
||||
//
|
||||
// Deprecated: use [Model.ScrollDown] instead.
|
||||
func (m *Model) LineDown(n int) (lines []string) {
|
||||
return m.ScrollDown(n)
|
||||
}
|
||||
|
||||
// ScrollDown moves the view down by the given number of lines.
|
||||
func (m *Model) ScrollDown(n int) (lines []string) {
|
||||
if m.AtBottom() || n == 0 || len(m.lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -241,7 +272,15 @@ func (m *Model) LineDown(n int) (lines []string) {
|
||||
|
||||
// LineUp moves the view down by the given number of lines. Returns the new
|
||||
// lines to show.
|
||||
//
|
||||
// Deprecated: use [Model.ScrollUp] instead.
|
||||
func (m *Model) LineUp(n int) (lines []string) {
|
||||
return m.ScrollUp(n)
|
||||
}
|
||||
|
||||
// ScrollUp moves the view down by the given number of lines. Returns the new
|
||||
// lines to show.
|
||||
func (m *Model) ScrollUp(n int) (lines []string) {
|
||||
if m.AtTop() || n == 0 || len(m.lines) == 0 {
|
||||
return nil
|
||||
}
|
||||
@@ -258,6 +297,31 @@ func (m *Model) LineUp(n int) (lines []string) {
|
||||
return m.lines[top:bottom]
|
||||
}
|
||||
|
||||
// SetHorizontalStep sets the default amount of columns to scroll left or right
|
||||
// with the default viewport key map.
|
||||
//
|
||||
// If set to 0 or less, horizontal scrolling is disabled.
|
||||
//
|
||||
// On v1, horizontal scrolling is disabled by default.
|
||||
func (m *Model) SetHorizontalStep(n int) {
|
||||
m.horizontalStep = max(n, 0)
|
||||
}
|
||||
|
||||
// SetXOffset sets the X offset.
|
||||
func (m *Model) SetXOffset(n int) {
|
||||
m.xOffset = clamp(n, 0, m.longestLineWidth-m.Width)
|
||||
}
|
||||
|
||||
// ScrollLeft moves the viewport to the left by the given number of columns.
|
||||
func (m *Model) ScrollLeft(n int) {
|
||||
m.SetXOffset(m.xOffset - n)
|
||||
}
|
||||
|
||||
// ScrollRight moves viewport to the right by the given number of columns.
|
||||
func (m *Model) ScrollRight(n int) {
|
||||
m.SetXOffset(m.xOffset + n)
|
||||
}
|
||||
|
||||
// TotalLineCount returns the total number of lines (both hidden and visible) within the viewport.
|
||||
func (m Model) TotalLineCount() int {
|
||||
return len(m.lines)
|
||||
@@ -305,6 +369,8 @@ func Sync(m Model) tea.Cmd {
|
||||
//
|
||||
// lines := model.ViewDown(1)
|
||||
// cmd := ViewDown(m, lines)
|
||||
//
|
||||
// Deprecated: high performance rendering is deprecated in Bubble Tea.
|
||||
func ViewDown(m Model, lines []string) tea.Cmd {
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
@@ -313,12 +379,14 @@ func ViewDown(m Model, lines []string) tea.Cmd {
|
||||
|
||||
// XXX: high performance rendering is deprecated in Bubble Tea. In a v2 we
|
||||
// won't need to return a command here.
|
||||
return tea.ScrollDown(lines, top, bottom) //nolint:staticcheck
|
||||
return tea.ScrollDown(lines, top, bottom)
|
||||
}
|
||||
|
||||
// ViewUp is a high performance command the moves the viewport down by a given
|
||||
// number of lines height. Use Model.ViewUp to get the lines that should be
|
||||
// rendered.
|
||||
//
|
||||
// Deprecated: high performance rendering is deprecated in Bubble Tea.
|
||||
func ViewUp(m Model, lines []string) tea.Cmd {
|
||||
if len(lines) == 0 {
|
||||
return nil
|
||||
@@ -327,40 +395,7 @@ func ViewUp(m Model, lines []string) tea.Cmd {
|
||||
|
||||
// XXX: high performance rendering is deprecated in Bubble Tea. In a v2 we
|
||||
// won't need to return a command here.
|
||||
return tea.ScrollUp(lines, top, bottom) //nolint:staticcheck
|
||||
}
|
||||
|
||||
// SetHorizontalStep sets the amount of cells that the viewport moves in the
|
||||
// default viewport keymapping. If set to 0 or less, horizontal scrolling is
|
||||
// disabled.
|
||||
func (m *Model) SetHorizontalStep(n int) {
|
||||
if n < 0 {
|
||||
n = 0
|
||||
}
|
||||
|
||||
m.horizontalStep = n
|
||||
}
|
||||
|
||||
// MoveLeft moves the viewport to the left by the given number of columns.
|
||||
func (m *Model) MoveLeft(cols int) {
|
||||
m.xOffset -= cols
|
||||
if m.xOffset < 0 {
|
||||
m.xOffset = 0
|
||||
}
|
||||
}
|
||||
|
||||
// MoveRight moves viewport to the right by the given number of columns.
|
||||
func (m *Model) MoveRight(cols int) {
|
||||
// prevents over scrolling to the right
|
||||
if m.xOffset >= m.longestLineWidth-m.Width {
|
||||
return
|
||||
}
|
||||
m.xOffset += cols
|
||||
}
|
||||
|
||||
// Resets lines indent to zero.
|
||||
func (m *Model) ResetIndent() {
|
||||
m.xOffset = 0
|
||||
return tea.ScrollUp(lines, top, bottom)
|
||||
}
|
||||
|
||||
// Update handles standard message-based viewport updates.
|
||||
@@ -383,46 +418,46 @@ func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) {
|
||||
case tea.KeyMsg:
|
||||
switch {
|
||||
case key.Matches(msg, m.KeyMap.PageDown):
|
||||
lines := m.ViewDown()
|
||||
lines := m.PageDown()
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewDown(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.PageUp):
|
||||
lines := m.ViewUp()
|
||||
lines := m.PageUp()
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewUp(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.HalfPageDown):
|
||||
lines := m.HalfViewDown()
|
||||
lines := m.HalfPageDown()
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewDown(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.HalfPageUp):
|
||||
lines := m.HalfViewUp()
|
||||
lines := m.HalfPageUp()
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewUp(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.Down):
|
||||
lines := m.LineDown(1)
|
||||
lines := m.ScrollDown(1)
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewDown(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.Up):
|
||||
lines := m.LineUp(1)
|
||||
lines := m.ScrollUp(1)
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewUp(m, lines)
|
||||
}
|
||||
|
||||
case key.Matches(msg, m.KeyMap.Left):
|
||||
m.MoveLeft(m.horizontalStep)
|
||||
m.ScrollLeft(m.horizontalStep)
|
||||
|
||||
case key.Matches(msg, m.KeyMap.Right):
|
||||
m.MoveRight(m.horizontalStep)
|
||||
m.ScrollRight(m.horizontalStep)
|
||||
}
|
||||
|
||||
case tea.MouseMsg:
|
||||
@@ -431,13 +466,13 @@ func (m Model) updateAsModel(msg tea.Msg) (Model, tea.Cmd) {
|
||||
}
|
||||
switch msg.Button { //nolint:exhaustive
|
||||
case tea.MouseButtonWheelUp:
|
||||
lines := m.LineUp(m.MouseWheelDelta)
|
||||
lines := m.ScrollUp(m.MouseWheelDelta)
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewUp(m, lines)
|
||||
}
|
||||
|
||||
case tea.MouseButtonWheelDown:
|
||||
lines := m.LineDown(m.MouseWheelDelta)
|
||||
lines := m.ScrollDown(m.MouseWheelDelta)
|
||||
if m.HighPerformanceRendering {
|
||||
cmd = ViewDown(m, lines)
|
||||
}
|
||||
|
||||
+33
-22
@@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const defaultHorizontalStep = 6
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -12,6 +14,7 @@ func TestNew(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := New(10, 10)
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
|
||||
if !m.initialized {
|
||||
t.Errorf("on create by New, Model should be initialized")
|
||||
@@ -38,6 +41,7 @@ func TestSetInitialValues(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := Model{}
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
m.setInitialValues()
|
||||
|
||||
if m.horizontalStep != defaultHorizontalStep {
|
||||
@@ -53,6 +57,7 @@ func TestSetHorizontalStep(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := New(10, 10)
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
|
||||
if m.horizontalStep != defaultHorizontalStep {
|
||||
t.Errorf("default horizontalStep should be %d, got %d", defaultHorizontalStep, m.horizontalStep)
|
||||
@@ -69,6 +74,7 @@ func TestSetHorizontalStep(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := New(10, 10)
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
|
||||
if m.horizontalStep != defaultHorizontalStep {
|
||||
t.Errorf("default horizontalStep should be %d, got %d", defaultHorizontalStep, m.horizontalStep)
|
||||
@@ -82,7 +88,7 @@ func TestSetHorizontalStep(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMoveLeft(t *testing.T) {
|
||||
func TestScrollLeft(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
zeroPosition := 0
|
||||
@@ -91,25 +97,28 @@ func TestMoveLeft(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
m := New(10, 10)
|
||||
m.longestLineWidth = 100
|
||||
if m.xOffset != zeroPosition {
|
||||
t.Errorf("default indent should be %d, got %d", zeroPosition, m.xOffset)
|
||||
}
|
||||
|
||||
m.MoveLeft(m.horizontalStep)
|
||||
m.ScrollLeft(m.horizontalStep)
|
||||
if m.xOffset != zeroPosition {
|
||||
t.Errorf("indent should be %d, got %d", zeroPosition, m.xOffset)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("move", func(t *testing.T) {
|
||||
t.Run("scroll", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
m := New(10, 10)
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
m.longestLineWidth = 100
|
||||
if m.xOffset != zeroPosition {
|
||||
t.Errorf("default indent should be %d, got %d", zeroPosition, m.xOffset)
|
||||
}
|
||||
|
||||
m.xOffset = defaultHorizontalStep * 2
|
||||
m.MoveLeft(m.horizontalStep)
|
||||
m.ScrollLeft(m.horizontalStep)
|
||||
newIndent := defaultHorizontalStep
|
||||
if m.xOffset != newIndent {
|
||||
t.Errorf("indent should be %d, got %d", newIndent, m.xOffset)
|
||||
@@ -117,21 +126,22 @@ func TestMoveLeft(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestMoveRight(t *testing.T) {
|
||||
func TestScrollRight(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
t.Run("move", func(t *testing.T) {
|
||||
t.Run("scroll", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
zeroPosition := 0
|
||||
|
||||
m := New(10, 10)
|
||||
m.SetHorizontalStep(defaultHorizontalStep)
|
||||
m.SetContent("Some line that is longer than width")
|
||||
if m.xOffset != zeroPosition {
|
||||
t.Errorf("default indent should be %d, got %d", zeroPosition, m.xOffset)
|
||||
}
|
||||
|
||||
m.MoveRight(m.horizontalStep)
|
||||
m.ScrollRight(m.horizontalStep)
|
||||
newIndent := defaultHorizontalStep
|
||||
if m.xOffset != newIndent {
|
||||
t.Errorf("indent should be %d, got %d", newIndent, m.xOffset)
|
||||
@@ -150,7 +160,7 @@ func TestResetIndent(t *testing.T) {
|
||||
m := New(10, 10)
|
||||
m.xOffset = 500
|
||||
|
||||
m.ResetIndent()
|
||||
m.SetXOffset(0)
|
||||
if m.xOffset != zeroPosition {
|
||||
t.Errorf("indent should be %d, got %d", zeroPosition, m.xOffset)
|
||||
}
|
||||
@@ -253,8 +263,9 @@ func TestVisibleLines(t *testing.T) {
|
||||
numberOfLines := 10
|
||||
|
||||
m := New(10, numberOfLines)
|
||||
m.lines = defaultList
|
||||
m.YOffset = 7
|
||||
m.horizontalStep = defaultHorizontalStep // remove on v2
|
||||
m.SetContent(strings.Join(defaultList, "\n"))
|
||||
m.SetYOffset(7)
|
||||
|
||||
// default list
|
||||
list := m.visibleLines()
|
||||
@@ -273,8 +284,8 @@ func TestVisibleLines(t *testing.T) {
|
||||
t.Errorf("first list item has to have prefix %s", perceptPrefix)
|
||||
}
|
||||
|
||||
// move right
|
||||
m.MoveRight(m.horizontalStep)
|
||||
// scroll right
|
||||
m.ScrollRight(m.horizontalStep)
|
||||
list = m.visibleLines()
|
||||
|
||||
newPrefix := perceptPrefix[m.xOffset:]
|
||||
@@ -282,12 +293,12 @@ func TestVisibleLines(t *testing.T) {
|
||||
t.Errorf("first list item has to have prefix %s, get %s", newPrefix, list[0])
|
||||
}
|
||||
|
||||
if list[lastItem] != "..." {
|
||||
if list[lastItem] != "" {
|
||||
t.Errorf("last item should be empty, got %s", list[lastItem])
|
||||
}
|
||||
|
||||
// move left
|
||||
m.MoveLeft(m.horizontalStep)
|
||||
// scroll left
|
||||
m.ScrollLeft(m.horizontalStep)
|
||||
list = m.visibleLines()
|
||||
if !strings.HasPrefix(list[0], perceptPrefix) {
|
||||
t.Errorf("first list item has to have prefix %s", perceptPrefix)
|
||||
@@ -328,8 +339,8 @@ func TestVisibleLines(t *testing.T) {
|
||||
t.Errorf("%dth list item should the the same as %dth default list item", lastItemIdx, initLastItem)
|
||||
}
|
||||
|
||||
// move right
|
||||
m.MoveRight(horizontalStep)
|
||||
// scroll right
|
||||
m.ScrollRight(horizontalStep)
|
||||
list = m.visibleLines()
|
||||
|
||||
for i := range list {
|
||||
@@ -339,8 +350,8 @@ func TestVisibleLines(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// move left
|
||||
m.MoveLeft(horizontalStep)
|
||||
// scroll left
|
||||
m.ScrollLeft(horizontalStep)
|
||||
list = m.visibleLines()
|
||||
for i := range list {
|
||||
if list[i] != initList[i] {
|
||||
@@ -348,9 +359,9 @@ func TestVisibleLines(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// move left second times do not change lites if indent == 0
|
||||
// scroll left second times do not change lites if indent == 0
|
||||
m.xOffset = 0
|
||||
m.MoveLeft(horizontalStep)
|
||||
m.ScrollLeft(horizontalStep)
|
||||
list = m.visibleLines()
|
||||
for i := range list {
|
||||
if list[i] != initList[i] {
|
||||
@@ -370,7 +381,7 @@ func TestRightOverscroll(t *testing.T) {
|
||||
m.SetContent(content)
|
||||
|
||||
for i := 0; i < 10; i++ {
|
||||
m.MoveRight(m.horizontalStep)
|
||||
m.ScrollRight(m.horizontalStep)
|
||||
}
|
||||
|
||||
visibleLines := m.visibleLines()
|
||||
|
||||
Reference in New Issue
Block a user