-
Notifications
You must be signed in to change notification settings - Fork 0
/
.bash_completion
103 lines (96 loc) · 3.57 KB
/
.bash_completion
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
#!/bin/bash
#
# General custom completion functions sourced by
# /usr/share/bash-completion/bash_completion.
# Creates a new completion wrapper function, where COMP_WORDS, COMP_CWORD,
# COMP_LINE and COMP_POINT are set to what they would be for the aliased
# command, so the called completion function works with the alias as well.
#
# COMP_WORDS has to be the actual command with arguments and the current words
# on the command line without the alias itself.
#
# The COMP_CWORD index into COMP_WORDS has to be increased by the number of
# words of the actual command. We substract 1, because while completing the
# alias we're already at index 1. On index 0 we would complete the alias itself
# and this function wouldn't be called.
#
# The COMP_LINE contains all COMP_WORDS separated by spaces.
#
# The current cursor position COMP_POINT, relative to the beginning of the
# current command, has to be increased by the length of the actual command minus
# the length of the alias. We again substract 1, because while completing the
# alias we're already at COMP_POINT 2.
#
# @param $1 name of the actual completion function
# @param $2 name of the completion wrapper function
# @param $3 name of the alias
# @param $4... actual command name and arguments
function _alias_comp_wrapper {
local debug=false
local comp_func_name="$1"
local wrap_func_name="$2"
local alias="$3"
shift 3
local line=$*
local words=("$@")
# We don't want to expand or re-split the words in our created wrapper
# function. An alias='cmd1 arg $(cmd2 arg)' should have the inital words
# 'cmd1', 'arg' and '$(cmd2 arg)'.
words=("${words[@]/#/\'}")
words=("${words[@]/%/\'}")
if $debug; then
local print_debug="
printf '\\nwords: '
printf \"'%s' \" \"\${COMP_WORDS[@]}\"
printf '\\n'
printf \"line: '%s'\\n\" \"\$COMP_LINE\"
printf 'cword: %s\\n' \"\$COMP_CWORD\"
printf 'point: %s\\n' \"\$COMP_POINT\"
"
fi
local func="
function $wrap_func_name {
COMP_WORDS=(${words[*]} \"\${COMP_WORDS[@]:1}\")
(( COMP_CWORD+=$#-1 ))
printf -v COMP_LINE '%s ' \"\${COMP_WORDS[@]}\"
COMP_LINE=\${COMP_LINE%?}
(( COMP_POINT+=${#line}-${#alias}-1 ))
$print_debug
$comp_func_name
}"
eval "$func"
}
# Stores completion words for an aliased command in the given array, where each
# command substitution is treated as one word.
#
# @param $1 alias
# @param $2 array by name
function _alias_comp_words {
local cmd=()
local cmd_sub=""
local cmd_sub_cnt=0
local w
for w in $(alias "$1" | sed "s/.*='\\(\\bsudo \\b\\)\\?\\(.*\\)'/\\2/"); do
# No negative lookbehind required since the opening bracket needs to be
# escaped if '$(' should be literal when executing the alias
if [[ $w = *"\$("* ]]; then
(( cmd_sub_cnt+=$(grep -o "\$(" <<< "$w" | wc -l) ))
fi
if [ $cmd_sub_cnt -gt 0 ]; then
cmd_sub="${cmd_sub}${w} "
# Match closing brackets with negative lookbehind for a backslash
if grep -P '(?<!\\)\)' <<< "$w" > /dev/null; then
(( cmd_sub_cnt-=$(grep -oP '(?<!\\)\)' <<< "$w" | wc -l) ))
if [ $cmd_sub_cnt -eq 0 ]; then
cmd_sub=${cmd_sub%?}
cmd=("${cmd[@]}" "${cmd_sub}")
cmd_sub=""
fi
fi
else
cmd=("${cmd[@]}" "$w")
fi
done
eval "$2=(\"\${cmd[@]}\")"
}
# vim: set filetype=sh: