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