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