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