Change-Id: I4bbd93d1956a9da679be6a7b0f682c2eaa9f444d
Reviewed-on: http://photon-jenkins.eng.vmware.com:8082/1307
Tested-by: gerrit-photon <photon-checkins@vmware.com>
Reviewed-by: Vinay Kulkarni <kulkarniv@vmware.com>
... | ... |
@@ -1,7 +1,7 @@ |
1 | 1 |
Summary: Bourne-Again SHell |
2 | 2 |
Name: bash |
3 | 3 |
Version: 4.3.30 |
4 |
-Release: 4%{?dist} |
|
4 |
+Release: 5%{?dist} |
|
5 | 5 |
License: GPLv3 |
6 | 6 |
URL: http://www.gnu.org/software/bash/ |
7 | 7 |
Group: System Environment/Base |
... | ... |
@@ -9,6 +9,7 @@ Vendor: VMware, Inc. |
9 | 9 |
Distribution: Photon |
10 | 10 |
Source0: http://ftp.gnu.org/gnu/bash/%{name}-%{version}.tar.gz |
11 | 11 |
%define sha1 bash=33b1bcc5dca1b72f28b2baeca6efa0d422097964 |
12 |
+Source1: bash_completion |
|
12 | 13 |
Patch0: http://www.linuxfromscratch.org/patches/downloads/bash/bash-4.3.30-upstream_fixes-2.patch |
13 | 14 |
Patch1: fix-save_bash_input-segfault.patch |
14 | 15 |
Patch2: bash-4.3.patch |
... | ... |
@@ -43,6 +44,8 @@ ln -s bash %{buildroot}/bin/sh |
43 | 43 |
install -vdm 755 %{buildroot}/etc |
44 | 44 |
install -vdm 755 %{buildroot}/etc/profile.d |
45 | 45 |
install -vdm 755 %{buildroot}/etc/skel |
46 |
+install -vdm 755 %{buildroot}/usr/share/bash-completion |
|
47 |
+install -m 0644 %{SOURCE1} %{buildroot}/usr/share/bash-completion |
|
46 | 48 |
|
47 | 49 |
# Create dircolors |
48 | 50 |
cat > %{buildroot}/etc/profile.d/dircolors.sh << "EOF" |
... | ... |
@@ -116,6 +119,16 @@ export LANG="${LANG:-C}" |
116 | 116 |
# End /etc/profile.d/i18n.sh |
117 | 117 |
EOF |
118 | 118 |
|
119 |
+# bash completion |
|
120 |
+cat > %{buildroot}/etc/profile.d/bash_completion.sh << "EOF" |
|
121 |
+# enable bash completion in interactive shells |
|
122 |
+if ! shopt -oq posix; then |
|
123 |
+ if [ -f /usr/share/bash-completion/bash_completion ]; then |
|
124 |
+ . /usr/share/bash-completion/bash_completion |
|
125 |
+ fi |
|
126 |
+fi |
|
127 |
+EOF |
|
128 |
+ |
|
119 | 129 |
cat > %{buildroot}/etc/bash.bashrc << "EOF" |
120 | 130 |
# Begin /etc/bash.bashrc |
121 | 131 |
# Written for Beyond Linux From Scratch |
... | ... |
@@ -235,17 +248,20 @@ fi |
235 | 235 |
%files |
236 | 236 |
%defattr(-,root,root) |
237 | 237 |
/bin/* |
238 |
-%{_sysconfdir} |
|
238 |
+%{_sysconfdir}/ |
|
239 | 239 |
%{_defaultdocdir}/%{name}-%{version}/* |
240 | 240 |
%{_defaultdocdir}/%{name}/* |
241 | 241 |
%{_mandir}/*/* |
242 |
+/usr/share/bash-completion/ |
|
242 | 243 |
|
243 | 244 |
%files lang -f %{name}.lang |
244 | 245 |
%defattr(-,root,root) |
245 | 246 |
|
246 | 247 |
%changelog |
247 |
-* Tue May 24 2016 Priyesh Padmavilasom <ppadmavilasom@vmware.com> 4.3.30-4 |
|
248 |
-- GA - Bump release of all rpms |
|
248 |
+* Fri Aug 19 2016 Alexey Makhalov <amakhalov@vmware.com> 4.3.30-5 |
|
249 |
+- Enable bash completion support |
|
250 |
+* Tue May 24 2016 Priyesh Padmavilasom <ppadmavilasom@vmware.com> 4.3.30-4 |
|
251 |
+- GA - Bump release of all rpms |
|
249 | 252 |
* Tue May 3 2016 Divya Thaluru <dthaluru@vmware.com> 4.3.30-3 |
250 | 253 |
- Fixing spec file to handle rpm upgrade scenario correctly |
251 | 254 |
* Thu Mar 10 2016 Divya Thaluru <dthaluru@vmware.com> 4.3.30-2 |
... | ... |
@@ -255,10 +271,10 @@ fi |
255 | 255 |
- Updated to version 4.3.30 |
256 | 256 |
* Wed Aug 05 2015 Kumar Kaushik <kaushikk@vmware.com> 4.3-4 |
257 | 257 |
- Adding post unstall section. |
258 |
-* Wed Jul 22 2015 Alexey Makhalov <amakhalov@vmware.com> 4.3-3 |
|
259 |
-- Fix segfault in save_bash_input. |
|
260 |
-* Tue Jun 30 2015 Alexey Makhalov <amakhalov@vmware.com> 4.3-2 |
|
261 |
-- /etc/profile.d permission fix. Pack /etc files into rpm |
|
262 |
-* Wed Oct 22 2014 Divya Thaluru <dthaluru@vmware.com> 4.3-1 |
|
263 |
-- Initial version |
|
258 |
+* Wed Jul 22 2015 Alexey Makhalov <amakhalov@vmware.com> 4.3-3 |
|
259 |
+- Fix segfault in save_bash_input. |
|
260 |
+* Tue Jun 30 2015 Alexey Makhalov <amakhalov@vmware.com> 4.3-2 |
|
261 |
+- /etc/profile.d permission fix. Pack /etc files into rpm |
|
262 |
+* Wed Oct 22 2014 Divya Thaluru <dthaluru@vmware.com> 4.3-1 |
|
263 |
+- Initial version |
|
264 | 264 |
|
265 | 265 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,1995 @@ |
0 |
+# -*- shell-script -*- |
|
1 |
+# |
|
2 |
+# bash_completion - programmable completion functions for bash 4.1+ |
|
3 |
+# |
|
4 |
+# Copyright © 2006-2008, Ian Macdonald <ian@caliban.org> |
|
5 |
+# © 2009-2013, Bash Completion Maintainers |
|
6 |
+# <bash-completion-devel@lists.alioth.debian.org> |
|
7 |
+# |
|
8 |
+# This program is free software; you can redistribute it and/or modify |
|
9 |
+# it under the terms of the GNU General Public License as published by |
|
10 |
+# the Free Software Foundation; either version 2, or (at your option) |
|
11 |
+# any later version. |
|
12 |
+# |
|
13 |
+# This program is distributed in the hope that it will be useful, |
|
14 |
+# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
+# GNU General Public License for more details. |
|
17 |
+# |
|
18 |
+# You should have received a copy of the GNU General Public License |
|
19 |
+# along with this program; if not, write to the Free Software Foundation, |
|
20 |
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
|
21 |
+# |
|
22 |
+# The latest version of this software can be obtained here: |
|
23 |
+# |
|
24 |
+# http://bash-completion.alioth.debian.org/ |
|
25 |
+# |
|
26 |
+# RELEASE: 2.1 |
|
27 |
+ |
|
28 |
+if [[ $- == *v* ]]; then |
|
29 |
+ BASH_COMPLETION_ORIGINAL_V_VALUE="-v" |
|
30 |
+else |
|
31 |
+ BASH_COMPLETION_ORIGINAL_V_VALUE="+v" |
|
32 |
+fi |
|
33 |
+ |
|
34 |
+if [[ ${BASH_COMPLETION_DEBUG-} ]]; then |
|
35 |
+ set -v |
|
36 |
+else |
|
37 |
+ set +v |
|
38 |
+fi |
|
39 |
+ |
|
40 |
+# Set the following to the location of the backwards compat completion dir. |
|
41 |
+# |
|
42 |
+: ${BASH_COMPLETION_COMPAT_DIR:=/etc/bash_completion.d} |
|
43 |
+readonly BASH_COMPLETION_COMPAT_DIR |
|
44 |
+ |
|
45 |
+# Blacklisted completions, causing problems with our code. |
|
46 |
+# |
|
47 |
+_blacklist_glob='@(acroread.sh)' |
|
48 |
+ |
|
49 |
+# Turn on extended globbing and programmable completion |
|
50 |
+shopt -s extglob progcomp |
|
51 |
+ |
|
52 |
+# A lot of the following one-liners were taken directly from the |
|
53 |
+# completion examples provided with the bash 2.04 source distribution |
|
54 |
+ |
|
55 |
+# Make directory commands see only directories |
|
56 |
+complete -d pushd |
|
57 |
+ |
|
58 |
+# start of section containing compspecs that can be handled within bash |
|
59 |
+ |
|
60 |
+# user commands see only users |
|
61 |
+complete -u write chfn groups slay w sux runuser |
|
62 |
+ |
|
63 |
+# bg completes with stopped jobs |
|
64 |
+complete -A stopped -P '"%' -S '"' bg |
|
65 |
+ |
|
66 |
+# other job commands |
|
67 |
+complete -j -P '"%' -S '"' fg jobs disown |
|
68 |
+ |
|
69 |
+# readonly and unset complete with shell variables |
|
70 |
+complete -v readonly unset |
|
71 |
+ |
|
72 |
+# set completes with set options |
|
73 |
+complete -A setopt set |
|
74 |
+ |
|
75 |
+# shopt completes with shopt options |
|
76 |
+complete -A shopt shopt |
|
77 |
+ |
|
78 |
+# helptopics |
|
79 |
+complete -A helptopic help |
|
80 |
+ |
|
81 |
+# unalias completes with aliases |
|
82 |
+complete -a unalias |
|
83 |
+ |
|
84 |
+# bind completes with readline bindings (make this more intelligent) |
|
85 |
+complete -A binding bind |
|
86 |
+ |
|
87 |
+# type and which complete on commands |
|
88 |
+complete -c command type which |
|
89 |
+ |
|
90 |
+# builtin completes on builtins |
|
91 |
+complete -b builtin |
|
92 |
+ |
|
93 |
+# start of section containing completion functions called by other functions |
|
94 |
+ |
|
95 |
+# Check if we're running on the given userland |
|
96 |
+# @param $1 userland to check for |
|
97 |
+_userland() |
|
98 |
+{ |
|
99 |
+ local userland=$( uname -s ) |
|
100 |
+ [[ $userland == @(Linux|GNU/*) ]] && userland=GNU |
|
101 |
+ [[ $userland == $1 ]] |
|
102 |
+} |
|
103 |
+ |
|
104 |
+# This function sets correct SysV init directories |
|
105 |
+# |
|
106 |
+_sysvdirs() |
|
107 |
+{ |
|
108 |
+ sysvdirs=( ) |
|
109 |
+ [[ -d /etc/rc.d/init.d ]] && sysvdirs+=( /etc/rc.d/init.d ) |
|
110 |
+ [[ -d /etc/init.d ]] && sysvdirs+=( /etc/init.d ) |
|
111 |
+ # Slackware uses /etc/rc.d |
|
112 |
+ [[ -f /etc/slackware-version ]] && sysvdirs=( /etc/rc.d ) |
|
113 |
+} |
|
114 |
+ |
|
115 |
+# This function checks whether we have a given program on the system. |
|
116 |
+# |
|
117 |
+_have() |
|
118 |
+{ |
|
119 |
+ # Completions for system administrator commands are installed as well in |
|
120 |
+ # case completion is attempted via `sudo command ...'. |
|
121 |
+ PATH=$PATH:/usr/sbin:/sbin:/usr/local/sbin type $1 &>/dev/null |
|
122 |
+} |
|
123 |
+ |
|
124 |
+# Backwards compatibility for compat completions that use have(). |
|
125 |
+# @deprecated should no longer be used; generally not needed with dynamically |
|
126 |
+# loaded completions, and _have is suitable for runtime use. |
|
127 |
+have() |
|
128 |
+{ |
|
129 |
+ unset -v have |
|
130 |
+ _have $1 && have=yes |
|
131 |
+} |
|
132 |
+ |
|
133 |
+# This function checks whether a given readline variable |
|
134 |
+# is `on'. |
|
135 |
+# |
|
136 |
+_rl_enabled() |
|
137 |
+{ |
|
138 |
+ [[ "$( bind -v )" = *$1+([[:space:]])on* ]] |
|
139 |
+} |
|
140 |
+ |
|
141 |
+# This function shell-quotes the argument |
|
142 |
+quote() |
|
143 |
+{ |
|
144 |
+ local quoted=${1//\'/\'\\\'\'} |
|
145 |
+ printf "'%s'" "$quoted" |
|
146 |
+} |
|
147 |
+ |
|
148 |
+# @see _quote_readline_by_ref() |
|
149 |
+quote_readline() |
|
150 |
+{ |
|
151 |
+ local quoted |
|
152 |
+ _quote_readline_by_ref "$1" ret |
|
153 |
+ printf %s "$ret" |
|
154 |
+} # quote_readline() |
|
155 |
+ |
|
156 |
+ |
|
157 |
+# This function shell-dequotes the argument |
|
158 |
+dequote() |
|
159 |
+{ |
|
160 |
+ eval printf %s "$1" 2> /dev/null |
|
161 |
+} |
|
162 |
+ |
|
163 |
+ |
|
164 |
+# Assign variable one scope above the caller |
|
165 |
+# Usage: local "$1" && _upvar $1 "value(s)" |
|
166 |
+# Param: $1 Variable name to assign value to |
|
167 |
+# Param: $* Value(s) to assign. If multiple values, an array is |
|
168 |
+# assigned, otherwise a single value is assigned. |
|
169 |
+# NOTE: For assigning multiple variables, use '_upvars'. Do NOT |
|
170 |
+# use multiple '_upvar' calls, since one '_upvar' call might |
|
171 |
+# reassign a variable to be used by another '_upvar' call. |
|
172 |
+# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference |
|
173 |
+_upvar() |
|
174 |
+{ |
|
175 |
+ if unset -v "$1"; then # Unset & validate varname |
|
176 |
+ if (( $# == 2 )); then |
|
177 |
+ eval $1=\"\$2\" # Return single value |
|
178 |
+ else |
|
179 |
+ eval $1=\(\"\${@:2}\"\) # Return array |
|
180 |
+ fi |
|
181 |
+ fi |
|
182 |
+} |
|
183 |
+ |
|
184 |
+ |
|
185 |
+# Assign variables one scope above the caller |
|
186 |
+# Usage: local varname [varname ...] && |
|
187 |
+# _upvars [-v varname value] | [-aN varname [value ...]] ... |
|
188 |
+# Available OPTIONS: |
|
189 |
+# -aN Assign next N values to varname as array |
|
190 |
+# -v Assign single value to varname |
|
191 |
+# Return: 1 if error occurs |
|
192 |
+# See: http://fvue.nl/wiki/Bash:_Passing_variables_by_reference |
|
193 |
+_upvars() |
|
194 |
+{ |
|
195 |
+ if ! (( $# )); then |
|
196 |
+ echo "${FUNCNAME[0]}: usage: ${FUNCNAME[0]} [-v varname"\ |
|
197 |
+ "value] | [-aN varname [value ...]] ..." 1>&2 |
|
198 |
+ return 2 |
|
199 |
+ fi |
|
200 |
+ while (( $# )); do |
|
201 |
+ case $1 in |
|
202 |
+ -a*) |
|
203 |
+ # Error checking |
|
204 |
+ [[ ${1#-a} ]] || { echo "bash: ${FUNCNAME[0]}: \`$1': missing"\ |
|
205 |
+ "number specifier" 1>&2; return 1; } |
|
206 |
+ printf %d "${1#-a}" &> /dev/null || { echo "bash:"\ |
|
207 |
+ "${FUNCNAME[0]}: \`$1': invalid number specifier" 1>&2 |
|
208 |
+ return 1; } |
|
209 |
+ # Assign array of -aN elements |
|
210 |
+ [[ "$2" ]] && unset -v "$2" && eval $2=\(\"\${@:3:${1#-a}}\"\) && |
|
211 |
+ shift $((${1#-a} + 2)) || { echo "bash: ${FUNCNAME[0]}:"\ |
|
212 |
+ "\`$1${2+ }$2': missing argument(s)" 1>&2; return 1; } |
|
213 |
+ ;; |
|
214 |
+ -v) |
|
215 |
+ # Assign single value |
|
216 |
+ [[ "$2" ]] && unset -v "$2" && eval $2=\"\$3\" && |
|
217 |
+ shift 3 || { echo "bash: ${FUNCNAME[0]}: $1: missing"\ |
|
218 |
+ "argument(s)" 1>&2; return 1; } |
|
219 |
+ ;; |
|
220 |
+ *) |
|
221 |
+ echo "bash: ${FUNCNAME[0]}: $1: invalid option" 1>&2 |
|
222 |
+ return 1 ;; |
|
223 |
+ esac |
|
224 |
+ done |
|
225 |
+} |
|
226 |
+ |
|
227 |
+ |
|
228 |
+# Reassemble command line words, excluding specified characters from the |
|
229 |
+# list of word completion separators (COMP_WORDBREAKS). |
|
230 |
+# @param $1 chars Characters out of $COMP_WORDBREAKS which should |
|
231 |
+# NOT be considered word breaks. This is useful for things like scp where |
|
232 |
+# we want to return host:path and not only path, so we would pass the |
|
233 |
+# colon (:) as $1 here. |
|
234 |
+# @param $2 words Name of variable to return words to |
|
235 |
+# @param $3 cword Name of variable to return cword to |
|
236 |
+# |
|
237 |
+__reassemble_comp_words_by_ref() |
|
238 |
+{ |
|
239 |
+ local exclude i j line ref |
|
240 |
+ # Exclude word separator characters? |
|
241 |
+ if [[ $1 ]]; then |
|
242 |
+ # Yes, exclude word separator characters; |
|
243 |
+ # Exclude only those characters, which were really included |
|
244 |
+ exclude="${1//[^$COMP_WORDBREAKS]}" |
|
245 |
+ fi |
|
246 |
+ |
|
247 |
+ # Default to cword unchanged |
|
248 |
+ eval $3=$COMP_CWORD |
|
249 |
+ # Are characters excluded which were former included? |
|
250 |
+ if [[ $exclude ]]; then |
|
251 |
+ # Yes, list of word completion separators has shrunk; |
|
252 |
+ line=$COMP_LINE |
|
253 |
+ # Re-assemble words to complete |
|
254 |
+ for (( i=0, j=0; i < ${#COMP_WORDS[@]}; i++, j++)); do |
|
255 |
+ # Is current word not word 0 (the command itself) and is word not |
|
256 |
+ # empty and is word made up of just word separator characters to |
|
257 |
+ # be excluded and is current word not preceded by whitespace in |
|
258 |
+ # original line? |
|
259 |
+ while [[ $i -gt 0 && ${COMP_WORDS[$i]} == +([$exclude]) ]]; do |
|
260 |
+ # Is word separator not preceded by whitespace in original line |
|
261 |
+ # and are we not going to append to word 0 (the command |
|
262 |
+ # itself), then append to current word. |
|
263 |
+ [[ $line != [$' \t']* ]] && (( j >= 2 )) && ((j--)) |
|
264 |
+ # Append word separator to current or new word |
|
265 |
+ ref="$2[$j]" |
|
266 |
+ eval $2[$j]=\${!ref}\${COMP_WORDS[i]} |
|
267 |
+ # Indicate new cword |
|
268 |
+ [[ $i == $COMP_CWORD ]] && eval $3=$j |
|
269 |
+ # Remove optional whitespace + word separator from line copy |
|
270 |
+ line=${line#*"${COMP_WORDS[$i]}"} |
|
271 |
+ # Start new word if word separator in original line is |
|
272 |
+ # followed by whitespace. |
|
273 |
+ [[ $line == [$' \t']* ]] && ((j++)) |
|
274 |
+ # Indicate next word if available, else end *both* while and |
|
275 |
+ # for loop |
|
276 |
+ (( $i < ${#COMP_WORDS[@]} - 1)) && ((i++)) || break 2 |
|
277 |
+ done |
|
278 |
+ # Append word to current word |
|
279 |
+ ref="$2[$j]" |
|
280 |
+ eval $2[$j]=\${!ref}\${COMP_WORDS[i]} |
|
281 |
+ # Remove optional whitespace + word from line copy |
|
282 |
+ line=${line#*"${COMP_WORDS[i]}"} |
|
283 |
+ # Indicate new cword |
|
284 |
+ [[ $i == $COMP_CWORD ]] && eval $3=$j |
|
285 |
+ done |
|
286 |
+ [[ $i == $COMP_CWORD ]] && eval $3=$j |
|
287 |
+ else |
|
288 |
+ # No, list of word completions separators hasn't changed; |
|
289 |
+ eval $2=\( \"\${COMP_WORDS[@]}\" \) |
|
290 |
+ fi |
|
291 |
+} # __reassemble_comp_words_by_ref() |
|
292 |
+ |
|
293 |
+ |
|
294 |
+# @param $1 exclude Characters out of $COMP_WORDBREAKS which should NOT be |
|
295 |
+# considered word breaks. This is useful for things like scp where |
|
296 |
+# we want to return host:path and not only path, so we would pass the |
|
297 |
+# colon (:) as $1 in this case. |
|
298 |
+# @param $2 words Name of variable to return words to |
|
299 |
+# @param $3 cword Name of variable to return cword to |
|
300 |
+# @param $4 cur Name of variable to return current word to complete to |
|
301 |
+# @see __reassemble_comp_words_by_ref() |
|
302 |
+__get_cword_at_cursor_by_ref() |
|
303 |
+{ |
|
304 |
+ local cword words=() |
|
305 |
+ __reassemble_comp_words_by_ref "$1" words cword |
|
306 |
+ |
|
307 |
+ local i cur index=$COMP_POINT lead=${COMP_LINE:0:$COMP_POINT} |
|
308 |
+ # Cursor not at position 0 and not leaded by just space(s)? |
|
309 |
+ if [[ $index -gt 0 && ( $lead && ${lead//[[:space:]]} ) ]]; then |
|
310 |
+ cur=$COMP_LINE |
|
311 |
+ for (( i = 0; i <= cword; ++i )); do |
|
312 |
+ while [[ |
|
313 |
+ # Current word fits in $cur? |
|
314 |
+ ${#cur} -ge ${#words[i]} && |
|
315 |
+ # $cur doesn't match cword? |
|
316 |
+ "${cur:0:${#words[i]}}" != "${words[i]}" |
|
317 |
+ ]]; do |
|
318 |
+ # Strip first character |
|
319 |
+ cur="${cur:1}" |
|
320 |
+ # Decrease cursor position |
|
321 |
+ ((index--)) |
|
322 |
+ done |
|
323 |
+ |
|
324 |
+ # Does found word match cword? |
|
325 |
+ if [[ $i -lt $cword ]]; then |
|
326 |
+ # No, cword lies further; |
|
327 |
+ local old_size=${#cur} |
|
328 |
+ cur="${cur#"${words[i]}"}" |
|
329 |
+ local new_size=${#cur} |
|
330 |
+ index=$(( index - old_size + new_size )) |
|
331 |
+ fi |
|
332 |
+ done |
|
333 |
+ # Clear $cur if just space(s) |
|
334 |
+ [[ $cur && ! ${cur//[[:space:]]} ]] && cur= |
|
335 |
+ # Zero $index if negative |
|
336 |
+ [[ $index -lt 0 ]] && index=0 |
|
337 |
+ fi |
|
338 |
+ |
|
339 |
+ local "$2" "$3" "$4" && _upvars -a${#words[@]} $2 "${words[@]}" \ |
|
340 |
+ -v $3 "$cword" -v $4 "${cur:0:$index}" |
|
341 |
+} |
|
342 |
+ |
|
343 |
+ |
|
344 |
+# Get the word to complete and optional previous words. |
|
345 |
+# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases |
|
346 |
+# where the user is completing in the middle of a word. |
|
347 |
+# (For example, if the line is "ls foobar", |
|
348 |
+# and the cursor is here --------> ^ |
|
349 |
+# Also one is able to cross over possible wordbreak characters. |
|
350 |
+# Usage: _get_comp_words_by_ref [OPTIONS] [VARNAMES] |
|
351 |
+# Available VARNAMES: |
|
352 |
+# cur Return cur via $cur |
|
353 |
+# prev Return prev via $prev |
|
354 |
+# words Return words via $words |
|
355 |
+# cword Return cword via $cword |
|
356 |
+# |
|
357 |
+# Available OPTIONS: |
|
358 |
+# -n EXCLUDE Characters out of $COMP_WORDBREAKS which should NOT be |
|
359 |
+# considered word breaks. This is useful for things like scp |
|
360 |
+# where we want to return host:path and not only path, so we |
|
361 |
+# would pass the colon (:) as -n option in this case. |
|
362 |
+# -c VARNAME Return cur via $VARNAME |
|
363 |
+# -p VARNAME Return prev via $VARNAME |
|
364 |
+# -w VARNAME Return words via $VARNAME |
|
365 |
+# -i VARNAME Return cword via $VARNAME |
|
366 |
+# |
|
367 |
+# Example usage: |
|
368 |
+# |
|
369 |
+# $ _get_comp_words_by_ref -n : cur prev |
|
370 |
+# |
|
371 |
+_get_comp_words_by_ref() |
|
372 |
+{ |
|
373 |
+ local exclude flag i OPTIND=1 |
|
374 |
+ local cur cword words=() |
|
375 |
+ local upargs=() upvars=() vcur vcword vprev vwords |
|
376 |
+ |
|
377 |
+ while getopts "c:i:n:p:w:" flag "$@"; do |
|
378 |
+ case $flag in |
|
379 |
+ c) vcur=$OPTARG ;; |
|
380 |
+ i) vcword=$OPTARG ;; |
|
381 |
+ n) exclude=$OPTARG ;; |
|
382 |
+ p) vprev=$OPTARG ;; |
|
383 |
+ w) vwords=$OPTARG ;; |
|
384 |
+ esac |
|
385 |
+ done |
|
386 |
+ while [[ $# -ge $OPTIND ]]; do |
|
387 |
+ case ${!OPTIND} in |
|
388 |
+ cur) vcur=cur ;; |
|
389 |
+ prev) vprev=prev ;; |
|
390 |
+ cword) vcword=cword ;; |
|
391 |
+ words) vwords=words ;; |
|
392 |
+ *) echo "bash: $FUNCNAME(): \`${!OPTIND}': unknown argument" \ |
|
393 |
+ 1>&2; return 1 |
|
394 |
+ esac |
|
395 |
+ let "OPTIND += 1" |
|
396 |
+ done |
|
397 |
+ |
|
398 |
+ __get_cword_at_cursor_by_ref "$exclude" words cword cur |
|
399 |
+ |
|
400 |
+ [[ $vcur ]] && { upvars+=("$vcur" ); upargs+=(-v $vcur "$cur" ); } |
|
401 |
+ [[ $vcword ]] && { upvars+=("$vcword"); upargs+=(-v $vcword "$cword"); } |
|
402 |
+ [[ $vprev && $cword -ge 1 ]] && { upvars+=("$vprev" ); upargs+=(-v $vprev |
|
403 |
+ "${words[cword - 1]}"); } |
|
404 |
+ [[ $vwords ]] && { upvars+=("$vwords"); upargs+=(-a${#words[@]} $vwords |
|
405 |
+ "${words[@]}"); } |
|
406 |
+ |
|
407 |
+ (( ${#upvars[@]} )) && local "${upvars[@]}" && _upvars "${upargs[@]}" |
|
408 |
+} |
|
409 |
+ |
|
410 |
+ |
|
411 |
+# Get the word to complete. |
|
412 |
+# This is nicer than ${COMP_WORDS[$COMP_CWORD]}, since it handles cases |
|
413 |
+# where the user is completing in the middle of a word. |
|
414 |
+# (For example, if the line is "ls foobar", |
|
415 |
+# and the cursor is here --------> ^ |
|
416 |
+# @param $1 string Characters out of $COMP_WORDBREAKS which should NOT be |
|
417 |
+# considered word breaks. This is useful for things like scp where |
|
418 |
+# we want to return host:path and not only path, so we would pass the |
|
419 |
+# colon (:) as $1 in this case. |
|
420 |
+# @param $2 integer Index number of word to return, negatively offset to the |
|
421 |
+# current word (default is 0, previous is 1), respecting the exclusions |
|
422 |
+# given at $1. For example, `_get_cword "=:" 1' returns the word left of |
|
423 |
+# the current word, respecting the exclusions "=:". |
|
424 |
+# @deprecated Use `_get_comp_words_by_ref cur' instead |
|
425 |
+# @see _get_comp_words_by_ref() |
|
426 |
+_get_cword() |
|
427 |
+{ |
|
428 |
+ local LC_CTYPE=C |
|
429 |
+ local cword words |
|
430 |
+ __reassemble_comp_words_by_ref "$1" words cword |
|
431 |
+ |
|
432 |
+ # return previous word offset by $2 |
|
433 |
+ if [[ ${2//[^0-9]/} ]]; then |
|
434 |
+ printf "%s" "${words[cword-$2]}" |
|
435 |
+ elif [[ "${#words[cword]}" -eq 0 || "$COMP_POINT" == "${#COMP_LINE}" ]]; then |
|
436 |
+ printf "%s" "${words[cword]}" |
|
437 |
+ else |
|
438 |
+ local i |
|
439 |
+ local cur="$COMP_LINE" |
|
440 |
+ local index="$COMP_POINT" |
|
441 |
+ for (( i = 0; i <= cword; ++i )); do |
|
442 |
+ while [[ |
|
443 |
+ # Current word fits in $cur? |
|
444 |
+ "${#cur}" -ge ${#words[i]} && |
|
445 |
+ # $cur doesn't match cword? |
|
446 |
+ "${cur:0:${#words[i]}}" != "${words[i]}" |
|
447 |
+ ]]; do |
|
448 |
+ # Strip first character |
|
449 |
+ cur="${cur:1}" |
|
450 |
+ # Decrease cursor position |
|
451 |
+ ((index--)) |
|
452 |
+ done |
|
453 |
+ |
|
454 |
+ # Does found word matches cword? |
|
455 |
+ if [[ "$i" -lt "$cword" ]]; then |
|
456 |
+ # No, cword lies further; |
|
457 |
+ local old_size="${#cur}" |
|
458 |
+ cur="${cur#${words[i]}}" |
|
459 |
+ local new_size="${#cur}" |
|
460 |
+ index=$(( index - old_size + new_size )) |
|
461 |
+ fi |
|
462 |
+ done |
|
463 |
+ |
|
464 |
+ if [[ "${words[cword]:0:${#cur}}" != "$cur" ]]; then |
|
465 |
+ # We messed up! At least return the whole word so things |
|
466 |
+ # keep working |
|
467 |
+ printf "%s" "${words[cword]}" |
|
468 |
+ else |
|
469 |
+ printf "%s" "${cur:0:$index}" |
|
470 |
+ fi |
|
471 |
+ fi |
|
472 |
+} # _get_cword() |
|
473 |
+ |
|
474 |
+ |
|
475 |
+# Get word previous to the current word. |
|
476 |
+# This is a good alternative to `prev=${COMP_WORDS[COMP_CWORD-1]}' because bash4 |
|
477 |
+# will properly return the previous word with respect to any given exclusions to |
|
478 |
+# COMP_WORDBREAKS. |
|
479 |
+# @deprecated Use `_get_comp_words_by_ref cur prev' instead |
|
480 |
+# @see _get_comp_words_by_ref() |
|
481 |
+# |
|
482 |
+_get_pword() |
|
483 |
+{ |
|
484 |
+ if [[ $COMP_CWORD -ge 1 ]]; then |
|
485 |
+ _get_cword "${@:-}" 1 |
|
486 |
+ fi |
|
487 |
+} |
|
488 |
+ |
|
489 |
+ |
|
490 |
+# If the word-to-complete contains a colon (:), left-trim COMPREPLY items with |
|
491 |
+# word-to-complete. |
|
492 |
+# With a colon in COMP_WORDBREAKS, words containing |
|
493 |
+# colons are always completed as entire words if the word to complete contains |
|
494 |
+# a colon. This function fixes this, by removing the colon-containing-prefix |
|
495 |
+# from COMPREPLY items. |
|
496 |
+# The preferred solution is to remove the colon (:) from COMP_WORDBREAKS in |
|
497 |
+# your .bashrc: |
|
498 |
+# |
|
499 |
+# # Remove colon (:) from list of word completion separators |
|
500 |
+# COMP_WORDBREAKS=${COMP_WORDBREAKS//:} |
|
501 |
+# |
|
502 |
+# See also: Bash FAQ - E13) Why does filename completion misbehave if a colon |
|
503 |
+# appears in the filename? - http://tiswww.case.edu/php/chet/bash/FAQ |
|
504 |
+# @param $1 current word to complete (cur) |
|
505 |
+# @modifies global array $COMPREPLY |
|
506 |
+# |
|
507 |
+__ltrim_colon_completions() |
|
508 |
+{ |
|
509 |
+ if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then |
|
510 |
+ # Remove colon-word prefix from COMPREPLY items |
|
511 |
+ local colon_word=${1%"${1##*:}"} |
|
512 |
+ local i=${#COMPREPLY[*]} |
|
513 |
+ while [[ $((--i)) -ge 0 ]]; do |
|
514 |
+ COMPREPLY[$i]=${COMPREPLY[$i]#"$colon_word"} |
|
515 |
+ done |
|
516 |
+ fi |
|
517 |
+} # __ltrim_colon_completions() |
|
518 |
+ |
|
519 |
+ |
|
520 |
+# This function quotes the argument in a way so that readline dequoting |
|
521 |
+# results in the original argument. This is necessary for at least |
|
522 |
+# `compgen' which requires its arguments quoted/escaped: |
|
523 |
+# |
|
524 |
+# $ ls "a'b/" |
|
525 |
+# c |
|
526 |
+# $ compgen -f "a'b/" # Wrong, doesn't return output |
|
527 |
+# $ compgen -f "a\'b/" # Good |
|
528 |
+# a\'b/c |
|
529 |
+# |
|
530 |
+# See also: |
|
531 |
+# - http://lists.gnu.org/archive/html/bug-bash/2009-03/msg00155.html |
|
532 |
+# - http://www.mail-archive.com/bash-completion-devel@lists.alioth.\ |
|
533 |
+# debian.org/msg01944.html |
|
534 |
+# @param $1 Argument to quote |
|
535 |
+# @param $2 Name of variable to return result to |
|
536 |
+_quote_readline_by_ref() |
|
537 |
+{ |
|
538 |
+ if [ -z "$1" ]; then |
|
539 |
+ # avoid quoting if empty |
|
540 |
+ printf -v $2 %s "$1" |
|
541 |
+ elif [[ $1 == \'* ]]; then |
|
542 |
+ # Leave out first character |
|
543 |
+ printf -v $2 %s "${1:1}" |
|
544 |
+ elif [[ $1 == ~* ]]; then |
|
545 |
+ # avoid escaping first ~ |
|
546 |
+ printf -v $2 ~%q "${1:1}" |
|
547 |
+ else |
|
548 |
+ printf -v $2 %q "$1" |
|
549 |
+ fi |
|
550 |
+ |
|
551 |
+ # Replace double escaping ( \\ ) by single ( \ ) |
|
552 |
+ # This happens always when argument is already escaped at cmdline, |
|
553 |
+ # and passed to this function as e.g.: file\ with\ spaces |
|
554 |
+ [[ ${!2} == *\\* ]] && printf -v $2 %s "${1//\\\\/\\}" |
|
555 |
+ |
|
556 |
+ # If result becomes quoted like this: $'string', re-evaluate in order to |
|
557 |
+ # drop the additional quoting. See also: http://www.mail-archive.com/ |
|
558 |
+ # bash-completion-devel@lists.alioth.debian.org/msg01942.html |
|
559 |
+ [[ ${!2} == \$* ]] && eval $2=${!2} |
|
560 |
+} # _quote_readline_by_ref() |
|
561 |
+ |
|
562 |
+ |
|
563 |
+# This function performs file and directory completion. It's better than |
|
564 |
+# simply using 'compgen -f', because it honours spaces in filenames. |
|
565 |
+# @param $1 If `-d', complete only on directories. Otherwise filter/pick only |
|
566 |
+# completions with `.$1' and the uppercase version of it as file |
|
567 |
+# extension. |
|
568 |
+# |
|
569 |
+_filedir() |
|
570 |
+{ |
|
571 |
+ local i IFS=$'\n' xspec |
|
572 |
+ |
|
573 |
+ _tilde "$cur" || return 0 |
|
574 |
+ |
|
575 |
+ local -a toks |
|
576 |
+ local quoted x tmp |
|
577 |
+ |
|
578 |
+ _quote_readline_by_ref "$cur" quoted |
|
579 |
+ x=$( compgen -d -- "$quoted" ) && |
|
580 |
+ while read -r tmp; do |
|
581 |
+ toks+=( "$tmp" ) |
|
582 |
+ done <<< "$x" |
|
583 |
+ |
|
584 |
+ if [[ "$1" != -d ]]; then |
|
585 |
+ # Munge xspec to contain uppercase version too |
|
586 |
+ # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306 |
|
587 |
+ xspec=${1:+"!*.@($1|${1^^})"} |
|
588 |
+ x=$( compgen -f -X "$xspec" -- $quoted ) && |
|
589 |
+ while read -r tmp; do |
|
590 |
+ toks+=( "$tmp" ) |
|
591 |
+ done <<< "$x" |
|
592 |
+ fi |
|
593 |
+ |
|
594 |
+ # If the filter failed to produce anything, try without it if configured to |
|
595 |
+ [[ -n ${COMP_FILEDIR_FALLBACK:-} && \ |
|
596 |
+ -n "$1" && "$1" != -d && ${#toks[@]} -lt 1 ]] && \ |
|
597 |
+ x=$( compgen -f -- $quoted ) && |
|
598 |
+ while read -r tmp; do |
|
599 |
+ toks+=( "$tmp" ) |
|
600 |
+ done <<< "$x" |
|
601 |
+ |
|
602 |
+ |
|
603 |
+ if [[ ${#toks[@]} -ne 0 ]]; then |
|
604 |
+ # 2>/dev/null for direct invocation, e.g. in the _filedir unit test |
|
605 |
+ compopt -o filenames 2>/dev/null |
|
606 |
+ COMPREPLY+=( "${toks[@]}" ) |
|
607 |
+ fi |
|
608 |
+} # _filedir() |
|
609 |
+ |
|
610 |
+ |
|
611 |
+# This function splits $cur=--foo=bar into $prev=--foo, $cur=bar, making it |
|
612 |
+# easier to support both "--foo bar" and "--foo=bar" style completions. |
|
613 |
+# `=' should have been removed from COMP_WORDBREAKS when setting $cur for |
|
614 |
+# this to be useful. |
|
615 |
+# Returns 0 if current option was split, 1 otherwise. |
|
616 |
+# |
|
617 |
+_split_longopt() |
|
618 |
+{ |
|
619 |
+ if [[ "$cur" == --?*=* ]]; then |
|
620 |
+ # Cut also backslash before '=' in case it ended up there |
|
621 |
+ # for some reason. |
|
622 |
+ prev="${cur%%?(\\)=*}" |
|
623 |
+ cur="${cur#*=}" |
|
624 |
+ return 0 |
|
625 |
+ fi |
|
626 |
+ |
|
627 |
+ return 1 |
|
628 |
+} |
|
629 |
+ |
|
630 |
+# Complete variables. |
|
631 |
+# @return True (0) if variables were completed, |
|
632 |
+# False (> 0) if not. |
|
633 |
+_variables() |
|
634 |
+{ |
|
635 |
+ if [[ $cur =~ ^(\$\{?)([A-Za-z0-9_]*)$ ]]; then |
|
636 |
+ [[ $cur == *{* ]] && local suffix=} || local suffix= |
|
637 |
+ COMPREPLY+=( $( compgen -P ${BASH_REMATCH[1]} -S "$suffix" -v -- \ |
|
638 |
+ "${BASH_REMATCH[2]}" ) ) |
|
639 |
+ return 0 |
|
640 |
+ fi |
|
641 |
+ return 1 |
|
642 |
+} |
|
643 |
+ |
|
644 |
+# Initialize completion and deal with various general things: do file |
|
645 |
+# and variable completion where appropriate, and adjust prev, words, |
|
646 |
+# and cword as if no redirections exist so that completions do not |
|
647 |
+# need to deal with them. Before calling this function, make sure |
|
648 |
+# cur, prev, words, and cword are local, ditto split if you use -s. |
|
649 |
+# |
|
650 |
+# Options: |
|
651 |
+# -n EXCLUDE Passed to _get_comp_words_by_ref -n with redirection chars |
|
652 |
+# -e XSPEC Passed to _filedir as first arg for stderr redirections |
|
653 |
+# -o XSPEC Passed to _filedir as first arg for other output redirections |
|
654 |
+# -i XSPEC Passed to _filedir as first arg for stdin redirections |
|
655 |
+# -s Split long options with _split_longopt, implies -n = |
|
656 |
+# @return True (0) if completion needs further processing, |
|
657 |
+# False (> 0) no further processing is necessary. |
|
658 |
+# |
|
659 |
+_init_completion() |
|
660 |
+{ |
|
661 |
+ local exclude= flag outx errx inx OPTIND=1 |
|
662 |
+ |
|
663 |
+ while getopts "n:e:o:i:s" flag "$@"; do |
|
664 |
+ case $flag in |
|
665 |
+ n) exclude+=$OPTARG ;; |
|
666 |
+ e) errx=$OPTARG ;; |
|
667 |
+ o) outx=$OPTARG ;; |
|
668 |
+ i) inx=$OPTARG ;; |
|
669 |
+ s) split=false ; exclude+== ;; |
|
670 |
+ esac |
|
671 |
+ done |
|
672 |
+ |
|
673 |
+ # For some reason completion functions are not invoked at all by |
|
674 |
+ # bash (at least as of 4.1.7) after the command line contains an |
|
675 |
+ # ampersand so we don't get a chance to deal with redirections |
|
676 |
+ # containing them, but if we did, hopefully the below would also |
|
677 |
+ # do the right thing with them... |
|
678 |
+ |
|
679 |
+ COMPREPLY=() |
|
680 |
+ local redir="@(?([0-9])<|?([0-9&])>?(>)|>&)" |
|
681 |
+ _get_comp_words_by_ref -n "$exclude<>&" cur prev words cword |
|
682 |
+ |
|
683 |
+ # Complete variable names. |
|
684 |
+ _variables && return 1 |
|
685 |
+ |
|
686 |
+ # Complete on files if current is a redirect possibly followed by a |
|
687 |
+ # filename, e.g. ">foo", or previous is a "bare" redirect, e.g. ">". |
|
688 |
+ if [[ $cur == $redir* || $prev == $redir ]]; then |
|
689 |
+ local xspec |
|
690 |
+ case $cur in |
|
691 |
+ 2'>'*) xspec=$errx ;; |
|
692 |
+ *'>'*) xspec=$outx ;; |
|
693 |
+ *'<'*) xspec=$inx ;; |
|
694 |
+ *) |
|
695 |
+ case $prev in |
|
696 |
+ 2'>'*) xspec=$errx ;; |
|
697 |
+ *'>'*) xspec=$outx ;; |
|
698 |
+ *'<'*) xspec=$inx ;; |
|
699 |
+ esac |
|
700 |
+ ;; |
|
701 |
+ esac |
|
702 |
+ cur="${cur##$redir}" |
|
703 |
+ _filedir $xspec |
|
704 |
+ return 1 |
|
705 |
+ fi |
|
706 |
+ |
|
707 |
+ # Remove all redirections so completions don't have to deal with them. |
|
708 |
+ local i skip |
|
709 |
+ for (( i=1; i < ${#words[@]}; )); do |
|
710 |
+ if [[ ${words[i]} == $redir* ]]; then |
|
711 |
+ # If "bare" redirect, remove also the next word (skip=2). |
|
712 |
+ [[ ${words[i]} == $redir ]] && skip=2 || skip=1 |
|
713 |
+ words=( "${words[@]:0:i}" "${words[@]:i+skip}" ) |
|
714 |
+ [[ $i -le $cword ]] && cword=$(( cword - skip )) |
|
715 |
+ else |
|
716 |
+ i=$(( ++i )) |
|
717 |
+ fi |
|
718 |
+ done |
|
719 |
+ |
|
720 |
+ [[ $cword -le 0 ]] && return 1 |
|
721 |
+ prev=${words[cword-1]} |
|
722 |
+ |
|
723 |
+ [[ ${split-} ]] && _split_longopt && split=true |
|
724 |
+ |
|
725 |
+ return 0 |
|
726 |
+} |
|
727 |
+ |
|
728 |
+# Helper function for _parse_help and _parse_usage. |
|
729 |
+__parse_options() |
|
730 |
+{ |
|
731 |
+ local option option2 i IFS=$' \t\n,/|' |
|
732 |
+ |
|
733 |
+ # Take first found long option, or first one (short) if not found. |
|
734 |
+ option= |
|
735 |
+ for i in $1; do |
|
736 |
+ case $i in |
|
737 |
+ ---*) break ;; |
|
738 |
+ --?*) option=$i ; break ;; |
|
739 |
+ -?*) [[ $option ]] || option=$i ;; |
|
740 |
+ *) break ;; |
|
741 |
+ esac |
|
742 |
+ done |
|
743 |
+ [[ $option ]] || return 0 |
|
744 |
+ |
|
745 |
+ IFS=$' \t\n' # affects parsing of the regexps below... |
|
746 |
+ |
|
747 |
+ # Expand --[no]foo to --foo and --nofoo etc |
|
748 |
+ if [[ $option =~ (\[((no|dont)-?)\]). ]]; then |
|
749 |
+ option2=${option/"${BASH_REMATCH[1]}"/} |
|
750 |
+ option2=${option2%%[<{().[]*} |
|
751 |
+ printf '%s\n' "${option2/=*/=}" |
|
752 |
+ option=${option/"${BASH_REMATCH[1]}"/"${BASH_REMATCH[2]}"} |
|
753 |
+ fi |
|
754 |
+ |
|
755 |
+ option=${option%%[<{().[]*} |
|
756 |
+ printf '%s\n' "${option/=*/=}" |
|
757 |
+} |
|
758 |
+ |
|
759 |
+# Parse GNU style help output of the given command. |
|
760 |
+# @param $1 command; if "-", read from stdin and ignore rest of args |
|
761 |
+# @param $2 command options (default: --help) |
|
762 |
+# |
|
763 |
+_parse_help() |
|
764 |
+{ |
|
765 |
+ eval local cmd=$( quote "$1" ) |
|
766 |
+ local line |
|
767 |
+ { case $cmd in |
|
768 |
+ -) cat ;; |
|
769 |
+ *) LC_ALL=C "$( dequote "$cmd" )" ${2:---help} 2>&1 ;; |
|
770 |
+ esac } \ |
|
771 |
+ | while read -r line; do |
|
772 |
+ |
|
773 |
+ [[ $line == *([ $'\t'])-* ]] || continue |
|
774 |
+ # transform "-f FOO, --foo=FOO" to "-f , --foo=FOO" etc |
|
775 |
+ while [[ $line =~ \ |
|
776 |
+ ((^|[^-])-[A-Za-z0-9?][[:space:]]+)\[?[A-Z0-9]+\]? ]]; do |
|
777 |
+ line=${line/"${BASH_REMATCH[0]}"/"${BASH_REMATCH[1]}"} |
|
778 |
+ done |
|
779 |
+ __parse_options "${line// or /, }" |
|
780 |
+ |
|
781 |
+ done |
|
782 |
+} |
|
783 |
+ |
|
784 |
+# Parse BSD style usage output (options in brackets) of the given command. |
|
785 |
+# @param $1 command; if "-", read from stdin and ignore rest of args |
|
786 |
+# @param $2 command options (default: --usage) |
|
787 |
+# |
|
788 |
+_parse_usage() |
|
789 |
+{ |
|
790 |
+ eval local cmd=$( quote "$1" ) |
|
791 |
+ local line match option i char |
|
792 |
+ { case $cmd in |
|
793 |
+ -) cat ;; |
|
794 |
+ *) LC_ALL=C "$( dequote "$cmd" )" ${2:---usage} 2>&1 ;; |
|
795 |
+ esac } \ |
|
796 |
+ | while read -r line; do |
|
797 |
+ |
|
798 |
+ while [[ $line =~ \[[[:space:]]*(-[^]]+)[[:space:]]*\] ]]; do |
|
799 |
+ match=${BASH_REMATCH[0]} |
|
800 |
+ option=${BASH_REMATCH[1]} |
|
801 |
+ case $option in |
|
802 |
+ -?(\[)+([a-zA-Z0-9?])) |
|
803 |
+ # Treat as bundled short options |
|
804 |
+ for (( i=1; i < ${#option}; i++ )); do |
|
805 |
+ char=${option:i:1} |
|
806 |
+ [[ $char != '[' ]] && printf '%s\n' -$char |
|
807 |
+ done |
|
808 |
+ ;; |
|
809 |
+ *) |
|
810 |
+ __parse_options "$option" |
|
811 |
+ ;; |
|
812 |
+ esac |
|
813 |
+ line=${line#*"$match"} |
|
814 |
+ done |
|
815 |
+ |
|
816 |
+ done |
|
817 |
+} |
|
818 |
+ |
|
819 |
+# This function completes on signal names (minus the SIG prefix) |
|
820 |
+# @param $1 prefix |
|
821 |
+_signals() |
|
822 |
+{ |
|
823 |
+ local -a sigs=( $( compgen -P "$1" -A signal "SIG${cur#$1}" ) ) |
|
824 |
+ COMPREPLY+=( "${sigs[@]/#${1}SIG/${1}}" ) |
|
825 |
+} |
|
826 |
+ |
|
827 |
+# This function completes on known mac addresses |
|
828 |
+# |
|
829 |
+_mac_addresses() |
|
830 |
+{ |
|
831 |
+ local re='\([A-Fa-f0-9]\{2\}:\)\{5\}[A-Fa-f0-9]\{2\}' |
|
832 |
+ local PATH="$PATH:/sbin:/usr/sbin" |
|
833 |
+ |
|
834 |
+ # Local interfaces |
|
835 |
+ # - ifconfig on Linux: HWaddr or ether |
|
836 |
+ # - ifconfig on FreeBSD: ether |
|
837 |
+ # - ip link: link/ether |
|
838 |
+ COMPREPLY+=( $( \ |
|
839 |
+ { LC_ALL=C ifconfig -a || ip link show; } 2>/dev/null | sed -ne \ |
|
840 |
+ "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]].*/\1/p" -ne \ |
|
841 |
+ "s/.*[[:space:]]HWaddr[[:space:]]\{1,\}\($re\)[[:space:]]*$/\1/p" -ne \ |
|
842 |
+ "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]].*|\2|p" -ne \ |
|
843 |
+ "s|.*[[:space:]]\(link/\)\{0,1\}ether[[:space:]]\{1,\}\($re\)[[:space:]]*$|\2|p" |
|
844 |
+ ) ) |
|
845 |
+ |
|
846 |
+ # ARP cache |
|
847 |
+ COMPREPLY+=( $( { arp -an || ip neigh show; } 2>/dev/null | sed -ne \ |
|
848 |
+ "s/.*[[:space:]]\($re\)[[:space:]].*/\1/p" -ne \ |
|
849 |
+ "s/.*[[:space:]]\($re\)[[:space:]]*$/\1/p" ) ) |
|
850 |
+ |
|
851 |
+ # /etc/ethers |
|
852 |
+ COMPREPLY+=( $( sed -ne \ |
|
853 |
+ "s/^[[:space:]]*\($re\)[[:space:]].*/\1/p" /etc/ethers 2>/dev/null ) ) |
|
854 |
+ |
|
855 |
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]}' -- "$cur" ) ) |
|
856 |
+ __ltrim_colon_completions "$cur" |
|
857 |
+} |
|
858 |
+ |
|
859 |
+# This function completes on configured network interfaces |
|
860 |
+# |
|
861 |
+_configured_interfaces() |
|
862 |
+{ |
|
863 |
+ if [[ -f /etc/debian_version ]]; then |
|
864 |
+ # Debian system |
|
865 |
+ COMPREPLY=( $( compgen -W "$( sed -ne 's|^iface \([^ ]\{1,\}\).*$|\1|p'\ |
|
866 |
+ /etc/network/interfaces )" -- "$cur" ) ) |
|
867 |
+ elif [[ -f /etc/SuSE-release ]]; then |
|
868 |
+ # SuSE system |
|
869 |
+ COMPREPLY=( $( compgen -W "$( printf '%s\n' \ |
|
870 |
+ /etc/sysconfig/network/ifcfg-* | \ |
|
871 |
+ sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) |
|
872 |
+ elif [[ -f /etc/pld-release ]]; then |
|
873 |
+ # PLD Linux |
|
874 |
+ COMPREPLY=( $( compgen -W "$( command ls -B \ |
|
875 |
+ /etc/sysconfig/interfaces | \ |
|
876 |
+ sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) |
|
877 |
+ else |
|
878 |
+ # Assume Red Hat |
|
879 |
+ COMPREPLY=( $( compgen -W "$( printf '%s\n' \ |
|
880 |
+ /etc/sysconfig/network-scripts/ifcfg-* | \ |
|
881 |
+ sed -ne 's|.*ifcfg-\(.*\)|\1|p' )" -- "$cur" ) ) |
|
882 |
+ fi |
|
883 |
+} |
|
884 |
+ |
|
885 |
+# Local IP addresses. |
|
886 |
+# |
|
887 |
+_ip_addresses() |
|
888 |
+{ |
|
889 |
+ local PATH=$PATH:/sbin |
|
890 |
+ COMPREPLY+=( $( compgen -W \ |
|
891 |
+ "$( { LC_ALL=C ifconfig -a || ip addr show; } 2>/dev/null | |
|
892 |
+ sed -ne 's/.*addr:\([^[:space:]]*\).*/\1/p' \ |
|
893 |
+ -ne 's|.*inet[[:space:]]\{1,\}\([^[:space:]/]*\).*|\1|p' )" \ |
|
894 |
+ -- "$cur" ) ) |
|
895 |
+} |
|
896 |
+ |
|
897 |
+# This function completes on available kernels |
|
898 |
+# |
|
899 |
+_kernel_versions() |
|
900 |
+{ |
|
901 |
+ COMPREPLY=( $( compgen -W '$( command ls /lib/modules )' -- "$cur" ) ) |
|
902 |
+} |
|
903 |
+ |
|
904 |
+# This function completes on all available network interfaces |
|
905 |
+# -a: restrict to active interfaces only |
|
906 |
+# -w: restrict to wireless interfaces only |
|
907 |
+# |
|
908 |
+_available_interfaces() |
|
909 |
+{ |
|
910 |
+ local cmd PATH=$PATH:/sbin |
|
911 |
+ |
|
912 |
+ if [[ ${1:-} == -w ]]; then |
|
913 |
+ cmd="iwconfig" |
|
914 |
+ elif [[ ${1:-} == -a ]]; then |
|
915 |
+ cmd="{ ifconfig || ip link show up; }" |
|
916 |
+ else |
|
917 |
+ cmd="{ ifconfig -a || ip link show; }" |
|
918 |
+ fi |
|
919 |
+ |
|
920 |
+ COMPREPLY=( $( eval $cmd 2>/dev/null | awk \ |
|
921 |
+ '/^[^ \t]/ { if ($1 ~ /^[0-9]+:/) { print $2 } else { print $1 } }' ) ) |
|
922 |
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]/%[[:punct:]]/}' -- "$cur" ) ) |
|
923 |
+} |
|
924 |
+ |
|
925 |
+# Echo number of CPUs, falling back to 1 on failure. |
|
926 |
+_ncpus() |
|
927 |
+{ |
|
928 |
+ local var=NPROCESSORS_ONLN |
|
929 |
+ [[ $OSTYPE == *linux* ]] && var=_$var |
|
930 |
+ local n=$( getconf $var 2>/dev/null ) |
|
931 |
+ printf %s ${n:-1} |
|
932 |
+} |
|
933 |
+ |
|
934 |
+# Perform tilde (~) completion |
|
935 |
+# @return True (0) if completion needs further processing, |
|
936 |
+# False (> 0) if tilde is followed by a valid username, completions |
|
937 |
+# are put in COMPREPLY and no further processing is necessary. |
|
938 |
+_tilde() |
|
939 |
+{ |
|
940 |
+ local result=0 |
|
941 |
+ if [[ $1 == \~* && $1 != */* ]]; then |
|
942 |
+ # Try generate ~username completions |
|
943 |
+ COMPREPLY=( $( compgen -P '~' -u "${1#\~}" ) ) |
|
944 |
+ result=${#COMPREPLY[@]} |
|
945 |
+ # 2>/dev/null for direct invocation, e.g. in the _tilde unit test |
|
946 |
+ [[ $result -gt 0 ]] && compopt -o filenames 2>/dev/null |
|
947 |
+ fi |
|
948 |
+ return $result |
|
949 |
+} |
|
950 |
+ |
|
951 |
+ |
|
952 |
+# Expand variable starting with tilde (~) |
|
953 |
+# We want to expand ~foo/... to /home/foo/... to avoid problems when |
|
954 |
+# word-to-complete starting with a tilde is fed to commands and ending up |
|
955 |
+# quoted instead of expanded. |
|
956 |
+# Only the first portion of the variable from the tilde up to the first slash |
|
957 |
+# (~../) is expanded. The remainder of the variable, containing for example |
|
958 |
+# a dollar sign variable ($) or asterisk (*) is not expanded. |
|
959 |
+# Example usage: |
|
960 |
+# |
|
961 |
+# $ v="~"; __expand_tilde_by_ref v; echo "$v" |
|
962 |
+# |
|
963 |
+# Example output: |
|
964 |
+# |
|
965 |
+# v output |
|
966 |
+# -------- ---------------- |
|
967 |
+# ~ /home/user |
|
968 |
+# ~foo/bar /home/foo/bar |
|
969 |
+# ~foo/$HOME /home/foo/$HOME |
|
970 |
+# ~foo/a b /home/foo/a b |
|
971 |
+# ~foo/* /home/foo/* |
|
972 |
+# |
|
973 |
+# @param $1 Name of variable (not the value of the variable) to expand |
|
974 |
+__expand_tilde_by_ref() |
|
975 |
+{ |
|
976 |
+ # Does $1 start with tilde (~)? |
|
977 |
+ if [[ ${!1} == \~* ]]; then |
|
978 |
+ # Does $1 contain slash (/)? |
|
979 |
+ if [[ ${!1} == */* ]]; then |
|
980 |
+ # Yes, $1 contains slash; |
|
981 |
+ # 1: Remove * including and after first slash (/), i.e. "~a/b" |
|
982 |
+ # becomes "~a". Double quotes allow eval. |
|
983 |
+ # 2: Remove * before the first slash (/), i.e. "~a/b" |
|
984 |
+ # becomes "b". Single quotes prevent eval. |
|
985 |
+ # +-----1----+ +---2----+ |
|
986 |
+ eval $1="${!1/%\/*}"/'${!1#*/}' |
|
987 |
+ else |
|
988 |
+ # No, $1 doesn't contain slash |
|
989 |
+ eval $1="${!1}" |
|
990 |
+ fi |
|
991 |
+ fi |
|
992 |
+} # __expand_tilde_by_ref() |
|
993 |
+ |
|
994 |
+ |
|
995 |
+# This function expands tildes in pathnames |
|
996 |
+# |
|
997 |
+_expand() |
|
998 |
+{ |
|
999 |
+ # FIXME: Why was this here? |
|
1000 |
+ #[ "$cur" != "${cur%\\}" ] && cur+="\\" |
|
1001 |
+ |
|
1002 |
+ # Expand ~username type directory specifications. We want to expand |
|
1003 |
+ # ~foo/... to /home/foo/... to avoid problems when $cur starting with |
|
1004 |
+ # a tilde is fed to commands and ending up quoted instead of expanded. |
|
1005 |
+ |
|
1006 |
+ if [[ "$cur" == \~*/* ]]; then |
|
1007 |
+ eval cur=$cur 2>/dev/null |
|
1008 |
+ elif [[ "$cur" == \~* ]]; then |
|
1009 |
+ cur=${cur#\~} |
|
1010 |
+ COMPREPLY=( $( compgen -P '~' -u "$cur" ) ) |
|
1011 |
+ [[ ${#COMPREPLY[@]} -eq 1 ]] && eval COMPREPLY[0]=${COMPREPLY[0]} |
|
1012 |
+ return ${#COMPREPLY[@]} |
|
1013 |
+ fi |
|
1014 |
+} |
|
1015 |
+ |
|
1016 |
+# This function completes on process IDs. |
|
1017 |
+# AIX and Solaris ps prefers X/Open syntax. |
|
1018 |
+[[ $OSTYPE == *@(solaris|aix)* ]] && |
|
1019 |
+_pids() |
|
1020 |
+{ |
|
1021 |
+ COMPREPLY=( $( compgen -W '$( command ps -efo pid | sed 1d )' -- "$cur" )) |
|
1022 |
+} || |
|
1023 |
+_pids() |
|
1024 |
+{ |
|
1025 |
+ COMPREPLY=( $( compgen -W '$( command ps axo pid= )' -- "$cur" ) ) |
|
1026 |
+} |
|
1027 |
+ |
|
1028 |
+# This function completes on process group IDs. |
|
1029 |
+# AIX and SunOS prefer X/Open, all else should be BSD. |
|
1030 |
+[[ $OSTYPE == *@(solaris|aix)* ]] && |
|
1031 |
+_pgids() |
|
1032 |
+{ |
|
1033 |
+ COMPREPLY=( $( compgen -W '$( command ps -efo pgid | sed 1d )' -- "$cur" )) |
|
1034 |
+} || |
|
1035 |
+_pgids() |
|
1036 |
+{ |
|
1037 |
+ COMPREPLY=( $( compgen -W '$( command ps axo pgid= )' -- "$cur" )) |
|
1038 |
+} |
|
1039 |
+ |
|
1040 |
+# This function completes on process names. |
|
1041 |
+# AIX and SunOS prefer X/Open, all else should be BSD. |
|
1042 |
+[[ $OSTYPE == *@(solaris|aix)* ]] && |
|
1043 |
+_pnames() |
|
1044 |
+{ |
|
1045 |
+ COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps -efo comm | \ |
|
1046 |
+ sed -e 1d -e "s:.*/::" -e "s/^-//" | sort -u )' -- "$cur" ) ) |
|
1047 |
+} || |
|
1048 |
+_pnames() |
|
1049 |
+{ |
|
1050 |
+ # FIXME: completes "[kblockd/0]" to "0". Previously it was completed |
|
1051 |
+ # to "kblockd" which isn't correct either. "kblockd/0" would be |
|
1052 |
+ # arguably most correct, but killall from psmisc 22 treats arguments |
|
1053 |
+ # containing "/" specially unless -r is given so that wouldn't quite |
|
1054 |
+ # work either. Perhaps it'd be best to not complete these to anything |
|
1055 |
+ # for now. |
|
1056 |
+ # Not using "ps axo comm" because under some Linux kernels, it |
|
1057 |
+ # truncates command names (see e.g. http://bugs.debian.org/497540#19) |
|
1058 |
+ COMPREPLY=( $( compgen -X '<defunct>' -W '$( command ps axo command= | \ |
|
1059 |
+ sed -e "s/ .*//" -e "s:.*/::" -e "s/:$//" -e "s/^[[(-]//" \ |
|
1060 |
+ -e "s/[])]$//" | sort -u )' -- "$cur" ) ) |
|
1061 |
+} |
|
1062 |
+ |
|
1063 |
+# This function completes on user IDs |
|
1064 |
+# |
|
1065 |
+_uids() |
|
1066 |
+{ |
|
1067 |
+ if type getent &>/dev/null; then |
|
1068 |
+ COMPREPLY=( $( compgen -W '$( getent passwd | cut -d: -f3 )' -- "$cur" ) ) |
|
1069 |
+ elif type perl &>/dev/null; then |
|
1070 |
+ COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($uid) = (getpwent)[2]) { print $uid . "\n" }'"'"' )' -- "$cur" ) ) |
|
1071 |
+ else |
|
1072 |
+ # make do with /etc/passwd |
|
1073 |
+ COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/passwd )' -- "$cur" ) ) |
|
1074 |
+ fi |
|
1075 |
+} |
|
1076 |
+ |
|
1077 |
+# This function completes on group IDs |
|
1078 |
+# |
|
1079 |
+_gids() |
|
1080 |
+{ |
|
1081 |
+ if type getent &>/dev/null; then |
|
1082 |
+ COMPREPLY=( $( compgen -W '$( getent group | cut -d: -f3 )' \ |
|
1083 |
+ -- "$cur" ) ) |
|
1084 |
+ elif type perl &>/dev/null; then |
|
1085 |
+ COMPREPLY=( $( compgen -W '$( perl -e '"'"'while (($gid) = (getgrent)[2]) { print $gid . "\n" }'"'"' )' -- "$cur" ) ) |
|
1086 |
+ else |
|
1087 |
+ # make do with /etc/group |
|
1088 |
+ COMPREPLY=( $( compgen -W '$( cut -d: -f3 /etc/group )' -- "$cur" ) ) |
|
1089 |
+ fi |
|
1090 |
+} |
|
1091 |
+ |
|
1092 |
+# Glob for matching various backup files. |
|
1093 |
+# |
|
1094 |
+_backup_glob='@(#*#|*@(~|.@(bak|orig|rej|swp|dpkg*|rpm@(orig|new|save))))' |
|
1095 |
+ |
|
1096 |
+# Complete on xinetd services |
|
1097 |
+# |
|
1098 |
+_xinetd_services() |
|
1099 |
+{ |
|
1100 |
+ local xinetddir=/etc/xinetd.d |
|
1101 |
+ if [[ -d $xinetddir ]]; then |
|
1102 |
+ local restore_nullglob=$(shopt -p nullglob); shopt -s nullglob |
|
1103 |
+ local -a svcs=( $( printf '%s\n' $xinetddir/!($_backup_glob) ) ) |
|
1104 |
+ $restore_nullglob |
|
1105 |
+ COMPREPLY+=( $( compgen -W '${svcs[@]#$xinetddir/}' -- "$cur" ) ) |
|
1106 |
+ fi |
|
1107 |
+} |
|
1108 |
+ |
|
1109 |
+# This function completes on services |
|
1110 |
+# |
|
1111 |
+_services() |
|
1112 |
+{ |
|
1113 |
+ local sysvdirs |
|
1114 |
+ _sysvdirs |
|
1115 |
+ |
|
1116 |
+ local restore_nullglob=$(shopt -p nullglob); shopt -s nullglob |
|
1117 |
+ COMPREPLY=( $( printf '%s\n' ${sysvdirs[0]}/!($_backup_glob|functions) ) ) |
|
1118 |
+ $restore_nullglob |
|
1119 |
+ |
|
1120 |
+ COMPREPLY+=( $( systemctl list-units --full --all 2>/dev/null | \ |
|
1121 |
+ awk '$1 ~ /\.service$/ { sub("\\.service$", "", $1); print $1 }' ) ) |
|
1122 |
+ |
|
1123 |
+ COMPREPLY=( $( compgen -W '${COMPREPLY[@]#${sysvdirs[0]}/}' -- "$cur" ) ) |
|
1124 |
+} |
|
1125 |
+ |
|
1126 |
+# This completes on a list of all available service scripts for the |
|
1127 |
+# 'service' command and/or the SysV init.d directory, followed by |
|
1128 |
+# that script's available commands |
|
1129 |
+# |
|
1130 |
+_service() |
|
1131 |
+{ |
|
1132 |
+ local cur prev words cword |
|
1133 |
+ _init_completion || return |
|
1134 |
+ |
|
1135 |
+ # don't complete past 2nd token |
|
1136 |
+ [[ $cword -gt 2 ]] && return 0 |
|
1137 |
+ |
|
1138 |
+ if [[ $cword -eq 1 && $prev == ?(*/)service ]]; then |
|
1139 |
+ _services |
|
1140 |
+ [[ -e /etc/mandrake-release ]] && _xinetd_services |
|
1141 |
+ else |
|
1142 |
+ local sysvdirs |
|
1143 |
+ _sysvdirs |
|
1144 |
+ COMPREPLY=( $( compgen -W '`sed -e "y/|/ /" \ |
|
1145 |
+ -ne "s/^.*\(U\|msg_u\)sage.*{\(.*\)}.*$/\2/p" \ |
|
1146 |
+ ${sysvdirs[0]}/${prev##*/} 2>/dev/null` start stop' -- "$cur" ) ) |
|
1147 |
+ fi |
|
1148 |
+} && |
|
1149 |
+complete -F _service service |
|
1150 |
+_sysvdirs |
|
1151 |
+for svcdir in ${sysvdirs[@]}; do |
|
1152 |
+ for svc in $svcdir/!($_backup_glob); do |
|
1153 |
+ [[ -x $svc ]] && complete -F _service $svc |
|
1154 |
+ done |
|
1155 |
+done |
|
1156 |
+unset svc svcdir sysvdirs |
|
1157 |
+ |
|
1158 |
+# This function completes on modules |
|
1159 |
+# |
|
1160 |
+_modules() |
|
1161 |
+{ |
|
1162 |
+ local modpath |
|
1163 |
+ modpath=/lib/modules/$1 |
|
1164 |
+ COMPREPLY=( $( compgen -W "$( command ls -RL $modpath 2>/dev/null | \ |
|
1165 |
+ sed -ne 's/^\(.*\)\.k\{0,1\}o\(\.[gx]z\)\{0,1\}$/\1/p' )" -- "$cur" ) ) |
|
1166 |
+} |
|
1167 |
+ |
|
1168 |
+# This function completes on installed modules |
|
1169 |
+# |
|
1170 |
+_installed_modules() |
|
1171 |
+{ |
|
1172 |
+ COMPREPLY=( $( compgen -W "$( PATH="$PATH:/sbin" lsmod | \ |
|
1173 |
+ awk '{if (NR != 1) print $1}' )" -- "$1" ) ) |
|
1174 |
+} |
|
1175 |
+ |
|
1176 |
+# This function completes on user or user:group format; as for chown and cpio. |
|
1177 |
+# |
|
1178 |
+# The : must be added manually; it will only complete usernames initially. |
|
1179 |
+# The legacy user.group format is not supported. |
|
1180 |
+# |
|
1181 |
+# @param $1 If -u, only return users/groups the user has access to in |
|
1182 |
+# context of current completion. |
|
1183 |
+_usergroup() |
|
1184 |
+{ |
|
1185 |
+ if [[ $cur = *\\\\* || $cur = *:*:* ]]; then |
|
1186 |
+ # Give up early on if something seems horribly wrong. |
|
1187 |
+ return |
|
1188 |
+ elif [[ $cur = *\\:* ]]; then |
|
1189 |
+ # Completing group after 'user\:gr<TAB>'. |
|
1190 |
+ # Reply with a list of groups prefixed with 'user:', readline will |
|
1191 |
+ # escape to the colon. |
|
1192 |
+ local prefix |
|
1193 |
+ prefix=${cur%%*([^:])} |
|
1194 |
+ prefix=${prefix//\\} |
|
1195 |
+ local mycur="${cur#*[:]}" |
|
1196 |
+ if [[ $1 == -u ]]; then |
|
1197 |
+ _allowed_groups "$mycur" |
|
1198 |
+ else |
|
1199 |
+ local IFS=$'\n' |
|
1200 |
+ COMPREPLY=( $( compgen -g -- "$mycur" ) ) |
|
1201 |
+ fi |
|
1202 |
+ COMPREPLY=( $( compgen -P "$prefix" -W "${COMPREPLY[@]}" ) ) |
|
1203 |
+ elif [[ $cur = *:* ]]; then |
|
1204 |
+ # Completing group after 'user:gr<TAB>'. |
|
1205 |
+ # Reply with a list of unprefixed groups since readline with split on : |
|
1206 |
+ # and only replace the 'gr' part |
|
1207 |
+ local mycur="${cur#*:}" |
|
1208 |
+ if [[ $1 == -u ]]; then |
|
1209 |
+ _allowed_groups "$mycur" |
|
1210 |
+ else |
|
1211 |
+ local IFS=$'\n' |
|
1212 |
+ COMPREPLY=( $( compgen -g -- "$mycur" ) ) |
|
1213 |
+ fi |
|
1214 |
+ else |
|
1215 |
+ # Completing a partial 'usernam<TAB>'. |
|
1216 |
+ # |
|
1217 |
+ # Don't suffix with a : because readline will escape it and add a |
|
1218 |
+ # slash. It's better to complete into 'chown username ' than 'chown |
|
1219 |
+ # username\:'. |
|
1220 |
+ if [[ $1 == -u ]]; then |
|
1221 |
+ _allowed_users "$cur" |
|
1222 |
+ else |
|
1223 |
+ local IFS=$'\n' |
|
1224 |
+ COMPREPLY=( $( compgen -u -- "$cur" ) ) |
|
1225 |
+ fi |
|
1226 |
+ fi |
|
1227 |
+} |
|
1228 |
+ |
|
1229 |
+_allowed_users() |
|
1230 |
+{ |
|
1231 |
+ if _complete_as_root; then |
|
1232 |
+ local IFS=$'\n' |
|
1233 |
+ COMPREPLY=( $( compgen -u -- "${1:-$cur}" ) ) |
|
1234 |
+ else |
|
1235 |
+ local IFS=$'\n ' |
|
1236 |
+ COMPREPLY=( $( compgen -W \ |
|
1237 |
+ "$( id -un 2>/dev/null || whoami 2>/dev/null )" -- "${1:-$cur}" ) ) |
|
1238 |
+ fi |
|
1239 |
+} |
|
1240 |
+ |
|
1241 |
+_allowed_groups() |
|
1242 |
+{ |
|
1243 |
+ if _complete_as_root; then |
|
1244 |
+ local IFS=$'\n' |
|
1245 |
+ COMPREPLY=( $( compgen -g -- "$1" ) ) |
|
1246 |
+ else |
|
1247 |
+ local IFS=$'\n ' |
|
1248 |
+ COMPREPLY=( $( compgen -W \ |
|
1249 |
+ "$( id -Gn 2>/dev/null || groups 2>/dev/null )" -- "$1" ) ) |
|
1250 |
+ fi |
|
1251 |
+} |
|
1252 |
+ |
|
1253 |
+# This function completes on valid shells |
|
1254 |
+# |
|
1255 |
+_shells() |
|
1256 |
+{ |
|
1257 |
+ local shell rest |
|
1258 |
+ while read -r shell rest; do |
|
1259 |
+ [[ $shell == /* && $shell == "$cur"* ]] && COMPREPLY+=( $shell ) |
|
1260 |
+ done 2>/dev/null < /etc/shells |
|
1261 |
+} |
|
1262 |
+ |
|
1263 |
+# This function completes on valid filesystem types |
|
1264 |
+# |
|
1265 |
+_fstypes() |
|
1266 |
+{ |
|
1267 |
+ local fss |
|
1268 |
+ |
|
1269 |
+ if [[ -e /proc/filesystems ]]; then |
|
1270 |
+ # Linux |
|
1271 |
+ fss="$( cut -d$'\t' -f2 /proc/filesystems ) |
|
1272 |
+ $( awk '! /\*/ { print $NF }' /etc/filesystems 2>/dev/null )" |
|
1273 |
+ else |
|
1274 |
+ # Generic |
|
1275 |
+ fss="$( awk '/^[ \t]*[^#]/ { print $3 }' /etc/fstab 2>/dev/null ) |
|
1276 |
+ $( awk '/^[ \t]*[^#]/ { print $3 }' /etc/mnttab 2>/dev/null ) |
|
1277 |
+ $( awk '/^[ \t]*[^#]/ { print $4 }' /etc/vfstab 2>/dev/null ) |
|
1278 |
+ $( awk '{ print $1 }' /etc/dfs/fstypes 2>/dev/null ) |
|
1279 |
+ $( [[ -d /etc/fs ]] && command ls /etc/fs )" |
|
1280 |
+ fi |
|
1281 |
+ |
|
1282 |
+ [[ -n $fss ]] && COMPREPLY+=( $( compgen -W "$fss" -- "$cur" ) ) |
|
1283 |
+} |
|
1284 |
+ |
|
1285 |
+# Get real command. |
|
1286 |
+# - arg: $1 Command |
|
1287 |
+# - stdout: Filename of command in PATH with possible symbolic links resolved. |
|
1288 |
+# Empty string if command not found. |
|
1289 |
+# - return: True (0) if command found, False (> 0) if not. |
|
1290 |
+_realcommand() |
|
1291 |
+{ |
|
1292 |
+ type -P "$1" > /dev/null && { |
|
1293 |
+ if type -p realpath > /dev/null; then |
|
1294 |
+ realpath "$(type -P "$1")" |
|
1295 |
+ elif type -p greadlink > /dev/null; then |
|
1296 |
+ greadlink -f "$(type -P "$1")" |
|
1297 |
+ elif type -p readlink > /dev/null; then |
|
1298 |
+ readlink -f "$(type -P "$1")" |
|
1299 |
+ else |
|
1300 |
+ type -P "$1" |
|
1301 |
+ fi |
|
1302 |
+ } |
|
1303 |
+} |
|
1304 |
+ |
|
1305 |
+# This function returns the first argument, excluding options |
|
1306 |
+# @param $1 chars Characters out of $COMP_WORDBREAKS which should |
|
1307 |
+# NOT be considered word breaks. See __reassemble_comp_words_by_ref. |
|
1308 |
+_get_first_arg() |
|
1309 |
+{ |
|
1310 |
+ local i |
|
1311 |
+ |
|
1312 |
+ arg= |
|
1313 |
+ for (( i=1; i < COMP_CWORD; i++ )); do |
|
1314 |
+ if [[ "${COMP_WORDS[i]}" != -* ]]; then |
|
1315 |
+ arg=${COMP_WORDS[i]} |
|
1316 |
+ break |
|
1317 |
+ fi |
|
1318 |
+ done |
|
1319 |
+} |
|
1320 |
+ |
|
1321 |
+ |
|
1322 |
+# This function counts the number of args, excluding options |
|
1323 |
+# @param $1 chars Characters out of $COMP_WORDBREAKS which should |
|
1324 |
+# NOT be considered word breaks. See __reassemble_comp_words_by_ref. |
|
1325 |
+_count_args() |
|
1326 |
+{ |
|
1327 |
+ local i cword words |
|
1328 |
+ __reassemble_comp_words_by_ref "$1" words cword |
|
1329 |
+ |
|
1330 |
+ args=1 |
|
1331 |
+ for i in "${words[@]:1:cword-1}"; do |
|
1332 |
+ [[ "$i" != -* ]] && args=$(($args+1)) |
|
1333 |
+ done |
|
1334 |
+} |
|
1335 |
+ |
|
1336 |
+# This function completes on PCI IDs |
|
1337 |
+# |
|
1338 |
+_pci_ids() |
|
1339 |
+{ |
|
1340 |
+ COMPREPLY+=( $( compgen -W \ |
|
1341 |
+ "$( PATH="$PATH:/sbin" lspci -n | awk '{print $3}')" -- "$cur" ) ) |
|
1342 |
+} |
|
1343 |
+ |
|
1344 |
+# This function completes on USB IDs |
|
1345 |
+# |
|
1346 |
+_usb_ids() |
|
1347 |
+{ |
|
1348 |
+ COMPREPLY+=( $( compgen -W \ |
|
1349 |
+ "$( PATH="$PATH:/sbin" lsusb | awk '{print $6}' )" -- "$cur" ) ) |
|
1350 |
+} |
|
1351 |
+ |
|
1352 |
+# CD device names |
|
1353 |
+_cd_devices() |
|
1354 |
+{ |
|
1355 |
+ COMPREPLY+=( $( compgen -f -d -X "!*/?([amrs])cd*" -- "${cur:-/dev/}" ) ) |
|
1356 |
+} |
|
1357 |
+ |
|
1358 |
+# DVD device names |
|
1359 |
+_dvd_devices() |
|
1360 |
+{ |
|
1361 |
+ COMPREPLY+=( $( compgen -f -d -X "!*/?(r)dvd*" -- "${cur:-/dev/}" ) ) |
|
1362 |
+} |
|
1363 |
+ |
|
1364 |
+# TERM environment variable values |
|
1365 |
+_terms() |
|
1366 |
+{ |
|
1367 |
+ COMPREPLY+=( $( compgen -W \ |
|
1368 |
+ "$( sed -ne 's/^\([^[:space:]#|]\{2,\}\)|.*/\1/p' /etc/termcap \ |
|
1369 |
+ 2>/dev/null )" -- "$cur" ) ) |
|
1370 |
+ COMPREPLY+=( $( compgen -W "$( { toe -a 2>/dev/null || toe 2>/dev/null; } \ |
|
1371 |
+ | awk '{ print $1 }' | sort -u )" -- "$cur" ) ) |
|
1372 |
+} |
|
1373 |
+ |
|
1374 |
+# a little help for FreeBSD ports users |
|
1375 |
+[[ $OSTYPE == *freebsd* ]] && complete -W 'index search fetch fetch-list |
|
1376 |
+ extract patch configure build install reinstall deinstall clean |
|
1377 |
+ clean-depends kernel buildworld' make |
|
1378 |
+ |
|
1379 |
+# This function provides simple user@host completion |
|
1380 |
+# |
|
1381 |
+_user_at_host() |
|
1382 |
+{ |
|
1383 |
+ local cur prev words cword |
|
1384 |
+ _init_completion -n : || return |
|
1385 |
+ |
|
1386 |
+ if [[ $cur == *@* ]]; then |
|
1387 |
+ _known_hosts_real "$cur" |
|
1388 |
+ else |
|
1389 |
+ COMPREPLY=( $( compgen -u -- "$cur" ) ) |
|
1390 |
+ fi |
|
1391 |
+ |
|
1392 |
+ return 0 |
|
1393 |
+} |
|
1394 |
+shopt -u hostcomplete && complete -F _user_at_host -o nospace talk ytalk finger |
|
1395 |
+ |
|
1396 |
+# NOTE: Using this function as a helper function is deprecated. Use |
|
1397 |
+# `_known_hosts_real' instead. |
|
1398 |
+_known_hosts() |
|
1399 |
+{ |
|
1400 |
+ local cur prev words cword |
|
1401 |
+ _init_completion -n : || return |
|
1402 |
+ |
|
1403 |
+ # NOTE: Using `_known_hosts' as a helper function and passing options |
|
1404 |
+ # to `_known_hosts' is deprecated: Use `_known_hosts_real' instead. |
|
1405 |
+ local options |
|
1406 |
+ [[ "$1" == -a || "$2" == -a ]] && options=-a |
|
1407 |
+ [[ "$1" == -c || "$2" == -c ]] && options+=" -c" |
|
1408 |
+ _known_hosts_real $options -- "$cur" |
|
1409 |
+} # _known_hosts() |
|
1410 |
+ |
|
1411 |
+# Helper function for completing _known_hosts. |
|
1412 |
+# This function performs host completion based on ssh's config and known_hosts |
|
1413 |
+# files, as well as hostnames reported by avahi-browse if |
|
1414 |
+# COMP_KNOWN_HOSTS_WITH_AVAHI is set to a non-empty value. Also hosts from |
|
1415 |
+# HOSTFILE (compgen -A hostname) are added, unless |
|
1416 |
+# COMP_KNOWN_HOSTS_WITH_HOSTFILE is set to an empty value. |
|
1417 |
+# Usage: _known_hosts_real [OPTIONS] CWORD |
|
1418 |
+# Options: -a Use aliases |
|
1419 |
+# -c Use `:' suffix |
|
1420 |
+# -F configfile Use `configfile' for configuration settings |
|
1421 |
+# -p PREFIX Use PREFIX |
|
1422 |
+# Return: Completions, starting with CWORD, are added to COMPREPLY[] |
|
1423 |
+_known_hosts_real() |
|
1424 |
+{ |
|
1425 |
+ local configfile flag prefix |
|
1426 |
+ local cur curd awkcur user suffix aliases i host |
|
1427 |
+ local -a kh khd config |
|
1428 |
+ |
|
1429 |
+ local OPTIND=1 |
|
1430 |
+ while getopts "acF:p:" flag "$@"; do |
|
1431 |
+ case $flag in |
|
1432 |
+ a) aliases='yes' ;; |
|
1433 |
+ c) suffix=':' ;; |
|
1434 |
+ F) configfile=$OPTARG ;; |
|
1435 |
+ p) prefix=$OPTARG ;; |
|
1436 |
+ esac |
|
1437 |
+ done |
|
1438 |
+ [[ $# -lt $OPTIND ]] && echo "error: $FUNCNAME: missing mandatory argument CWORD" |
|
1439 |
+ cur=${!OPTIND}; let "OPTIND += 1" |
|
1440 |
+ [[ $# -ge $OPTIND ]] && echo "error: $FUNCNAME("$@"): unprocessed arguments:"\ |
|
1441 |
+ $(while [[ $# -ge $OPTIND ]]; do printf '%s\n' ${!OPTIND}; shift; done) |
|
1442 |
+ |
|
1443 |
+ [[ $cur == *@* ]] && user=${cur%@*}@ && cur=${cur#*@} |
|
1444 |
+ kh=() |
|
1445 |
+ |
|
1446 |
+ # ssh config files |
|
1447 |
+ if [[ -n $configfile ]]; then |
|
1448 |
+ [[ -r $configfile ]] && config+=( "$configfile" ) |
|
1449 |
+ else |
|
1450 |
+ for i in /etc/ssh/ssh_config ~/.ssh/config ~/.ssh2/config; do |
|
1451 |
+ [[ -r $i ]] && config+=( "$i" ) |
|
1452 |
+ done |
|
1453 |
+ fi |
|
1454 |
+ |
|
1455 |
+ # Known hosts files from configs |
|
1456 |
+ if [[ ${#config[@]} -gt 0 ]]; then |
|
1457 |
+ local OIFS=$IFS IFS=$'\n' j |
|
1458 |
+ local -a tmpkh |
|
1459 |
+ # expand paths (if present) to global and user known hosts files |
|
1460 |
+ # TODO(?): try to make known hosts files with more than one consecutive |
|
1461 |
+ # spaces in their name work (watch out for ~ expansion |
|
1462 |
+ # breakage! Alioth#311595) |
|
1463 |
+ tmpkh=( $( awk 'sub("^[ \t]*([Gg][Ll][Oo][Bb][Aa][Ll]|[Uu][Ss][Ee][Rr])[Kk][Nn][Oo][Ww][Nn][Hh][Oo][Ss][Tt][Ss][Ff][Ii][Ll][Ee][ \t]+", "") { print $0 }' "${config[@]}" | sort -u ) ) |
|
1464 |
+ IFS=$OIFS |
|
1465 |
+ for i in "${tmpkh[@]}"; do |
|
1466 |
+ # First deal with quoted entries... |
|
1467 |
+ while [[ $i =~ ^([^\"]*)\"([^\"]*)\"(.*)$ ]]; do |
|
1468 |
+ i=${BASH_REMATCH[1]}${BASH_REMATCH[3]} |
|
1469 |
+ j=${BASH_REMATCH[2]} |
|
1470 |
+ __expand_tilde_by_ref j # Eval/expand possible `~' or `~user' |
|
1471 |
+ [[ -r $j ]] && kh+=( "$j" ) |
|
1472 |
+ done |
|
1473 |
+ # ...and then the rest. |
|
1474 |
+ for j in $i; do |
|
1475 |
+ __expand_tilde_by_ref j # Eval/expand possible `~' or `~user' |
|
1476 |
+ [[ -r $j ]] && kh+=( "$j" ) |
|
1477 |
+ done |
|
1478 |
+ done |
|
1479 |
+ fi |
|
1480 |
+ |
|
1481 |
+ if [[ -z $configfile ]]; then |
|
1482 |
+ # Global and user known_hosts files |
|
1483 |
+ for i in /etc/ssh/ssh_known_hosts /etc/ssh/ssh_known_hosts2 \ |
|
1484 |
+ /etc/known_hosts /etc/known_hosts2 ~/.ssh/known_hosts \ |
|
1485 |
+ ~/.ssh/known_hosts2; do |
|
1486 |
+ [[ -r $i ]] && kh+=( "$i" ) |
|
1487 |
+ done |
|
1488 |
+ for i in /etc/ssh2/knownhosts ~/.ssh2/hostkeys; do |
|
1489 |
+ [[ -d $i ]] && khd+=( "$i"/*pub ) |
|
1490 |
+ done |
|
1491 |
+ fi |
|
1492 |
+ |
|
1493 |
+ # If we have known_hosts files to use |
|
1494 |
+ if [[ ${#kh[@]} -gt 0 || ${#khd[@]} -gt 0 ]]; then |
|
1495 |
+ # Escape slashes and dots in paths for awk |
|
1496 |
+ awkcur=${cur//\//\\\/} |
|
1497 |
+ awkcur=${awkcur//\./\\\.} |
|
1498 |
+ curd=$awkcur |
|
1499 |
+ |
|
1500 |
+ if [[ "$awkcur" == [0-9]*[.:]* ]]; then |
|
1501 |
+ # Digits followed by a dot or a colon - just search for that |
|
1502 |
+ awkcur="^$awkcur[.:]*" |
|
1503 |
+ elif [[ "$awkcur" == [0-9]* ]]; then |
|
1504 |
+ # Digits followed by no dot or colon - search for digits followed |
|
1505 |
+ # by a dot or a colon |
|
1506 |
+ awkcur="^$awkcur.*[.:]" |
|
1507 |
+ elif [[ -z $awkcur ]]; then |
|
1508 |
+ # A blank - search for a dot, a colon, or an alpha character |
|
1509 |
+ awkcur="[a-z.:]" |
|
1510 |
+ else |
|
1511 |
+ awkcur="^$awkcur" |
|
1512 |
+ fi |
|
1513 |
+ |
|
1514 |
+ if [[ ${#kh[@]} -gt 0 ]]; then |
|
1515 |
+ # FS needs to look for a comma separated list |
|
1516 |
+ COMPREPLY+=( $( awk 'BEGIN {FS=","} |
|
1517 |
+ /^\s*[^|\#]/ { |
|
1518 |
+ sub("^@[^ ]+ +", ""); \ |
|
1519 |
+ sub(" .*$", ""); \ |
|
1520 |
+ for (i=1; i<=NF; ++i) { \ |
|
1521 |
+ sub("^\\[", "", $i); sub("\\](:[0-9]+)?$", "", $i); \ |
|
1522 |
+ if ($i !~ /[*?]/ && $i ~ /'"$awkcur"'/) {print $i} \ |
|
1523 |
+ }}' "${kh[@]}" 2>/dev/null ) ) |
|
1524 |
+ fi |
|
1525 |
+ if [[ ${#khd[@]} -gt 0 ]]; then |
|
1526 |
+ # Needs to look for files called |
|
1527 |
+ # .../.ssh2/key_22_<hostname>.pub |
|
1528 |
+ # dont fork any processes, because in a cluster environment, |
|
1529 |
+ # there can be hundreds of hostkeys |
|
1530 |
+ for i in "${khd[@]}" ; do |
|
1531 |
+ if [[ "$i" == *key_22_$curd*.pub && -r "$i" ]]; then |
|
1532 |
+ host=${i/#*key_22_/} |
|
1533 |
+ host=${host/%.pub/} |
|
1534 |
+ COMPREPLY+=( $host ) |
|
1535 |
+ fi |
|
1536 |
+ done |
|
1537 |
+ fi |
|
1538 |
+ |
|
1539 |
+ # apply suffix and prefix |
|
1540 |
+ for (( i=0; i < ${#COMPREPLY[@]}; i++ )); do |
|
1541 |
+ COMPREPLY[i]=$prefix$user${COMPREPLY[i]}$suffix |
|
1542 |
+ done |
|
1543 |
+ fi |
|
1544 |
+ |
|
1545 |
+ # append any available aliases from config files |
|
1546 |
+ if [[ ${#config[@]} -gt 0 && -n "$aliases" ]]; then |
|
1547 |
+ local hosts=$( sed -ne 's/^[ \t]*[Hh][Oo][Ss][Tt]\([Nn][Aa][Mm][Ee]\)\{0,1\}['"$'\t '"']\{1,\}\([^#*?]*\)\(#.*\)\{0,1\}$/\2/p' "${config[@]}" ) |
|
1548 |
+ COMPREPLY+=( $( compgen -P "$prefix$user" \ |
|
1549 |
+ -S "$suffix" -W "$hosts" -- "$cur" ) ) |
|
1550 |
+ fi |
|
1551 |
+ |
|
1552 |
+ # This feature is disabled because it does not scale to |
|
1553 |
+ # larger networks. See: |
|
1554 |
+ # https://bugs.launchpad.net/ubuntu/+source/bash-completion/+bug/510591 |
|
1555 |
+ # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=574950 |
|
1556 |
+ |
|
1557 |
+ # Add hosts reported by avahi-browse, if desired and it's available. |
|
1558 |
+ #if [[ ${COMP_KNOWN_HOSTS_WITH_AVAHI:-} ]] && \ |
|
1559 |
+ #type avahi-browse &>/dev/null; then |
|
1560 |
+ # The original call to avahi-browse also had "-k", to avoid lookups |
|
1561 |
+ # into avahi's services DB. We don't need the name of the service, and |
|
1562 |
+ # if it contains ";", it may mistify the result. But on Gentoo (at |
|
1563 |
+ # least), -k wasn't available (even if mentioned in the manpage) some |
|
1564 |
+ # time ago, so... |
|
1565 |
+ #COMPREPLY+=( $( compgen -P "$prefix$user" -S "$suffix" -W \ |
|
1566 |
+ # "$( avahi-browse -cpr _workstation._tcp 2>/dev/null | \ |
|
1567 |
+ # awk -F';' '/^=/ { print $7 }' | sort -u )" -- "$cur" ) ) |
|
1568 |
+ #fi |
|
1569 |
+ |
|
1570 |
+ # Add hosts reported by ruptime. |
|
1571 |
+ COMPREPLY+=( $( compgen -W \ |
|
1572 |
+ "$( ruptime 2>/dev/null | awk '!/^ruptime:/ { print $1 }' )" \ |
|
1573 |
+ -- "$cur" ) ) |
|
1574 |
+ |
|
1575 |
+ # Add results of normal hostname completion, unless |
|
1576 |
+ # `COMP_KNOWN_HOSTS_WITH_HOSTFILE' is set to an empty value. |
|
1577 |
+ if [[ -n ${COMP_KNOWN_HOSTS_WITH_HOSTFILE-1} ]]; then |
|
1578 |
+ COMPREPLY+=( |
|
1579 |
+ $( compgen -A hostname -P "$prefix$user" -S "$suffix" -- "$cur" ) ) |
|
1580 |
+ fi |
|
1581 |
+ |
|
1582 |
+ __ltrim_colon_completions "$prefix$user$cur" |
|
1583 |
+ |
|
1584 |
+ return 0 |
|
1585 |
+} # _known_hosts_real() |
|
1586 |
+complete -F _known_hosts traceroute traceroute6 tracepath tracepath6 \ |
|
1587 |
+ fping fping6 telnet rsh rlogin ftp dig mtr ssh-installkeys showmount |
|
1588 |
+ |
|
1589 |
+# This meta-cd function observes the CDPATH variable, so that cd additionally |
|
1590 |
+# completes on directories under those specified in CDPATH. |
|
1591 |
+# |
|
1592 |
+_cd() |
|
1593 |
+{ |
|
1594 |
+ local cur prev words cword |
|
1595 |
+ _init_completion || return |
|
1596 |
+ |
|
1597 |
+ local IFS=$'\n' i j k |
|
1598 |
+ |
|
1599 |
+ compopt -o filenames |
|
1600 |
+ |
|
1601 |
+ # Use standard dir completion if no CDPATH or parameter starts with /, |
|
1602 |
+ # ./ or ../ |
|
1603 |
+ if [[ -z "${CDPATH:-}" || "$cur" == ?(.)?(.)/* ]]; then |
|
1604 |
+ _filedir -d |
|
1605 |
+ return 0 |
|
1606 |
+ fi |
|
1607 |
+ |
|
1608 |
+ local -r mark_dirs=$(_rl_enabled mark-directories && echo y) |
|
1609 |
+ local -r mark_symdirs=$(_rl_enabled mark-symlinked-directories && echo y) |
|
1610 |
+ |
|
1611 |
+ # we have a CDPATH, so loop on its contents |
|
1612 |
+ for i in ${CDPATH//:/$'\n'}; do |
|
1613 |
+ # create an array of matched subdirs |
|
1614 |
+ k="${#COMPREPLY[@]}" |
|
1615 |
+ for j in $( compgen -d $i/$cur ); do |
|
1616 |
+ if [[ ( $mark_symdirs && -h $j || $mark_dirs && ! -h $j ) && ! -d ${j#$i/} ]]; then |
|
1617 |
+ j+="/" |
|
1618 |
+ fi |
|
1619 |
+ COMPREPLY[k++]=${j#$i/} |
|
1620 |
+ done |
|
1621 |
+ done |
|
1622 |
+ |
|
1623 |
+ _filedir -d |
|
1624 |
+ |
|
1625 |
+ if [[ ${#COMPREPLY[@]} -eq 1 ]]; then |
|
1626 |
+ i=${COMPREPLY[0]} |
|
1627 |
+ if [[ "$i" == "$cur" && $i != "*/" ]]; then |
|
1628 |
+ COMPREPLY[0]="${i}/" |
|
1629 |
+ fi |
|
1630 |
+ fi |
|
1631 |
+ |
|
1632 |
+ return 0 |
|
1633 |
+} |
|
1634 |
+if shopt -q cdable_vars; then |
|
1635 |
+ complete -v -F _cd -o nospace cd |
|
1636 |
+else |
|
1637 |
+ complete -F _cd -o nospace cd |
|
1638 |
+fi |
|
1639 |
+ |
|
1640 |
+# a wrapper method for the next one, when the offset is unknown |
|
1641 |
+_command() |
|
1642 |
+{ |
|
1643 |
+ local offset i |
|
1644 |
+ |
|
1645 |
+ # find actual offset, as position of the first non-option |
|
1646 |
+ offset=1 |
|
1647 |
+ for (( i=1; i <= COMP_CWORD; i++ )); do |
|
1648 |
+ if [[ "${COMP_WORDS[i]}" != -* ]]; then |
|
1649 |
+ offset=$i |
|
1650 |
+ break |
|
1651 |
+ fi |
|
1652 |
+ done |
|
1653 |
+ _command_offset $offset |
|
1654 |
+} |
|
1655 |
+ |
|
1656 |
+# A meta-command completion function for commands like sudo(8), which need to |
|
1657 |
+# first complete on a command, then complete according to that command's own |
|
1658 |
+# completion definition. |
|
1659 |
+# |
|
1660 |
+_command_offset() |
|
1661 |
+{ |
|
1662 |
+ # rewrite current completion context before invoking |
|
1663 |
+ # actual command completion |
|
1664 |
+ |
|
1665 |
+ # find new first word position, then |
|
1666 |
+ # rewrite COMP_LINE and adjust COMP_POINT |
|
1667 |
+ local word_offset=$1 i j |
|
1668 |
+ for (( i=0; i < $word_offset; i++ )); do |
|
1669 |
+ for (( j=0; j <= ${#COMP_LINE}; j++ )); do |
|
1670 |
+ [[ "$COMP_LINE" == "${COMP_WORDS[i]}"* ]] && break |
|
1671 |
+ COMP_LINE=${COMP_LINE:1} |
|
1672 |
+ ((COMP_POINT--)) |
|
1673 |
+ done |
|
1674 |
+ COMP_LINE=${COMP_LINE#"${COMP_WORDS[i]}"} |
|
1675 |
+ ((COMP_POINT-=${#COMP_WORDS[i]})) |
|
1676 |
+ done |
|
1677 |
+ |
|
1678 |
+ # shift COMP_WORDS elements and adjust COMP_CWORD |
|
1679 |
+ for (( i=0; i <= COMP_CWORD - $word_offset; i++ )); do |
|
1680 |
+ COMP_WORDS[i]=${COMP_WORDS[i+$word_offset]} |
|
1681 |
+ done |
|
1682 |
+ for (( i; i <= COMP_CWORD; i++ )); do |
|
1683 |
+ unset COMP_WORDS[i] |
|
1684 |
+ done |
|
1685 |
+ ((COMP_CWORD -= $word_offset)) |
|
1686 |
+ |
|
1687 |
+ COMPREPLY=() |
|
1688 |
+ local cur |
|
1689 |
+ _get_comp_words_by_ref cur |
|
1690 |
+ |
|
1691 |
+ if [[ $COMP_CWORD -eq 0 ]]; then |
|
1692 |
+ local IFS=$'\n' |
|
1693 |
+ compopt -o filenames |
|
1694 |
+ COMPREPLY=( $( compgen -d -c -- "$cur" ) ) |
|
1695 |
+ else |
|
1696 |
+ local cmd=${COMP_WORDS[0]} compcmd=${COMP_WORDS[0]} |
|
1697 |
+ local cspec=$( complete -p $cmd 2>/dev/null ) |
|
1698 |
+ |
|
1699 |
+ # If we have no completion for $cmd yet, see if we have for basename |
|
1700 |
+ if [[ ! $cspec && $cmd == */* ]]; then |
|
1701 |
+ cspec=$( complete -p ${cmd##*/} 2>/dev/null ) |
|
1702 |
+ [[ $cspec ]] && compcmd=${cmd##*/} |
|
1703 |
+ fi |
|
1704 |
+ # If still nothing, just load it for the basename |
|
1705 |
+ if [[ ! $cspec ]]; then |
|
1706 |
+ compcmd=${cmd##*/} |
|
1707 |
+ _completion_loader $compcmd |
|
1708 |
+ cspec=$( complete -p $compcmd 2>/dev/null ) |
|
1709 |
+ fi |
|
1710 |
+ |
|
1711 |
+ if [[ -n $cspec ]]; then |
|
1712 |
+ if [[ ${cspec#* -F } != $cspec ]]; then |
|
1713 |
+ # complete -F <function> |
|
1714 |
+ |
|
1715 |
+ # get function name |
|
1716 |
+ local func=${cspec#*-F } |
|
1717 |
+ func=${func%% *} |
|
1718 |
+ |
|
1719 |
+ if [[ ${#COMP_WORDS[@]} -ge 2 ]]; then |
|
1720 |
+ $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" "${COMP_WORDS[${#COMP_WORDS[@]}-2]}" |
|
1721 |
+ else |
|
1722 |
+ $func $cmd "${COMP_WORDS[${#COMP_WORDS[@]}-1]}" |
|
1723 |
+ fi |
|
1724 |
+ |
|
1725 |
+ # restore initial compopts |
|
1726 |
+ local opt |
|
1727 |
+ while [[ $cspec == *" -o "* ]]; do |
|
1728 |
+ # FIXME: should we take "+o opt" into account? |
|
1729 |
+ cspec=${cspec#*-o } |
|
1730 |
+ opt=${cspec%% *} |
|
1731 |
+ compopt -o $opt |
|
1732 |
+ cspec=${cspec#$opt} |
|
1733 |
+ done |
|
1734 |
+ else |
|
1735 |
+ cspec=${cspec#complete} |
|
1736 |
+ cspec=${cspec%%$compcmd} |
|
1737 |
+ COMPREPLY=( $( eval compgen "$cspec" -- '$cur' ) ) |
|
1738 |
+ fi |
|
1739 |
+ elif [[ ${#COMPREPLY[@]} -eq 0 ]]; then |
|
1740 |
+ # XXX will probably never happen as long as completion loader loads |
|
1741 |
+ # *something* for every command thrown at it ($cspec != empty) |
|
1742 |
+ _minimal |
|
1743 |
+ fi |
|
1744 |
+ fi |
|
1745 |
+} |
|
1746 |
+complete -F _command aoss command do else eval exec ltrace nice nohup padsp \ |
|
1747 |
+ then time tsocks vsound xargs |
|
1748 |
+ |
|
1749 |
+_root_command() |
|
1750 |
+{ |
|
1751 |
+ local PATH=$PATH:/sbin:/usr/sbin:/usr/local/sbin |
|
1752 |
+ local root_command=$1 |
|
1753 |
+ _command |
|
1754 |
+} |
|
1755 |
+complete -F _root_command fakeroot gksu gksudo kdesudo really |
|
1756 |
+ |
|
1757 |
+# Return true if the completion should be treated as running as root |
|
1758 |
+_complete_as_root() |
|
1759 |
+{ |
|
1760 |
+ [[ $EUID -eq 0 || ${root_command:-} ]] |
|
1761 |
+} |
|
1762 |
+ |
|
1763 |
+_longopt() |
|
1764 |
+{ |
|
1765 |
+ local cur prev words cword split |
|
1766 |
+ _init_completion -s || return |
|
1767 |
+ |
|
1768 |
+ case "${prev,,}" in |
|
1769 |
+ --help|--usage|--version) |
|
1770 |
+ return 0 |
|
1771 |
+ ;; |
|
1772 |
+ --*dir*) |
|
1773 |
+ _filedir -d |
|
1774 |
+ return 0 |
|
1775 |
+ ;; |
|
1776 |
+ --*file*|--*path*) |
|
1777 |
+ _filedir |
|
1778 |
+ return 0 |
|
1779 |
+ ;; |
|
1780 |
+ --+([-a-z0-9_])) |
|
1781 |
+ local argtype=$( $1 --help 2>&1 | sed -ne \ |
|
1782 |
+ "s|.*$prev\[\{0,1\}=[<[]\{0,1\}\([-A-Za-z0-9_]\{1,\}\).*|\1|p" ) |
|
1783 |
+ case ${argtype,,} in |
|
1784 |
+ *dir*) |
|
1785 |
+ _filedir -d |
|
1786 |
+ return 0 |
|
1787 |
+ ;; |
|
1788 |
+ *file*|*path*) |
|
1789 |
+ _filedir |
|
1790 |
+ return 0 |
|
1791 |
+ ;; |
|
1792 |
+ esac |
|
1793 |
+ ;; |
|
1794 |
+ esac |
|
1795 |
+ |
|
1796 |
+ $split && return 0 |
|
1797 |
+ |
|
1798 |
+ if [[ "$cur" == -* ]]; then |
|
1799 |
+ COMPREPLY=( $( compgen -W "$( $1 --help 2>&1 | \ |
|
1800 |
+ sed -ne 's/.*\(--[-A-Za-z0-9]\{1,\}=\{0,1\}\).*/\1/p' | sort -u )" \ |
|
1801 |
+ -- "$cur" ) ) |
|
1802 |
+ [[ $COMPREPLY == *= ]] && compopt -o nospace |
|
1803 |
+ elif [[ "$1" == @(mk|rm)dir ]]; then |
|
1804 |
+ _filedir -d |
|
1805 |
+ else |
|
1806 |
+ _filedir |
|
1807 |
+ fi |
|
1808 |
+} |
|
1809 |
+# makeinfo and texi2dvi are defined elsewhere. |
|
1810 |
+complete -F _longopt a2ps awk base64 bash bc bison cat colordiff cp csplit \ |
|
1811 |
+ cut date df diff dir du enscript env expand fmt fold gperf \ |
|
1812 |
+ grep grub head indent irb ld ldd less ln ls m4 md5sum mkdir mkfifo mknod \ |
|
1813 |
+ mv netstat nl nm objcopy objdump od paste pr ptx readelf rm rmdir \ |
|
1814 |
+ sed seq sha{,1,224,256,384,512}sum shar sort split strip sum tac tail tee \ |
|
1815 |
+ texindex touch tr uname unexpand uniq units vdir wc who |
|
1816 |
+ |
|
1817 |
+declare -A _xspecs |
|
1818 |
+_filedir_xspec() |
|
1819 |
+{ |
|
1820 |
+ local cur prev words cword |
|
1821 |
+ _init_completion || return |
|
1822 |
+ |
|
1823 |
+ _tilde "$cur" || return 0 |
|
1824 |
+ |
|
1825 |
+ local IFS=$'\n' xspec=${_xspecs[${1##*/}]} tmp |
|
1826 |
+ local -a toks |
|
1827 |
+ |
|
1828 |
+ toks=( $( |
|
1829 |
+ compgen -d -- "$(quote_readline "$cur")" | { |
|
1830 |
+ while read -r tmp; do |
|
1831 |
+ printf '%s\n' $tmp |
|
1832 |
+ done |
|
1833 |
+ } |
|
1834 |
+ )) |
|
1835 |
+ |
|
1836 |
+ # Munge xspec to contain uppercase version too |
|
1837 |
+ # http://thread.gmane.org/gmane.comp.shells.bash.bugs/15294/focus=15306 |
|
1838 |
+ eval xspec="${xspec}" |
|
1839 |
+ local matchop=! |
|
1840 |
+ if [[ $xspec == !* ]]; then |
|
1841 |
+ xspec=${xspec#!} |
|
1842 |
+ matchop=@ |
|
1843 |
+ fi |
|
1844 |
+ xspec="$matchop($xspec|${xspec^^})" |
|
1845 |
+ |
|
1846 |
+ toks+=( $( |
|
1847 |
+ eval compgen -f -X "!$xspec" -- "\$(quote_readline "\$cur")" | { |
|
1848 |
+ while read -r tmp; do |
|
1849 |
+ [[ -n $tmp ]] && printf '%s\n' $tmp |
|
1850 |
+ done |
|
1851 |
+ } |
|
1852 |
+ )) |
|
1853 |
+ |
|
1854 |
+ if [[ ${#toks[@]} -ne 0 ]]; then |
|
1855 |
+ compopt -o filenames |
|
1856 |
+ COMPREPLY=( "${toks[@]}" ) |
|
1857 |
+ fi |
|
1858 |
+} |
|
1859 |
+ |
|
1860 |
+_install_xspec() |
|
1861 |
+{ |
|
1862 |
+ local xspec=$1 cmd |
|
1863 |
+ shift |
|
1864 |
+ for cmd in $@; do |
|
1865 |
+ _xspecs[$cmd]=$xspec |
|
1866 |
+ done |
|
1867 |
+ complete -F _filedir_xspec $@ |
|
1868 |
+} |
|
1869 |
+# bzcmp, bzdiff, bz*grep, bzless, bzmore intentionally not here, see Debian: #455510 |
|
1870 |
+_install_xspec '!*.?(t)bz?(2)' bunzip2 bzcat pbunzip2 pbzcat lbunzip2 lbzcat |
|
1871 |
+_install_xspec '!*.@(zip|[ejsw]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|epub|apk|do[ct][xm]|p[op]t[mx]|xl[st][xm])' unzip zipinfo |
|
1872 |
+_install_xspec '*.Z' compress znew |
|
1873 |
+# zcmp, zdiff, z*grep, zless, zmore intentionally not here, see Debian: #455510 |
|
1874 |
+_install_xspec '!*.@(Z|[gGd]z|t[ag]z)' gunzip zcat unpigz |
|
1875 |
+_install_xspec '!*.Z' uncompress |
|
1876 |
+# lzcmp, lzdiff intentionally not here, see Debian: #455510 |
|
1877 |
+_install_xspec '!*.@(tlz|lzma)' lzcat lzegrep lzfgrep lzgrep lzless lzmore unlzma |
|
1878 |
+_install_xspec '!*.@(?(t)xz|tlz|lzma)' unxz xzcat |
|
1879 |
+_install_xspec '!*.lrz' lrunzip |
|
1880 |
+_install_xspec '!*.@(gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx)' ee |
|
1881 |
+_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|svg)' qiv |
|
1882 |
+_install_xspec '!*.@(gif|jp?(e)g|tif?(f)|png|p[bgp]m|bmp|x[bp]m|rle|rgb|pcx|fits|pm|?(e)ps)' xv |
|
1883 |
+_install_xspec '!*.@(@(?(e)ps|?(E)PS|pdf|PDF)?(.gz|.GZ|.bz2|.BZ2|.Z))' gv ggv kghostview |
|
1884 |
+_install_xspec '!*.@(dvi|DVI)?(.@(gz|Z|bz2))' xdvi kdvi |
|
1885 |
+_install_xspec '!*.dvi' dvips dviselect dvitype dvipdf advi dvipdfm dvipdfmx |
|
1886 |
+_install_xspec '!*.[pf]df' acroread gpdf |
|
1887 |
+_install_xspec '!*.@(pdf|fdf)?(.@(gz|xz|Z|bz2))' xpdf |
|
1888 |
+_install_xspec '!*.@(?(e)ps|pdf)' kpdf |
|
1889 |
+_install_xspec '!*.@(okular|@(?(e|x)ps|?(E|X)PS|[pf]df|[PF]DF|dvi|DVI|cb[rz]|CB[RZ]|djv?(u)|DJV?(U)|dvi|DVI|gif|jp?(e)g|miff|tif?(f)|pn[gm]|p[bgp]m|bmp|xpm|ico|xwd|tga|pcx|GIF|JP?(E)G|MIFF|TIF?(F)|PN[GM]|P[BGP]M|BMP|XPM|ICO|XWD|TGA|PCX|epub|EPUB|odt|ODT|fb?(2)|FB?(2)|mobi|MOBI|g3|G3|chm|CHM)?(.?(gz|GZ|bz2|BZ2)))' okular |
|
1890 |
+_install_xspec '!*.pdf' epdfview |
|
1891 |
+_install_xspec '!*.@(cb[rz7t]|djv?(u)|?(e)ps|pdf)' zathura |
|
1892 |
+_install_xspec '!*.@(?(e)ps|pdf)' ps2pdf ps2pdf12 ps2pdf13 ps2pdf14 ps2pdfwr |
|
1893 |
+_install_xspec '!*.texi*' makeinfo texi2html |
|
1894 |
+_install_xspec '!*.@(?(la)tex|texi|dtx|ins|ltx|dbj)' tex latex slitex jadetex pdfjadetex pdftex pdflatex texi2dvi |
|
1895 |
+_install_xspec '!*.mp3' mpg123 mpg321 madplay |
|
1896 |
+_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp[234]|MP[234]|m4[pv]|M4[PV]|mkv|MKV|og[agmvx]|OG[AGMVX]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM)|+([0-9]).@(vdr|VDR))?(.part)' xine aaxine fbxine |
|
1897 |
+_install_xspec '!*@(.@(mp?(e)g|MP?(E)G|wma|avi|AVI|asf|vob|VOB|bin|dat|divx|DIVX|vcd|ps|pes|fli|flv|FLV|fxm|FXM|viv|rm|ram|yuv|mov|MOV|qt|QT|wmv|mp[234]|MP[234]|m4[pv]|M4[PV]|mkv|MKV|og[agmvx]|OG[AGMVX]|t[ps]|T[PS]|m2t?(s)|M2T?(S)|wav|WAV|flac|FLAC|asx|ASX|mng|MNG|srt|m[eo]d|M[EO]D|s[3t]m|S[3T]M|it|IT|xm|XM|iso|ISO)|+([0-9]).@(vdr|VDR))?(.part)' kaffeine dragon |
|
1898 |
+_install_xspec '!*.@(avi|asf|wmv)' aviplay |
|
1899 |
+_install_xspec '!*.@(rm?(j)|ra?(m)|smi?(l))' realplay |
|
1900 |
+_install_xspec '!*.@(mpg|mpeg|avi|mov|qt)' xanim |
|
1901 |
+_install_xspec '!*.@(og[ag]|m3u|flac|spx)' ogg123 |
|
1902 |
+_install_xspec '!*.@(mp3|og[ag]|pls|m3u)' gqmpeg freeamp |
|
1903 |
+_install_xspec '!*.fig' xfig |
|
1904 |
+_install_xspec '!*.@(mid?(i)|cmf)' playmidi |
|
1905 |
+_install_xspec '!*.@(mid?(i)|rmi|rcp|[gr]36|g18|mod|xm|it|x3m|s[3t]m|kar)' timidity |
|
1906 |
+_install_xspec '!*.@(669|abc|am[fs]|d[bs]m|dmf|far|it|mdl|m[eo]d|mid?(i)|mt[2m]|okta|p[st]m|s[3t]m|ult|umx|wav|xm)' modplugplay modplug123 |
|
1907 |
+_install_xspec '*.@(o|so|so.!(conf|*/*)|a|[rs]pm|gif|jp?(e)g|mp3|mp?(e)g|avi|asf|ogg|class)' vi vim gvim rvim view rview rgvim rgview gview emacs xemacs sxemacs kate kwrite |
|
1908 |
+_install_xspec '!*.@(zip|z|gz|tgz)' bzme |
|
1909 |
+# konqueror not here on purpose, it's more than a web/html browser |
|
1910 |
+_install_xspec '!*.@(?([xX]|[sS])[hH][tT][mM]?([lL]))' netscape mozilla lynx galeon dillo elinks amaya firefox mozilla-firefox iceweasel google-chrome chromium-browser epiphany |
|
1911 |
+_install_xspec '!*.@(sxw|stw|sxg|sgl|doc?([mx])|dot?([mx])|rtf|txt|htm|html|?(f)odt|ott|odm)' oowriter |
|
1912 |
+_install_xspec '!*.@(sxi|sti|pps?(x)|ppt?([mx])|pot?([mx])|?(f)odp|otp)' ooimpress |
|
1913 |
+_install_xspec '!*.@(sxc|stc|xls?([bmx])|xlw|xlt?([mx])|[ct]sv|?(f)ods|ots)' oocalc |
|
1914 |
+_install_xspec '!*.@(sxd|std|sda|sdd|?(f)odg|otg)' oodraw |
|
1915 |
+_install_xspec '!*.@(sxm|smf|mml|odf)' oomath |
|
1916 |
+_install_xspec '!*.odb' oobase |
|
1917 |
+_install_xspec '!*.[rs]pm' rpm2cpio |
|
1918 |
+_install_xspec '!*.aux' bibtex |
|
1919 |
+_install_xspec '!*.po' poedit gtranslator kbabel lokalize |
|
1920 |
+_install_xspec '!*.@([Pp][Rr][Gg]|[Cc][Ll][Pp])' harbour gharbour hbpp |
|
1921 |
+_install_xspec '!*.[Hh][Rr][Bb]' hbrun |
|
1922 |
+_install_xspec '!*.ly' lilypond ly2dvi |
|
1923 |
+_install_xspec '!*.@(dif?(f)|?(d)patch)?(.@([gx]z|bz2|lzma))' cdiff |
|
1924 |
+_install_xspec '!@(*.@(ks|jks|jceks|p12|pfx|bks|ubr|gkr|cer|crt|cert|p7b|pkipath|pem|p10|csr|crl)|cacerts)' portecle |
|
1925 |
+_install_xspec '!*.@(mp[234c]|og[ag]|@(fl|a)ac|m4[abp]|spx|tta|w?(a)v|wma|aif?(f)|asf|ape)' kid3 kid3-qt |
|
1926 |
+_install_xspec '!*.py' pyflakes |
|
1927 |
+unset -f _install_xspec |
|
1928 |
+ |
|
1929 |
+# Minimal completion to use as fallback in _completion_loader. |
|
1930 |
+_minimal() |
|
1931 |
+{ |
|
1932 |
+ local cur prev words cword split |
|
1933 |
+ _init_completion -s || return |
|
1934 |
+ $split && return |
|
1935 |
+ _filedir |
|
1936 |
+} |
|
1937 |
+# Complete the empty string to allow completion of '>', '>>', and '<' |
|
1938 |
+# http://lists.gnu.org/archive/html/bug-bash/2012-01/msg00045.html |
|
1939 |
+complete -F _minimal '' |
|
1940 |
+ |
|
1941 |
+ |
|
1942 |
+# set up dynamic completion loading |
|
1943 |
+_completion_loader() |
|
1944 |
+{ |
|
1945 |
+ local compfile=./completions |
|
1946 |
+ [[ $BASH_SOURCE == */* ]] && compfile="${BASH_SOURCE%/*}/completions" |
|
1947 |
+ compfile+="/${1##*/}" |
|
1948 |
+ |
|
1949 |
+ # Avoid trying to source dirs; https://bugzilla.redhat.com/903540 |
|
1950 |
+ [[ -f "$compfile" ]] && . "$compfile" &>/dev/null && return 124 |
|
1951 |
+ |
|
1952 |
+ # Need to define *something*, otherwise there will be no completion at all. |
|
1953 |
+ complete -F _minimal "$1" && return 124 |
|
1954 |
+} && |
|
1955 |
+complete -D -F _completion_loader |
|
1956 |
+ |
|
1957 |
+# Function for loading and calling functions from dynamically loaded |
|
1958 |
+# completion files that may not have been sourced yet. |
|
1959 |
+# @param $1 completion file to load function from in case it is missing |
|
1960 |
+# @param $2... function and its arguments |
|
1961 |
+_xfunc() |
|
1962 |
+{ |
|
1963 |
+ set -- "$@" |
|
1964 |
+ local srcfile=$1 |
|
1965 |
+ shift |
|
1966 |
+ declare -F $1 &>/dev/null || { |
|
1967 |
+ local compdir=./completions |
|
1968 |
+ [[ $BASH_SOURCE == */* ]] && compdir="${BASH_SOURCE%/*}/completions" |
|
1969 |
+ . "$compdir/$srcfile" |
|
1970 |
+ } |
|
1971 |
+ "$@" |
|
1972 |
+} |
|
1973 |
+ |
|
1974 |
+# source compat completion directory definitions |
|
1975 |
+if [[ -d $BASH_COMPLETION_COMPAT_DIR && -r $BASH_COMPLETION_COMPAT_DIR && \ |
|
1976 |
+ -x $BASH_COMPLETION_COMPAT_DIR ]]; then |
|
1977 |
+ for i in $(LC_ALL=C command ls "$BASH_COMPLETION_COMPAT_DIR"); do |
|
1978 |
+ i=$BASH_COMPLETION_COMPAT_DIR/$i |
|
1979 |
+ [[ ${i##*/} != @($_backup_glob|Makefile*|$_blacklist_glob) \ |
|
1980 |
+ && -f $i && -r $i ]] && . "$i" |
|
1981 |
+ done |
|
1982 |
+fi |
|
1983 |
+unset i _blacklist_glob |
|
1984 |
+ |
|
1985 |
+# source user completion file |
|
1986 |
+[[ ${BASH_SOURCE[0]} != ~/.bash_completion && -r ~/.bash_completion ]] \ |
|
1987 |
+ && . ~/.bash_completion |
|
1988 |
+unset -f have |
|
1989 |
+unset have |
|
1990 |
+ |
|
1991 |
+set $BASH_COMPLETION_ORIGINAL_V_VALUE |
|
1992 |
+unset BASH_COMPLETION_ORIGINAL_V_VALUE |
|
1993 |
+ |
|
1994 |
+# ex: ts=4 sw=4 et filetype=sh |