702 lines
16 KiB
Go
702 lines
16 KiB
Go
package motion
|
|
|
|
import (
|
|
"git.gophernest.net/azpect/TextEditor/internal/action"
|
|
"git.gophernest.net/azpect/TextEditor/internal/core"
|
|
tea "github.com/charmbracelet/bubbletea"
|
|
)
|
|
|
|
// isWordChar: Returns true if the character is a word character (alphanumeric
|
|
// or underscore).
|
|
func isWordChar(c byte) bool {
|
|
return (c >= 'a' && c <= 'z') ||
|
|
(c >= 'A' && c <= 'Z') ||
|
|
(c >= '0' && c <= '9') ||
|
|
c == '_'
|
|
}
|
|
|
|
// isWordPunctuation: Returns true if the character is punctuation (not whitespace
|
|
// and not a word character).
|
|
func isWordPunctuation(c byte) bool {
|
|
return c != ' ' && c != '\t' && !isWordChar(c)
|
|
}
|
|
|
|
// nextWordStart: Finds the start of the next word from position (x,y), handling
|
|
// word boundaries and line crossing.
|
|
func nextWordStart(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Skip current class
|
|
if x < len(line) {
|
|
if isWordChar(line[x]) {
|
|
for x < len(line) && isWordChar(line[x]) {
|
|
x++
|
|
}
|
|
} else if line[x] != ' ' && line[x] != '\t' {
|
|
// punctuation class
|
|
for x < len(line) && isWordPunctuation(line[x]) {
|
|
x++
|
|
}
|
|
}
|
|
}
|
|
|
|
// Skip whitespace and cross lines if needed
|
|
for {
|
|
// Walk over white space
|
|
for x < len(line) && (line[x] == ' ' || line[x] == '\t') {
|
|
x++
|
|
}
|
|
|
|
// Were on the new word, nothing else to do (no lines to cross
|
|
if x < len(line) {
|
|
break
|
|
}
|
|
|
|
// If next line is the end of the file, exit now
|
|
if y+1 >= buf.LineCount() {
|
|
return x, y
|
|
}
|
|
|
|
// Move to first char of next line
|
|
y++
|
|
line = buf.Line(y)
|
|
x = 0
|
|
|
|
// If the first char of the new line is no whitespace, stay here!
|
|
if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
|
|
break
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// nextWORDStart: Finds the start of the next WORD from position (x,y), treating
|
|
// all non-whitespace as a single class.
|
|
func nextWORDStart(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Skip current WORD (all non-whitespace is one class for W)
|
|
for x < len(line) && line[x] != ' ' && line[x] != '\t' {
|
|
x++
|
|
}
|
|
|
|
// Skip whitespace and cross lines if needed
|
|
for {
|
|
// Walk over white space
|
|
for x < len(line) && (line[x] == ' ' || line[x] == '\t') {
|
|
x++
|
|
}
|
|
|
|
// Were on the new word, nothing else to do (no lines to cross
|
|
if x < len(line) {
|
|
break
|
|
}
|
|
|
|
// If next line is the end of the file, exit now
|
|
if y+1 >= buf.LineCount() {
|
|
return x, y
|
|
}
|
|
|
|
// Move to first char of next line
|
|
y++
|
|
line = buf.Line(y)
|
|
x = 0
|
|
|
|
// If the first char of the new line is no whitespace, stay here!
|
|
if len(line) > 0 && line[0] != ' ' && line[0] != '\t' {
|
|
break
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// nextWordEnd: Finds the end of the next word from position (x,y), respecting
|
|
// word character classes.
|
|
func nextWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Advance once to avoid being stuck on the current end
|
|
x++
|
|
if x >= len(line) {
|
|
// At last line of file, pin cursor to end of file
|
|
if y+1 >= buf.LineCount() {
|
|
return len(line) - 1, y
|
|
}
|
|
|
|
// Otherwise, move to next line
|
|
y++
|
|
x = 0
|
|
line = buf.Line(y)
|
|
}
|
|
|
|
// Skip whitespace and cross lines if needed
|
|
for {
|
|
// Walk over white space
|
|
for x < len(line) && (line[x] == ' ' || line[x] == '\t') {
|
|
x++
|
|
}
|
|
|
|
// Were on the new word, nothing else to do (no lines to cross
|
|
if x < len(line) {
|
|
break
|
|
}
|
|
|
|
// If next line is the end of the file, exit now
|
|
if y+1 >= buf.LineCount() {
|
|
return x, y
|
|
}
|
|
|
|
// Move to first char of next line
|
|
y++
|
|
line = buf.Line(y)
|
|
x = 0
|
|
}
|
|
|
|
// Move to end of current char class, stop before it ends
|
|
if isWordChar(line[x]) {
|
|
for x+1 < len(line) && isWordChar(line[x+1]) {
|
|
x++
|
|
}
|
|
} else {
|
|
for x+1 < len(line) &&
|
|
line[x+1] != ' ' &&
|
|
line[x+1] != '\t' &&
|
|
!isWordChar(line[x+1]) {
|
|
x++
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// nextWORDEnd: Finds the end of the next WORD from position (x,y), treating
|
|
// all non-whitespace as a single class.
|
|
func nextWORDEnd(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Advance once to avoid being stuck on the current end
|
|
x++
|
|
if x >= len(line) {
|
|
// At last line of file, pin cursor to end of file
|
|
if y+1 >= buf.LineCount() {
|
|
return len(line) - 1, y
|
|
}
|
|
|
|
// Otherwise, move to next line
|
|
y++
|
|
x = 0
|
|
line = buf.Line(y)
|
|
}
|
|
|
|
// Skip whitespace and cross lines if needed
|
|
for {
|
|
// Walk over white space
|
|
for x < len(line) && (line[x] == ' ' || line[x] == '\t') {
|
|
x++
|
|
}
|
|
|
|
// Were on the new word, nothing else to do (no lines to cross
|
|
if x < len(line) {
|
|
break
|
|
}
|
|
|
|
// If next line is the end of the file, exit now
|
|
if y+1 >= buf.LineCount() {
|
|
return x, y
|
|
}
|
|
|
|
// Move to first char of next line
|
|
y++
|
|
line = buf.Line(y)
|
|
x = 0
|
|
}
|
|
|
|
// Move to end of current WORD (all non-whitespace is one class)
|
|
for x+1 < len(line) && line[x+1] != ' ' && line[x+1] != '\t' {
|
|
x++
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// prevWordStart: Finds the start of the previous word from position (x,y),
|
|
// moving backward through character classes.
|
|
func prevWordStart(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Back one to avoid being stuck on the current start
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0 // beginning of file, stay put
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if x < 0 {
|
|
return 0, y // landed on an empty line
|
|
}
|
|
}
|
|
|
|
// Skip whitespace backward, crossing lines if needed
|
|
for {
|
|
for x >= 0 && (line[x] == ' ' || line[x] == '\t') {
|
|
x--
|
|
}
|
|
if x >= 0 {
|
|
break // landed on a non-whitespace char
|
|
}
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if len(line) == 0 {
|
|
return 0, y // empty line acts as a word boundary
|
|
}
|
|
}
|
|
|
|
// Skip to the start of the current char class
|
|
if isWordChar(line[x]) {
|
|
for x-1 >= 0 && isWordChar(line[x-1]) {
|
|
x--
|
|
}
|
|
} else {
|
|
for x-1 >= 0 && isWordPunctuation(line[x-1]) {
|
|
x--
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// MoveForwardWord implements Motion (w) - charwise
|
|
type MoveForwardWord struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveForwardWord.Execute: Moves the cursor forward by Count words (w motion).
|
|
func (a MoveForwardWord) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = nextWordStart(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveForwardWord.Type: Returns CharwiseExclusive for word motion.
|
|
func (a MoveForwardWord) Type() core.MotionType { return core.CharwiseExclusive }
|
|
|
|
// MoveForwardWord.WithCount: Returns a new MoveForwardWord with the given count.
|
|
func (a MoveForwardWord) WithCount(n int) action.Action {
|
|
return MoveForwardWord{Count: n}
|
|
}
|
|
|
|
// MoveForwardWORD implements Motion (W) - charwise
|
|
type MoveForwardWORD struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveForwardWORD.Execute: Moves the cursor forward by Count WORDs (W motion).
|
|
func (a MoveForwardWORD) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = nextWORDStart(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveForwardWORD.Type: Returns CharwiseExclusive for WORD motion.
|
|
func (a MoveForwardWORD) Type() core.MotionType { return core.CharwiseExclusive }
|
|
|
|
// MoveForwardWORD.WithCount: Returns a new MoveForwardWORD with the given count.
|
|
func (a MoveForwardWORD) WithCount(n int) action.Action {
|
|
return MoveForwardWORD{Count: n}
|
|
}
|
|
|
|
// MoveForwardWordEnd implements Motion (e) - charwise
|
|
type MoveForwardWordEnd struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveForwardWordEnd.Execute: Moves the cursor to the end of the Count-th word (e motion).
|
|
func (a MoveForwardWordEnd) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = nextWordEnd(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveForwardWordEnd.Type: Returns CharwiseInclusive for word-end motion.
|
|
func (a MoveForwardWordEnd) Type() core.MotionType { return core.CharwiseInclusive }
|
|
|
|
// MoveForwardWordEnd.WithCount: Returns a new MoveForwardWordEnd with the given count.
|
|
func (a MoveForwardWordEnd) WithCount(n int) action.Action {
|
|
return MoveForwardWordEnd{Count: n}
|
|
}
|
|
|
|
// MoveForwardWORDEnd implements Motion (E) - charwise
|
|
type MoveForwardWORDEnd struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveForwardWORDEnd.Execute: Moves the cursor to the end of the Count-th WORD (E motion).
|
|
func (a MoveForwardWORDEnd) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = nextWORDEnd(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveForwardWORDEnd.Type: Returns CharwiseInclusive for WORD-end motion.
|
|
func (a MoveForwardWORDEnd) Type() core.MotionType { return core.CharwiseInclusive }
|
|
|
|
// MoveForwardWORDEnd.WithCount: Returns a new MoveForwardWORDEnd with the given count.
|
|
func (a MoveForwardWORDEnd) WithCount(n int) action.Action {
|
|
return MoveForwardWORDEnd{Count: n}
|
|
}
|
|
|
|
// MoveBackwardWord implements Motion (b) - charwise
|
|
type MoveBackwardWord struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveBackwardWord.Execute: Moves the cursor backward by Count words (b motion).
|
|
func (a MoveBackwardWord) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = prevWordStart(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveBackwardWord.Type: Returns CharwiseExclusive for backward word motion.
|
|
func (a MoveBackwardWord) Type() core.MotionType { return core.CharwiseExclusive }
|
|
|
|
// MoveBackwardWord.WithCount: Returns a new MoveBackwardWord with the given count.
|
|
func (a MoveBackwardWord) WithCount(n int) action.Action {
|
|
return MoveBackwardWord{Count: n}
|
|
}
|
|
|
|
// prevWORDStart: Finds the start of the previous WORD from position (x,y),
|
|
// treating all non-whitespace as a single class.
|
|
func prevWORDStart(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
|
|
// Back one to avoid being stuck on the current start
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0 // beginning of file, stay put
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if x < 0 {
|
|
return 0, y // landed on an empty line
|
|
}
|
|
}
|
|
|
|
// Skip whitespace backward, crossing lines if needed
|
|
for {
|
|
for x >= 0 && (line[x] == ' ' || line[x] == '\t') {
|
|
x--
|
|
}
|
|
if x >= 0 {
|
|
break // landed on a non-whitespace char
|
|
}
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if len(line) == 0 {
|
|
return 0, y // empty line acts as a word boundary
|
|
}
|
|
}
|
|
|
|
// Skip to the start of the WORD (all non-whitespace is one class)
|
|
for x-1 >= 0 && line[x-1] != ' ' && line[x-1] != '\t' {
|
|
x--
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// prevWordEnd: Finds the end of the previous word from position (x,y),
|
|
// respecting word character classes.
|
|
func prevWordEnd(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
origY := y
|
|
|
|
// Back one to avoid being stuck on the current end
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0 // beginning of file, stay put
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
// Don't return early for empty line - we'll handle it in whitespace skip
|
|
}
|
|
|
|
// Skip backward through current word class if we're on one
|
|
// BUT: if we crossed lines in the "back one" step, we're already at the end of a word
|
|
if y == origY && x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
|
if isWordChar(line[x]) {
|
|
// Skip word characters
|
|
for x >= 0 && isWordChar(line[x]) {
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if x < 0 {
|
|
return 0, y
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// Skip punctuation
|
|
for x >= 0 && isWordPunctuation(line[x]) {
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if x < 0 {
|
|
return 0, y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Skip whitespace backward, crossing lines if needed
|
|
for {
|
|
for x >= 0 && (line[x] == ' ' || line[x] == '\t') {
|
|
x--
|
|
}
|
|
if x >= 0 {
|
|
break // landed on a non-whitespace char, this is our word end!
|
|
}
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if len(line) == 0 {
|
|
return 0, y // empty line acts as a word boundary
|
|
}
|
|
}
|
|
|
|
// Now x,y is at the start of the target word. Move forward to its end.
|
|
if x >= 0 {
|
|
if isWordChar(line[x]) {
|
|
for x+1 < len(line) && isWordChar(line[x+1]) {
|
|
x++
|
|
}
|
|
} else if isWordPunctuation(line[x]) {
|
|
for x+1 < len(line) && isWordPunctuation(line[x+1]) {
|
|
x++
|
|
}
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// prevWORDEnd: Finds the end of the previous WORD from position (x,y),
|
|
// treating all non-whitespace as a single class.
|
|
func prevWORDEnd(buf *core.Buffer, x, y int) (int, int) {
|
|
line := buf.Line(y)
|
|
origY := y
|
|
|
|
// Back one to avoid being stuck on the current end
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0 // beginning of file, stay put
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
// Don't return early for empty line - we'll handle it in whitespace skip
|
|
}
|
|
|
|
// Skip backward through current WORD if we're on one
|
|
// BUT: if we crossed lines in the "back one" step, we're already at the end of a WORD
|
|
if y == origY && x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
|
for x >= 0 && line[x] != ' ' && line[x] != '\t' {
|
|
x--
|
|
if x < 0 {
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if x < 0 {
|
|
return 0, y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Skip whitespace backward, crossing lines if needed
|
|
for {
|
|
for x >= 0 && (line[x] == ' ' || line[x] == '\t') {
|
|
x--
|
|
}
|
|
if x >= 0 {
|
|
break // landed on a non-whitespace char, this is our WORD end!
|
|
}
|
|
if y == 0 {
|
|
return 0, 0
|
|
}
|
|
y--
|
|
line = buf.Line(y)
|
|
x = len(line) - 1
|
|
if len(line) == 0 {
|
|
return 0, y // empty line acts as a word boundary
|
|
}
|
|
}
|
|
|
|
// Now x,y is at the start of the target WORD. Move forward to its end.
|
|
if x >= 0 {
|
|
for x+1 < len(line) && line[x+1] != ' ' && line[x+1] != '\t' {
|
|
x++
|
|
}
|
|
}
|
|
|
|
return x, y
|
|
}
|
|
|
|
// MoveBackwardWORD implements Motion (B) - charwise
|
|
type MoveBackwardWORD struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveBackwardWORD.Execute: Moves the cursor backward by Count WORDs (B motion).
|
|
func (a MoveBackwardWORD) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = prevWORDStart(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveBackwardWORD.Type: Returns CharwiseExclusive for backward WORD motion.
|
|
func (a MoveBackwardWORD) Type() core.MotionType { return core.CharwiseExclusive }
|
|
|
|
// MoveBackwardWORD.WithCount: Returns a new MoveBackwardWORD with the given count.
|
|
func (a MoveBackwardWORD) WithCount(n int) action.Action {
|
|
return MoveBackwardWORD{Count: n}
|
|
}
|
|
|
|
// MoveBackwardWordEnd implements Motion (ge) - charwise
|
|
type MoveBackwardWordEnd struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveBackwardWordEnd.Execute: Moves the cursor to the end of the previous word (ge motion).
|
|
func (a MoveBackwardWordEnd) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = prevWordEnd(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveBackwardWordEnd.Type: Returns CharwiseInclusive for backward word-end motion.
|
|
func (a MoveBackwardWordEnd) Type() core.MotionType { return core.CharwiseInclusive }
|
|
|
|
// MoveBackwardWordEnd.WithCount: Returns a new MoveBackwardWordEnd with the given count.
|
|
func (a MoveBackwardWordEnd) WithCount(n int) action.Action {
|
|
return MoveBackwardWordEnd{Count: n}
|
|
}
|
|
|
|
// MoveBackwardWORDEnd implements Motion (gE) - charwise
|
|
type MoveBackwardWORDEnd struct {
|
|
Count int
|
|
}
|
|
|
|
// MoveBackwardWORDEnd.Execute: Moves the cursor to the end of the previous WORD (gE motion).
|
|
func (a MoveBackwardWORDEnd) Execute(m action.Model) tea.Cmd {
|
|
win := m.ActiveWindow()
|
|
buf := m.ActiveBuffer()
|
|
|
|
x := win.Cursor.Col
|
|
y := win.Cursor.Line
|
|
for i := 0; i < a.Count; i++ {
|
|
x, y = prevWORDEnd(buf, x, y)
|
|
}
|
|
win.SetCursorCol(x)
|
|
win.SetCursorLine(y)
|
|
return nil
|
|
}
|
|
|
|
// MoveBackwardWORDEnd.Type: Returns CharwiseInclusive for backward WORD-end motion.
|
|
func (a MoveBackwardWORDEnd) Type() core.MotionType { return core.CharwiseInclusive }
|
|
|
|
// MoveBackwardWORDEnd.WithCount: Returns a new MoveBackwardWORDEnd with the given count.
|
|
func (a MoveBackwardWORDEnd) WithCount(n int) action.Action {
|
|
return MoveBackwardWORDEnd{Count: n}
|
|
}
|