mirror of
https://github.com/Maks1mS/bubbles.git
synced 2025-03-14 13:03:44 +03:00
feat(textarea): motions for seeking to characters (f/t/T/F/a/i)
This commit is contained in:
parent
2cffee5f40
commit
907f5e659d
@ -41,9 +41,6 @@ type Action int
|
|||||||
const (
|
const (
|
||||||
// ActionMove moves the cursor.
|
// ActionMove moves the cursor.
|
||||||
ActionMove Action = iota
|
ActionMove Action = iota
|
||||||
// ActionSeek seeks the cursor to the desired character.
|
|
||||||
// Used in conjunction with f/F/t/T.
|
|
||||||
ActionSeek
|
|
||||||
// ActionReplace replaces text.
|
// ActionReplace replaces text.
|
||||||
ActionReplace
|
ActionReplace
|
||||||
// ActionDelete deletes text.
|
// ActionDelete deletes text.
|
||||||
@ -80,6 +77,53 @@ type NormalCommand struct {
|
|||||||
Action Action
|
Action Action
|
||||||
// Range is the range of characters to perform the action on.
|
// Range is the range of characters to perform the action on.
|
||||||
Range Range
|
Range Range
|
||||||
|
// Seeking is the type of seeking that is in progress.
|
||||||
|
Seeking SeekType
|
||||||
|
}
|
||||||
|
|
||||||
|
// SeekType are the possible types of seeking that can be in progress.
|
||||||
|
type SeekType int
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SeekNone is the default seeking action.
|
||||||
|
SeekNone SeekType = iota
|
||||||
|
// SeekForwardTo is the seeking action for f.
|
||||||
|
SeekForwardTo // f
|
||||||
|
// SeekBackwardTo is the seeking action for F.
|
||||||
|
SeekBackwardTo // F
|
||||||
|
// SeekForwardUntil is the seeking action for t.
|
||||||
|
SeekForwardUntil // t
|
||||||
|
// SeekBackwardUntil is the seeking action for T.
|
||||||
|
SeekBackwardUntil // T
|
||||||
|
// SeekAround is the seeking action for a.
|
||||||
|
SeekAround // a
|
||||||
|
// SeekInner is the seeking action for i.
|
||||||
|
SeekInner // i
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsSeeking returns whether the command is in the middle of seeking a range.
|
||||||
|
func (n *NormalCommand) IsSeeking() bool {
|
||||||
|
return n.Seeking != SeekNone
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSeekingForward returns whether the seeking action is in the forward direction (f, t).
|
||||||
|
func (n *NormalCommand) IsSeekingForward() bool {
|
||||||
|
return n.Seeking == SeekForwardTo || n.Seeking == SeekForwardUntil
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSeekingBackward returns whether the seeking action is in the backward direction (F, T).
|
||||||
|
func (n *NormalCommand) IsSeekingBackward() bool {
|
||||||
|
return n.Seeking == SeekBackwardTo || n.Seeking == SeekBackwardUntil
|
||||||
|
}
|
||||||
|
|
||||||
|
// executeMsg executes a command.
|
||||||
|
type executeMsg NormalCommand
|
||||||
|
|
||||||
|
// executeCmd implements tea.Cmd for an executeMsg.
|
||||||
|
func executeCmd(n NormalCommand) tea.Cmd {
|
||||||
|
return func() tea.Msg {
|
||||||
|
return executeMsg(n)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) insertUpdate(msg tea.Msg) tea.Cmd {
|
func (m *Model) insertUpdate(msg tea.Msg) tea.Cmd {
|
||||||
@ -195,10 +239,55 @@ func (m *Model) insertUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
|
|
||||||
func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
var execute bool
|
|
||||||
|
|
||||||
switch msg := msg.(type) {
|
switch msg := msg.(type) {
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
|
if m.command.IsSeeking() {
|
||||||
|
if len(msg.Runes) <= 0 {
|
||||||
|
m.command = &NormalCommand{}
|
||||||
|
}
|
||||||
|
switch m.command.Buffer {
|
||||||
|
case "a":
|
||||||
|
m.command.Range = m.findPairRange(msg.Runes[0])
|
||||||
|
return executeCmd(*m.command)
|
||||||
|
case "i":
|
||||||
|
pr := m.findPairRange(msg.Runes[0])
|
||||||
|
|
||||||
|
pr.Start.Col++
|
||||||
|
pr.End.Col--
|
||||||
|
|
||||||
|
m.command.Range = pr
|
||||||
|
return executeCmd(*m.command)
|
||||||
|
case "f":
|
||||||
|
end := m.findCharRight(msg.Runes[0])
|
||||||
|
m.command.Range = Range{
|
||||||
|
Start: Position{m.row, m.col},
|
||||||
|
End: end,
|
||||||
|
}
|
||||||
|
case "F":
|
||||||
|
start := m.findCharLeft(msg.Runes[0])
|
||||||
|
m.command.Range = Range{
|
||||||
|
Start: start,
|
||||||
|
End: Position{m.row, m.col},
|
||||||
|
}
|
||||||
|
case "t":
|
||||||
|
end := m.findCharRight(msg.Runes[0])
|
||||||
|
end.Col--
|
||||||
|
m.command.Range = Range{
|
||||||
|
Start: Position{m.row, m.col},
|
||||||
|
End: end,
|
||||||
|
}
|
||||||
|
case "T":
|
||||||
|
start := m.findCharLeft(msg.Runes[0])
|
||||||
|
start.Col++
|
||||||
|
m.command.Range = Range{
|
||||||
|
Start: start,
|
||||||
|
End: Position{m.row, m.col},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
|
}
|
||||||
|
|
||||||
if m.command.Action == ActionReplace {
|
if m.command.Action == ActionReplace {
|
||||||
for i := m.col; i < m.col+max(m.command.Count, 1); i++ {
|
for i := m.col; i < m.col+max(m.command.Count, 1); i++ {
|
||||||
if i >= len(m.value[m.row]) || len(msg.Runes) <= 0 {
|
if i >= len(m.value[m.row]) || len(msg.Runes) <= 0 {
|
||||||
@ -207,7 +296,7 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
m.value[m.row][i] = msg.Runes[0]
|
m.value[m.row][i] = msg.Runes[0]
|
||||||
}
|
}
|
||||||
m.command = &NormalCommand{}
|
m.command = &NormalCommand{}
|
||||||
return nil
|
break
|
||||||
}
|
}
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "esc":
|
case "esc":
|
||||||
@ -219,8 +308,7 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: 0},
|
End: Position{Row: m.row, Col: 0},
|
||||||
}
|
}
|
||||||
execute = true
|
return executeCmd(*m.command)
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v := m.command.Buffer + msg.String()
|
v := m.command.Buffer + msg.String()
|
||||||
@ -241,27 +329,27 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
row = len(m.value) - 1
|
row = len(m.value) - 1
|
||||||
}
|
}
|
||||||
m.row = clamp(row, 0, len(m.value)-1)
|
m.row = clamp(row, 0, len(m.value)-1)
|
||||||
return nil
|
return executeCmd(*m.command)
|
||||||
case "g":
|
case "g":
|
||||||
if m.command.Buffer == "g" {
|
if m.command.Buffer == "g" {
|
||||||
m.command = &NormalCommand{}
|
|
||||||
m.row = clamp(m.command.Count-1, 0, len(m.value)-1)
|
m.row = clamp(m.command.Count-1, 0, len(m.value)-1)
|
||||||
} else {
|
return executeCmd(*m.command)
|
||||||
m.command = &NormalCommand{Buffer: "g"}
|
|
||||||
}
|
}
|
||||||
return nil
|
m.command = &NormalCommand{Buffer: "g"}
|
||||||
case "x":
|
case "x":
|
||||||
m.command.Action = ActionDelete
|
m.command.Action = ActionDelete
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: m.col + max(m.command.Count, 1)},
|
End: Position{Row: m.row, Col: m.col + max(m.command.Count, 1)},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "X":
|
case "X":
|
||||||
m.command.Action = ActionDelete
|
m.command.Action = ActionDelete
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: m.col - max(m.command.Count, 1)},
|
End: Position{Row: m.row, Col: m.col - max(m.command.Count, 1)},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "c":
|
case "c":
|
||||||
if m.command.Action == ActionChange {
|
if m.command.Action == ActionChange {
|
||||||
m.CursorStart()
|
m.CursorStart()
|
||||||
@ -286,42 +374,67 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
m.command.Action = ActionDelete
|
m.command.Action = ActionDelete
|
||||||
case "y":
|
case "y":
|
||||||
m.command.Action = ActionYank
|
m.command.Action = ActionYank
|
||||||
|
case "t", "T", "f", "F":
|
||||||
|
m.command.Buffer = msg.String()
|
||||||
|
switch msg.String() {
|
||||||
|
case "t":
|
||||||
|
m.command.Seeking = SeekForwardUntil
|
||||||
|
case "T":
|
||||||
|
m.command.Seeking = SeekBackwardUntil
|
||||||
|
case "f":
|
||||||
|
m.command.Seeking = SeekForwardTo
|
||||||
|
case "F":
|
||||||
|
m.command.Seeking = SeekBackwardTo
|
||||||
|
}
|
||||||
case "r":
|
case "r":
|
||||||
m.command.Action = ActionReplace
|
m.command.Action = ActionReplace
|
||||||
case "i":
|
case "i":
|
||||||
|
if m.command.Action != ActionMove {
|
||||||
|
m.command.Buffer = "i"
|
||||||
|
m.command.Seeking = SeekInner
|
||||||
|
return nil
|
||||||
|
}
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: m.col},
|
End: Position{Row: m.row, Col: m.col},
|
||||||
}
|
}
|
||||||
cmd = m.SetMode(ModeInsert)
|
return tea.Sequentially(executeCmd(*m.command), m.SetMode(ModeInsert))
|
||||||
case "I":
|
case "I":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: 0},
|
End: Position{Row: m.row, Col: 0},
|
||||||
}
|
}
|
||||||
cmd = m.SetMode(ModeInsert)
|
return tea.Sequentially(executeCmd(*m.command), m.SetMode(ModeInsert))
|
||||||
case "a":
|
case "a":
|
||||||
|
if m.command.Action != ActionMove {
|
||||||
|
m.command.Buffer = "a"
|
||||||
|
m.command.Seeking = SeekAround
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: m.col + 1},
|
End: Position{Row: m.row, Col: m.col + 1},
|
||||||
}
|
}
|
||||||
cmd = m.SetMode(ModeInsert)
|
return tea.Sequentially(executeCmd(*m.command), m.SetMode(ModeInsert))
|
||||||
case "A":
|
case "A":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{Row: m.row, Col: m.col},
|
Start: Position{Row: m.row, Col: m.col},
|
||||||
End: Position{Row: m.row, Col: len(m.value[m.row]) + 1},
|
End: Position{Row: m.row, Col: len(m.value[m.row]) + 1},
|
||||||
}
|
}
|
||||||
cmd = m.SetMode(ModeInsert)
|
return tea.Sequentially(executeCmd(*m.command), m.SetMode(ModeInsert))
|
||||||
case "^":
|
case "^":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: Position{m.row, 0},
|
End: Position{m.row, 0},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "$":
|
case "$":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: Position{m.row, len(m.value[m.row])},
|
End: Position{m.row, len(m.value[m.row])},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "e", "E":
|
case "e", "E":
|
||||||
end := m.findWordEndRight(max(m.command.Count, 1), msg.String() == "E")
|
end := m.findWordEndRight(max(m.command.Count, 1), msg.String() == "E")
|
||||||
if m.command.Action == ActionDelete {
|
if m.command.Action == ActionDelete {
|
||||||
@ -331,16 +444,19 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: end,
|
End: end,
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "w", "W":
|
case "w", "W":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: m.findWordStartRight(max(m.command.Count, 1), msg.String() == "W"),
|
End: m.findWordStartRight(max(m.command.Count, 1), msg.String() == "W"),
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "b", "B":
|
case "b", "B":
|
||||||
m.command.Range = Range{
|
m.command.Range = Range{
|
||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: m.findWordLeft(max(m.command.Count, 1), msg.String() == "B"),
|
End: m.findWordLeft(max(m.command.Count, 1), msg.String() == "B"),
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "h", "l":
|
case "h", "l":
|
||||||
direction := 1
|
direction := 1
|
||||||
if msg.String() == "h" {
|
if msg.String() == "h" {
|
||||||
@ -351,6 +467,7 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: Position{m.row, clamp(m.col+(direction*max(m.command.Count, 1)), 0, len(m.value[m.row]))},
|
End: Position{m.row, clamp(m.col+(direction*max(m.command.Count, 1)), 0, len(m.value[m.row]))},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "j", "k":
|
case "j", "k":
|
||||||
direction := 1
|
direction := 1
|
||||||
if msg.String() == "k" {
|
if msg.String() == "k" {
|
||||||
@ -379,6 +496,7 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
Start: Position{m.row, m.col},
|
Start: Position{m.row, m.col},
|
||||||
End: Position{row, col},
|
End: Position{row, col},
|
||||||
}
|
}
|
||||||
|
return executeCmd(*m.command)
|
||||||
case "C":
|
case "C":
|
||||||
m.deleteAfterCursor()
|
m.deleteAfterCursor()
|
||||||
m.command = &NormalCommand{}
|
m.command = &NormalCommand{}
|
||||||
@ -390,6 +508,7 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
case "J":
|
case "J":
|
||||||
m.CursorEnd()
|
m.CursorEnd()
|
||||||
m.mergeLineBelow(m.row)
|
m.mergeLineBelow(m.row)
|
||||||
|
m.command = &NormalCommand{}
|
||||||
return nil
|
return nil
|
||||||
case "p":
|
case "p":
|
||||||
cmd = Paste
|
cmd = Paste
|
||||||
@ -399,19 +518,18 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
m.lastCharOffset = 0
|
m.lastCharOffset = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.ContainsAny(msg.String(), "iIaAeEwWbBhjklp$^xX") || execute {
|
case executeMsg:
|
||||||
switch m.command.Action {
|
switch m.command.Action {
|
||||||
case ActionDelete:
|
case ActionDelete:
|
||||||
m.deleteRange(m.command.Range)
|
m.deleteRange(m.command.Range)
|
||||||
case ActionChange:
|
case ActionChange:
|
||||||
m.deleteRange(m.command.Range)
|
m.deleteRange(m.command.Range)
|
||||||
cmd = m.SetMode(ModeInsert)
|
cmd = m.SetMode(ModeInsert)
|
||||||
case ActionMove:
|
case ActionMove:
|
||||||
m.row = clamp(m.command.Range.End.Row, 0, len(m.value)-1)
|
m.row = clamp(m.command.Range.End.Row, 0, len(m.value)-1)
|
||||||
m.col = clamp(m.command.Range.End.Col, 0, len(m.value[m.row]))
|
m.col = clamp(m.command.Range.End.Col, 0, len(m.value[m.row]))
|
||||||
}
|
|
||||||
m.command = &NormalCommand{}
|
|
||||||
}
|
}
|
||||||
|
m.command = &NormalCommand{}
|
||||||
|
|
||||||
case pasteMsg:
|
case pasteMsg:
|
||||||
m.handlePaste(string(msg))
|
m.handlePaste(string(msg))
|
||||||
@ -420,6 +538,52 @@ func (m *Model) normalUpdate(msg tea.Msg) tea.Cmd {
|
|||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) findCharLeft(r rune) Position {
|
||||||
|
col := m.col
|
||||||
|
|
||||||
|
for col > 0 {
|
||||||
|
col--
|
||||||
|
if m.value[m.row][col] == r {
|
||||||
|
return Position{m.row, col}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Position{m.row, m.col}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) findCharRight(r rune) Position {
|
||||||
|
col := m.col
|
||||||
|
|
||||||
|
for col < len(m.value[m.row]) {
|
||||||
|
col++
|
||||||
|
if m.value[m.row][col] == r {
|
||||||
|
return Position{m.row, col}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Position{m.row, m.col}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) findPairRange(r rune) Range {
|
||||||
|
var startRune, endRune rune
|
||||||
|
|
||||||
|
switch r {
|
||||||
|
case '(', ')':
|
||||||
|
startRune, endRune = '(', ')'
|
||||||
|
case '{', '}':
|
||||||
|
startRune, endRune = '{', '}'
|
||||||
|
case '[', ']':
|
||||||
|
startRune, endRune = '[', ']'
|
||||||
|
case '<', '>':
|
||||||
|
startRune, endRune = '<', '>'
|
||||||
|
case '"', '\'':
|
||||||
|
startRune, endRune = r, r
|
||||||
|
}
|
||||||
|
|
||||||
|
return Range{
|
||||||
|
Start: m.findCharLeft(startRune),
|
||||||
|
End: m.findCharRight(endRune),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// findWordLeft locates the start of the word on the left of the current word.
|
// findWordLeft locates the start of the word on the left of the current word.
|
||||||
// It takes whether or not to break words on spaces or any non-alpha-numeric
|
// It takes whether or not to break words on spaces or any non-alpha-numeric
|
||||||
// character as an argument.
|
// character as an argument.
|
||||||
@ -546,6 +710,21 @@ func (m *Model) deleteRange(r Range) {
|
|||||||
maxCol = clamp(maxCol, 0, len(m.value[r.Start.Row]))
|
maxCol = clamp(maxCol, 0, len(m.value[r.Start.Row]))
|
||||||
|
|
||||||
if r.Start.Row == r.End.Row {
|
if r.Start.Row == r.End.Row {
|
||||||
|
// If the action is delete and from a seek action, we need to delete
|
||||||
|
// the range inclusively.
|
||||||
|
if m.command.IsSeeking() {
|
||||||
|
if m.command.IsSeekingForward() {
|
||||||
|
maxCol = min(maxCol+1, len(m.value[r.Start.Row]))
|
||||||
|
} else if m.command.IsSeekingBackward() {
|
||||||
|
minCol = max(minCol-1, 0)
|
||||||
|
} else if m.command.Seeking == SeekAround {
|
||||||
|
maxCol = min(maxCol+1, len(m.value[r.Start.Row]))
|
||||||
|
minCol = max(minCol-1, 0)
|
||||||
|
} else if m.command.Seeking == SeekInner {
|
||||||
|
maxCol = min(maxCol+1, len(m.value[r.Start.Row]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m.value[r.Start.Row] = append(m.value[r.Start.Row][:minCol], m.value[r.Start.Row][maxCol:]...)
|
m.value[r.Start.Row] = append(m.value[r.Start.Row][:minCol], m.value[r.Start.Row][maxCol:]...)
|
||||||
m.SetCursor(minCol)
|
m.SetCursor(minCol)
|
||||||
return
|
return
|
||||||
|
@ -683,13 +683,21 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cmd tea.Cmd
|
var cmd tea.Cmd
|
||||||
|
|
||||||
switch m.mode {
|
switch m.mode {
|
||||||
case ModeInsert:
|
case ModeInsert:
|
||||||
cmd = m.insertUpdate(msg)
|
cmd = m.insertUpdate(msg)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
// Sometimes, we need to enter insert mode after executing a command.
|
||||||
|
switch msg.(type) {
|
||||||
|
case executeMsg:
|
||||||
|
cmd = m.normalUpdate(msg)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
|
}
|
||||||
case ModeNormal:
|
case ModeNormal:
|
||||||
cmd = m.normalUpdate(msg)
|
cmd = m.normalUpdate(msg)
|
||||||
|
cmds = append(cmds, cmd)
|
||||||
}
|
}
|
||||||
cmds = append(cmds, cmd)
|
|
||||||
|
|
||||||
vp, cmd := m.viewport.Update(msg)
|
vp, cmd := m.viewport.Update(msg)
|
||||||
m.viewport = &vp
|
m.viewport = &vp
|
||||||
|
Loading…
Reference in New Issue
Block a user