forked from reeflective/readline
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvim-mode.go
158 lines (131 loc) · 3.36 KB
/
vim-mode.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package readline
import (
"fmt"
)
//
// Mode switching ------------------------------------------------------------------ //
//
func (rl *Instance) enterVisualMode() {
rl.local = visual
rl.visualLine = false
rl.mark = rl.pos
}
func (rl *Instance) enterVisualLineMode() {
rl.local = visual
rl.visualLine = true
rl.mark = 0 // start at the beginning of the line.
}
func (rl *Instance) exitVisualMode() {
for i, reg := range rl.regions {
if reg.regionType == "visual" {
if len(rl.regions) > i {
rl.regions = append(rl.regions[:i], rl.regions[i+1:]...)
}
}
}
rl.visualLine = false
rl.mark = -1
if rl.local != visual {
return
}
rl.local = ""
}
// enterVioppMode adds a widget to the list of widgets waiting for an operator/action,
// enters the vi operator pending mode and updates the cursor.
func (rl *Instance) enterVioppMode(widget string) {
// When the widget is empty, we just want to update the cursor.
if widget == "" {
rl.isViopp = true
return
}
rl.local = viopp
act := action{
widget: widget,
iterations: rl.getIterations(),
}
// Push the widget on the stack of widgets
rl.pendingActions = append(rl.pendingActions, act)
}
func (rl *Instance) exitVioppMode() {
if rl.local == viopp {
rl.local = ""
}
rl.isViopp = false
}
// isVimEscape checks if the key matches the custom Vim mode escapes,
// and returns the corresponding callback if it matches.
func (rl *Instance) isVimEscape(key string) (cb EventCallback, yes bool) {
if rl.main == emacs {
return
}
// Make the callback even if not used
cb = func(_ string, _ []rune, _ int) EventReturn {
// Reset any incremental search parameters
// if we were currently editing its buffer.
rl.resetIsearch()
rl.resetHintText()
// Most of the time this will be caught as if this
// callback/widget was found on the local keymap,
// thus avoiding the update of the completion system:
// do it here instead.
rl.updateCompletion()
event := EventReturn{
Widget: "vi-cmd-mode",
NewLine: rl.line,
NewPos: rl.pos,
}
return event
}
// Escape is builtin
if len(key) == 1 && key[0] == charEscape {
return cb, true
}
return
}
//
// Mode printing ------------------------------------------------------------------ //
//
const (
vimInsertStr = "[I]"
vimReplaceOnceStr = "[V]"
vimReplaceManyStr = "[R]"
vimDeleteStr = "[D]"
vimKeysStr = "[N]"
)
func (rl *Instance) refreshVimStatus() {
rl.Prompt.compute(rl)
rl.redisplay()
}
// viHintMessage - lmorg's way of showing Vim status is to overwrite the hint.
// Currently not used, as there is a possibility to show the current Vim mode in the prompt.
func (rl *Instance) viHintMessage() {
defer func() {
rl.clearHelpers()
rl.renderHelpers()
}()
// The internal VI operator pending is used when
// we don't bother changing the keymap just to read a key.
if rl.isViopp {
vioppMsg := fmt.Sprintf("viopp: %s", rl.keys)
rl.hint = []rune(vioppMsg)
return
}
// The local keymap, most of the time, has priority
switch rl.local {
case viopp:
vioppMsg := fmt.Sprintf("viopp: %s", rl.keys)
rl.hint = []rune(vioppMsg)
return
case visual:
return
}
// But if not, we check for the global keymap
switch rl.main {
case viins:
rl.hint = []rune("-- INSERT --")
case vicmd:
rl.hint = []rune("-- VIM KEYS -- (press `i` to return to normal editing mode)")
default:
rl.getHintText()
}
}