177 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			177 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			Go
		
	
	
	
| 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
 | |
| }
 |