1package readline 2 3const ( 4 VIM_NORMAL = iota 5 VIM_INSERT 6 VIM_VISUAL 7) 8 9type opVim struct { 10 cfg *Config 11 op *Operation 12 vimMode int 13} 14 15func newVimMode(op *Operation) *opVim { 16 ov := &opVim{ 17 cfg: op.cfg, 18 op: op, 19 } 20 ov.SetVimMode(ov.cfg.VimMode) 21 return ov 22} 23 24func (o *opVim) SetVimMode(on bool) { 25 if o.cfg.VimMode && !on { // turn off 26 o.ExitVimMode() 27 } 28 o.cfg.VimMode = on 29 o.vimMode = VIM_INSERT 30} 31 32func (o *opVim) ExitVimMode() { 33 o.vimMode = VIM_INSERT 34} 35 36func (o *opVim) IsEnableVimMode() bool { 37 return o.cfg.VimMode 38} 39 40func (o *opVim) handleVimNormalMovement(r rune, readNext func() rune) (t rune, handled bool) { 41 rb := o.op.buf 42 handled = true 43 switch r { 44 case 'h': 45 t = CharBackward 46 case 'j': 47 t = CharNext 48 case 'k': 49 t = CharPrev 50 case 'l': 51 t = CharForward 52 case '0', '^': 53 rb.MoveToLineStart() 54 case '$': 55 rb.MoveToLineEnd() 56 case 'x': 57 rb.Delete() 58 if rb.IsCursorInEnd() { 59 rb.MoveBackward() 60 } 61 case 'r': 62 rb.Replace(readNext()) 63 case 'd': 64 next := readNext() 65 switch next { 66 case 'd': 67 rb.Erase() 68 case 'w': 69 rb.DeleteWord() 70 case 'h': 71 rb.Backspace() 72 case 'l': 73 rb.Delete() 74 } 75 case 'p': 76 rb.Yank() 77 case 'b', 'B': 78 rb.MoveToPrevWord() 79 case 'w', 'W': 80 rb.MoveToNextWord() 81 case 'e', 'E': 82 rb.MoveToEndWord() 83 case 'f', 'F', 't', 'T': 84 next := readNext() 85 prevChar := r == 't' || r == 'T' 86 reverse := r == 'F' || r == 'T' 87 switch next { 88 case CharEsc: 89 default: 90 rb.MoveTo(next, prevChar, reverse) 91 } 92 default: 93 return r, false 94 } 95 return t, true 96} 97 98func (o *opVim) handleVimNormalEnterInsert(r rune, readNext func() rune) (t rune, handled bool) { 99 rb := o.op.buf 100 handled = true 101 switch r { 102 case 'i': 103 case 'I': 104 rb.MoveToLineStart() 105 case 'a': 106 rb.MoveForward() 107 case 'A': 108 rb.MoveToLineEnd() 109 case 's': 110 rb.Delete() 111 case 'S': 112 rb.Erase() 113 case 'c': 114 next := readNext() 115 switch next { 116 case 'c': 117 rb.Erase() 118 case 'w': 119 rb.DeleteWord() 120 case 'h': 121 rb.Backspace() 122 case 'l': 123 rb.Delete() 124 } 125 default: 126 return r, false 127 } 128 129 o.EnterVimInsertMode() 130 return 131} 132 133func (o *opVim) HandleVimNormal(r rune, readNext func() rune) (t rune) { 134 switch r { 135 case CharEnter, CharInterrupt: 136 o.ExitVimMode() 137 return r 138 } 139 140 if r, handled := o.handleVimNormalMovement(r, readNext); handled { 141 return r 142 } 143 144 if r, handled := o.handleVimNormalEnterInsert(r, readNext); handled { 145 return r 146 } 147 148 // invalid operation 149 o.op.t.Bell() 150 return 0 151} 152 153func (o *opVim) EnterVimInsertMode() { 154 o.vimMode = VIM_INSERT 155} 156 157func (o *opVim) ExitVimInsertMode() { 158 o.vimMode = VIM_NORMAL 159} 160 161func (o *opVim) HandleVim(r rune, readNext func() rune) rune { 162 if o.vimMode == VIM_NORMAL { 163 return o.HandleVimNormal(r, readNext) 164 } 165 if r == CharEsc { 166 o.ExitVimInsertMode() 167 return 0 168 } 169 170 switch o.vimMode { 171 case VIM_INSERT: 172 return r 173 case VIM_VISUAL: 174 } 175 return r 176} 177