Add parser
This commit is contained in:
147
internal/editor/cmd.go
Normal file
147
internal/editor/cmd.go
Normal file
@@ -0,0 +1,147 @@
|
||||
package editor
|
||||
|
||||
type CmdKind int
|
||||
|
||||
const (
|
||||
CmdMoveLeft CmdKind = iota
|
||||
CmdMoveDown
|
||||
CmdMoveUp
|
||||
CmdMoveRight
|
||||
|
||||
CmdMoveToStart
|
||||
CmdMoveToEnd
|
||||
CmdMoveToNonBlank
|
||||
CmdMoveToColumn
|
||||
|
||||
CmdMoveByWord
|
||||
CmdMoveBackwardByWord
|
||||
CmdMoveToEndOfWord
|
||||
CmdMoveByLooseWord
|
||||
CmdMoveBackwardByLooseWord
|
||||
CmdMoveToEndOfLooseWord
|
||||
|
||||
CmdMoveToNonBlankOfNextLine
|
||||
CmdMoveToNonBlankOfPrevLine
|
||||
CmdMoveToLastLine
|
||||
CmdMoveToLine
|
||||
|
||||
CmdMoveBySentence
|
||||
CmdMoveBackwardBySentence
|
||||
CmdMoveByParagraph
|
||||
CmdMoveBackwardByParagraph
|
||||
CmdMoveBySection
|
||||
CmdMoveBackwardBySection
|
||||
|
||||
CmdMoveToTopOfView
|
||||
CmdMoveToMiddleOfView
|
||||
CmdMoveToBottomOfView
|
||||
CmdMoveToBelowTopOfView
|
||||
CmdMoveToAboveBottomOfView
|
||||
|
||||
CmdMarkSet
|
||||
CmdMarkMoveTo
|
||||
CmdMarkMoveToLine
|
||||
|
||||
CmdMarkBack
|
||||
CmdMarkBackToLine
|
||||
|
||||
CmdViewDown
|
||||
CmdViewUp
|
||||
CmdViewDownHalf
|
||||
CmdViewUpHalf
|
||||
CmdViewDownLine
|
||||
CmdViewUpLine
|
||||
|
||||
CmdViewToTop
|
||||
CmdViewToMiddle
|
||||
CmdViewToBottom
|
||||
|
||||
CmdViewRedraw
|
||||
|
||||
CmdSearchForward
|
||||
CmdSearchBackward
|
||||
CmdSearchNextMatch
|
||||
CmdSearchPrevMatch
|
||||
CmdSearchRepeatForward
|
||||
CmdSearchRepeatBackward
|
||||
|
||||
CmdFindForward
|
||||
CmdFindBackward
|
||||
CmdFindBeforeForward
|
||||
CmdFindBeforeBackward
|
||||
CmdFindNextMatch
|
||||
CmdFindPrevMatch
|
||||
|
||||
CmdInsertBefore
|
||||
CmdInsertAfter
|
||||
CmdInsertBeforeNonBlank
|
||||
CmdInsertAfterEnd
|
||||
CmdInsertOverwrite
|
||||
|
||||
CmdInsertOpenBelow
|
||||
CmdInsertOpenAbove
|
||||
|
||||
CmdOpCopyLine
|
||||
CmdOpCopyRegion
|
||||
CmdOpCopyLineRegion
|
||||
CmdOpCopyWord
|
||||
CmdOpCopyToEnd
|
||||
CmdOpCopyLineIntoReg
|
||||
|
||||
CmdOpPaste
|
||||
CmdOpPasteBefore
|
||||
CmdOpPasteFromReg
|
||||
|
||||
CmdOpDelete
|
||||
CmdOpDeleteBefore
|
||||
CmdOpDeleteLine
|
||||
CmdOpDelteRegion
|
||||
CmdOpDeleteLineRegion
|
||||
CmdOpDeleteWord
|
||||
CmdOpDelteToEnd
|
||||
|
||||
CmdOpChangeLine
|
||||
CmdOpChangeRegion
|
||||
CmdOpChangeLineRegion
|
||||
CmdOpChangeWord
|
||||
CmdOpChangeToEnd
|
||||
CmdOpSubst
|
||||
CmdOpSubstLine
|
||||
|
||||
CmdEditReplace
|
||||
CmdEditJoin
|
||||
CmdEditIndent
|
||||
CmdEditOutdent
|
||||
CmdEditIndentRegion
|
||||
CmdEditOutdentRegion
|
||||
|
||||
CmdMiscShowInfo
|
||||
CmdMiscRepeat
|
||||
CmdMiscUndo
|
||||
CmdMiscRestore
|
||||
CmdMiscSaveAndQuit
|
||||
|
||||
CmdPromptMoveToLine
|
||||
|
||||
CmdPromptSaveAndQuit
|
||||
CmdPromptSave
|
||||
CmdPromptForceSave
|
||||
CmdPromptQuit
|
||||
CmdPromptForceQuit
|
||||
CmdPromptOpen
|
||||
CmdPromptForceOpen
|
||||
CmdPromptRead
|
||||
CmdPromptNext
|
||||
CmdPromptPrev
|
||||
|
||||
CmdPromptShell
|
||||
|
||||
CmdPromptSaveAll
|
||||
CmdPromptQuitAll
|
||||
CmdPromptForceQuitAll
|
||||
)
|
||||
|
||||
type Cmd struct {
|
||||
Kind CmdKind
|
||||
Num int
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package editor
|
||||
|
||||
type Combuf struct {
|
||||
buf []rune
|
||||
cache string
|
||||
}
|
||||
|
||||
const maxCombufLen = 256
|
||||
|
||||
func NewCombuf() *Combuf {
|
||||
return &Combuf{
|
||||
buf: make([]rune, 0),
|
||||
cache: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (cb *Combuf) String() string {
|
||||
return string(cb.buf)
|
||||
}
|
||||
|
||||
func (cb *Combuf) InsertRune(r rune) {
|
||||
cb.buf = append(cb.buf, r)
|
||||
cb.cache = cb.String()
|
||||
}
|
||||
|
||||
func (cb *Combuf) Clear() {
|
||||
if len(cb.buf) > maxCombufLen {
|
||||
cb.buf = make([]rune, 0)
|
||||
} else {
|
||||
cb.buf = cb.buf[:0]
|
||||
}
|
||||
}
|
||||
|
||||
func (cb *Combuf) Cache() string {
|
||||
return cb.cache
|
||||
}
|
||||
|
||||
func (cb *Combuf) ClearAll() {
|
||||
cb.Clear()
|
||||
cb.cache = ""
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package editor
|
||||
|
||||
// key: i
|
||||
func (ed *Editor) InsertBefore() {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.ins.Init(ed.CurrentLine(), ed.col)
|
||||
ed.mode = ModeInsert
|
||||
}
|
||||
|
||||
// key: a
|
||||
func (ed *Editor) InsertAfter() {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
rc := ed.RuneCount()
|
||||
if ed.col >= rc-1 {
|
||||
ed.col = rc
|
||||
} else {
|
||||
ed.MoveRight(1)
|
||||
}
|
||||
ed.InsertBefore()
|
||||
}
|
||||
|
||||
// key: x
|
||||
func (ed *Editor) OpDelete(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
if len(ed.CurrentLine()) < 1 {
|
||||
ed.Ring()
|
||||
return
|
||||
}
|
||||
rs := []rune(ed.CurrentLine())
|
||||
if ed.col < 1 {
|
||||
ed.lines[ed.row] = string(rs[1:])
|
||||
} else {
|
||||
head := string(rs[:ed.col])
|
||||
tail := string(rs[ed.col+1:])
|
||||
ed.lines[ed.row] = head + tail
|
||||
}
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// key: ZZ
|
||||
func (ed *Editor) MiscSaveAndQuit() {
|
||||
ed.quit = true
|
||||
}
|
||||
@@ -23,11 +23,11 @@ type Editor struct {
|
||||
w, h int
|
||||
x, y int
|
||||
lines []string
|
||||
ins *Insert
|
||||
inp *Input
|
||||
mode Mode
|
||||
path string
|
||||
bell bool
|
||||
combuf *Combuf
|
||||
parser *Parser
|
||||
quit bool
|
||||
}
|
||||
|
||||
@@ -63,11 +63,11 @@ func Init(args []string) *Editor {
|
||||
x: 0,
|
||||
y: 0,
|
||||
lines: make([]string, 1),
|
||||
ins: NewInsert(),
|
||||
inp: NewInput(),
|
||||
mode: ModeCommand,
|
||||
path: path,
|
||||
bell: false,
|
||||
combuf: NewCombuf(),
|
||||
parser: NewParser(),
|
||||
quit: false,
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ func (ed *Editor) Finish() {
|
||||
|
||||
func (ed *Editor) Line(row int) string {
|
||||
if ed.mode == ModeInsert && row == ed.row {
|
||||
return ed.ins.Line()
|
||||
return ed.inp.Line()
|
||||
} else {
|
||||
return ed.lines[row]
|
||||
}
|
||||
@@ -142,8 +142,8 @@ func (ed *Editor) InsertRune(r rune) {
|
||||
if ed.mode != ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.ins.WriteRune(r)
|
||||
ed.col = ed.ins.Column()
|
||||
ed.inp.WriteRune(r)
|
||||
ed.col = ed.inp.Column()
|
||||
}
|
||||
|
||||
func (ed *Editor) Ring() {
|
||||
|
||||
69
internal/editor/input.go
Normal file
69
internal/editor/input.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Input struct {
|
||||
head, tail string
|
||||
body *RuneBuf
|
||||
}
|
||||
|
||||
const maxBodyLen = 1024
|
||||
|
||||
func NewInput() *Input {
|
||||
return &Input{
|
||||
head: "",
|
||||
tail: "",
|
||||
body: new(RuneBuf),
|
||||
}
|
||||
}
|
||||
|
||||
func (inp *Input) Reset() {
|
||||
inp.head = ""
|
||||
inp.tail = ""
|
||||
if inp.body.Len() > maxBodyLen {
|
||||
inp.body = new(RuneBuf)
|
||||
} else {
|
||||
inp.body.Reset()
|
||||
}
|
||||
}
|
||||
|
||||
func (inp *Input) Init(line string, col int) {
|
||||
inp.Reset()
|
||||
rs := []rune(line)
|
||||
inp.head = string(rs[:col])
|
||||
if col < len(rs) {
|
||||
inp.tail = string(rs[col:])
|
||||
} else {
|
||||
inp.tail = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (inp *Input) WriteRune(r rune) {
|
||||
inp.body.WriteRune(r)
|
||||
}
|
||||
|
||||
func (inp *Input) Line() string {
|
||||
return inp.head + inp.body.String() + inp.tail
|
||||
}
|
||||
|
||||
func (inp *Input) Newline() []string {
|
||||
lines := []string{
|
||||
inp.head + inp.body.String(),
|
||||
inp.tail,
|
||||
}
|
||||
inp.head = ""
|
||||
inp.body.Reset()
|
||||
// tail is intentionally preserved
|
||||
return lines
|
||||
}
|
||||
|
||||
func (inp *Input) Column() int {
|
||||
s := inp.head + inp.body.String()
|
||||
return utf8.RuneCountInString(s)
|
||||
}
|
||||
|
||||
func (inp *Input) Backspace() bool {
|
||||
return inp.body.Backspace()
|
||||
}
|
||||
@@ -1,69 +1,24 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
type Insert struct {
|
||||
head, tail string
|
||||
body *RuneBuf
|
||||
}
|
||||
|
||||
const maxBodyLen = 1024
|
||||
|
||||
func NewInsert() *Insert {
|
||||
return &Insert{
|
||||
head: "",
|
||||
tail: "",
|
||||
body: new(RuneBuf),
|
||||
// i : Switch to insert mode before cursor.
|
||||
func (ed *Editor) InsertBefore(n int) {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.inp.Init(ed.CurrentLine(), ed.col)
|
||||
ed.mode = ModeInsert
|
||||
}
|
||||
|
||||
func (ins *Insert) Reset() {
|
||||
ins.head = ""
|
||||
ins.tail = ""
|
||||
if ins.body.Len() > maxBodyLen {
|
||||
ins.body = new(RuneBuf)
|
||||
// a : Switch to insert mode after cursor.
|
||||
func (ed *Editor) InsertAfter(n int) {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
rc := ed.RuneCount()
|
||||
if ed.col >= rc-1 {
|
||||
ed.col = rc
|
||||
} else {
|
||||
ins.body.Reset()
|
||||
ed.MoveRight(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (ins *Insert) Init(line string, col int) {
|
||||
ins.Reset()
|
||||
rs := []rune(line)
|
||||
ins.head = string(rs[:col])
|
||||
if col < len(rs) {
|
||||
ins.tail = string(rs[col:])
|
||||
} else {
|
||||
ins.tail = ""
|
||||
}
|
||||
}
|
||||
|
||||
func (ins *Insert) WriteRune(r rune) {
|
||||
ins.body.WriteRune(r)
|
||||
}
|
||||
|
||||
func (ins *Insert) Line() string {
|
||||
return ins.head + ins.body.String() + ins.tail
|
||||
}
|
||||
|
||||
func (ins *Insert) Newline() []string {
|
||||
lines := []string{
|
||||
ins.head + ins.body.String(),
|
||||
ins.tail,
|
||||
}
|
||||
ins.head = ""
|
||||
ins.body.Reset()
|
||||
// tail is intentionally preserved
|
||||
return lines
|
||||
}
|
||||
|
||||
func (ins *Insert) Column() int {
|
||||
s := ins.head + ins.body.String()
|
||||
return utf8.RuneCountInString(s)
|
||||
}
|
||||
|
||||
func (ins *Insert) Backspace() bool {
|
||||
return ins.body.Backspace()
|
||||
ed.InsertBefore(n)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"tea.kareha.org/lab/termi"
|
||||
)
|
||||
|
||||
@@ -11,8 +8,8 @@ func (ed *Editor) ExitInsert() {
|
||||
if ed.mode != ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.lines[ed.row] = ed.ins.Line()
|
||||
ed.ins.Reset()
|
||||
ed.lines[ed.row] = ed.inp.Line()
|
||||
ed.inp.Reset()
|
||||
ed.mode = ModeCommand
|
||||
ed.MoveLeft(1)
|
||||
}
|
||||
@@ -29,7 +26,7 @@ func (ed *Editor) InsertNewline() {
|
||||
} else {
|
||||
after = []string{}
|
||||
}
|
||||
lines := ed.ins.Newline()
|
||||
lines := ed.inp.Newline()
|
||||
ed.lines = append(append(before, lines...), after...)
|
||||
ed.row++
|
||||
ed.col = 0
|
||||
@@ -40,7 +37,7 @@ func (ed *Editor) Backspace() {
|
||||
if ed.mode != ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
if !ed.ins.Backspace() {
|
||||
if !ed.inp.Backspace() {
|
||||
ed.Ring()
|
||||
return
|
||||
}
|
||||
@@ -48,59 +45,6 @@ func (ed *Editor) Backspace() {
|
||||
// col is already confined
|
||||
}
|
||||
|
||||
var cmdRe = regexp.MustCompile("^(\\d*)([:mziaIARoOdyYxXDsScCpPrJ><\\.uUZ]*)(\\d*)([hjkl0\\$\\^|wbeWBE\\n\\+\\-G\\)\\(\\}\\{\\]\\[HML'`/?nNfFtT;,g]*)(.*?)$")
|
||||
var letterRe = regexp.MustCompile("([m'`fFtT;,r])(.)$")
|
||||
var letterSubRe = regexp.MustCompile("[fFtT;,]")
|
||||
|
||||
func (ed *Editor) Run(noNum bool, num int, op string, noSubnub bool, subnum int, mv string, letter string, replay bool) bool {
|
||||
switch op {
|
||||
case "x":
|
||||
ed.OpDelete(num)
|
||||
return true
|
||||
}
|
||||
|
||||
switch op {
|
||||
case "i":
|
||||
ed.InsertBefore()
|
||||
return true
|
||||
case "a":
|
||||
ed.InsertAfter()
|
||||
return true
|
||||
case "ZZ":
|
||||
ed.MiscSaveAndQuit()
|
||||
return true
|
||||
}
|
||||
|
||||
switch mv {
|
||||
case "h":
|
||||
ed.MoveLeft(num)
|
||||
return true
|
||||
case "j":
|
||||
ed.MoveDown(num)
|
||||
return true
|
||||
case "k":
|
||||
ed.MoveUp(num)
|
||||
return true
|
||||
case "l":
|
||||
ed.MoveRight(num)
|
||||
return true
|
||||
case "0":
|
||||
ed.MoveToStart()
|
||||
return true
|
||||
case "$":
|
||||
ed.MoveToEnd()
|
||||
return true
|
||||
case "^":
|
||||
ed.MoveToNonBlank()
|
||||
return true
|
||||
case "|":
|
||||
ed.MoveToColumn(num)
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (ed *Editor) Main() {
|
||||
for !ed.quit {
|
||||
ed.Draw()
|
||||
@@ -111,71 +55,17 @@ func (ed *Editor) Main() {
|
||||
switch key.Kind {
|
||||
case termi.KeyRune:
|
||||
if key.Rune == termi.RuneEscape {
|
||||
ed.combuf.ClearAll()
|
||||
ed.parser.ClearAll()
|
||||
ed.Ring()
|
||||
continue
|
||||
}
|
||||
ed.combuf.InsertRune(key.Rune)
|
||||
ed.parser.InsertRune(key.Rune)
|
||||
|
||||
comb := ed.combuf.String()
|
||||
m := cmdRe.FindStringSubmatch(comb)
|
||||
/*
|
||||
if len(m) < 1 {
|
||||
// TODO error "not (yet) a vi command [" + comb + "]"
|
||||
ed.combuf.Clear()
|
||||
continue
|
||||
c, ok := ed.parser.Parse()
|
||||
if ok {
|
||||
if ed.Run(c) {
|
||||
ed.parser.Clear()
|
||||
}
|
||||
*/
|
||||
var numStr, op, subnumStr, mv string
|
||||
if len(m) > 0 {
|
||||
numStr, op, subnumStr, mv = m[1], m[2], m[3], m[4]
|
||||
}
|
||||
m = letterRe.FindStringSubmatch(comb)
|
||||
var letterCommand, letter string
|
||||
if len(m) > 0 {
|
||||
letterCommand, letter = m[1], m[2]
|
||||
}
|
||||
if letterCommand != "" {
|
||||
if letterCommand == "m" || letterCommand == "r" {
|
||||
op = letterCommand
|
||||
mv = ""
|
||||
} else if letterCommand == "'" || letterCommand == "`" {
|
||||
mv = letterCommand
|
||||
} else if letterSubRe.MatchString(letterCommand) {
|
||||
mv = letterCommand
|
||||
}
|
||||
}
|
||||
|
||||
noNum := false
|
||||
num := 1
|
||||
if numStr == "" {
|
||||
noNum = true
|
||||
} else if numStr == "0" {
|
||||
mv = "0"
|
||||
} else {
|
||||
n, err := strconv.Atoi(numStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
num = n
|
||||
}
|
||||
|
||||
noSubnum := false
|
||||
subnum := 1
|
||||
if subnumStr == "" {
|
||||
noSubnum = true
|
||||
} else if subnumStr == "0" {
|
||||
mv = "0"
|
||||
} else {
|
||||
n, err := strconv.Atoi(subnumStr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
subnum = n
|
||||
}
|
||||
|
||||
if ed.Run(noNum, num, op, noSubnum, subnum, mv, letter, false) {
|
||||
ed.combuf.Clear()
|
||||
}
|
||||
case termi.KeyUp:
|
||||
ed.MoveUp(1)
|
||||
|
||||
6
internal/editor/misc.go
Normal file
6
internal/editor/misc.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package editor
|
||||
|
||||
// ZZ : Save and quit.
|
||||
func (ed *Editor) MiscSaveAndQuit() {
|
||||
ed.quit = true
|
||||
}
|
||||
21
internal/editor/op.go
Normal file
21
internal/editor/op.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package editor
|
||||
|
||||
// x : Delete character under cursor.
|
||||
func (ed *Editor) OpDelete(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
if len(ed.CurrentLine()) < 1 {
|
||||
ed.Ring()
|
||||
return
|
||||
}
|
||||
rs := []rune(ed.CurrentLine())
|
||||
if ed.col < 1 {
|
||||
ed.lines[ed.row] = string(rs[1:])
|
||||
} else {
|
||||
head := string(rs[:ed.col])
|
||||
tail := string(rs[ed.col+1:])
|
||||
ed.lines[ed.row] = head + tail
|
||||
}
|
||||
ed.Confine()
|
||||
}
|
||||
192
internal/editor/parser.go
Normal file
192
internal/editor/parser.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
buf []rune
|
||||
cache string
|
||||
}
|
||||
|
||||
const maxParserLen = 256
|
||||
|
||||
func NewParser() *Parser {
|
||||
return &Parser{
|
||||
buf: make([]rune, 0),
|
||||
cache: "",
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) String() string {
|
||||
return string(p.buf)
|
||||
}
|
||||
|
||||
func (p *Parser) InsertRune(r rune) {
|
||||
p.buf = append(p.buf, r)
|
||||
p.cache = p.String()
|
||||
}
|
||||
|
||||
func (p *Parser) Clear() {
|
||||
if len(p.buf) > maxParserLen {
|
||||
p.buf = make([]rune, 0)
|
||||
} else {
|
||||
p.buf = p.buf[:0]
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Parser) Cache() string {
|
||||
return p.cache
|
||||
}
|
||||
|
||||
func (p *Parser) ClearAll() {
|
||||
p.Clear()
|
||||
p.cache = ""
|
||||
}
|
||||
|
||||
func (p *Parser) ParseMove(noNum bool, num int, op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "h":
|
||||
return Cmd{
|
||||
Kind: CmdMoveLeft,
|
||||
Num: num,
|
||||
}, true
|
||||
case "j":
|
||||
return Cmd{
|
||||
Kind: CmdMoveDown,
|
||||
Num: num,
|
||||
}, true
|
||||
case "k":
|
||||
return Cmd{
|
||||
Kind: CmdMoveUp,
|
||||
Num: num,
|
||||
}, true
|
||||
case "l":
|
||||
return Cmd{
|
||||
Kind: CmdMoveRight,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "0": // special
|
||||
return Cmd{Kind: CmdMoveToStart}, true
|
||||
case "$":
|
||||
return Cmd{Kind: CmdMoveToEnd}, true
|
||||
case "^":
|
||||
return Cmd{Kind: CmdMoveToNonBlank}, true
|
||||
case "|":
|
||||
return Cmd{
|
||||
Kind: CmdMoveToColumn,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseInsert(num int, op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "i":
|
||||
return Cmd{
|
||||
Kind: CmdInsertBefore,
|
||||
Num: num,
|
||||
}, true
|
||||
case "a":
|
||||
return Cmd{
|
||||
Kind: CmdInsertAfter,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseOp(num int, op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "x":
|
||||
return Cmd{
|
||||
Kind: CmdOpDelete,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseMisc(op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "ZZ":
|
||||
return Cmd{Kind: CmdMiscSaveAndQuit}, true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) Parse() (Cmd, bool) {
|
||||
if len(p.buf) < 1 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
if len(p.buf) == 1 {
|
||||
if p.buf[0] == '0' { // special
|
||||
return Cmd{Kind: CmdMoveToStart}, true
|
||||
}
|
||||
}
|
||||
|
||||
i := 0
|
||||
for i < len(p.buf) {
|
||||
if p.buf[i] < '0' || p.buf[i] > '9' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
noNum := i == 0
|
||||
num := 1
|
||||
if i > 0 {
|
||||
s := string(p.buf[:i])
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
num = n
|
||||
}
|
||||
|
||||
iPrev := i
|
||||
for i < len(p.buf) {
|
||||
if p.buf[i] >= '0' && p.buf[i] <= '9' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
if i <= iPrev {
|
||||
return Cmd{}, false
|
||||
}
|
||||
op := string(p.buf[iPrev:i])
|
||||
cmd, ok := p.ParseMove(noNum, num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseInsert(num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseOp(num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseMisc(op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
56
internal/editor/run.go
Normal file
56
internal/editor/run.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package editor
|
||||
|
||||
func (ed *Editor) Run(c Cmd) bool {
|
||||
switch c.Kind {
|
||||
case CmdMoveLeft:
|
||||
ed.MoveLeft(c.Num)
|
||||
return true
|
||||
case CmdMoveDown:
|
||||
ed.MoveDown(c.Num)
|
||||
return true
|
||||
case CmdMoveUp:
|
||||
ed.MoveUp(c.Num)
|
||||
return true
|
||||
case CmdMoveRight:
|
||||
ed.MoveRight(c.Num)
|
||||
return true
|
||||
|
||||
case CmdMoveToStart:
|
||||
ed.MoveToStart()
|
||||
return true
|
||||
case CmdMoveToEnd:
|
||||
ed.MoveToEnd()
|
||||
return true
|
||||
case CmdMoveToNonBlank:
|
||||
ed.MoveToNonBlank()
|
||||
return true
|
||||
case CmdMoveToColumn:
|
||||
ed.MoveToColumn(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
|
||||
case CmdInsertBefore:
|
||||
ed.InsertBefore(c.Num)
|
||||
return true
|
||||
case CmdInsertAfter:
|
||||
ed.InsertAfter(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
|
||||
case CmdOpDelete:
|
||||
ed.OpDelete(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
|
||||
case CmdMiscSaveAndQuit:
|
||||
ed.MiscSaveAndQuit()
|
||||
return true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func (ed *Editor) DrawStatus() {
|
||||
if ed.bell {
|
||||
termi.EnableInvert()
|
||||
}
|
||||
termi.Printf("[%s] %s %d,%d %s", ed.combuf.Cache(), m, ed.row, ed.col, ed.path)
|
||||
termi.Printf("[%s] %s %d,%d %s", ed.parser.Cache(), m, ed.row, ed.col, ed.path)
|
||||
if ed.bell {
|
||||
termi.DisableInvert()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user