-
Notifications
You must be signed in to change notification settings - Fork 3
/
zsh-autoquoter.zsh
119 lines (101 loc) · 2.99 KB
/
zsh-autoquoter.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
declare -ga ZAQ_PREFIXES
declare -ga ZAQ_PREFIXES_GREEDY
_zaq_count_args() {
echo $#
}
_zaq_check_prefix() {
setopt LOCAL_OPTIONS
setopt EXTENDED_GLOB
local prefix input stripped leading_quote expected_ending_quote greedy
prefix=$1
input=$2
greedy=$3
if [[ $greedy = "true" ]]; then
stripped=${input##$~prefix }
else
stripped=${input#$~prefix }
fi
if [[ "$input" = "$stripped" ]]; then
return 1
fi
# if it's already quoted, don't re-quote it.
# this is a separate assignment to take advantage
# of the fact that assignments to expansions like this
# do not glob words. i cannot wrap this pattern in double
# quotes without being unable to enter double-quotes in
# the alternative. seems like a zsh bug to me.
leading_quote=${(M)stripped#(\'|\"|$\')}
if [[ "$leading_quote" ]]; then
expected_ending_quote="${leading_quote#$}"
if [[ "${(M)stripped%$expected_ending_quote}" ]]; then
# We've checked that we start and end with a quote, but we could still
# be in a case like this:
#
# git commit -m "fix" the "bug"
#
# So, finally, we check that the arguments to be quoted actually evaluates
# to a single word.
if [[ $(_zaq_count_args ${(z)stripped}) = 1 ]]; then
return 1
fi
fi
fi
echo $(( $#input - $#stripped ))
return 0
}
_zaq_prefix_length() {
local prefix
for prefix in $ZAQ_PREFIXES; do
if _zaq_check_prefix "$prefix" "$1" false; then
return 0
fi
done
for prefix in $ZAQ_PREFIXES_GREEDY; do
if _zaq_check_prefix "$prefix" "$1" true; then
return 0
fi
done
return 1
}
autoquote() {
local prefix_length command args smart_single_quoted double_quoted
if prefix_length=$(_zaq_prefix_length "$BUFFER"); then
command=${BUFFER:0:$prefix_length}
args=${BUFFER:$prefix_length}
# we use (q+) instead of (q-) because (q-) will sometimes escape with
# backslashes instead of quotes, and (q+) doesn't seem to do that:
#
# $ x="it's"
# $ echo ${(q-)x}
# it\'s
# $ echo ${(q+)x}
# 'it'\''s'
#
# (we always want to escape with quotes so that our "don't double-escape"
# logic works correctly)
smart_single_quoted=${(q+)args}
double_quoted=${(qqq)args}
if [[ $#smart_single_quoted -lt $#double_quoted ]]; then
BUFFER="$command$smart_single_quoted"
else
BUFFER="$command$double_quoted"
fi
fi
zle .accept-line
}
zle -N accept-line autoquote
_zsh_highlight_highlighter_zaq_predicate() {
_zsh_highlight_buffer_modified
}
# if ZSH_HIGHLIGHT_STYLES has not already been declared,
# the substitution-assignment will be a syntax error.
if [[ ${(t)ZSH_HIGHLIGHT_STYLES} != 'association' ]]; then
declare -gA ZSH_HIGHLIGHT_STYLES
fi
: ${ZSH_HIGHLIGHT_STYLES[zaq:string]:=fg=yellow,underline}
_zsh_highlight_highlighter_zaq_paint() {
local prefix_length
if prefix_length=$(_zaq_prefix_length "$BUFFER"); then
_zsh_highlight_add_highlight "$prefix_length" $#BUFFER zaq:string
fi
}