-
Notifications
You must be signed in to change notification settings - Fork 2
/
bash_completion
384 lines (348 loc) · 11.4 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
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
#!/usr/bin/env bash
#
# bash-complete-partial-path v1.1.0-dev
#
# Zsh-like expansion of incomplete file paths for Bash.
# Source this file from your ~/.bashrc and use `_bcpp --defaults`
# to enable the described behavior.
#
# Example: `/u/s/a<Tab>` will be expanded into `/usr/share/applications`
#
# https://github.com/sio/bash-complete-partial-path
#
# Copyright 2018-2019 Vitaly Potyarkin
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Detect sed binary once at load time
#
_bcpp_sed_detect() {
local SED GNU_SED
SED="sed"
GNU_SED="gsed" # macOS ships BSD sed by default, gnu-sed has to be installed with brew
if [[ $OSTYPE == darwin* || $OSTYPE == freebsd* ]]
then
if type "$GNU_SED" &> /dev/null
then
SED="$GNU_SED"
else
echo "bash-complete-partial-path: Please install GNU sed (gsed)" >&2
fi
fi
echo "command $SED"
}
#
# Take a single incomplete path and fill it with wildcards
# e.g. /u/s/app/ -> /u*/s*/app*
#
_bcpp_put_wildcards() {
local PROCESSED TILDE_EXPANSION INPUT
INPUT="$*"
PROCESSED=$( \
echo "$INPUT" | \
$_BCPP_SED \
-Ee 's:([^\*\~])/:\1*/:g;
s:([^\/\*])$:\1*:g;
s:^(\~[^\/]*)\*\/:\1/:;
s:(\.+)\*/:\1/:g;
s:(^|/)(\$[^/]+)\*(/|$):\2\3:g'
)
eval "TILDE_EXPANSION=$(\
printf \
'%q' \
"$PROCESSED"|$_BCPP_SED -e 's:^\\\~:~:g' -Ee 's:(^|/)\\(\$):\1\2:g' \
)"
# Workaround for Mingw pseudo directories for drives,
# i.e. `/c/` refers to drive `C:\`, but glob `/c*/` returns no matches
if [[ "$INPUT" =~ ^\/[a-zA-Z]\/.* && -d "${INPUT::2}" ]]
then
TILDE_EXPANSION="${TILDE_EXPANSION::2}${TILDE_EXPANSION:3}"
fi
echo "$TILDE_EXPANSION"
}
# Run a job in background without printing job control messages and without a
# subshell
# https://stackoverflow.com/a/51061046
_bcpp_silent_bg() {
{ 2>&3 "$@"& } 3>&2 2>/dev/null
builtin disown &>/dev/null # Prevent whine if job has already completed
return 0 # do not clutter $? value (last exit code)
}
# Helper function for wrapping compgen output to named pipe
_bcpp_compgen() {
local wildcards="$1"
local pipe="$2"
compgen -G "$wildcards" "$wildcards" 2>/dev/null >"$pipe"
}
#
# Bash completion function for expanding partial paths
#
# This is a generic worker. It accepts 'file' or 'directory' as the first
# argument to specify desired completion behavior
#
_bcpp_complete() {
local WILDCARDS ACTION LINE OPTION INPUT QUOTE
ACTION="$1"
if [[ "_$1" == "_-d" ]]
then # _filedir compatibility
ACTION="directory"
fi
if [[ "$COMP_CWORD" -ge 0 ]]
then
INPUT="${COMP_WORDS[$COMP_CWORD]}"
else
INPUT=""
fi
# Detect and strip opened quotes
if [[ "${INPUT:0:1}" == "'" || "${INPUT:0:1}" == '"' ]]
then
QUOTE="${INPUT:0:1}"
INPUT="${INPUT:1}"
else
QUOTE=""
fi
# Prepare the reply
COMPREPLY=()
compopt -o nospace
compopt -o bashdefault
compopt -o default
# If input is already a valid path, do not try to be clever
if [[ -e "$INPUT" ]]
then
if [[ "_$ACTION" == "_directory" ]]
then
OPTION="dirnames"
else
OPTION="filenames"
fi
if [[ -d "$INPUT" && "${INPUT: -1}" != '/' ]]
then
COMPREPLY=("$INPUT/")
else
readarray -t COMPREPLY < <(compgen -o "$OPTION" "$INPUT")
local i
for i in "${!COMPREPLY[@]}"
do
COMPREPLY[i]="$(printf "%q" "${COMPREPLY[i]}")"
done
fi
return
fi
# Add wildcards to each path element
WILDCARDS=$(_bcpp_put_wildcards "$INPUT")
# Collect completion options
local pipe
pipe="$_BCPP_FIFO"
[[ -z "$pipe" ]] && return 1 # fail on empty filename
command mkfifo "$pipe"
local monitor
[[ "$-" == *m* ]] && monitor=yes || monitor=no
[[ "$monitor" == yes ]] && set +m
_bcpp_silent_bg _bcpp_compgen "$WILDCARDS" "$pipe"
while read -r -d $'\n' LINE
do
if [[ "_$ACTION" == "_directory" && ! -d "$LINE" ]]
then # skip non-directory paths when looking for directory
continue
fi
if [[ -z "$LINE" ]]
then # skip empty suggestions
continue
fi
if [[ -z "$QUOTE" ]]
then # escape special characters unless user has opened a quote
LINE=$(printf "%q" "$LINE")
fi
COMPREPLY+=("$LINE")
done < "$pipe"
command rm "$pipe"
[[ "$monitor" == yes ]] && set -m
}
# Wrappers
_bcpp_complete_dir() { _bcpp_complete directory; }
_bcpp_complete_file() { _bcpp_complete file; }
# Manage enhanced path completion
_bcpp() {
local DEFAULT ALL KEYS ARG USAGE UNKNOWN
DEFAULT="--files --dirs --cooperate --nocase --readline"
ALL="--files --dirs --cooperate --nocase --readline"
USAGE=(
"Usage: ${FUNCNAME[0]} OPTIONS"
" Manage enhanced path completion in bash"
""
"Options:"
" --defaults"
" Enable the subset of features recommended by maintainer."
" Currently equals to:"
" \"$DEFAULT\""
" --all"
" Enable all optional features. Equals to:"
" \"$ALL\""
" --help"
" Show this help message"
""
"Individual feature flags:"
" --files"
" Enable enhanced completion for file paths"
" --dirs"
" Complete \`cd\` with paths to directories only"
" --cooperate"
" Cooperate with system-wide bash-completion if it's in use."
" This function must be invoked AFTER the main bash-completion"
" is loaded."
" Deprecated alias: --override"
" --nocase"
" Make path completion case insensitive"
" --readline"
" Configure readline for better user experience. Equals to:"
" \"--readline-menu --readline-color --readline-misc\""
" --readline-color"
" Enable colors in completion"
" --readline-menu"
" Use \`menu-complete\` when Tab key is pressed instead of default"
" \`complete\`. Use Shift+Tab to return to previous suggestion"
" --readline-misc"
" Other useful readline tweaks"
""
"Copyright 2018-2019 Vitaly Potyarkin"
"<https://github.com/sio/bash-complete-partial-path>"
""
"This program is Free Software and comes with ABSOLUTELY NO WARRANTY,"
"to the extent permitted by applicable law. For more information see:"
"<http://www.apache.org/licenses/LICENSE-2.0>"
)
# Modify selected features list
for ARG in "$@"
do
case "$ARG" in
--defaults)
# shellcheck disable=SC2086
set -- "$@" $DEFAULT ;;
--all)
# shellcheck disable=SC2086
set -- "$@" $ALL ;;
esac
done
# Detect selected features
KEYS=""
for ARG in "$@"
do
case "$ARG" in
--files)
KEYS="${KEYS}f" ;;
--dirs)
KEYS="${KEYS}d" ;;
--cooperate|--override)
KEYS="${KEYS}o" ;;
--nocase)
KEYS="${KEYS}c" ;;
--readline)
KEYS="${KEYS}mlr" ;;
--readline-menu)
KEYS="${KEYS}m" ;;
--readline-color)
KEYS="${KEYS}l" ;;
--readline-misc)
KEYS="${KEYS}r" ;;
--help|--usage|-h)
KEYS="${KEYS}H" ;;
--defaults|--all)
;;
*)
KEYS="${KEYS}U"
UNKNOWN+=("$ARG")
;;
esac
done
# Special cases that terminate function
if [[ "$KEYS" == *H* || -z "$*" ]] # --help|--usage|-h
then
printf "%s\n" "${USAGE[@]}"
return 0
fi
if [[ "$KEYS" == *U* ]] # unknown arguments
then
echo -e \
"Unknown arguments: ${UNKNOWN[*]}" \
"\nRefer to \`${FUNCNAME[0]} --help\` for more information" \
>&2
return 1
fi
# Enable selected functionality. The order of execution does not depend on
# the order of command line parameters
if [[ "$KEYS" == *o* ]] # --cooperate|--override
then
local DYNAMIC
DYNAMIC=$(complete -p|grep -E -- '-D.*_completion_loader|_completion_loader.*-D')
local _bcpp_filedir_original_code
_bcpp_filedir_original_code=$(declare -f _filedir|tail -n+2)
if [[ -n "$_bcpp_filedir_original_code" ]]
then
type _bcpp_filedir_original &>/dev/null || \
eval "_bcpp_filedir_original() $_bcpp_filedir_original_code"
# shellcheck disable=SC2329 # invoked from outside of this script
_filedir() {
_bcpp_filedir_original "$@"
[ "${#COMPREPLY[@]}" -eq 0 ] && _bcpp_complete "$@"
}
fi
local _bcpp_filedir_xspec_original_code
_bcpp_filedir_xspec_original_code=$(declare -f _filedir_xspec|tail -n+2)
if [[ -n "$_bcpp_filedir_xspec_original_code" ]]
then
type _bcpp_filedir_xspec_original &>/dev/null || \
eval "_bcpp_filedir_xspec_original() $_bcpp_filedir_xspec_original_code"
# shellcheck disable=SC2329 # invoked from outside of this script
_filedir_xspec() {
_bcpp_filedir_xspec_original "$@"
[ "${#COMPREPLY[@]}" -eq 0 ] && _bcpp_complete "$@"
}
fi
fi
if [[ "$KEYS" == *f* ]] # --files
then
# Do not overwrite default completion function if dynamic completion
# loader is enabled
[[ -z "$DYNAMIC" ]] && complete -D -F _bcpp_complete_file
fi
if [[ "$KEYS" == *d* ]] # --dirs
then
complete -F _bcpp_complete_dir cd
complete -F _bcpp_complete_dir pushd
fi
if [[ "$KEYS" == *c* ]] # --nocase
then
shopt -s nocaseglob
bind 'set completion-ignore-case on'
fi
if [[ "$KEYS" == *m* ]] # --readline-menu
then
bind 'TAB:menu-complete'
bind '"\e[Z": menu-complete-backward' # Shift+Tab
bind 'set menu-complete-display-prefix on'
fi
if [[ "$KEYS" == *l* ]] # --readline-color
then
bind 'set colored-completion-prefix on'
bind 'set colored-stats on'
fi
if [[ "$KEYS" == *r* ]] # --readline-misc
then
bind 'set show-all-if-ambiguous on'
bind 'set show-all-if-unmodified on'
fi
# Calculate location for fifo file
_BCPP_FIFO=$(mktemp -u --tmpdir 'bcpp_pipe_XXXXXXXX' 2>/dev/null || mktemp -u -t 'bcpp_pipe')
# Detect sed command
_BCPP_SED=$(_bcpp_sed_detect)
}