-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy patheasy_motion.plugin.zsh
173 lines (155 loc) · 5.85 KB
/
easy_motion.plugin.zsh
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# Configuration values
_EASY_MOTION_DIM_DEFAULT="fg=242"
_EASY_MOTION_HIGHLIGHT_DEFAULT="fg=196,bold"
_EASY_MOTION_HIGHLIGHT_2_FIRST_DEFAULT="fg=11,bold"
_EASY_MOTION_HIGHLIGHT_2_SECOND_DEFAULT="fg=3,bold"
_EASY_MOTION_TARGET_KEYS_DEFAULT="asdghklqwertyuiopzxcvbnmfj;"
_EASY_MOTION_SMART_CASE_DEFAULT="false"
_EASY_MOTION_ROOT_DIR="${0:h}"
_EASY_MOTION_EXTRA_MOTION=""
function vi-easy-motion () {
local saved_buffer
local saved_cursor
local saved_predisplay
local saved_postdisplay
local -a saved_region_highlight
local jumped
local ret
function _easy-motion-setup-variables {
: "${EASY_MOTION_DIM:=${_EASY_MOTION_DIM_DEFAULT}}"
: "${EASY_MOTION_HIGHLIGHT:=${_EASY_MOTION_HIGHLIGHT_DEFAULT}}"
: "${EASY_MOTION_HIGHLIGHT_2_FIRST:=${_EASY_MOTION_HIGHLIGHT_2_FIRST_DEFAULT}}"
: "${EASY_MOTION_HIGHLIGHT_2_SECOND:=${_EASY_MOTION_HIGHLIGHT_2_SECOND_DEFAULT}}"
: "${EASY_MOTION_TARGET_KEYS:=${_EASY_MOTION_TARGET_KEYS_DEFAULT}}"
: "${EASY_MOTION_SMART_CASE:=${_EASY_MOTION_SMART_CASE_DEFAULT}}"
}
function _easy-motion-save-state {
saved_buffer="${BUFFER}"
saved_cursor="${CURSOR}"
saved_predisplay="${PREDISPLAY}"
saved_postdisplay="${POSTDISPLAY}"
saved_region_highlight=("${region_highlight[@]}")
}
function _easy-motion-main {
local is_in_viopp state line
local add_newline
local region_type region_pos region_pos_offset region_key
local target_index mark
declare -A region_type_to_highlight
region_type_to_highlight=( \
["s"]="${EASY_MOTION_HIGHLIGHT}" \
["p1"]="${EASY_MOTION_HIGHLIGHT_2_FIRST}" \
["p2"]="${EASY_MOTION_HIGHLIGHT_2_SECOND}" \
)
PREDISPLAY=""
POSTDISPLAY=""
jumped=0
is_in_viopp="$(( MARK < 0 ))"
state="none"
# In bash, "command | while ..." would not work because while runs in a subshell and variables cannot be modified.
# But in zsh, the while loop is NOT executed in its own subshell.
"${_EASY_MOTION_ROOT_DIR}/easy_motion.py" "${EASY_MOTION_TARGET_KEYS}" "${CURSOR}" "${is_in_viopp}" "${EASY_MOTION_SMART_CASE}" "${BUFFER}" </dev/tty 2>/dev/null | \
while read -r line; do
add_newline=0
case "${line}" in
highlight_start)
state="highlight"
region_pos_offset=0
region_highlight=( "0 $#BUFFER ${EASY_MOTION_DIM}" )
BUFFER="${saved_buffer}"
# Restore the cursor position on every new highlighting round
CURSOR="${saved_cursor}"
continue
;;
highlight_end)
# Update the dimmed text area if newline characters were added to the `BUFFER`
if (( region_pos_offset > 0 )); then
region_highlight[1]="0 $#BUFFER ${EASY_MOTION_DIM}"
fi
state="none"
# Force a redisplay of the command line
zle -R
continue
;;
jump)
state="jump"
continue
;;
*)
;;
esac
case "${state}" in
highlight)
read -r region_type region_pos region_key <<< "${line}"
(( region_pos += region_pos_offset ))
region_highlight+=( "${region_pos} $(( region_pos + 1 )) ${region_type_to_highlight[${region_type}]}" )
if [[ "${BUFFER[$((region_pos + 1))]}" == $'\n' ]]; then
add_newline=1
fi
BUFFER[$((region_pos + 1))]="${region_key}"
if (( add_newline )); then
BUFFER="$(printf "%s\n%s" "${BUFFER:0:$(( region_pos + 1 ))}" "${BUFFER:$(( region_pos + 1 ))}")"
if (( region_pos <= CURSOR )); then
(( ++CURSOR ))
fi
(( ++region_pos_offset ))
fi
;;
jump)
read -r target_index mark _EASY_MOTION_EXTRA_MOTION <<< "${line}"
if [[ -n "${target_index}" ]]; then
CURSOR="${target_index}"
fi
if [[ -n "${mark}" ]]; then
MARK="${mark}"
fi
jumped=1
state="none"
;;
esac
done || return 2
return 0
}
function _easy-motion-restore-state {
BUFFER="${saved_buffer}"
if ! (( jumped )); then
CURSOR="${saved_cursor}"
fi
PREDISPLAY="${saved_predisplay}"
POSTDISPLAY="${saved_postdisplay}"
region_highlight=("${saved_region_highlight[@]}")
}
_easy-motion-setup-variables && \
_easy-motion-save-state && \
_easy-motion-main && \
ret="$?"
_easy-motion-restore-state
return "${ret}"
}
# Wrap vi operators to be able to move the cursor
# after an operator was executed
function vi-change vi-delete vi-down-case vi-oper-swap-case vi-up-case vi-yank () {
local ret
zle ".${WIDGET}"
ret=$?
if [[ -n "${_EASY_MOTION_EXTRA_MOTION}" ]]; then
# Do not repeat the follong motion widgets
unset NUMERIC
case "${_EASY_MOTION_EXTRA_MOTION}" in
W)
zle vi-forward-blank-word
;;
*)
;;
esac
_EASY_MOTION_EXTRA_MOTION=""
fi
return "${ret}"
}
zle -N vi-easy-motion
zle -N vi-change
zle -N vi-delete
zle -N vi-down-case
zle -N vi-oper-swap-case
zle -N vi-up-case
zle -N vi-yank