Gentoo Archives: gentoo-commits

From: "Michał Górny" <mgorny@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/gentoo-bashcomp:master commit in: helpers/, completions/
Date: Sun, 31 Aug 2014 21:19:11
Message-Id: 1409512692.238b95dfeb8f32f592756797786a998b0f07c748.mgorny@gentoo
1 commit: 238b95dfeb8f32f592756797786a998b0f07c748
2 Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
3 AuthorDate: Sun Aug 31 18:49:57 2014 +0000
4 Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
5 CommitDate: Sun Aug 31 19:18:12 2014 +0000
6 URL: http://sources.gentoo.org/gitweb/?p=proj/gentoo-bashcomp.git;a=commit;h=238b95df
7
8 Split common functions out of completions.
9
10 The goal is to install the reusable functions in helpersdir from where
11 they can be reused by other completions.
12
13 ---
14 completions/gentoo | 390 +---------------------------------------------
15 helpers/gentoo-common.sh | 395 +++++++++++++++++++++++++++++++++++++++++++++++
16 2 files changed, 396 insertions(+), 389 deletions(-)
17
18 diff --git a/completions/gentoo b/completions/gentoo
19 index 0e54841..30a1eb1 100644
20 --- a/completions/gentoo
21 +++ b/completions/gentoo
22 @@ -3,377 +3,7 @@
23 # Copyright 1999-2013 Gentoo Foundation
24 # Distributed under the terms of the GNU General Public License, v2 or later
25
26 -# Retrieve PORTDIR/PORTDIR_OVERLAY location.
27 -#
28 -# In order of highest to lowest priority:
29 -# /etc/portage/repos.conf{,/*}
30 -# /usr/share/portage/config/repos.conf
31 -# /etc/portage/make.conf
32 -# /etc/make.conf
33 -# /usr/share/portage/config/make.globals
34 -#
35 -# The first two files are in repos.conf format and must be parsed for the
36 -# variable "location". The rest are make.conf style and are simply sourced
37 -# for PORTDIR and PORTDIR_OVERLAY. While repos.conf overrides any value of
38 -# PORTDIR set in make.conf, PORTDIR_OVERLAY is incremental (combined across
39 -# available sources).
40 -#
41 -# This would be a hell of a lot simpler if we used portageq, but also about
42 -# 500 times slower.
43 -_portdir() {
44 - local mainreponame mainrepopath overlayname overlaypath
45 -
46 - if [[ -e @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf ]]; then
47 - if [[ ${1} == -o ]]; then
48 - for overlayname in $(_parsereposconf -l); do
49 - overlaypath+=($(_parsereposconf ${overlayname} location))
50 - done
51 -
52 - source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
53 - source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
54 -
55 - overlaypath+=(${PORTDIR_OVERLAY})
56 -
57 - # strip out duplicates
58 - overlaypath=($(printf "%s\n" "${overlaypath[@]}" | sort -u))
59 -
60 - echo "${overlaypath[@]}"
61 - else
62 - mainreponame=$(_parsereposconf DEFAULT main-repo)
63 - mainrepopath=$(_parsereposconf ${mainreponame} location)
64 -
65 - echo "${mainrepopath}"
66 - fi
67 - else
68 - source @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/make.globals 2>/dev/null
69 - source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
70 - source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
71 -
72 - echo "${PORTDIR}"
73 -
74 - if [[ ${1} == -o ]]; then
75 - echo "${PORTDIR_OVERLAY}"
76 - fi
77 - fi
78 -}
79 -
80 -# _parsereposconf [-l] <repo> <variable>
81 -# -l lists available repos
82 -_parsereposconf() {
83 - local f insection line section v value var
84 -
85 - for f in @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf \
86 - @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf \
87 - @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf/*.conf; do
88 -
89 - [[ -f ${f} ]] || continue
90 - insection=0
91 -
92 - while read -r line; do
93 - # skip comments and blank lines
94 - [[ -z ${line} || ${line} == '#'* ]] && continue
95 -
96 - if [[ ${insection} == 1 && ${line} == '['*']' ]]; then
97 - # End of the section we were interested in so stop
98 - secname+=(${line//[(\[|\])]/}) # record name for -l
99 - break
100 - elif [[ ${line} == '['*']' ]]; then
101 - # Entering a new section, check if it's the one we want
102 - section=${line//[(\[|\])]/}
103 - [[ ${section} == "${1}" ]] && insection=1
104 - secname+=(${section}) # record name for -l
105 - elif [[ ${insection} == 1 ]]; then
106 - # We're in the section we want, grab the values
107 - var=${line%%=*}
108 - var=${var// /}
109 - value=${line#*=}
110 - value=${value# }
111 - [[ ${var} == ${2} ]] && v=${value}
112 - fi
113 - continue
114 - done < "${f}"
115 - done
116 -
117 - if [[ ${1} == -l ]]; then
118 - echo "${secname[@]}"
119 - else
120 - echo "${v}"
121 - fi
122 -}
123 -
124 -# like _pkgname but completes on package names only (no category)
125 -_pkgname_only()
126 -{
127 - local i pd
128 - local cur="$1"
129 - shift
130 - local dir="$@"
131 -
132 - COMPREPLY=($(compgen -W "$(\
133 - for pd in $dir ; do \
134 - builtin cd ${pd}; \
135 - for i in *-*/${cur}*; do \
136 - [[ -d ${i} ]] && { local x=${i##*/} ; echo ${x%-[0-9]*}; } \
137 - done ; \
138 - done)" -- ${cur}))
139 -}
140 -
141 -#
142 -# This function completes package names.
143 -#
144 -# usage: pkgname <mode> <current-directory>
145 -#
146 -# Where mode is one of:
147 -# -A Search all available packages (except for those in the overlays)
148 -# -I Only search the installed packages
149 -#
150 -# TODO: Look at breaking this function out and making it a "universal"
151 -# category/package name completion function.
152 -#
153 -_pkgname()
154 -{
155 - local mode cur portdir only
156 - mode="$1"
157 - cur="$2"
158 - portdir=$(_portdir -o)
159 - # Ignore '=' at the beginning of the current completion
160 - [[ ${cur:1:1} == "=" ]] && cur=${cur:2}
161 - [[ ${cur:0:1} == "=" ]] && cur=${cur:1}
162 - case $mode in
163 - -I)
164 - # Complete either the category or the complete package name
165 - if [[ $cur == */* ]]; then
166 - COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" )" -- $cur))
167 - else
168 - COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" -S /)" -- $cur))
169 - fi
170 - # We may just have finished completing the category.
171 - # Make sure there isn't anything more to complete now.
172 - if [[ ${#COMPREPLY[@]} == 1 ]]; then
173 - COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$COMPREPLY*")" -- $cur))
174 - fi
175 -
176 - if [[ -z "${COMPREPLY}" ]] ; then
177 - only=1
178 - _pkgname_only ${cur} @GENTOO_PORTAGE_EPREFIX@/var/db/pkg
179 - fi
180 - ;;
181 - -A)
182 - # Complete either the category or the complete package name
183 - if [[ $cur == */* ]]; then
184 - # Once the category has been completed, it's safe to use ${portdir}
185 - # to continue completion.
186 - local ww=$(\
187 - for pd in ${portdir} ; do
188 - builtin cd ${pd};
189 - compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ;
190 - done)
191 - COMPREPLY=($(\
192 - for x in ${ww}; do echo $x; done|sort -u
193 - ))
194 - # When we've completed most of the name, also display the version for
195 - # possible completion.
196 - if [[ ${#COMPREPLY[@]} -le 1 || ${cur:${#cur}-1:1} == "-" ]] \
197 - && [[ ${cur} != */ ]]; then
198 - # Use the portage cache to complete specific versions from
199 - COMPREPLY=(${COMPREPLY[@]} $(
200 - for pd in ${portdir}; do
201 - if [[ -d ${pd}/metadata/md5-cache ]]; then
202 - builtin cd ${pd}/metadata/md5-cache
203 - compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
204 - elif [[ -d ${pd}/metadata/cache ]]; then
205 - builtin cd ${pd}/metadata/cache
206 - compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
207 - fi
208 - done
209 - ))
210 - fi
211 - else
212 - # 1. Collect all the categories among ${portdir}
213 - local ww=$(\
214 - for pd in ${portdir}; do
215 - builtin cd ${pd};
216 - compgen -X "!@(*-*|virtual)" -S '/' -G "$cur*";
217 - done)
218 -
219 - # 2. Now ugly hack to delete duplicate categories
220 - local w x
221 - for x in ${ww} ; do w="${x}\n${w}"; done
222 - local words=$(echo -e ${w} | sort -u)
223 -
224 - COMPREPLY=($(compgen -W "$words" -- $cur))
225 -
226 - if [[ ${#COMPREPLY[@]} == 1 ]]; then
227 - COMPREPLY=($(compgen -W "$(
228 - for pd in ${portdir}; do
229 - if [[ -d ${pd}/metadata/md5-cache ]]; then
230 - builtin cd ${pd}/metadata/md5-cache
231 - compgen -G "$COMPREPLY*"
232 - elif [[ -d ${pd}/metadata/cache ]]; then
233 - builtin cd ${pd}/metadata/cache
234 - compgen -G "$COMPREPLY*"
235 - fi
236 - done
237 - )" -- $cur))
238 - fi
239 - fi
240 -
241 - if [[ -z "${COMPREPLY}" ]] ; then
242 - only=1
243 - _pkgname_only ${cur} ${portdir}
244 - fi
245 - ;;
246 - *)
247 - # Somebody screwed up! :-)
248 - ;;
249 - esac
250 - # 'equery' wants an '=' in front of specific package versions.
251 - # Add it if there is only one selected package and it isn't there already.
252 - if [[ ${#COMPREPLY[@]} == 1 && ${COMP_WORDS[COMP_CWORD]:0:1} != "=" ]]
253 - then
254 - [[ -z "${only}" ]] && COMPREPLY=("="$COMPREPLY)
255 - fi
256 -}
257 -
258 -#
259 -# This is an helper function for completion of "-o <list>" / "--option=<list>"
260 -# kind of command lines options.
261 -#
262 -# Usage: _list_compgen <current> <sep> <item1>[<sep><item2> ...]
263 -# - <current>: what we have so far on the command line
264 -# - <sep>: the separator character used in lists
265 -# - <itemN>: a valid item
266 -# Returns: the function outputs each possible completion (one per line),
267 -# and returns 0. Typical usage is COMPREPLY=($(_list_compgen ...)).
268 -#
269 -# Note: items must not contain the <sep> character (no backslash escaping has
270 -# been implemented).
271 -#
272 -_list_compgen()
273 -{
274 - # Read the three parameters.
275 - local current="${1}" ; shift
276 - local sep="${1}" ; shift
277 - local items="${*}"
278 -
279 - # This is the maximum number of "<current><sep><other_item>" possible
280 - # completions that should be listed in case <current> is a valid list.
281 - # Setting it to a negative value means "no bound" (always list everything).
282 - # Setting it to 0 means "never list anything" (only suggest <sep>).
283 - # Setting it to a positive value N means "list up to N possible items, and
284 - # only suggest <sep> if there are more".
285 - # It is probably not worth a parameter, thus it will defaults to my
286 - # prefered setting (1) if not already defined in the environment.
287 - local max_others_number=${max_others_number:-1}
288 -
289 - # Save IFS. The <sep> character will be used instead in the following.
290 - local saved_IFS="${IFS}"
291 - IFS="${sep}"
292 -
293 - # Split the current items list in two parts:
294 - # - current_item is the last one (maybe partial or even empty)
295 - # - prefix_item are items are the previous ones
296 - local current_item="${current##*${sep}}"
297 - local prefix_items="${current%${current_item}}"
298 -
299 - # Iterate through valid items to recognize those that are:
300 - # - partial matches of the <current_item>
301 - # - already used in the list prefix
302 - # - not used in the list prefix, and not an exact match of <current_item>
303 - # Also check whether the <current_item> is exactly a valid one.
304 - local matching_items
305 - local other_items
306 - local exact_match
307 - local my_item
308 - for my_item in ${items} ; do
309 - if [[ "${sep}${prefix_items}${sep}" == *"${sep}${my_item}${sep}"* ]] ; then
310 - # The item has already been used in the list prefix: ignore it.
311 - continue
312 - elif [[ "${my_item}" == "${current_item}" ]] ; then
313 - # The item _exactly_ matches the <current_item>: that means that we
314 - # will have to suggest some more items to add behind.
315 - exact_match=1
316 - elif [[ "${my_item}" == "${current_item}"* ]] ; then
317 - # The item matches the <current_item>: it will be a possible
318 - # completion. It will also be a possible additional item in case of
319 - # exact match.
320 - matching_items="${matching_items}${sep}${my_item}"
321 - other_items="${other_items}${sep}${my_item}"
322 - else
323 - # The item neither matches the <current_item> nor has been already
324 - # used: it will only be a possible additional item in case of exact
325 - # match.
326 - other_items="${other_items}${sep}${my_item}"
327 - fi
328 - done
329 - matching_items="${matching_items#${sep}}"
330 - other_items="${other_items#${sep}}"
331 -
332 - # Takes care of the case where <current_item> is not exactly valid but
333 - # there is only one matching item: force this completion, and handle it
334 - # just as an exact match.
335 - if [[ -z "${exact_match}" ]] \
336 - && [[ "${matching_items}" != *"${sep}"* ]] ; then
337 - exact_match=1
338 - current="${current%${current_item}}${matching_items}"
339 - current_item="${matching_items}"
340 - matching_items=""
341 - other_items="${sep}${other_items}${sep}"
342 - other_items="${other_items/${sep}${current_item}${sep}/${sep}}"
343 - other_items="${other_items#${sep}}"
344 - other_items="${other_items%${sep}}"
345 - fi
346 -
347 - # List all possible completions. They are stored in an array.
348 - # XXX: maybe if should be COMPREPLY directly? (with no output at the end)
349 - local my_compreply=()
350 - local i=0
351 - if [[ -n "${exact_match}" ]] ; then
352 - # Found an exact match? Then add "<current>".
353 - my_compreply[${i}]="${current}"
354 - let i++
355 - fi
356 - if [[ -n "${matching_items}" ]] ; then
357 - # Found some matching items?
358 - # Then add "<prefix_items><matching_item>".
359 - for my_item in ${matching_items} ; do
360 - my_compreply[${i}]="${prefix_items}${my_item}"
361 - let i++
362 - done
363 - fi
364 - if [[ -n "${exact_match}" ]] \
365 - && [[ -n "${other_items}" ]] ; then
366 - # Found an exact match and some other possible items remain?
367 - # First, count them:
368 - local count_others=0
369 - for my_item in ${other_items} ; do
370 - let count_others++
371 - done
372 - # Then decide how to behave depending on the max_others_number setting:
373 - if (( max_others_number < 0 )) \
374 - || (( count_others <= max_others_number )) ; then
375 - # List the possible "<current><sep><other_item>" completions.
376 - for my_item in ${other_items} ; do
377 - my_compreply[${i}]="${current}${sep}${my_item}"
378 - let i++
379 - done
380 - else # Only suggest adding the <sep> character.
381 - my_compreply[${i}]="${current}${sep}"
382 - let i++
383 - fi
384 - fi
385 -
386 - # Restore IFS.
387 - IFS="${saved_IFS}"
388 -
389 - # Output the array of possible completions and returns.
390 - local j=0
391 - while (( i > j )) ; do
392 - echo ${my_compreply[$j]}
393 - let j++
394 - done
395 - return 0
396 -}
397 +source "@helpersdir@/gentoo-common.sh"
398
399 #
400 # emerge completion command
401 @@ -1128,24 +758,6 @@ _browserconfig()
402 complete -F _browserconfig browser-config
403
404 #
405 -# Helper routine for the subcommand 'meta' of 'equery'
406 -# (Used two times, by _equery and _epkginfo, therefore in an extra function)
407 -#
408 -_equery_meta()
409 -{
410 - local cur="$1"
411 -
412 - case $cur in
413 - -*)
414 - COMPREPLY=($(compgen -W "--help -h --description -d --herd -H --keywords -k --maintainer -m --useflags -u --upstream -U --xml -x" -- $cur))
415 - ;;
416 - *)
417 - _pkgname -A $cur
418 - ;;
419 - esac
420 -}
421 -
422 -#
423 # Bash completion for the Gentoo 'equery' command
424 #
425 _equery()
426
427 diff --git a/helpers/gentoo-common.sh b/helpers/gentoo-common.sh
428 new file mode 100644
429 index 0000000..c0be688
430 --- /dev/null
431 +++ b/helpers/gentoo-common.sh
432 @@ -0,0 +1,395 @@
433 +# Gentoo Linux Bash Shell Command Completion
434 +# Common functions to use in other completions
435 +#
436 +# Copyright 1999-2013 Gentoo Foundation
437 +# Distributed under the terms of the GNU General Public License, v2 or later
438 +
439 +# Retrieve PORTDIR/PORTDIR_OVERLAY location.
440 +#
441 +# In order of highest to lowest priority:
442 +# /etc/portage/repos.conf{,/*}
443 +# /usr/share/portage/config/repos.conf
444 +# /etc/portage/make.conf
445 +# /etc/make.conf
446 +# /usr/share/portage/config/make.globals
447 +#
448 +# The first two files are in repos.conf format and must be parsed for the
449 +# variable "location". The rest are make.conf style and are simply sourced
450 +# for PORTDIR and PORTDIR_OVERLAY. While repos.conf overrides any value of
451 +# PORTDIR set in make.conf, PORTDIR_OVERLAY is incremental (combined across
452 +# available sources).
453 +#
454 +# This would be a hell of a lot simpler if we used portageq, but also about
455 +# 500 times slower.
456 +_portdir() {
457 + local mainreponame mainrepopath overlayname overlaypath
458 +
459 + if [[ -e @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf ]]; then
460 + if [[ ${1} == -o ]]; then
461 + for overlayname in $(_parsereposconf -l); do
462 + overlaypath+=($(_parsereposconf ${overlayname} location))
463 + done
464 +
465 + source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
466 + source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
467 +
468 + overlaypath+=(${PORTDIR_OVERLAY})
469 +
470 + # strip out duplicates
471 + overlaypath=($(printf "%s\n" "${overlaypath[@]}" | sort -u))
472 +
473 + echo "${overlaypath[@]}"
474 + else
475 + mainreponame=$(_parsereposconf DEFAULT main-repo)
476 + mainrepopath=$(_parsereposconf ${mainreponame} location)
477 +
478 + echo "${mainrepopath}"
479 + fi
480 + else
481 + source @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/make.globals 2>/dev/null
482 + source @GENTOO_PORTAGE_EPREFIX@/etc/make.conf 2>/dev/null
483 + source @GENTOO_PORTAGE_EPREFIX@/etc/portage/make.conf 2>/dev/null
484 +
485 + echo "${PORTDIR}"
486 +
487 + if [[ ${1} == -o ]]; then
488 + echo "${PORTDIR_OVERLAY}"
489 + fi
490 + fi
491 +}
492 +
493 +# _parsereposconf [-l] <repo> <variable>
494 +# -l lists available repos
495 +_parsereposconf() {
496 + local f insection line section v value var
497 +
498 + for f in @GENTOO_PORTAGE_EPREFIX@/usr/share/portage/config/repos.conf \
499 + @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf \
500 + @GENTOO_PORTAGE_EPREFIX@/etc/portage/repos.conf/*.conf; do
501 +
502 + [[ -f ${f} ]] || continue
503 + insection=0
504 +
505 + while read -r line; do
506 + # skip comments and blank lines
507 + [[ -z ${line} || ${line} == '#'* ]] && continue
508 +
509 + if [[ ${insection} == 1 && ${line} == '['*']' ]]; then
510 + # End of the section we were interested in so stop
511 + secname+=(${line//[(\[|\])]/}) # record name for -l
512 + break
513 + elif [[ ${line} == '['*']' ]]; then
514 + # Entering a new section, check if it's the one we want
515 + section=${line//[(\[|\])]/}
516 + [[ ${section} == "${1}" ]] && insection=1
517 + secname+=(${section}) # record name for -l
518 + elif [[ ${insection} == 1 ]]; then
519 + # We're in the section we want, grab the values
520 + var=${line%%=*}
521 + var=${var// /}
522 + value=${line#*=}
523 + value=${value# }
524 + [[ ${var} == ${2} ]] && v=${value}
525 + fi
526 + continue
527 + done < "${f}"
528 + done
529 +
530 + if [[ ${1} == -l ]]; then
531 + echo "${secname[@]}"
532 + else
533 + echo "${v}"
534 + fi
535 +}
536 +
537 +# like _pkgname but completes on package names only (no category)
538 +_pkgname_only()
539 +{
540 + local i pd
541 + local cur="$1"
542 + shift
543 + local dir="$@"
544 +
545 + COMPREPLY=($(compgen -W "$(\
546 + for pd in $dir ; do \
547 + builtin cd ${pd}; \
548 + for i in *-*/${cur}*; do \
549 + [[ -d ${i} ]] && { local x=${i##*/} ; echo ${x%-[0-9]*}; } \
550 + done ; \
551 + done)" -- ${cur}))
552 +}
553 +
554 +#
555 +# This function completes package names.
556 +#
557 +# usage: pkgname <mode> <current-directory>
558 +#
559 +# Where mode is one of:
560 +# -A Search all available packages (except for those in the overlays)
561 +# -I Only search the installed packages
562 +#
563 +# TODO: Look at breaking this function out and making it a "universal"
564 +# category/package name completion function.
565 +#
566 +_pkgname()
567 +{
568 + local mode cur portdir only
569 + mode="$1"
570 + cur="$2"
571 + portdir=$(_portdir -o)
572 + # Ignore '=' at the beginning of the current completion
573 + [[ ${cur:1:1} == "=" ]] && cur=${cur:2}
574 + [[ ${cur:0:1} == "=" ]] && cur=${cur:1}
575 + case $mode in
576 + -I)
577 + # Complete either the category or the complete package name
578 + if [[ $cur == */* ]]; then
579 + COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" )" -- $cur))
580 + else
581 + COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$cur*" -S /)" -- $cur))
582 + fi
583 + # We may just have finished completing the category.
584 + # Make sure there isn't anything more to complete now.
585 + if [[ ${#COMPREPLY[@]} == 1 ]]; then
586 + COMPREPLY=($(builtin cd @GENTOO_PORTAGE_EPREFIX@/var/db/pkg; compgen -W "$(compgen -G "$COMPREPLY*")" -- $cur))
587 + fi
588 +
589 + if [[ -z "${COMPREPLY}" ]] ; then
590 + only=1
591 + _pkgname_only ${cur} @GENTOO_PORTAGE_EPREFIX@/var/db/pkg
592 + fi
593 + ;;
594 + -A)
595 + # Complete either the category or the complete package name
596 + if [[ $cur == */* ]]; then
597 + # Once the category has been completed, it's safe to use ${portdir}
598 + # to continue completion.
599 + local ww=$(\
600 + for pd in ${portdir} ; do
601 + builtin cd ${pd};
602 + compgen -W "$(compgen -G "${cur}*")" -- "${cur}" ;
603 + done)
604 + COMPREPLY=($(\
605 + for x in ${ww}; do echo $x; done|sort -u
606 + ))
607 + # When we've completed most of the name, also display the version for
608 + # possible completion.
609 + if [[ ${#COMPREPLY[@]} -le 1 || ${cur:${#cur}-1:1} == "-" ]] \
610 + && [[ ${cur} != */ ]]; then
611 + # Use the portage cache to complete specific versions from
612 + COMPREPLY=(${COMPREPLY[@]} $(
613 + for pd in ${portdir}; do
614 + if [[ -d ${pd}/metadata/md5-cache ]]; then
615 + builtin cd ${pd}/metadata/md5-cache
616 + compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
617 + elif [[ -d ${pd}/metadata/cache ]]; then
618 + builtin cd ${pd}/metadata/cache
619 + compgen -W "$(compgen -G "${cur}*")" -- "${cur}"
620 + fi
621 + done
622 + ))
623 + fi
624 + else
625 + # 1. Collect all the categories among ${portdir}
626 + local ww=$(\
627 + for pd in ${portdir}; do
628 + builtin cd ${pd};
629 + compgen -X "!@(*-*|virtual)" -S '/' -G "$cur*";
630 + done)
631 +
632 + # 2. Now ugly hack to delete duplicate categories
633 + local w x
634 + for x in ${ww} ; do w="${x}\n${w}"; done
635 + local words=$(echo -e ${w} | sort -u)
636 +
637 + COMPREPLY=($(compgen -W "$words" -- $cur))
638 +
639 + if [[ ${#COMPREPLY[@]} == 1 ]]; then
640 + COMPREPLY=($(compgen -W "$(
641 + for pd in ${portdir}; do
642 + if [[ -d ${pd}/metadata/md5-cache ]]; then
643 + builtin cd ${pd}/metadata/md5-cache
644 + compgen -G "$COMPREPLY*"
645 + elif [[ -d ${pd}/metadata/cache ]]; then
646 + builtin cd ${pd}/metadata/cache
647 + compgen -G "$COMPREPLY*"
648 + fi
649 + done
650 + )" -- $cur))
651 + fi
652 + fi
653 +
654 + if [[ -z "${COMPREPLY}" ]] ; then
655 + only=1
656 + _pkgname_only ${cur} ${portdir}
657 + fi
658 + ;;
659 + *)
660 + # Somebody screwed up! :-)
661 + ;;
662 + esac
663 + # 'equery' wants an '=' in front of specific package versions.
664 + # Add it if there is only one selected package and it isn't there already.
665 + if [[ ${#COMPREPLY[@]} == 1 && ${COMP_WORDS[COMP_CWORD]:0:1} != "=" ]]
666 + then
667 + [[ -z "${only}" ]] && COMPREPLY=("="$COMPREPLY)
668 + fi
669 +}
670 +
671 +#
672 +# This is an helper function for completion of "-o <list>" / "--option=<list>"
673 +# kind of command lines options.
674 +#
675 +# Usage: _list_compgen <current> <sep> <item1>[<sep><item2> ...]
676 +# - <current>: what we have so far on the command line
677 +# - <sep>: the separator character used in lists
678 +# - <itemN>: a valid item
679 +# Returns: the function outputs each possible completion (one per line),
680 +# and returns 0. Typical usage is COMPREPLY=($(_list_compgen ...)).
681 +#
682 +# Note: items must not contain the <sep> character (no backslash escaping has
683 +# been implemented).
684 +#
685 +_list_compgen()
686 +{
687 + # Read the three parameters.
688 + local current="${1}" ; shift
689 + local sep="${1}" ; shift
690 + local items="${*}"
691 +
692 + # This is the maximum number of "<current><sep><other_item>" possible
693 + # completions that should be listed in case <current> is a valid list.
694 + # Setting it to a negative value means "no bound" (always list everything).
695 + # Setting it to 0 means "never list anything" (only suggest <sep>).
696 + # Setting it to a positive value N means "list up to N possible items, and
697 + # only suggest <sep> if there are more".
698 + # It is probably not worth a parameter, thus it will defaults to my
699 + # prefered setting (1) if not already defined in the environment.
700 + local max_others_number=${max_others_number:-1}
701 +
702 + # Save IFS. The <sep> character will be used instead in the following.
703 + local saved_IFS="${IFS}"
704 + IFS="${sep}"
705 +
706 + # Split the current items list in two parts:
707 + # - current_item is the last one (maybe partial or even empty)
708 + # - prefix_item are items are the previous ones
709 + local current_item="${current##*${sep}}"
710 + local prefix_items="${current%${current_item}}"
711 +
712 + # Iterate through valid items to recognize those that are:
713 + # - partial matches of the <current_item>
714 + # - already used in the list prefix
715 + # - not used in the list prefix, and not an exact match of <current_item>
716 + # Also check whether the <current_item> is exactly a valid one.
717 + local matching_items
718 + local other_items
719 + local exact_match
720 + local my_item
721 + for my_item in ${items} ; do
722 + if [[ "${sep}${prefix_items}${sep}" == *"${sep}${my_item}${sep}"* ]] ; then
723 + # The item has already been used in the list prefix: ignore it.
724 + continue
725 + elif [[ "${my_item}" == "${current_item}" ]] ; then
726 + # The item _exactly_ matches the <current_item>: that means that we
727 + # will have to suggest some more items to add behind.
728 + exact_match=1
729 + elif [[ "${my_item}" == "${current_item}"* ]] ; then
730 + # The item matches the <current_item>: it will be a possible
731 + # completion. It will also be a possible additional item in case of
732 + # exact match.
733 + matching_items="${matching_items}${sep}${my_item}"
734 + other_items="${other_items}${sep}${my_item}"
735 + else
736 + # The item neither matches the <current_item> nor has been already
737 + # used: it will only be a possible additional item in case of exact
738 + # match.
739 + other_items="${other_items}${sep}${my_item}"
740 + fi
741 + done
742 + matching_items="${matching_items#${sep}}"
743 + other_items="${other_items#${sep}}"
744 +
745 + # Takes care of the case where <current_item> is not exactly valid but
746 + # there is only one matching item: force this completion, and handle it
747 + # just as an exact match.
748 + if [[ -z "${exact_match}" ]] \
749 + && [[ "${matching_items}" != *"${sep}"* ]] ; then
750 + exact_match=1
751 + current="${current%${current_item}}${matching_items}"
752 + current_item="${matching_items}"
753 + matching_items=""
754 + other_items="${sep}${other_items}${sep}"
755 + other_items="${other_items/${sep}${current_item}${sep}/${sep}}"
756 + other_items="${other_items#${sep}}"
757 + other_items="${other_items%${sep}}"
758 + fi
759 +
760 + # List all possible completions. They are stored in an array.
761 + # XXX: maybe if should be COMPREPLY directly? (with no output at the end)
762 + local my_compreply=()
763 + local i=0
764 + if [[ -n "${exact_match}" ]] ; then
765 + # Found an exact match? Then add "<current>".
766 + my_compreply[${i}]="${current}"
767 + let i++
768 + fi
769 + if [[ -n "${matching_items}" ]] ; then
770 + # Found some matching items?
771 + # Then add "<prefix_items><matching_item>".
772 + for my_item in ${matching_items} ; do
773 + my_compreply[${i}]="${prefix_items}${my_item}"
774 + let i++
775 + done
776 + fi
777 + if [[ -n "${exact_match}" ]] \
778 + && [[ -n "${other_items}" ]] ; then
779 + # Found an exact match and some other possible items remain?
780 + # First, count them:
781 + local count_others=0
782 + for my_item in ${other_items} ; do
783 + let count_others++
784 + done
785 + # Then decide how to behave depending on the max_others_number setting:
786 + if (( max_others_number < 0 )) \
787 + || (( count_others <= max_others_number )) ; then
788 + # List the possible "<current><sep><other_item>" completions.
789 + for my_item in ${other_items} ; do
790 + my_compreply[${i}]="${current}${sep}${my_item}"
791 + let i++
792 + done
793 + else # Only suggest adding the <sep> character.
794 + my_compreply[${i}]="${current}${sep}"
795 + let i++
796 + fi
797 + fi
798 +
799 + # Restore IFS.
800 + IFS="${saved_IFS}"
801 +
802 + # Output the array of possible completions and returns.
803 + local j=0
804 + while (( i > j )) ; do
805 + echo ${my_compreply[$j]}
806 + let j++
807 + done
808 + return 0
809 +}
810 +
811 +#
812 +# Helper routine for the subcommand 'meta' of 'equery'
813 +# (Used two times, by _equery and _epkginfo, therefore in an extra function)
814 +#
815 +_equery_meta()
816 +{
817 + local cur="$1"
818 +
819 + case $cur in
820 + -*)
821 + COMPREPLY=($(compgen -W "--help -h --description -d --herd -H --keywords -k --maintainer -m --useflags -u --upstream -U --xml -x" -- $cur))
822 + ;;
823 + *)
824 + _pkgname -A $cur
825 + ;;
826 + esac
827 +}