1
0
mirror of https://github.com/moparisthebest/pacman synced 2024-08-13 17:03:46 -04:00

bash_completion : full rewrite with many improvements

* Undeclared local vars with common enough names to warrant breakage
* Performance issues with _pacman trying to replicate /usr/bin/pacman
  with find and other slow tools.
* Performance issues with expanding an array (with sometimes hundreds of
  items) over three times.
* Expanding said array to remove already completed entries had the side
  effect of braking filenames with spaces and or \n.
* add -D --database options and --print
* fix dirs showing up when they shouldn't in completions
* completions regarding database entries shouldn't trigger filename
  completion.

This is now down to 106 lines. The original one (master) is 365 lines
long, yet this one retains all functionality.

The work is documented in FS#16630.

Signed-off-by: Andres P <stderr@mail.com>
Signed-off-by: Xavier Chantry <chantry.xavier@gmail.com>
Signed-off-by: Dan McGee <dan@archlinux.org>
This commit is contained in:
Andres P 2010-05-18 17:56:47 -04:30 committed by Dan McGee
parent ae73d75660
commit 80f7c1707c

View File

@ -1,370 +1,108 @@
# vim: set ft=sh ts=2 sw=2 et:
# file: /etc/bash_completion.d/pacman
# This file is in the public domain.
# Bash completion for pacman
# Original: Manolis Tzanidakis <mtzanidakis@freemail.gr>
#
# Distributed under the terms of the GNU General Public License, v2 or later.
#
## initial functions
rem_selected ()
{
# (Adapted from bash_completion by Ian Macdonald <ian@caliban.org>)
# This removes any options from the list of completions that have
# already been specified on the command line.
COMPREPLY=($(\echo "${COMP_WORDS[@]}" | \
(while read -d ' ' i; do
[ "${i}" == "" ] && continue
# flatten array with spaces on either side,
# otherwise we cannot grep on word boundaries of
# first and last word
COMPREPLY=" ${COMPREPLY[@]} "
# remove word from list of completions
COMPREPLY=(${COMPREPLY/ ${i%% *} / })
_arch_compgen() {
local i r
COMPREPLY=($(compgen -W '$*' -- "$cur"))
for ((i=1; i < ${#COMP_WORDS[@]}-1; i++)); do
for r in ${!COMPREPLY[@]}; do
if [[ ${COMP_WORDS[i]} = ${COMPREPLY[r]} ]]; then
unset 'COMPREPLY[r]'; break
fi
done
\echo ${COMPREPLY[@]})))
return 0
done
}
_available_repos ()
{
COMPREPLY=( $( compgen -W "$(\grep '\[' /etc/pacman.conf | \grep -v -e 'options' -e '^#' | \tr -d '[]' )" -- $cur ) )
_arch_ptr2comp() {
local list= x y
for x; do
for y in '0 --' '1 -'; do
eval 'set -- ${'$x'[${y% *}]}'
list+=\ ${@/#/${y#* }}
done
done
_arch_compgen $list
}
_installed_pkgs ()
{
local installed_pkgs
installed_pkgs=$( \ls /var/lib/pacman/local/ )
COMPREPLY=( $( compgen -W "$( for i in $installed_pkgs; do \echo ${i%-*-*}; done )" -- $cur ) )
_arch_incomp() {
local r="\s-(-${1#* }\s|\w*${1% *})"; [[ $COMP_LINE =~ $r ]]
}
_available_pkgs ()
{
#find balks easilly on a find /foo/*/* type dir, especially one like
# /var/lib/pacman/*/*
# This little change-up removes the find *and* only uses enabled repos
local available_pkgs
local enabled_repos
enabled_repos=$( \grep '\[' /etc/pacman.conf | \grep -v -e 'options' -e '^#' | \tr -d '[]' )
available_pkgs=$( for r in $enabled_repos; do \echo /var/lib/pacman/sync/$r/*; done )
COMPREPLY=( $( compgen -W "$( for i in $available_pkgs; do j=${i##*/}; echo ${j%-*-*}; done )" -- $cur ) )
}
_installed_groups ()
{
local installed_groups
installed_groups=$( \find /var/lib/pacman/local -name desc -exec \sed -ne '/%GROUPS%/,/^$/{//d; p}' {} \; | \sort -u )
COMPREPLY=( $( compgen -W "$( for i in $installed_groups; do \echo ${i%-*-*}; done )" -- $cur ) )
}
_available_groups ()
{
#find balks easilly on a find /foo/*/* type dir, especially one like
# /var/lib/pacman/*/*
# This little change-up removes the find *and* only uses enabled repos
local available_groups
local enabled_repos
enabled_repos=$( \grep '\[' /etc/pacman.conf | \grep -v -e 'options' -e '^#' | tr -d '[]' )
available_groups=$( for r in $enabled_repos; do \sed '/%GROUPS%/,/^$/{//d; p}' /var/lib/pacman/sync/$r/*/desc | \sort -u; done )
COMPREPLY=( $( compgen -W "$( for i in $available_groups; do \echo ${i%-*-*}; done )" -- $cur ) )
}
## makepkg completion
_makepkg ()
{
local cur prev
_makepkg() {
local cur opts prev
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
cur=$(_get_cword)
prev=${COMP_WORDS[COMP_CWORD-1]}
case "$prev" in
-p)
_filedir
return 0
;;
--help|--cleancache)
COMPREPLY=''
return 0
;;
esac
if [[ "$cur" == -* ]]; then
COMPREPLY=( $( compgen -W '\
-A --ignorearch \
-b --builddeps \
-c --clean \
-C --cleancache \
-d --nodeps \
-e --noextract \
-f --force \
-g --geninteg \
-h --help \
-i --install \
-L --log \
-m --nocolor \
-o --nobuild \
-p \
-r --rmdeps \
-s --syncdeps \
--asroot \
--source \
--noconfirm \
--noprogressbar' -- $cur ) )
if [[ $cur = -* && ! $prev =~ ^-(-(cleancache|config|help)$|\w*[Chp]) ]]; then
opts=('allsource asroot clean cleancache config force geninteg help holdver
ignorearch install log nobuild nocolor noconfirm nodeps noextract
noprogressbar pkg repackage rmdeps skipinteg source syncdeps'
'A C L R c d e f g h i m o p r s')
_arch_ptr2comp opts
fi
rem_selected
true
}
complete -o default -F _makepkg makepkg
## pacman completion
_instring ()
{
str="${1}"
shift 1
for c in "${@}"; do
if [ $(\expr index "${str}" "${c}") -gt 0 ]; then
return 0
_pacman_pkg() {
_arch_compgen "$(
if [[ $2 ]]; then
\pacman -$1 | \cut -d' ' -f1 | \sort -u
else
\pacman -$1
fi
done
return 1
)"
}
_pacman ()
{
local a arg toparse op mod cur
_pacman_file() {
compopt -o filenames; _filedir 'pkg.tar.*'
}
_pacman() {
local common core cur database prev query remove sync upgrade o
COMPREPLY=()
cur=$(_get_cword)
prev=${COMP_WORDS[COMP_CWORD-1]}
database=('asdeps asexplicit')
query=('changelog check deps explicit file foreign groups info list owns
search unrequired upgrades' 'c e g i k l m o p s t u')
remove=('cascade dbonly nodeps nosave print recursive unneeded' 'c k n p s u')
sync=('asdeps asexplicit clean downloadonly force groups ignore ignoregroup
info list needed nodeps print refresh search sysupgrade'
'c f g i l p s u w y')
upgrade=('asdeps asexplicit force nodeps print' 'f p')
common=('arch cachedir config dbpath debug help logfile noconfirm
noprogressbar noscriptlet quiet root verbose' 'b d h q r v')
core=('database help query remove sync upgrade version' 'D Q R S U V h')
# This argument parsing is done so we can check for flag existance later
# right now it's a tad crappy, but does the job
for (( i=1; i < ${#COMP_WORDS[@]}-1; i++ )); do
a=${COMP_WORDS[i]}
arg="${a:0:2}"
toparse="${a:2}"
case "${arg}" in
-@(U|R|S|Q|h|V))
op="${arg/-}"
mod="${mod}${a:2}"
;;
--)
arg="${a:2}"
case "${arg}" in
remove) op="R" ;;
upgrade) op="U" ;;
query) op="Q" ;;
sync) op="S" ;;
help) op="h" ;;
version) op="V" ;;
verbose) mod="${mod}v" ;;
root) mod="${mod}r" ;;
dbpath) mod="${mod}b" ;;
nodeps) mod="${mod}d" ;;
force) mod="${mod}f" ;;
groups) mod="${mod}g" ;;
info) mod="${mod}i" ;;
list) mod="${mod}l" ;;
print) mod="${mod}p" ;;
search) mod="${mod}s" ;;
sysupgrade) mod="${mod}u" ;;
upgrades) mod="${mod}u" ;;
downloadonly) mod="${mod}w" ;;
refresh) mod="${mod}y" ;;
changelog) mod="${mod}c" ;;
deps) mod="${mod}d" ;;
explicit) mod="${mod}e" ;;
unrequired) mod="${mod}t" ;;
foreign) mod="${mod}m" ;;
owns) mod="${mod}o" ;;
file) mod="${mod}p" ;;
search) mod="${mod}s" ;;
upgrades) mod="${mod}u" ;;
cascade) mod="${mod}c" ;;
check) mod="${mod}k" ;;
dbonly) mod="${mod}k" ;;
nosave) mod="${mod}n" ;;
recursive) mod="${mod}s" ;;
unneeded) mod="${mod}u" ;;
esac ;;
*) toparse="${a}" ;;
esac
arglen=$(( ${#toparse}-1 ))
for c in $(\seq 0 "${arglen}"); do
arg=${toparse:$c:1}
[ "${arg}" != "-" ] && mod="${mod}${arg}"
done
for o in 'D database' 'Q query' 'R remove' 'S sync' 'U upgrade'; do
_arch_incomp "$o" && break
done
cur=${COMP_WORDS[COMP_CWORD]}
if [ $COMP_CWORD -eq 1 ] && [[ "$cur" == -* ]]; then
COMPREPLY=( $( compgen -W '\
-h --help \
-Q --query \
-R --remove \
-S --sync \
-U --upgrade \
-V --version \
' -- $cur ) )
rem_selected
return 0
fi
if [[ "$cur" == -* ]]; then
case "${op}" in
U)
COMPREPLY=( $( compgen -W '\
--asdeps \
--asexplicit \
-d --nodeps \
-f --force \
-h --help \
--config \
--logfile \
--noconfirm \
--noprogressbar \
--noscriptlet \
-v --verbose \
-r --root \
-b --dbpath \
-p --print \
--print-format \
--cachedir \
' -- $cur ) )
return 0
;;
R)
COMPREPLY=( $( compgen -W '\
-c --cascade \
-d --nodeps \
-h --help \
-k --dbonly \
-n --nosave \
-s --recursive \
-u --unneeded \
--config \
--logfile \
--noconfirm \
--noprogressbar \
--noscriptlet \
-v --verbose \
-r --root \
-b --dbpath \
-p --print \
--print-format \
--cachedir \
' -- $cur ) )
return 0
;;
S)
COMPREPLY=( $( compgen -W '\
--asdeps \
--asexplicit \
-c --clean \
-d --nodeps \
-f --force \
-g --groups \
-h --help \
-i --info \
-l --list \
-s --search \
-u --sysupgrade \
-w --downloadonly \
-y --refresh \
--needed \
--ignore \
--ignoregroup \
--config \
--logfile \
--noconfirm \
--noprogressbar \
--noscriptlet \
-v --verbose \
-r --root \
-b --dbpath \
-p --print \
--print-format \
--cachedir \
' -- $cur ) )
return 0
;;
if [[ $? != 0 ]]; then
_arch_ptr2comp core
elif ! [[ $prev =~ ^-\w*[Vbhr] ||
$prev = --@(cachedir|config|dbpath|help|logfile|root|version) ]]
then
[[ $cur = -* ]] && _arch_ptr2comp ${o#* } common ||
case ${o% *} in
D|R)
_pacman_pkg Qq;;
Q)
COMPREPLY=( $( compgen -W '\
-c --changelog \
-d --deps \
-e --explicit \
-g --groups \
-h --help \
-i --info \
-k --check \
-l --list \
-m --foreign \
-o --owns \
-p --file \
-s --search \
-t --unrequired \
-u --upgrades \
--config \
--logfile \
--noconfirm \
--noprogressbar \
--noscriptlet \
-v --verbose \
-r --root \
-b --dbpath \
--cachedir \
' -- $cur ) )
return 0
;;
esac
rem_selected
else
case "${op}" in
U)
COMPREPLY=( $( compgen -d -- "$cur" ) \
$( compgen -f -X '!*.pkg.tar.*' -- "$cur" ) )
return 0
;;
h|V)
COMPREPLY=''
return 0
;;
Q)
if _instring $mod g; then
_installed_groups
elif _instring $mod o; then
COMPREPLY=( $( compgen -d -- "$cur" ) \
$( compgen -f -- "$cur" ) )
elif _instring $mod p; then
COMPREPLY=( $( compgen -d -- "$cur" ) \
$( compgen -f -X '!*.pkg.tar.*' -- "$cur" ) )
elif _instring $mod u; then
COMPREPLY=''
return 0
else
_installed_pkgs
fi
return 0
;;
R)
_installed_pkgs
return 0
;;
{ _arch_incomp 'g groups' && _pacman_pkg Qg sort; } ||
{ _arch_incomp 'p file' && _pacman_file; } ||
_arch_incomp 'o owns' || _arch_incomp 'u upgrades' ||
_pacman_pkg Qq;;
S)
if _instring $mod l; then
_available_repos
else
_available_pkgs
fi
return 0
;;
esac
{ _arch_incomp 'g groups' && _pacman_pkg Sg; } ||
{ _arch_incomp 'l list' && _pacman_pkg Sl sort; } ||
_pacman_pkg Slq;;
U)
_pacman_file;;
esac
fi
rem_selected
true
}
complete -o filenames -F _pacman pacman
complete -F _makepkg -o default makepkg
complete -F _pacman -o default pacman
# ex:et ts=2 sw=2 ft=sh