Add dirty command parser from micro vi plugin
This commit is contained in:
223
commands.txt
Normal file
223
commands.txt
Normal file
@@ -0,0 +1,223 @@
|
||||
= Planned Commands for levi =
|
||||
|
||||
Implementation status:
|
||||
|
||||
* (Buggy): Already implemented, but has some bugs.
|
||||
* (Partially): Partially implemented.
|
||||
* (Planned): Not implemented yet, but planned.
|
||||
* (Stalled): Tried to implement, but not functional yet.
|
||||
* (Out of Scope): Not planned to implement.
|
||||
|
||||
Command categories:
|
||||
|
||||
* Motion
|
||||
* Marking
|
||||
* View
|
||||
* Search
|
||||
* Character Finding
|
||||
* Insertion
|
||||
* Operator (Copy / Delte / Change)
|
||||
* Editing
|
||||
* Miscellaneous
|
||||
* Prompt
|
||||
|
||||
== Motion Commands ==
|
||||
|
||||
=== Move by Character / Move by Line ===
|
||||
|
||||
* h : Move cursor left by character. (MoveLeft)
|
||||
* j : Move cursor down by line. (MoveDown)
|
||||
* k : Move cursor up by line. (MoveUp)
|
||||
* l : Move cursor right by character. (MoveRight)
|
||||
|
||||
=== Move in Line ===
|
||||
|
||||
* 0 : Move cursor to start of current line. (MoveToStart)
|
||||
* $ : Move cursor to end of current line. (MoveToEnd)
|
||||
* ^ : Move cursor to first non-blank character of current line. (MoveToNonBlank)
|
||||
* <num>| : Move cursor to column <num> of current line. (MoveToColumn)
|
||||
(Note: Proper vi's column number is visual-based, but levi' is rune-based.)
|
||||
|
||||
=== Move by Word / Move by Loose Word ===
|
||||
|
||||
* w : Move cursor forward by word. (MoveByWord)
|
||||
* b : Move cursor backward by word. (MoveBackwardByWord)
|
||||
* e : Move cursor to end of word. (MoveToEndOfWord)
|
||||
* W : Move cursor forward by loose word. (MoveByLooseWord)
|
||||
* B : Move cursor backward by loose word. (MoveBackwardByLooseWord)
|
||||
* E : Move cursor to end of loose word. (MoveToEndOfLooseWord)
|
||||
|
||||
=== Move by Line ===
|
||||
|
||||
* Enter, + : Move cursor to first non-blank character of next line. (MoveToNonBlankOfNextLine)
|
||||
* - : Move cursor to first non-blank character of previous line. (MoveToNonBlankOfPrevLine)
|
||||
* G : Move cursor to last line. (MoveToLastLine)
|
||||
* <num>G : Move cursor to line <num>. (MoveToLine)
|
||||
|
||||
=== Move by Block ===
|
||||
|
||||
* ) : Move cursor forward by sentence. (MoveBySentence)
|
||||
* ( : Move cursor backward by sentence. (MoveBackwardBySentence)
|
||||
* } : Move cursor forward by paragraph. (MoveByParagraph)
|
||||
* { : Move cursor backward by paragraph. (MoveBackwardByParagraph)
|
||||
(Note: Proper vi respects nroff/troff directives, but levi doesn't.)
|
||||
* ]] : Move cursor forward by section. (MoveBySection)
|
||||
(Note: Proper vi respects nroff/troff directives, but levi doesn't.)
|
||||
* [[ : Move cursor backward by section. (MoveBackwardBySection)
|
||||
(Note: Proper vi respects nroff/troff directives, but levi doesn't.)
|
||||
|
||||
=== Move in View ===
|
||||
|
||||
* H : Move cursor to top of view. (MoveToTopOfView)
|
||||
* M : Move cursor to middle of view. (MoveToMiddleOfView)
|
||||
* L : Move cursor to bottom of view. (MoveToBottomOfView)
|
||||
* <num>H : Move cursor below <num> lines from top of view. (MoveToBelowTopOfView)
|
||||
* <num>L : Move cursor above <num> lines from bottom of view. (MoveToAboveBottomOfView)
|
||||
|
||||
== Marking Commands ==
|
||||
|
||||
=== Set Mark / Move to Mark ===
|
||||
|
||||
* m<letter> : Mark current cursor position labelled by <letter>. (MarkSet)
|
||||
* `<letter> : Move cursor to marked position labelled by <letter>. (MarkMoveTo)
|
||||
* '<letter> : Move cursor to marked line labelled by <letter>. (MarkMoveToLine)
|
||||
|
||||
=== Move by Context ===
|
||||
|
||||
* `` : Move cursor to previous position in context. (MarkBack)
|
||||
* '' : Move cursor to previous line in context. (MarkBackToLine)
|
||||
|
||||
== View Commands ==
|
||||
|
||||
=== Scroll by View Height / Scroll by Line ===
|
||||
|
||||
* Ctrl-f : Scroll down by view height. (ViewDown)
|
||||
* Ctrl-b : Scroll up by view height. (ViewUp)
|
||||
* Ctrl-d : Scroll down by half view height. (ViewDownHalf)
|
||||
* Ctrl-u : Scroll up by half view height. (ViewUpHalf)
|
||||
* Ctrl-y : Scroll down by line. (ViewDownLine)
|
||||
* Ctrl-e : Scroll up by line. (ViewUpLine)
|
||||
|
||||
=== Reposition ===
|
||||
|
||||
* z Enter : Reposition cursor line to top of view. (ViewToTop)
|
||||
* z. : Reposition cursor line middle of view. (ViewToMiddle)
|
||||
* z- : Reposition cursor line bottom of view. (ViewToBottom)
|
||||
|
||||
=== Redraw ===
|
||||
|
||||
* Ctrl-l : Redraw view. (ViewRedraw)
|
||||
|
||||
== Search Commands ==
|
||||
|
||||
* /<pattern> Enter : Search <pattern> forward. (SearchForward)
|
||||
* ?<pattern> Enter : Search <pattern> backward. (SearchBackward)
|
||||
* n : Search next match. (SearchNextMatch)
|
||||
* N : Search previous match. (SearchPrevMatch)
|
||||
* / Enter : Repeat last search forward. (SearchRepeatForward)
|
||||
* ? Enter : Repeat last search backward. (SearchRepeatBackward)
|
||||
|
||||
== Character Finding Commands ==
|
||||
|
||||
* f<letter> : Find character <letter> forward in current line. (FindForward)
|
||||
* F<letter> : Find character <letter> backward in current line. (FindBackward)
|
||||
* t<letter> : Find before character <letter> forward in current line. (FindBeforeForward)
|
||||
* T<letter> : Find before character <letter> backward in current line. (FindBeforeBackward)
|
||||
* ; : Find next match. (FindNextMatch)
|
||||
* , : Find previous match. (FindPrevMatch)
|
||||
|
||||
== Insertion Commands ==
|
||||
|
||||
=== Enter Insert Mode ===
|
||||
|
||||
* i : Switch to insert mode before cursor. (InsertBefore)
|
||||
* a : Switch to insert mode after cursor. (InsertAfter)
|
||||
* I : Switch to insert mode before first non-blank character of current line. (InsertBeforeNonBlank)
|
||||
* A : Switch to insert mode after end of current line. (InsertAfterEnd)
|
||||
* R : Switch to replace (overwrite) mode. (InsertOverwrite)
|
||||
|
||||
=== Open Line ===
|
||||
|
||||
* o : Open a new line below and switch to insert mode. (InsertOpenBelow)
|
||||
* O : Open a new line above and switch to insert mode. (InsertOpenAbove)
|
||||
|
||||
== Operator Commands (Copy / Delte / Change) ==
|
||||
|
||||
=== Copy (Yank) ===
|
||||
|
||||
* yy, Y : Copy current line. (OpCopyLine)
|
||||
* y<mv> : Copy region from current cursor to destination of motion <mv>. (OpCopyRegion, OpCopyLineRegion)
|
||||
* yw : Copy word. (OpCopyWord)
|
||||
* y$ : Copy to end of current line. (OpCopyToEnd)
|
||||
* "<reg>yy : Copy current line into register <reg>. (OpCopyLineIntoReg)
|
||||
|
||||
=== Paste (Put) ===
|
||||
|
||||
* p : Paste after cursor. (OpPaste)
|
||||
* P : Paste before cursor. (OpPasteBefore)
|
||||
* "<reg>p : Paste from register <reg>. (OpPasteFromReg)
|
||||
|
||||
=== Delete ===
|
||||
|
||||
* x : Delete character under cursor. (OpDelete)
|
||||
* X : Delete character before cursor. (OpDeleteBefore)
|
||||
* dd : Delete current line. (OpDeleteLine)
|
||||
* d<mv> : Delete region from current cursor to destination of motion <mv>. (OpDeleteRegion, OpDeleteLineRegion)
|
||||
* dw : Delete word. (OpDeleteWord)
|
||||
* d$, D : Delete to end of current line. (OpDeleteToEnd)
|
||||
|
||||
=== Change / Substitute ===
|
||||
|
||||
* cc : Change current line. (OpChangeLine)
|
||||
* c<mv> : Change region from current cursor to destination of motion <mv>. (OpChangeRegion, OpChangeLineRegion)
|
||||
* cw : Change word. (OpChangeWord)
|
||||
* C : Change to end of current line. (OpChangeToEnd)
|
||||
* s : Substitute one character under cursor. (OpSubst)
|
||||
* S : Substtute current line (equals cc). (OpSubstLine)
|
||||
|
||||
== Editing Commands ==
|
||||
|
||||
* r : Replace single character under cursor. (EditReplace)
|
||||
* J : Join current line with next line. (EditJoin)
|
||||
* >> : Indent current line. (EditIndent)
|
||||
* << : Outdent current line. (EditOutdent)
|
||||
* > <mv> : Indent region from current cursor to destination of motion <mv>. (EditIndentRegion)
|
||||
* < <mv> : Outdent region from current cursor to destination of motion <mv>. (EditOutdentRegion)
|
||||
|
||||
== Miscellaneous Commands ==
|
||||
|
||||
* Ctrl-g : Show info such as current cursor position. (MiscShowInfo)
|
||||
* . : Repeat last edit. (MiscRepeat)
|
||||
* u : Undo. (MiscUndo)
|
||||
* U : Restore current line to previous state. (MiscRestore)
|
||||
* ZZ : Save and quit. (MiscSaveAndQuit)
|
||||
|
||||
== Prompt Commands ==
|
||||
|
||||
=== Move ===
|
||||
|
||||
* :<num> Enter : Move cursor to line <num>. (PromptMoveToLine)
|
||||
|
||||
=== File ===
|
||||
|
||||
* :wq Enter : Save current file and quit. (PromptSaveAndQuit)
|
||||
* :w Enter : Save current file. (PromptSave)
|
||||
* :w! Enter : Force save current file. (PromptForceSave)
|
||||
* :q Enter : Quit editor. (PromptQuit)
|
||||
* :q! Enter : Force quit editor. (PromptForceQuit)
|
||||
* :e Enter : Open file. (PromptOpen)
|
||||
* :e! Enter : Force open file. (PromptForceOpen)
|
||||
* :r Enter : Read file and insert to current buffer. (PromptRead)
|
||||
* :n Enter : Switch to next buffer (tab). (PromptNext)
|
||||
* :prev Enter : Switch to previous buffer (tab). (PromptPrev) (extension)
|
||||
|
||||
=== Utility ===
|
||||
|
||||
* :sh Enter : Execute shell. (PromptShell)
|
||||
(Note: Only Unix-like OSes are supported.)
|
||||
|
||||
=== From Vim ===
|
||||
|
||||
* :wa Enter : Save all files. (PromptSaveAll)
|
||||
* :qa Enter : Close all files and quit editor. (PromptQuitAll)
|
||||
* :qa! Enter : Force close all files and quit editor. (PromptForceQuitAll)
|
||||
41
internal/editor/combuf.go
Normal file
41
internal/editor/combuf.go
Normal file
@@ -0,0 +1,41 @@
|
||||
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,7 +1,7 @@
|
||||
package editor
|
||||
|
||||
// key: i
|
||||
func (ed *Editor) Insert() {
|
||||
func (ed *Editor) InsertBefore() {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
@@ -20,47 +20,11 @@ func (ed *Editor) InsertAfter() {
|
||||
} else {
|
||||
ed.MoveRight(1)
|
||||
}
|
||||
ed.Insert()
|
||||
}
|
||||
|
||||
// key: h
|
||||
func (ed *Editor) MoveLeft(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col -= n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// key: l
|
||||
func (ed *Editor) MoveRight(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col += n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// key: j
|
||||
func (ed *Editor) MoveDown(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.row += n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// key: k
|
||||
func (ed *Editor) MoveUp(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.row -= n
|
||||
ed.Confine()
|
||||
ed.InsertBefore()
|
||||
}
|
||||
|
||||
// key: x
|
||||
func (ed *Editor) DeleteRune(n int) {
|
||||
func (ed *Editor) OpDelete(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
@@ -78,3 +42,8 @@ func (ed *Editor) DeleteRune(n int) {
|
||||
}
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// key: ZZ
|
||||
func (ed *Editor) MiscSaveAndQuit() {
|
||||
ed.quit = true
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ type Mode int
|
||||
const (
|
||||
ModeCommand Mode = iota
|
||||
ModeInsert
|
||||
ModeSearch
|
||||
ModePrompt
|
||||
)
|
||||
|
||||
type Editor struct {
|
||||
@@ -25,6 +27,8 @@ type Editor struct {
|
||||
mode Mode
|
||||
path string
|
||||
bell bool
|
||||
combuf *Combuf
|
||||
quit bool
|
||||
}
|
||||
|
||||
func (ed *Editor) Load(path string) {
|
||||
@@ -51,18 +55,20 @@ func Init(args []string) *Editor {
|
||||
|
||||
w, h := termi.Size()
|
||||
ed := &Editor{
|
||||
col: 0,
|
||||
row: 0,
|
||||
vrow: 0,
|
||||
w: w,
|
||||
h: h,
|
||||
x: 0,
|
||||
y: 0,
|
||||
lines: make([]string, 1),
|
||||
ins: NewInsert(),
|
||||
mode: ModeCommand,
|
||||
path: path,
|
||||
bell: false,
|
||||
col: 0,
|
||||
row: 0,
|
||||
vrow: 0,
|
||||
w: w,
|
||||
h: h,
|
||||
x: 0,
|
||||
y: 0,
|
||||
lines: make([]string, 1),
|
||||
ins: NewInsert(),
|
||||
mode: ModeCommand,
|
||||
path: path,
|
||||
bell: false,
|
||||
combuf: NewCombuf(),
|
||||
quit: false,
|
||||
}
|
||||
|
||||
if path != "" {
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
|
||||
"tea.kareha.org/lab/termi"
|
||||
)
|
||||
|
||||
@@ -30,7 +33,7 @@ func (ed *Editor) InsertNewline() {
|
||||
ed.lines = append(append(before, lines...), after...)
|
||||
ed.row++
|
||||
ed.col = 0
|
||||
// row and col are confined automatically
|
||||
// row and col are already confined
|
||||
}
|
||||
|
||||
func (ed *Editor) Backspace() {
|
||||
@@ -42,11 +45,64 @@ func (ed *Editor) Backspace() {
|
||||
return
|
||||
}
|
||||
ed.col--
|
||||
// col is confined automatically
|
||||
// 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 {
|
||||
for !ed.quit {
|
||||
ed.Draw()
|
||||
|
||||
key := termi.ReadKey()
|
||||
@@ -54,25 +110,72 @@ func (ed *Editor) Main() {
|
||||
case ModeCommand:
|
||||
switch key.Kind {
|
||||
case termi.KeyRune:
|
||||
switch key.Rune {
|
||||
case 'q':
|
||||
return
|
||||
case 'i':
|
||||
ed.Insert()
|
||||
case 'a':
|
||||
ed.InsertAfter()
|
||||
case 'h':
|
||||
ed.MoveLeft(1)
|
||||
case 'l':
|
||||
ed.MoveRight(1)
|
||||
case 'j':
|
||||
ed.MoveDown(1)
|
||||
case 'k':
|
||||
ed.MoveUp(1)
|
||||
case 'x':
|
||||
ed.DeleteRune(1)
|
||||
default:
|
||||
if key.Rune == termi.RuneEscape {
|
||||
ed.combuf.ClearAll()
|
||||
ed.Ring()
|
||||
continue
|
||||
}
|
||||
ed.combuf.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
|
||||
}
|
||||
*/
|
||||
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)
|
||||
|
||||
82
internal/editor/move.go
Normal file
82
internal/editor/move.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package editor
|
||||
|
||||
// h : Move cursor left by character.
|
||||
func (ed *Editor) MoveLeft(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col -= n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// j : Move cursor down by line.
|
||||
func (ed *Editor) MoveDown(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.row += n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// k : Move cursor up by line.
|
||||
func (ed *Editor) MoveUp(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.row -= n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// l : Move cursor right by character.
|
||||
func (ed *Editor) MoveRight(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col += n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// 0 : Move cursor to start of current line.
|
||||
func (ed *Editor) MoveToStart() {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col = 0
|
||||
// col is already confined
|
||||
}
|
||||
|
||||
// $ : Move cursor to end of current line.
|
||||
func (ed *Editor) MoveToEnd() {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col = ed.RuneCount() - 1
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// ^ : Move cursor to first non-blank character of current line.
|
||||
func (ed *Editor) MoveToNonBlank() {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
line := ed.CurrentLine()
|
||||
i := 0
|
||||
for _, r := range line {
|
||||
if r != ' ' && r != '\t' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
ed.col = i
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// <num>| : Move cursor to column <num> of current line.
|
||||
// (Note: Proper vi's column number is visual-based, but levi' is rune-based.)
|
||||
func (ed *Editor) MoveToColumn(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.col = n - 1
|
||||
ed.Confine()
|
||||
}
|
||||
@@ -36,16 +36,22 @@ func (ed *Editor) DrawStatus() {
|
||||
var m string
|
||||
switch ed.mode {
|
||||
case ModeCommand:
|
||||
m = "c"
|
||||
m = "command"
|
||||
case ModeInsert:
|
||||
m = "i"
|
||||
m = "insert"
|
||||
case ModeSearch:
|
||||
m = "search"
|
||||
case ModePrompt:
|
||||
m = "prompt"
|
||||
default:
|
||||
panic("invalid mode")
|
||||
}
|
||||
|
||||
termi.MoveCursor(0, ed.h-1)
|
||||
if ed.bell {
|
||||
termi.EnableInvert()
|
||||
}
|
||||
termi.Printf("%s %d,%d %s", m, ed.row, ed.col, ed.path)
|
||||
termi.Printf("[%s] %s %d,%d %s", ed.combuf.Cache(), m, ed.row, ed.col, ed.path)
|
||||
if ed.bell {
|
||||
termi.DisableInvert()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user