Add command templates
This commit is contained in:
@@ -59,6 +59,7 @@ Command categories:
|
||||
* ) : Move cursor forward by sentence. (MoveBySentence)
|
||||
* ( : Move cursor backward by sentence. (MoveBackwardBySentence)
|
||||
* } : Move cursor forward by paragraph. (MoveByParagraph)
|
||||
(Note: Proper vi respects nroff/troff directives, but levi doesn't.)
|
||||
* { : Move cursor backward by paragraph. (MoveBackwardByParagraph)
|
||||
(Note: Proper vi respects nroff/troff directives, but levi doesn't.)
|
||||
* ]] : Move cursor forward by section. (MoveBySection)
|
||||
|
||||
@@ -2,6 +2,23 @@ package editor
|
||||
|
||||
type CmdKind int
|
||||
|
||||
type Loc struct {
|
||||
Row int
|
||||
Col int
|
||||
}
|
||||
|
||||
type Cmd struct {
|
||||
Kind CmdKind
|
||||
Num int
|
||||
Letter rune
|
||||
Pat string
|
||||
Reg rune
|
||||
Start Loc
|
||||
End Loc
|
||||
StartRow int
|
||||
EndRow int
|
||||
}
|
||||
|
||||
const (
|
||||
CmdInvalid CmdKind = iota
|
||||
|
||||
@@ -97,10 +114,10 @@ const (
|
||||
CmdOpDelete
|
||||
CmdOpDeleteBefore
|
||||
CmdOpDeleteLine
|
||||
CmdOpDelteRegion
|
||||
CmdOpDeleteRegion
|
||||
CmdOpDeleteLineRegion
|
||||
CmdOpDeleteWord
|
||||
CmdOpDelteToEnd
|
||||
CmdOpDeleteToEnd
|
||||
|
||||
CmdOpChangeLine
|
||||
CmdOpChangeRegion
|
||||
@@ -142,8 +159,3 @@ const (
|
||||
CmdPromptQuitAll
|
||||
CmdPromptForceQuitAll
|
||||
)
|
||||
|
||||
type Cmd struct {
|
||||
Kind CmdKind
|
||||
Num int
|
||||
}
|
||||
|
||||
110
internal/editor/draw.go
Normal file
110
internal/editor/draw.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
|
||||
"tea.kareha.org/lab/termi"
|
||||
)
|
||||
|
||||
func (ed *Editor) LineHeight(line string) int {
|
||||
rc := utf8.RuneCountInString(line)
|
||||
width := termi.StringWidth(line, rc)
|
||||
return 1 + max(width-1, 0)/ed.w
|
||||
}
|
||||
|
||||
func (ed *Editor) DrawBuffer() {
|
||||
y := 0
|
||||
for i := ed.vrow; i < len(ed.lines); i++ {
|
||||
line := ed.Line(i)
|
||||
|
||||
termi.MoveCursor(0, y)
|
||||
termi.Draw(line)
|
||||
|
||||
y += ed.LineHeight(line)
|
||||
if y >= ed.h-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for ; y < ed.h-1; y++ {
|
||||
termi.MoveCursor(0, y)
|
||||
termi.Draw("~")
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) DrawStatus() {
|
||||
var m string
|
||||
switch ed.mode {
|
||||
case ModeCommand:
|
||||
m = "vi command"
|
||||
case ModeInsert:
|
||||
m = "vi insert"
|
||||
case ModeSearch:
|
||||
m = "vi search"
|
||||
case ModePrompt:
|
||||
m = "vi prompt"
|
||||
default:
|
||||
panic("invalid mode")
|
||||
}
|
||||
|
||||
termi.MoveCursor(0, ed.h-1)
|
||||
if ed.message != "" {
|
||||
termi.EnableInvert()
|
||||
termi.Print(ed.message)
|
||||
termi.DisableInvert()
|
||||
ed.message = ""
|
||||
} else {
|
||||
termi.Printf("[%s] %s %d,%d %s", ed.parser.Cache(), m, ed.row, ed.col, ed.path)
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) UpdateCursor() {
|
||||
// XXX approximation
|
||||
width := termi.StringWidth(ed.CurrentLine(), ed.col)
|
||||
ed.x = width % ed.w
|
||||
dy := width / ed.w
|
||||
|
||||
if ed.row < ed.vrow {
|
||||
ed.vrow = ed.row
|
||||
}
|
||||
|
||||
y := 0
|
||||
for i := ed.vrow; i < ed.row; i++ {
|
||||
y += ed.LineHeight(ed.lines[i])
|
||||
}
|
||||
ed.y = y + dy
|
||||
|
||||
for ed.y >= ed.h-1 {
|
||||
ed.vrow++
|
||||
|
||||
y := 0
|
||||
for i := ed.vrow; i < ed.row; i++ {
|
||||
y += ed.LineHeight(ed.lines[i])
|
||||
}
|
||||
ed.y = y + dy
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) Repaint() {
|
||||
w, h := termi.Size()
|
||||
ed.w = w
|
||||
ed.h = h
|
||||
|
||||
termi.HideCursor()
|
||||
|
||||
termi.Clear()
|
||||
termi.HomeCursor()
|
||||
|
||||
ed.UpdateCursor()
|
||||
|
||||
ed.DrawBuffer()
|
||||
ed.DrawStatus()
|
||||
|
||||
termi.MoveCursor(ed.x, ed.y)
|
||||
|
||||
termi.ShowCursor()
|
||||
}
|
||||
|
||||
func (ed *Editor) Draw() {
|
||||
ed.Repaint()
|
||||
}
|
||||
41
internal/editor/edit.go
Normal file
41
internal/editor/edit.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package editor
|
||||
|
||||
//////////////////////
|
||||
// Editing Commands //
|
||||
//////////////////////
|
||||
|
||||
// r : Replace single character under cursor.
|
||||
func (ed *Editor) EditReplace(letter rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditReplace")
|
||||
}
|
||||
|
||||
// J : Join current line with next line.
|
||||
func (ed *Editor) EditJoin(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditJoin")
|
||||
}
|
||||
|
||||
// >> : Indent current line.
|
||||
func (ed *Editor) EditIndent(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditIndent")
|
||||
}
|
||||
|
||||
// << : Outdent current line.
|
||||
func (ed *Editor) EditOutdent(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditOutdent")
|
||||
}
|
||||
|
||||
// > <mv> : Indent region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) EditIndentRegion(start Loc, end Loc) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditIndentRegion")
|
||||
}
|
||||
|
||||
// < <mv> : Outdent region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) EditOutdentRegion(start Loc, end Loc) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("EditOutdentRegion")
|
||||
}
|
||||
@@ -146,6 +146,24 @@ func (ed *Editor) InsertRune(r rune) {
|
||||
ed.col = ed.inp.Column()
|
||||
}
|
||||
|
||||
func (ed *Editor) EnsureCommand() {
|
||||
if ed.mode == ModeCommand {
|
||||
return
|
||||
}
|
||||
|
||||
if ed.mode == ModeInsert {
|
||||
ed.lines[ed.row] = ed.inp.Line()
|
||||
ed.inp.Reset()
|
||||
ed.mode = ModeCommand
|
||||
ed.MoveLeft(1)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (ed *Editor) Ring(message string) {
|
||||
ed.message = message
|
||||
}
|
||||
|
||||
func (ed *Editor) Unimplemented(name string) {
|
||||
ed.Ring("not implemented (" + name + ")")
|
||||
}
|
||||
|
||||
41
internal/editor/find.go
Normal file
41
internal/editor/find.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package editor
|
||||
|
||||
////////////////////////////////
|
||||
// Character Finding Commands //
|
||||
////////////////////////////////
|
||||
|
||||
// f<letter> : Find character <letter> forward in current line.
|
||||
func (ed *Editor) FindForward(letter rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindForward")
|
||||
}
|
||||
|
||||
// F<letter> : Find character <letter> backward in current line.
|
||||
func (ed *Editor) FindBackward(letter rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindBackward")
|
||||
}
|
||||
|
||||
// t<letter> : Find before character <letter> forward in current line.
|
||||
func (ed *Editor) FindBeforeForward(letter rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindBeforeForward")
|
||||
}
|
||||
|
||||
// T<letter> : Find before character <letter> backward in current line.
|
||||
func (ed *Editor) FindBeforeBackward(letter rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindBeforeBackward")
|
||||
}
|
||||
|
||||
// ; : Find next match.
|
||||
func (ed *Editor) FindNextMatch(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindNextMatch")
|
||||
}
|
||||
|
||||
// , : Find previous match.
|
||||
func (ed *Editor) FindPrevMatch(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("FindPrevMatch")
|
||||
}
|
||||
@@ -1,19 +1,23 @@
|
||||
package editor
|
||||
|
||||
////////////////////////
|
||||
// Insertion Commands //
|
||||
////////////////////////
|
||||
|
||||
//
|
||||
// Enter Insert Mode
|
||||
//
|
||||
|
||||
// i : Switch to insert mode before cursor.
|
||||
func (ed *Editor) InsertBefore(n int) {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
ed.inp.Init(ed.CurrentLine(), ed.col)
|
||||
ed.mode = ModeInsert
|
||||
}
|
||||
|
||||
// a : Switch to insert mode after cursor.
|
||||
func (ed *Editor) InsertAfter(n int) {
|
||||
if ed.mode == ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
rc := ed.RuneCount()
|
||||
if ed.col >= rc-1 {
|
||||
ed.col = rc
|
||||
@@ -22,3 +26,37 @@ func (ed *Editor) InsertAfter(n int) {
|
||||
}
|
||||
ed.InsertBefore(n)
|
||||
}
|
||||
|
||||
// I : Switch to insert mode before first non-blank character of current line.
|
||||
func (ed *Editor) InsertBeforeNonBlank(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("InsertBeforeNonBlank")
|
||||
}
|
||||
|
||||
// A : Switch to insert mode after end of current line.
|
||||
func (ed *Editor) InsertAfterEnd(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("InsertAfterEnd")
|
||||
}
|
||||
|
||||
// R : Switch to replace (overwrite) mode.
|
||||
func (ed *Editor) InsertOverwrite(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("InsertOverwrite")
|
||||
}
|
||||
|
||||
//
|
||||
// Open Line
|
||||
//
|
||||
|
||||
// o : Open a new line below and switch to insert mode.
|
||||
func (ed *Editor) InsertOpenBelow(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("InsertOpenBelow")
|
||||
}
|
||||
|
||||
// O : Open a new line above and switch to insert mode.
|
||||
func (ed *Editor) InsertOpenAbove(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("InsertOpenAbove")
|
||||
}
|
||||
|
||||
@@ -4,16 +4,6 @@ import (
|
||||
"tea.kareha.org/lab/termi"
|
||||
)
|
||||
|
||||
func (ed *Editor) ExitInsert() {
|
||||
if ed.mode != ModeInsert {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.lines[ed.row] = ed.inp.Line()
|
||||
ed.inp.Reset()
|
||||
ed.mode = ModeCommand
|
||||
ed.MoveLeft(1)
|
||||
}
|
||||
|
||||
func (ed *Editor) InsertNewline() {
|
||||
if ed.mode != ModeInsert {
|
||||
panic("invalid state")
|
||||
@@ -85,7 +75,7 @@ func (ed *Editor) Main() {
|
||||
case termi.KeyRune:
|
||||
switch key.Rune {
|
||||
case termi.RuneEscape:
|
||||
ed.ExitInsert()
|
||||
ed.EnsureCommand()
|
||||
case termi.RuneEnter:
|
||||
ed.InsertNewline()
|
||||
case termi.RuneBackspace:
|
||||
@@ -96,16 +86,12 @@ func (ed *Editor) Main() {
|
||||
ed.InsertRune(key.Rune)
|
||||
}
|
||||
case termi.KeyUp:
|
||||
ed.ExitInsert()
|
||||
ed.MoveUp(1)
|
||||
case termi.KeyDown:
|
||||
ed.ExitInsert()
|
||||
ed.MoveDown(1)
|
||||
case termi.KeyRight:
|
||||
ed.ExitInsert()
|
||||
ed.MoveRight(1)
|
||||
case termi.KeyLeft:
|
||||
ed.ExitInsert()
|
||||
ed.MoveLeft(1)
|
||||
default:
|
||||
ed.Ring("unknown key")
|
||||
|
||||
43
internal/editor/mark.go
Normal file
43
internal/editor/mark.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package editor
|
||||
|
||||
//////////////////////
|
||||
// Marking Commands //
|
||||
//////////////////////
|
||||
|
||||
//
|
||||
// Set Mark / Move to Mark
|
||||
//
|
||||
|
||||
// m<letter> : Mark current cursor position labelled by <letter>.
|
||||
func (ed *Editor) MarkSet(letter rune) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MarkSet")
|
||||
}
|
||||
|
||||
// `<letter> : Move cursor to marked position labelled by <letter>.
|
||||
func (ed *Editor) MarkMoveTo(letter rune) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MarkMoveTo")
|
||||
}
|
||||
|
||||
// '<letter> : Move cursor to marked line labelled by <letter>.
|
||||
func (ed *Editor) MarkMoveToLine(letter rune) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MarkMoveToLine")
|
||||
}
|
||||
|
||||
//
|
||||
// Move by Context
|
||||
//
|
||||
|
||||
// “ : Move cursor to previous position in context.
|
||||
func (ed *Editor) MarkBack() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MarkBack")
|
||||
}
|
||||
|
||||
// ” : Move cursor to previous line in context.
|
||||
func (ed *Editor) MarkBackToLine() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MarkBackToLine")
|
||||
}
|
||||
@@ -1,6 +1,35 @@
|
||||
package editor
|
||||
|
||||
////////////////////////////
|
||||
// Miscellaneous Commands //
|
||||
////////////////////////////
|
||||
|
||||
// Ctrl-g : Show info such as current cursor position.
|
||||
func (ed *Editor) MiscShowInfo() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MiscShowInfo")
|
||||
}
|
||||
|
||||
// . : Repeat last edit.
|
||||
func (ed *Editor) MiscRepeat(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MiscRepeat")
|
||||
}
|
||||
|
||||
// u : Undo.
|
||||
func (ed *Editor) MiscUndo(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MiscUndo")
|
||||
}
|
||||
|
||||
// U : Restore current line to previous state.
|
||||
func (ed *Editor) MiscRestore() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MiscRestore")
|
||||
}
|
||||
|
||||
// ZZ : Save and quit.
|
||||
func (ed *Editor) MiscSaveAndQuit() {
|
||||
ed.EnsureCommand()
|
||||
ed.quit = true
|
||||
}
|
||||
|
||||
@@ -1,64 +1,62 @@
|
||||
package editor
|
||||
|
||||
/////////////////////
|
||||
// Motion Commands //
|
||||
/////////////////////
|
||||
|
||||
//
|
||||
// Move by Character / Move by Line
|
||||
//
|
||||
|
||||
// h : Move cursor left by character.
|
||||
func (ed *Editor) MoveLeft(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
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.EnsureCommand()
|
||||
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.EnsureCommand()
|
||||
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.EnsureCommand()
|
||||
ed.col += n
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
//
|
||||
// Move in Line
|
||||
//
|
||||
|
||||
// 0 : Move cursor to start of current line.
|
||||
func (ed *Editor) MoveToStart() {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
ed.col = 0
|
||||
// col is already confined
|
||||
ed.Confine() // redundant
|
||||
}
|
||||
|
||||
// $ : Move cursor to end of current line.
|
||||
func (ed *Editor) MoveToEnd() {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
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")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
line := ed.CurrentLine()
|
||||
i := 0
|
||||
for _, r := range line {
|
||||
@@ -74,9 +72,149 @@ func (ed *Editor) MoveToNonBlank() {
|
||||
// <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.EnsureCommand()
|
||||
ed.col = n - 1
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
//
|
||||
// Move by Word / Move by Loose Word
|
||||
//
|
||||
|
||||
// w : Move cursor forward by word.
|
||||
func (ed *Editor) MoveByWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveByWord")
|
||||
}
|
||||
|
||||
// b : Move cursor backward by word.
|
||||
func (ed *Editor) MoveBackwardByWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBackwardByWord")
|
||||
}
|
||||
|
||||
// e : Move cursor to end of word.
|
||||
func (ed *Editor) MoveToEndOfWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToEndOfWord")
|
||||
}
|
||||
|
||||
// W : Move cursor forward by loose word.
|
||||
func (ed *Editor) MoveByLooseWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveByLooseWord")
|
||||
}
|
||||
|
||||
// B : Move cursor backward by loose word.
|
||||
func (ed *Editor) MoveBackwardByLooseWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBackwardByLooseWord")
|
||||
}
|
||||
|
||||
// E : Move cursor to end of loose word.
|
||||
func (ed *Editor) MoveToEndOfLooseWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToEndOfLooseWord")
|
||||
}
|
||||
|
||||
//
|
||||
// Move by Line
|
||||
//
|
||||
|
||||
// Enter, + : Move cursor to first non-blank character of next line.
|
||||
func (ed *Editor) MoveToNonBlankOfNextLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToNonBlankOfNextLine")
|
||||
}
|
||||
|
||||
// - : Move cursor to first non-blank character of previous line.
|
||||
func (ed *Editor) MoveToNonBlankOfPrevLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToNonBlankOfPrevLine")
|
||||
}
|
||||
|
||||
// G : Move cursor to last line.
|
||||
func (ed *Editor) MoveToLastLine() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToLastLine")
|
||||
}
|
||||
|
||||
// <num>G : Move cursor to line <num>.
|
||||
func (ed *Editor) MoveToLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToLine")
|
||||
}
|
||||
|
||||
//
|
||||
// Move by Block
|
||||
//
|
||||
|
||||
// ) : Move cursor forward by sentence.
|
||||
func (ed *Editor) MoveBySentence(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBySentence")
|
||||
}
|
||||
|
||||
// ( : Move cursor backward by sentence.
|
||||
func (ed *Editor) MoveBackwardBySentence(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBackwardBySentence")
|
||||
}
|
||||
|
||||
// } : Move cursor forward by paragraph.
|
||||
func (ed *Editor) MoveByParagraph(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveByParagraph")
|
||||
}
|
||||
|
||||
// { : Move cursor backward by paragraph.
|
||||
func (ed *Editor) MoveBackwardByParagraph(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBackwardByParagraph")
|
||||
}
|
||||
|
||||
// ]] : Move cursor forward by section.
|
||||
func (ed *Editor) MoveBySection(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBySection")
|
||||
}
|
||||
|
||||
// [[ : Move cursor backward by section.
|
||||
func (ed *Editor) MoveBackwardBySection(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveBackwardBySection")
|
||||
}
|
||||
|
||||
//
|
||||
// Move in View
|
||||
//
|
||||
|
||||
// H : Move cursor to top of view.
|
||||
func (ed *Editor) MoveToTopOfView() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToTopOfView")
|
||||
}
|
||||
|
||||
// M : Move cursor to middle of view.
|
||||
func (ed *Editor) MoveToMiddleOfView() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToMiddleOfView")
|
||||
}
|
||||
|
||||
// L : Move cursor to bottom of view.
|
||||
func (ed *Editor) MoveToBottomOfView() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToBottomOfView")
|
||||
}
|
||||
|
||||
// <num>H : Move cursor below <num> lines from top of view.
|
||||
func (ed *Editor) MoveToBelowTopOfView(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToBelowTopOfView")
|
||||
}
|
||||
|
||||
// <num>L : Move cursor above <num> lines from bottom of view.
|
||||
func (ed *Editor) MoveToAboveBottomOfView(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("MoveToAboveBottomOfView")
|
||||
}
|
||||
|
||||
@@ -1,10 +1,78 @@
|
||||
package editor
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// Operator Commands (Copy / Delte / Change) //
|
||||
///////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// Copy (Yank)
|
||||
//
|
||||
|
||||
// yy, Y : Copy current line.
|
||||
func (ed *Editor) OpCopyLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyLine")
|
||||
}
|
||||
|
||||
// y<mv> : Copy region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpCopyRegion(start Loc, end Loc) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyRegion")
|
||||
}
|
||||
|
||||
// y<mv> : Copy region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpCopyLineRegion(start int, end int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyLineRegion")
|
||||
}
|
||||
|
||||
// yw : Copy word.
|
||||
func (ed *Editor) OpCopyWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyWord")
|
||||
}
|
||||
|
||||
// y$ : Copy to end of current line.
|
||||
func (ed *Editor) OpCopyToEnd(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyToEnd")
|
||||
}
|
||||
|
||||
// "<reg>yy : Copy current line into register <reg>.
|
||||
func (ed *Editor) OpCopyLineIntoReg(reg rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpCopyLineIntoReg")
|
||||
}
|
||||
|
||||
//
|
||||
// Paste (Put)
|
||||
//
|
||||
|
||||
// p : Paste after cursor.
|
||||
func (ed *Editor) OpPaste(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpPaste")
|
||||
}
|
||||
|
||||
// P : Paste before cursor.
|
||||
func (ed *Editor) OpPasteBefore(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpPasteBefore")
|
||||
}
|
||||
|
||||
// "<reg>p : Paste from register <reg>.
|
||||
func (ed *Editor) OpPasteFromReg(reg rune, n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpPasteFromReg")
|
||||
}
|
||||
|
||||
//
|
||||
// Delete
|
||||
//
|
||||
|
||||
// x : Delete character under cursor.
|
||||
func (ed *Editor) OpDelete(n int) {
|
||||
if ed.mode != ModeCommand {
|
||||
panic("invalid state")
|
||||
}
|
||||
ed.EnsureCommand()
|
||||
if len(ed.CurrentLine()) < 1 {
|
||||
ed.Ring("nothing to delete, line is empty")
|
||||
return
|
||||
@@ -19,3 +87,84 @@ func (ed *Editor) OpDelete(n int) {
|
||||
}
|
||||
ed.Confine()
|
||||
}
|
||||
|
||||
// X : Delete character before cursor.
|
||||
func (ed *Editor) OpDeleteBefore(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteBefore")
|
||||
}
|
||||
|
||||
// dd : Delete current line.
|
||||
func (ed *Editor) OpDeleteLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteLine")
|
||||
}
|
||||
|
||||
// d<mv> : Delete region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpDeleteRegion(start Loc, end Loc) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteRegion")
|
||||
}
|
||||
|
||||
// d<mv> : Delete region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpDeleteLineRegion(start int, end int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteLineRegion")
|
||||
}
|
||||
|
||||
// dw : Delete word.
|
||||
func (ed *Editor) OpDeleteWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteWord")
|
||||
}
|
||||
|
||||
// d$, D : Delete to end of current line.
|
||||
func (ed *Editor) OpDeleteToEnd(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpDeleteToEnd")
|
||||
}
|
||||
|
||||
//
|
||||
// Change / Substitute
|
||||
//
|
||||
|
||||
// cc : Change current line.
|
||||
func (ed *Editor) OpChangeLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpChangeLine")
|
||||
}
|
||||
|
||||
// c<mv> : Change region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpChangeRegion(start Loc, end Loc) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpChangeRegion")
|
||||
}
|
||||
|
||||
// c<mv> : Change region from current cursor to destination of motion <mv>.
|
||||
func (ed *Editor) OpChangeLineRegion(start int, end int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpChangeLineRegion")
|
||||
}
|
||||
|
||||
// cw : Change word.
|
||||
func (ed *Editor) OpChangeWord(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpChangeWord")
|
||||
}
|
||||
|
||||
// C : Change to end of current line.
|
||||
func (ed *Editor) OpChangeToEnd(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpChangeToEnd")
|
||||
}
|
||||
|
||||
// s : Substitute one character under cursor.
|
||||
func (ed *Editor) OpSubst(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("OpSubst")
|
||||
}
|
||||
|
||||
// S : Substtute current line (equals cc).
|
||||
func (ed *Editor) OpSubstLine(n int) {
|
||||
ed.OpChangeLine(n)
|
||||
}
|
||||
|
||||
@@ -56,12 +56,10 @@ var letterMoveSet = map[rune]struct{}{
|
||||
'F': {},
|
||||
't': {},
|
||||
'T': {},
|
||||
';': {},
|
||||
',': {},
|
||||
}
|
||||
|
||||
func (p *Parser) ParseMove(noNum bool, num int, op string, letter rune) (Cmd, bool) {
|
||||
switch op {
|
||||
func (p *Parser) ParseMove(noNum bool, num int, mv string, letter rune) (Cmd, bool) {
|
||||
switch mv {
|
||||
case "h":
|
||||
return Cmd{
|
||||
Kind: CmdMoveLeft,
|
||||
@@ -95,22 +93,280 @@ func (p *Parser) ParseMove(noNum bool, num int, op string, letter rune) (Cmd, bo
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
case "w":
|
||||
return Cmd{
|
||||
Kind: CmdMoveByWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "b":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBackwardByWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "e":
|
||||
return Cmd{
|
||||
Kind: CmdMoveToEndOfWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "W":
|
||||
return Cmd{
|
||||
Kind: CmdMoveByLooseWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "B":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBackwardByLooseWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "E":
|
||||
return Cmd{
|
||||
Kind: CmdMoveToEndOfLooseWord,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "\r", "+":
|
||||
return Cmd{
|
||||
Kind: CmdMoveToNonBlankOfNextLine,
|
||||
Num: num,
|
||||
}, true
|
||||
case "-":
|
||||
return Cmd{
|
||||
Kind: CmdMoveToNonBlankOfPrevLine,
|
||||
Num: num,
|
||||
}, true
|
||||
case "G":
|
||||
if noNum {
|
||||
return Cmd{Kind: CmdMoveToLastLine}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdMoveToLine,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
|
||||
case ")":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBySentence,
|
||||
Num: num,
|
||||
}, true
|
||||
case "(":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBackwardBySentence,
|
||||
Num: num,
|
||||
}, true
|
||||
case "}":
|
||||
return Cmd{
|
||||
Kind: CmdMoveByParagraph,
|
||||
Num: num,
|
||||
}, true
|
||||
case "{":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBackwardByParagraph,
|
||||
Num: num,
|
||||
}, true
|
||||
case "]]":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBySection,
|
||||
Num: num,
|
||||
}, true
|
||||
case "[[":
|
||||
return Cmd{
|
||||
Kind: CmdMoveBackwardBySection,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "H":
|
||||
if noNum {
|
||||
return Cmd{Kind: CmdMoveToTopOfView}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdMoveToBelowTopOfView,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
case "M":
|
||||
return Cmd{Kind: CmdMoveToMiddleOfView}, true
|
||||
case "L":
|
||||
if noNum {
|
||||
return Cmd{Kind: CmdMoveToBottomOfView}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdMoveToAboveBottomOfView,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
}
|
||||
|
||||
return p.ParseFind(num, mv, letter)
|
||||
}
|
||||
|
||||
func (p *Parser) ParseLetter(num int, op string, letter rune) (Cmd, bool) {
|
||||
if letter == 0 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
switch op {
|
||||
case "m":
|
||||
return Cmd{
|
||||
Kind: CmdMarkSet,
|
||||
Letter: letter,
|
||||
}, true
|
||||
case "`":
|
||||
if letter == '`' {
|
||||
return Cmd{Kind: CmdMarkBack}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdMarkMoveTo,
|
||||
Letter: letter,
|
||||
}, true
|
||||
}
|
||||
case "'":
|
||||
if letter == '\'' {
|
||||
return Cmd{Kind: CmdMarkBackToLine}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdMarkMoveToLine,
|
||||
Letter: letter,
|
||||
}, true
|
||||
}
|
||||
}
|
||||
|
||||
switch op {
|
||||
case "r":
|
||||
return Cmd{
|
||||
Kind: CmdEditReplace,
|
||||
Num: num,
|
||||
Letter: letter,
|
||||
}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseLetter(num int, op string, letter rune) (Cmd, bool) {
|
||||
func (p *Parser) ParseView(num int, op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "m":
|
||||
return Cmd{}, false // TODO
|
||||
case "'":
|
||||
return Cmd{}, false // TODO
|
||||
case "`":
|
||||
return Cmd{}, false // TODO
|
||||
case "r":
|
||||
return Cmd{}, false // TODO
|
||||
case "\x06": // Ctrl-f
|
||||
return Cmd{
|
||||
Kind: CmdViewDown,
|
||||
Num: num,
|
||||
}, true
|
||||
case "\x02": // Ctrl-b
|
||||
return Cmd{
|
||||
Kind: CmdViewUp,
|
||||
Num: num,
|
||||
}, true
|
||||
case "\x04": // Ctrl-d
|
||||
return Cmd{
|
||||
Kind: CmdViewDownHalf,
|
||||
Num: num,
|
||||
}, true
|
||||
case "\x15": // Ctrl-u
|
||||
return Cmd{
|
||||
Kind: CmdViewUpHalf,
|
||||
Num: num,
|
||||
}, true
|
||||
case "\x19": // Ctrl-y
|
||||
return Cmd{
|
||||
Kind: CmdViewDownLine,
|
||||
Num: num,
|
||||
}, true
|
||||
case "\x05": // Ctrl-e
|
||||
return Cmd{
|
||||
Kind: CmdViewUpLine,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "z\r":
|
||||
return Cmd{Kind: CmdViewToTop}, true
|
||||
case "z.":
|
||||
return Cmd{Kind: CmdViewToMiddle}, true
|
||||
case "z-":
|
||||
return Cmd{Kind: CmdViewToBottom}, true
|
||||
|
||||
case "\x0c": // Ctrl-l
|
||||
return Cmd{Kind: CmdViewRedraw}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseSearch(op string, pat string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "/":
|
||||
if pat == "" {
|
||||
return Cmd{Kind: CmdSearchRepeatForward}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdSearchForward,
|
||||
Pat: pat,
|
||||
}, true
|
||||
}
|
||||
case "?":
|
||||
if pat == "" {
|
||||
return Cmd{Kind: CmdSearchRepeatBackward}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdSearchBackward,
|
||||
Pat: pat,
|
||||
}, true
|
||||
}
|
||||
case "n":
|
||||
return Cmd{Kind: CmdSearchNextMatch}, true
|
||||
case "N":
|
||||
return Cmd{Kind: CmdSearchPrevMatch}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseFind(num int, op string, letter rune) (Cmd, bool) {
|
||||
switch op {
|
||||
case "f":
|
||||
if letter == 0 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
return Cmd{
|
||||
Kind: CmdFindForward,
|
||||
Num: num,
|
||||
Letter: letter,
|
||||
}, true
|
||||
case "F":
|
||||
if letter == 0 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
return Cmd{
|
||||
Kind: CmdFindBackward,
|
||||
Num: num,
|
||||
Letter: letter,
|
||||
}, true
|
||||
case "t":
|
||||
if letter == 0 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
return Cmd{
|
||||
Kind: CmdFindBeforeForward,
|
||||
Num: num,
|
||||
Letter: letter,
|
||||
}, true
|
||||
case "T":
|
||||
if letter == 0 {
|
||||
return Cmd{}, false
|
||||
}
|
||||
return Cmd{
|
||||
Kind: CmdFindBeforeBackward,
|
||||
Num: num,
|
||||
Letter: letter,
|
||||
}, true
|
||||
case ";":
|
||||
return Cmd{
|
||||
Kind: CmdFindNextMatch,
|
||||
Num: num,
|
||||
}, true
|
||||
case ",":
|
||||
return Cmd{
|
||||
Kind: CmdFindPrevMatch,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
@@ -128,19 +384,55 @@ func (p *Parser) ParseInsert(num int, op string) (Cmd, bool) {
|
||||
Kind: CmdInsertAfter,
|
||||
Num: num,
|
||||
}, true
|
||||
case "I":
|
||||
return Cmd{
|
||||
Kind: CmdInsertBeforeNonBlank,
|
||||
Num: num,
|
||||
}, true
|
||||
case "A":
|
||||
return Cmd{
|
||||
Kind: CmdInsertAfterEnd,
|
||||
Num: num,
|
||||
}, true
|
||||
case "R":
|
||||
return Cmd{
|
||||
Kind: CmdInsertOverwrite,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
case "o":
|
||||
return Cmd{
|
||||
Kind: CmdInsertOpenBelow,
|
||||
Num: num,
|
||||
}, true
|
||||
case "O":
|
||||
return Cmd{
|
||||
Kind: CmdInsertOpenAbove,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseMisc(op string) (Cmd, bool) {
|
||||
func (p *Parser) ParseMisc(num int, op string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "\x07": // Ctrl-g
|
||||
return Cmd{Kind: CmdMiscShowInfo}, true
|
||||
case ".":
|
||||
return Cmd{
|
||||
Kind: CmdMiscRepeat,
|
||||
Num: num,
|
||||
}, true
|
||||
case "u":
|
||||
return Cmd{
|
||||
Kind: CmdMiscUndo,
|
||||
Num: num,
|
||||
}, true
|
||||
case "U":
|
||||
return Cmd{Kind: CmdMiscRestore}, true
|
||||
case "ZZ":
|
||||
return Cmd{Kind: CmdMiscSaveAndQuit}, true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
@@ -148,19 +440,191 @@ func (p *Parser) ParseMisc(op string) (Cmd, bool) {
|
||||
|
||||
func (p *Parser) ParseOp(reg rune, num int, op string, noSubnum bool, subnum int, mv string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "yy", "Y":
|
||||
if reg == 0 {
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyLine,
|
||||
Num: num,
|
||||
}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyLineIntoReg,
|
||||
Num: num,
|
||||
Reg: reg,
|
||||
}, true
|
||||
}
|
||||
case "y":
|
||||
/*
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyRegion,
|
||||
Start: Loc{}, // TODO
|
||||
End: Loc{}, // TODO
|
||||
}, true
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyLineRegion,
|
||||
StartRow: 0, // TODO
|
||||
EndRow: 0, // TODO
|
||||
}, true
|
||||
*/
|
||||
case "yw":
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "y$":
|
||||
return Cmd{
|
||||
Kind: CmdOpCopyToEnd,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "p":
|
||||
if reg == 0 {
|
||||
return Cmd{
|
||||
Kind: CmdOpPaste,
|
||||
Num: num,
|
||||
}, true
|
||||
} else {
|
||||
return Cmd{
|
||||
Kind: CmdOpPasteFromReg,
|
||||
Num: num,
|
||||
Reg: reg,
|
||||
}, true
|
||||
}
|
||||
case "P":
|
||||
return Cmd{
|
||||
Kind: CmdOpPasteBefore,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
case "x":
|
||||
return Cmd{
|
||||
Kind: CmdOpDelete,
|
||||
Num: num,
|
||||
}, true
|
||||
case "X":
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteBefore,
|
||||
Num: num,
|
||||
}, true
|
||||
case "dd":
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteLine,
|
||||
Num: num,
|
||||
}, true
|
||||
case "d":
|
||||
/*
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteRegion,
|
||||
Start: Loc{}, // TODO
|
||||
End: Loc{}, // TODO
|
||||
}, true
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteLineRegion,
|
||||
StartRow: 0, // TODO
|
||||
EndRow: 0, // TODO
|
||||
}, true
|
||||
*/
|
||||
case "dw":
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "d$", "D":
|
||||
return Cmd{
|
||||
Kind: CmdOpDeleteToEnd,
|
||||
Num: num,
|
||||
}, true
|
||||
|
||||
// TODO
|
||||
case "cc":
|
||||
return Cmd{
|
||||
Kind: CmdOpChangeLine,
|
||||
Num: num,
|
||||
}, true
|
||||
case "c":
|
||||
/*
|
||||
return Cmd{
|
||||
Kind: CmdOpChangeRegion,
|
||||
Start: Loc{}, // TODO
|
||||
End: Loc{}, // TODO
|
||||
}, true
|
||||
return Cmd{
|
||||
Kind: CmdOpChangeLineRegion,
|
||||
StartRow: 0, // TODO
|
||||
EndRow: 0, // TODO
|
||||
}, true
|
||||
*/
|
||||
case "cw":
|
||||
return Cmd{
|
||||
Kind: CmdOpChangeWord,
|
||||
Num: num,
|
||||
}, true
|
||||
case "C":
|
||||
return Cmd{
|
||||
Kind: CmdOpChangeToEnd,
|
||||
Num: num,
|
||||
}, true
|
||||
case "s":
|
||||
return Cmd{
|
||||
Kind: CmdOpSubst,
|
||||
Num: num,
|
||||
}, true
|
||||
case "S":
|
||||
return Cmd{
|
||||
Kind: CmdOpSubstLine,
|
||||
Num: num,
|
||||
}, true
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
func (p *Parser) ParseEdit(num int, op string, noSubnum bool, subnum int, mv string) (Cmd, bool) {
|
||||
switch op {
|
||||
case "J":
|
||||
return Cmd{
|
||||
Kind: CmdEditJoin,
|
||||
Num: num,
|
||||
}, true
|
||||
case ">>":
|
||||
return Cmd{
|
||||
Kind: CmdEditIndent,
|
||||
Num: num,
|
||||
}, true
|
||||
case "<<":
|
||||
return Cmd{
|
||||
Kind: CmdEditOutdent,
|
||||
Num: num,
|
||||
}, true
|
||||
case ">":
|
||||
/*
|
||||
return Cmd{
|
||||
Kind: CmdEditIndentRegion,
|
||||
Start: Loc{}, // TODO
|
||||
End: Loc{}, // TODO
|
||||
}, true
|
||||
*/
|
||||
case "<":
|
||||
/*
|
||||
return Cmd{
|
||||
Kind: CmdEditOutdentRegion,
|
||||
Start: Loc{}, // TODO
|
||||
End: Loc{}, // TODO
|
||||
}, true
|
||||
*/
|
||||
}
|
||||
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
var compoundSet = map[rune]struct{}{
|
||||
']': {},
|
||||
'[': {},
|
||||
|
||||
'`': {},
|
||||
'\'': {},
|
||||
|
||||
'z': {},
|
||||
|
||||
'y': {},
|
||||
'd': {},
|
||||
'c': {},
|
||||
@@ -174,17 +638,15 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
if len(p.buf) == 1 {
|
||||
if p.buf[0] == '0' { // special
|
||||
return Cmd{Kind: CmdMoveToStart}, true
|
||||
}
|
||||
if p.buf[0] == '0' { // special
|
||||
return Cmd{Kind: CmdMoveToStart}, true
|
||||
}
|
||||
|
||||
i := 0
|
||||
var reg rune = 0
|
||||
if p.buf[i] == '"' {
|
||||
if len(p.buf) > i+1 {
|
||||
reg = p.buf[i+1]
|
||||
if p.buf[0] == '"' {
|
||||
if len(p.buf) > 1 {
|
||||
reg = p.buf[1]
|
||||
i += 2
|
||||
}
|
||||
}
|
||||
@@ -196,9 +658,9 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
}
|
||||
i++
|
||||
}
|
||||
noNum := i == iPrev
|
||||
noNum := i <= iPrev
|
||||
num := 1
|
||||
if i > 0 {
|
||||
if i > iPrev {
|
||||
s := string(p.buf[iPrev:i])
|
||||
n, err := strconv.Atoi(s)
|
||||
if err != nil {
|
||||
@@ -207,6 +669,37 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
num = n
|
||||
}
|
||||
|
||||
if i < len(p.buf) {
|
||||
var letter rune = 0
|
||||
_, ok := letterOpSet[p.buf[i]]
|
||||
if ok {
|
||||
if i+1 >= len(p.buf) {
|
||||
return Cmd{}, false
|
||||
}
|
||||
op := string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
cmd, ok := p.ParseLetter(num, op, letter)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
}
|
||||
_, ok = letterMoveSet[p.buf[i]]
|
||||
if ok {
|
||||
if i+1 >= len(p.buf) {
|
||||
return Cmd{}, false
|
||||
}
|
||||
mv := string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
cmd, ok := p.ParseFind(num, mv, letter)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
}
|
||||
if letter != 0 {
|
||||
return Cmd{Kind: CmdInvalid}, true
|
||||
}
|
||||
}
|
||||
|
||||
iPrev = i
|
||||
for i < len(p.buf) {
|
||||
if p.buf[i] >= '0' && p.buf[i] <= '9' {
|
||||
@@ -218,31 +711,6 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
return Cmd{}, false
|
||||
}
|
||||
|
||||
if i+1 < len(p.buf) {
|
||||
var letter rune = 0
|
||||
_, ok := letterOpSet[p.buf[i]]
|
||||
if ok {
|
||||
op := string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
cmd, ok := p.ParseLetter(num, op, letter)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
}
|
||||
_, ok = letterMoveSet[p.buf[i]]
|
||||
if ok {
|
||||
mv := string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
cmd, ok := p.ParseMove(noNum, num, mv, letter)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
}
|
||||
if letter != 0 {
|
||||
return Cmd{Kind: CmdInvalid}, true
|
||||
}
|
||||
}
|
||||
|
||||
mv := string(p.buf[iPrev:i])
|
||||
|
||||
cmd, ok := p.ParseMove(noNum, num, mv, 0)
|
||||
@@ -252,11 +720,23 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
op := mv
|
||||
opFirst := p.buf[iPrev]
|
||||
|
||||
cmd, ok = p.ParseView(num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
pat := ""
|
||||
if op == "/" || op == "?" {
|
||||
// TODO input pat
|
||||
}
|
||||
cmd, ok = p.ParseSearch(op, pat)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseInsert(num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseMisc(op)
|
||||
cmd, ok = p.ParseMisc(num, op)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
@@ -268,7 +748,7 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
}
|
||||
i++
|
||||
}
|
||||
noSubnum := i == iPrev
|
||||
noSubnum := i <= iPrev
|
||||
subnum := 1
|
||||
if i > iPrev {
|
||||
s := string(p.buf[iPrev:i])
|
||||
@@ -279,20 +759,14 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
subnum = n
|
||||
}
|
||||
|
||||
iPrev = i
|
||||
for i < len(p.buf) {
|
||||
if p.buf[i] >= '0' && p.buf[i] <= '9' {
|
||||
break
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
var letter rune = 0
|
||||
if i+1 < len(p.buf) {
|
||||
if i < len(p.buf) {
|
||||
_, ok := letterMoveSet[p.buf[i]]
|
||||
if ok {
|
||||
mv = string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
if i+1 < len(p.buf) {
|
||||
mv = string(p.buf[i : i+1])
|
||||
letter = p.buf[i+1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,6 +781,10 @@ func (p *Parser) Parse() (Cmd, bool) {
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
cmd, ok = p.ParseEdit(num, op, noSubnum, subnum, mv)
|
||||
if ok {
|
||||
return cmd, true
|
||||
}
|
||||
|
||||
if len(op) < 2 {
|
||||
_, ok := compoundSet[opFirst]
|
||||
|
||||
@@ -6,7 +6,9 @@ func (ed *Editor) Run(c Cmd) bool {
|
||||
ed.Ring("not (yet) a vi command [" + ed.parser.String() + "]")
|
||||
ed.parser.Clear()
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdMoveLeft:
|
||||
ed.MoveLeft(c.Num)
|
||||
return true
|
||||
@@ -33,28 +35,305 @@ func (ed *Editor) Run(c Cmd) bool {
|
||||
ed.MoveToColumn(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
case CmdMoveByWord:
|
||||
ed.MoveByWord(c.Num)
|
||||
return true
|
||||
case CmdMoveBackwardByWord:
|
||||
ed.MoveBackwardByWord(c.Num)
|
||||
return true
|
||||
case CmdMoveToEndOfWord:
|
||||
ed.MoveToEndOfWord(c.Num)
|
||||
return true
|
||||
case CmdMoveByLooseWord:
|
||||
ed.MoveByLooseWord(c.Num)
|
||||
return true
|
||||
case CmdMoveBackwardByLooseWord:
|
||||
ed.MoveBackwardByLooseWord(c.Num)
|
||||
return true
|
||||
case CmdMoveToEndOfLooseWord:
|
||||
ed.MoveToEndOfLooseWord(c.Num)
|
||||
return true
|
||||
|
||||
case CmdMoveToNonBlankOfNextLine:
|
||||
ed.MoveToNonBlankOfNextLine(c.Num)
|
||||
return true
|
||||
case CmdMoveToNonBlankOfPrevLine:
|
||||
ed.MoveToNonBlankOfPrevLine(c.Num)
|
||||
return true
|
||||
case CmdMoveToLastLine:
|
||||
ed.MoveToLastLine()
|
||||
return true
|
||||
case CmdMoveToLine:
|
||||
ed.MoveToLine(c.Num)
|
||||
return true
|
||||
|
||||
case CmdMoveBySentence:
|
||||
ed.MoveBySentence(c.Num)
|
||||
return true
|
||||
case CmdMoveBackwardBySentence:
|
||||
ed.MoveBackwardBySentence(c.Num)
|
||||
return true
|
||||
case CmdMoveByParagraph:
|
||||
ed.MoveByParagraph(c.Num)
|
||||
return true
|
||||
case CmdMoveBackwardByParagraph:
|
||||
ed.MoveBackwardByParagraph(c.Num)
|
||||
return true
|
||||
case CmdMoveBySection:
|
||||
ed.MoveBySection(c.Num)
|
||||
return true
|
||||
case CmdMoveBackwardBySection:
|
||||
ed.MoveBackwardBySection(c.Num)
|
||||
return true
|
||||
|
||||
case CmdMoveToTopOfView:
|
||||
ed.MoveToTopOfView()
|
||||
return true
|
||||
case CmdMoveToMiddleOfView:
|
||||
ed.MoveToMiddleOfView()
|
||||
return true
|
||||
case CmdMoveToBottomOfView:
|
||||
ed.MoveToBottomOfView()
|
||||
return true
|
||||
case CmdMoveToBelowTopOfView:
|
||||
ed.MoveToBelowTopOfView(c.Num)
|
||||
return true
|
||||
case CmdMoveToAboveBottomOfView:
|
||||
ed.MoveToAboveBottomOfView(c.Num)
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdMarkSet:
|
||||
ed.MarkSet(c.Letter)
|
||||
return true
|
||||
case CmdMarkMoveTo:
|
||||
ed.MarkMoveTo(c.Letter)
|
||||
return true
|
||||
case CmdMarkMoveToLine:
|
||||
ed.MarkMoveToLine(c.Letter)
|
||||
return true
|
||||
|
||||
case CmdMarkBack:
|
||||
ed.MarkBack()
|
||||
return true
|
||||
case CmdMarkBackToLine:
|
||||
ed.MarkBackToLine()
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdViewDown:
|
||||
ed.ViewDown(c.Num)
|
||||
return true
|
||||
case CmdViewUp:
|
||||
ed.ViewUp(c.Num)
|
||||
return true
|
||||
case CmdViewDownHalf:
|
||||
ed.ViewDownHalf(c.Num)
|
||||
return true
|
||||
case CmdViewUpHalf:
|
||||
ed.ViewUpHalf(c.Num)
|
||||
return true
|
||||
case CmdViewDownLine:
|
||||
ed.ViewDownLine(c.Num)
|
||||
return true
|
||||
case CmdViewUpLine:
|
||||
ed.ViewUpLine(c.Num)
|
||||
return true
|
||||
|
||||
case CmdViewToTop:
|
||||
ed.ViewToTop()
|
||||
return true
|
||||
case CmdViewToMiddle:
|
||||
ed.ViewToMiddle()
|
||||
return true
|
||||
case CmdViewToBottom:
|
||||
ed.ViewToBottom()
|
||||
return true
|
||||
|
||||
case CmdViewRedraw:
|
||||
ed.ViewRedraw()
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdSearchForward:
|
||||
ed.SearchForward(c.Pat)
|
||||
return true
|
||||
case CmdSearchBackward:
|
||||
ed.SearchBackward(c.Pat)
|
||||
return true
|
||||
case CmdSearchNextMatch:
|
||||
ed.SearchNextMatch()
|
||||
return true
|
||||
case CmdSearchPrevMatch:
|
||||
ed.SearchPrevMatch()
|
||||
return true
|
||||
case CmdSearchRepeatForward:
|
||||
ed.SearchRepeatForward()
|
||||
return true
|
||||
case CmdSearchRepeatBackward:
|
||||
ed.SearchRepeatBackward()
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdFindForward:
|
||||
ed.FindForward(c.Letter, c.Num)
|
||||
return true
|
||||
case CmdFindBackward:
|
||||
ed.FindBackward(c.Letter, c.Num)
|
||||
return true
|
||||
case CmdFindBeforeForward:
|
||||
ed.FindBeforeForward(c.Letter, c.Num)
|
||||
return true
|
||||
case CmdFindBeforeBackward:
|
||||
ed.FindBeforeBackward(c.Letter, c.Num)
|
||||
return true
|
||||
case CmdFindNextMatch:
|
||||
ed.FindNextMatch(c.Num)
|
||||
return true
|
||||
case CmdFindPrevMatch:
|
||||
ed.FindPrevMatch(c.Num)
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdInsertBefore:
|
||||
ed.InsertBefore(c.Num)
|
||||
return true
|
||||
case CmdInsertAfter:
|
||||
ed.InsertAfter(c.Num)
|
||||
return true
|
||||
case CmdInsertBeforeNonBlank:
|
||||
ed.InsertBeforeNonBlank(c.Num)
|
||||
return true
|
||||
case CmdInsertAfterEnd:
|
||||
ed.InsertAfterEnd(c.Num)
|
||||
return true
|
||||
case CmdInsertOverwrite:
|
||||
ed.InsertOverwrite(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
case CmdInsertOpenBelow:
|
||||
ed.InsertOpenBelow(c.Num)
|
||||
return true
|
||||
case CmdInsertOpenAbove:
|
||||
ed.InsertOpenAbove(c.Num)
|
||||
return true
|
||||
|
||||
case CmdOpCopyLine:
|
||||
ed.OpCopyLine(c.Num)
|
||||
return true
|
||||
case CmdOpCopyRegion:
|
||||
ed.OpCopyRegion(c.Start, c.End)
|
||||
return true
|
||||
case CmdOpCopyLineRegion:
|
||||
ed.OpCopyLineRegion(c.StartRow, c.EndRow)
|
||||
return true
|
||||
case CmdOpCopyWord:
|
||||
ed.OpCopyWord(c.Num)
|
||||
return true
|
||||
case CmdOpCopyToEnd:
|
||||
ed.OpCopyToEnd(c.Num)
|
||||
return true
|
||||
case CmdOpCopyLineIntoReg:
|
||||
ed.OpCopyLineIntoReg(c.Reg, c.Num)
|
||||
return true
|
||||
|
||||
case CmdOpPaste:
|
||||
ed.OpPaste(c.Num)
|
||||
return true
|
||||
case CmdOpPasteBefore:
|
||||
ed.OpPasteBefore(c.Num)
|
||||
return true
|
||||
case CmdOpPasteFromReg:
|
||||
ed.OpPasteFromReg(c.Reg, c.Num)
|
||||
return true
|
||||
|
||||
case CmdOpDelete:
|
||||
ed.OpDelete(c.Num)
|
||||
return true
|
||||
case CmdOpDeleteBefore:
|
||||
ed.OpDeleteBefore(c.Num)
|
||||
return true
|
||||
case CmdOpDeleteLine:
|
||||
ed.OpDeleteLine(c.Num)
|
||||
return true
|
||||
case CmdOpDeleteRegion:
|
||||
ed.OpDeleteRegion(c.Start, c.End)
|
||||
return true
|
||||
case CmdOpDeleteLineRegion:
|
||||
ed.OpDeleteLineRegion(c.StartRow, c.EndRow)
|
||||
return true
|
||||
case CmdOpDeleteWord:
|
||||
ed.OpDeleteWord(c.Num)
|
||||
return true
|
||||
case CmdOpDeleteToEnd:
|
||||
ed.OpDeleteToEnd(c.Num)
|
||||
return true
|
||||
|
||||
// TODO
|
||||
case CmdOpChangeLine:
|
||||
ed.OpChangeLine(c.Num)
|
||||
return true
|
||||
case CmdOpChangeRegion:
|
||||
ed.OpChangeRegion(c.Start, c.End)
|
||||
return true
|
||||
case CmdOpChangeLineRegion:
|
||||
ed.OpChangeLineRegion(c.StartRow, c.EndRow)
|
||||
return true
|
||||
case CmdOpChangeWord:
|
||||
ed.OpChangeWord(c.Num)
|
||||
return true
|
||||
case CmdOpChangeToEnd:
|
||||
ed.OpChangeToEnd(c.Num)
|
||||
return true
|
||||
case CmdOpSubst:
|
||||
ed.OpSubst(c.Num)
|
||||
return true
|
||||
case CmdOpSubstLine:
|
||||
ed.OpSubstLine(c.Num)
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdEditReplace:
|
||||
ed.EditReplace(c.Letter, c.Num)
|
||||
return true
|
||||
case CmdEditJoin:
|
||||
ed.EditJoin(c.Num)
|
||||
return true
|
||||
case CmdEditIndent:
|
||||
ed.EditIndent(c.Num)
|
||||
return true
|
||||
case CmdEditOutdent:
|
||||
ed.EditOutdent(c.Num)
|
||||
return true
|
||||
case CmdEditIndentRegion:
|
||||
ed.EditIndentRegion(c.Start, c.End)
|
||||
return true
|
||||
case CmdEditOutdentRegion:
|
||||
ed.EditOutdentRegion(c.Start, c.End)
|
||||
return true
|
||||
}
|
||||
|
||||
switch c.Kind {
|
||||
case CmdMiscShowInfo:
|
||||
ed.MiscShowInfo()
|
||||
return true
|
||||
case CmdMiscRepeat:
|
||||
ed.MiscRepeat(c.Num)
|
||||
return true
|
||||
case CmdMiscUndo:
|
||||
ed.MiscUndo(c.Num)
|
||||
return true
|
||||
case CmdMiscRestore:
|
||||
ed.MiscRestore()
|
||||
return true
|
||||
case CmdMiscSaveAndQuit:
|
||||
ed.MiscSaveAndQuit()
|
||||
return true
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
41
internal/editor/search.go
Normal file
41
internal/editor/search.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package editor
|
||||
|
||||
/////////////////////
|
||||
// Search Commands //
|
||||
/////////////////////
|
||||
|
||||
// /<pattern> Enter : Search <pattern> forward.
|
||||
func (ed *Editor) SearchForward(s string) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchForward")
|
||||
}
|
||||
|
||||
// ?<pattern> Enter : Search <pattern> backward.
|
||||
func (ed *Editor) SearchBackward(s string) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchBackward")
|
||||
}
|
||||
|
||||
// n : Search next match.
|
||||
func (ed *Editor) SearchNextMatch() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchNextMatch")
|
||||
}
|
||||
|
||||
// N : Search previous match.
|
||||
func (ed *Editor) SearchPrevMatch() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchPrevMatch")
|
||||
}
|
||||
|
||||
// / Enter : Repeat last search forward.
|
||||
func (ed *Editor) SearchRepeatForward() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchRepeatForward")
|
||||
}
|
||||
|
||||
// ? Enter : Repeat last search backward.
|
||||
func (ed *Editor) SearchRepeatBackward() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("SearchRepeatBackward")
|
||||
}
|
||||
@@ -1,110 +1,77 @@
|
||||
package editor
|
||||
|
||||
import (
|
||||
"unicode/utf8"
|
||||
///////////////////
|
||||
// View Commands //
|
||||
///////////////////
|
||||
|
||||
"tea.kareha.org/lab/termi"
|
||||
)
|
||||
//
|
||||
// Scroll by View Height / Scroll by Line
|
||||
//
|
||||
|
||||
func (ed *Editor) LineHeight(line string) int {
|
||||
rc := utf8.RuneCountInString(line)
|
||||
width := termi.StringWidth(line, rc)
|
||||
return 1 + max(width-1, 0)/ed.w
|
||||
// Ctrl-f : Scroll down by view height.
|
||||
func (ed *Editor) ViewDown(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewDown")
|
||||
}
|
||||
|
||||
func (ed *Editor) DrawBuffer() {
|
||||
y := 0
|
||||
for i := ed.vrow; i < len(ed.lines); i++ {
|
||||
line := ed.Line(i)
|
||||
|
||||
termi.MoveCursor(0, y)
|
||||
termi.Draw(line)
|
||||
|
||||
y += ed.LineHeight(line)
|
||||
if y >= ed.h-1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for ; y < ed.h-1; y++ {
|
||||
termi.MoveCursor(0, y)
|
||||
termi.Draw("~")
|
||||
}
|
||||
// Ctrl-b : Scroll up by view height.
|
||||
func (ed *Editor) ViewUp(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewUp")
|
||||
}
|
||||
|
||||
func (ed *Editor) DrawStatus() {
|
||||
var m string
|
||||
switch ed.mode {
|
||||
case ModeCommand:
|
||||
m = "vi command"
|
||||
case ModeInsert:
|
||||
m = "vi insert"
|
||||
case ModeSearch:
|
||||
m = "vi search"
|
||||
case ModePrompt:
|
||||
m = "vi prompt"
|
||||
default:
|
||||
panic("invalid mode")
|
||||
}
|
||||
|
||||
termi.MoveCursor(0, ed.h-1)
|
||||
if ed.message != "" {
|
||||
termi.EnableInvert()
|
||||
termi.Print(ed.message)
|
||||
termi.DisableInvert()
|
||||
ed.message = ""
|
||||
} else {
|
||||
termi.Printf("[%s] %s %d,%d %s", ed.parser.Cache(), m, ed.row, ed.col, ed.path)
|
||||
}
|
||||
// Ctrl-d : Scroll down by half view height.
|
||||
func (ed *Editor) ViewDownHalf(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewDownHalf")
|
||||
}
|
||||
|
||||
func (ed *Editor) UpdateCursor() {
|
||||
// XXX approximation
|
||||
width := termi.StringWidth(ed.CurrentLine(), ed.col)
|
||||
ed.x = width % ed.w
|
||||
dy := width / ed.w
|
||||
|
||||
if ed.row < ed.vrow {
|
||||
ed.vrow = ed.row
|
||||
}
|
||||
|
||||
y := 0
|
||||
for i := ed.vrow; i < ed.row; i++ {
|
||||
y += ed.LineHeight(ed.lines[i])
|
||||
}
|
||||
ed.y = y + dy
|
||||
|
||||
for ed.y >= ed.h-1 {
|
||||
ed.vrow++
|
||||
|
||||
y := 0
|
||||
for i := ed.vrow; i < ed.row; i++ {
|
||||
y += ed.LineHeight(ed.lines[i])
|
||||
}
|
||||
ed.y = y + dy
|
||||
}
|
||||
// Ctrl-u : Scroll up by half view height.
|
||||
func (ed *Editor) ViewUpHalf(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewUpHalf")
|
||||
}
|
||||
|
||||
func (ed *Editor) Repaint() {
|
||||
w, h := termi.Size()
|
||||
ed.w = w
|
||||
ed.h = h
|
||||
|
||||
termi.HideCursor()
|
||||
|
||||
termi.Clear()
|
||||
termi.HomeCursor()
|
||||
|
||||
ed.UpdateCursor()
|
||||
|
||||
ed.DrawBuffer()
|
||||
ed.DrawStatus()
|
||||
|
||||
termi.MoveCursor(ed.x, ed.y)
|
||||
|
||||
termi.ShowCursor()
|
||||
// Ctrl-y : Scroll down by line.
|
||||
func (ed *Editor) ViewDownLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewDownLine")
|
||||
}
|
||||
|
||||
func (ed *Editor) Draw() {
|
||||
ed.Repaint()
|
||||
// Ctrl-e : Scroll up by line.
|
||||
func (ed *Editor) ViewUpLine(n int) {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewUpLine")
|
||||
}
|
||||
|
||||
//
|
||||
// Reposition
|
||||
//
|
||||
|
||||
// z Enter : Reposition cursor line to top of view.
|
||||
func (ed *Editor) ViewToTop() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewToTop")
|
||||
}
|
||||
|
||||
// z. : Reposition cursor line middle of view.
|
||||
func (ed *Editor) ViewToMiddle() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewToMiddle")
|
||||
}
|
||||
|
||||
// z- : Reposition cursor line bottom of view.
|
||||
func (ed *Editor) ViewToBottom() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewToBottom")
|
||||
}
|
||||
|
||||
//
|
||||
// Redraw
|
||||
//
|
||||
|
||||
// Ctrl-l : Redraw view.
|
||||
func (ed *Editor) ViewRedraw() {
|
||||
ed.EnsureCommand()
|
||||
ed.Unimplemented("ViewRedraw")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user