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 |
+} |