174 lines
4.0 KiB
Go
174 lines
4.0 KiB
Go
package motion
|
|
|
|
import (
|
|
"git.gophernest.net/azpect/TextEditor/internal/action"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
// MoveToTop implements Motion (gg) - linewise
|
|
type MoveToTop struct{}
|
|
|
|
func (a MoveToTop) Execute(m action.Model) tea.Cmd {
|
|
m.SetCursorY(0)
|
|
m.ClampCursorX()
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToTop) Type() action.MotionType { return action.Linewise }
|
|
|
|
// MoveToBottom implements Motion (G) - linewise
|
|
type MoveToBottom struct{}
|
|
|
|
func (a MoveToBottom) Execute(m action.Model) tea.Cmd {
|
|
m.SetCursorY(m.LineCount() - 1)
|
|
m.ClampCursorX()
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToBottom) Type() action.MotionType { return action.Linewise }
|
|
|
|
// MoveToLineStart implements Motion (0) - charwise
|
|
type MoveToLineStart struct{}
|
|
|
|
func (a MoveToLineStart) Execute(m action.Model) tea.Cmd {
|
|
m.SetCursorX(0)
|
|
m.ClampCursorX()
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToLineStart) Type() action.MotionType { return action.CharwiseExclusive }
|
|
|
|
// MoveToLineEnd implements Motion ($) - charwise
|
|
type MoveToLineEnd struct{}
|
|
|
|
func (a MoveToLineEnd) Execute(m action.Model) tea.Cmd {
|
|
m.SetCursorX(len(m.Line(m.CursorY())))
|
|
m.ClampCursorX()
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToLineEnd) Type() action.MotionType { return action.CharwiseInclusive }
|
|
|
|
// MoveToLineContentStart implements Motion (_) - charwise
|
|
type MoveToLineContentStart struct{}
|
|
|
|
func (a MoveToLineContentStart) Execute(m action.Model) tea.Cmd {
|
|
line := m.Line(m.CursorY())
|
|
x := 0
|
|
for x < len(line) {
|
|
ch := line[x]
|
|
if ch != ' ' && ch != '\t' {
|
|
break
|
|
}
|
|
x++
|
|
}
|
|
|
|
// If we are on the last char, we overflew, back once
|
|
if x == len(line) && x > 0 {
|
|
x--
|
|
}
|
|
|
|
m.SetCursorX(x)
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToLineContentStart) Type() action.MotionType { return action.CharwiseExclusive }
|
|
|
|
// MoveToColumn implements Motion (|) - charwise
|
|
type MoveToColumn struct {
|
|
Count int
|
|
}
|
|
|
|
func (a MoveToColumn) Execute(m action.Model) tea.Cmd {
|
|
line := m.Line(m.CursorY())
|
|
col := min(a.Count-1, len(line)-1)
|
|
|
|
m.SetCursorX(col)
|
|
m.ClampCursorX()
|
|
return nil
|
|
}
|
|
|
|
func (a MoveToColumn) Type() action.MotionType { return action.CharwiseExclusive }
|
|
|
|
func (a MoveToColumn) WithCount(n int) action.Action {
|
|
return MoveToColumn{Count: n}
|
|
}
|
|
|
|
// TODO: Count for these, maybe?
|
|
|
|
// ScrollDownHalfPage implements Motion (ctrl+d) - linewise
|
|
type ScrollDownHalfPage struct{}
|
|
|
|
func (a ScrollDownHalfPage) Execute(m action.Model) tea.Cmd {
|
|
viewportHeight := m.ViewPortH()
|
|
if viewportHeight <= 0 {
|
|
return nil
|
|
}
|
|
|
|
scroll := viewportHeight / 2
|
|
scrollOff := m.Settings().ScrollOff
|
|
|
|
// Current relative position in viewport
|
|
relY := m.CursorY() - m.ScrollY()
|
|
|
|
// Scroll down, clamped to valid range
|
|
newScrollY := m.ScrollY() + scroll
|
|
maxScroll := max(0, m.LineCount()-viewportHeight)
|
|
newScrollY = min(newScrollY, maxScroll)
|
|
m.SetScrollY(newScrollY)
|
|
|
|
// Maintain relative position, respecting scrollOff
|
|
if relY < scrollOff {
|
|
relY = scrollOff
|
|
}
|
|
if relY > viewportHeight-1-scrollOff {
|
|
relY = viewportHeight - 1 - scrollOff
|
|
}
|
|
|
|
newCursorY := newScrollY + relY
|
|
newCursorY = max(0, min(newCursorY, m.LineCount()-1))
|
|
m.SetCursorY(newCursorY)
|
|
m.ClampCursorX()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a ScrollDownHalfPage) Type() action.MotionType { return action.Linewise }
|
|
|
|
// ScrollUpHalfPage implements Motion (ctrl+u) - linewise
|
|
type ScrollUpHalfPage struct{}
|
|
|
|
func (a ScrollUpHalfPage) Execute(m action.Model) tea.Cmd {
|
|
viewportHeight := m.ViewPortH()
|
|
if viewportHeight <= 0 {
|
|
return nil
|
|
}
|
|
scroll := viewportHeight / 2
|
|
scrollOff := m.Settings().ScrollOff
|
|
|
|
// Current relative position in viewport
|
|
relY := m.CursorY() - m.ScrollY()
|
|
|
|
// Scroll up, clamped to valid range
|
|
newScrollY := m.ScrollY() - scroll
|
|
newScrollY = max(0, newScrollY)
|
|
m.SetScrollY(newScrollY)
|
|
|
|
// Maintain relative position, respecting scrollOff
|
|
if relY < scrollOff {
|
|
relY = scrollOff
|
|
}
|
|
if relY > viewportHeight-1-scrollOff {
|
|
relY = viewportHeight - 1 - scrollOff
|
|
}
|
|
|
|
newCursorY := newScrollY + relY
|
|
newCursorY = max(0, min(newCursorY, m.LineCount()-1))
|
|
m.SetCursorY(newCursorY)
|
|
m.ClampCursorX()
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a ScrollUpHalfPage) Type() action.MotionType { return action.Linewise }
|