| package readline |
| |
| const ( |
| VIM_NORMAL = iota |
| VIM_INSERT |
| VIM_VISUAL |
| ) |
| |
| type opVim struct { |
| cfg *Config |
| op *Operation |
| vimMode int |
| } |
| |
| func newVimMode(op *Operation) *opVim { |
| ov := &opVim{ |
| cfg: op.cfg, |
| op: op, |
| } |
| ov.SetVimMode(ov.cfg.VimMode) |
| return ov |
| } |
| |
| func (o *opVim) SetVimMode(on bool) { |
| if o.cfg.VimMode && !on { // turn off |
| o.ExitVimMode() |
| } |
| o.cfg.VimMode = on |
| o.vimMode = VIM_INSERT |
| } |
| |
| func (o *opVim) ExitVimMode() { |
| o.vimMode = VIM_INSERT |
| } |
| |
| func (o *opVim) IsEnableVimMode() bool { |
| return o.cfg.VimMode |
| } |
| |
| func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) { |
| rb := o.op.buf |
| handled = true |
| switch r { |
| case 'h': |
| t = CharBackward |
| case 'j': |
| t = CharNext |
| case 'k': |
| t = CharPrev |
| case 'l': |
| t = CharForward |
| case '0', '^': |
| rb.MoveToLineStart() |
| case '$': |
| rb.MoveToLineEnd() |
| case 'x': |
| rb.Delete() |
| if rb.IsCursorInEnd() { |
| rb.MoveBackward() |
| } |
| case 'r': |
| rb.Replace(readNext()) |
| case 'd': |
| next := readNext() |
| switch next { |
| case 'd': |
| rb.Erase() |
| case 'w': |
| rb.DeleteWord() |
| case 'h': |
| rb.Backspace() |
| case 'l': |
| rb.Delete() |
| } |
| case 'p': |
| rb.Yank() |
| case 'b', 'B': |
| rb.MoveToPrevWord() |
| case 'w', 'W': |
| rb.MoveToNextWord() |
| case 'e', 'E': |
| rb.MoveToEndWord() |
| case 'f', 'F', 't', 'T': |
| next := readNext() |
| prevChar := r == 't' || r == 'T' |
| reverse := r == 'F' || r == 'T' |
| switch next { |
| case CharEsc: |
| default: |
| rb.MoveTo(next, prevChar, reverse) |
| } |
| default: |
| return r, false |
| } |
| return t, true |
| } |
| |
| func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) { |
| rb := o.op.buf |
| handled = true |
| switch r { |
| case 'i': |
| case 'I': |
| rb.MoveToLineStart() |
| case 'a': |
| rb.MoveForward() |
| case 'A': |
| rb.MoveToLineEnd() |
| case 's': |
| rb.Delete() |
| case 'S': |
| rb.Erase() |
| case 'c': |
| next := readNext() |
| switch next { |
| case 'c': |
| rb.Erase() |
| case 'w': |
| rb.DeleteWord() |
| case 'h': |
| rb.Backspace() |
| case 'l': |
| rb.Delete() |
| } |
| default: |
| return r, false |
| } |
| |
| o.EnterVimInsertMode() |
| return |
| } |
| |
| func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) { |
| switch r { |
| case CharEnter, CharInterrupt: |
| o.ExitVimMode() |
| return r |
| } |
| |
| if r, handled := o.handleVimNormalMovement(r, readNext); handled { |
| return r |
| } |
| |
| if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled { |
| return r |
| } |
| |
| // invalid operation |
| o.op.t.Bell() |
| return 0 |
| } |
| |
| func (o *opVim) EnterVimInsertMode() { |
| o.vimMode = VIM_INSERT |
| } |
| |
| func (o *opVim) ExitVimInsertMode() { |
| o.vimMode = VIM_NORMAL |
| } |
| |
| func (o *opVim) HandleVim(r rune, readNext func() rune) rune { |
| if o.vimMode == VIM_NORMAL { |
| return o.HandleVimNormal(r, readNext) |
| } |
| if r == CharEsc { |
| o.ExitVimInsertMode() |
| return 0 |
| } |
| |
| switch o.vimMode { |
| case VIM_INSERT: |
| return r |
| case VIM_VISUAL: |
| } |
| return r |
| } |