diff --git a/completions/crontab b/completions/crontab index 2cad8521..1e21f824 100644 --- a/completions/crontab +++ b/completions/crontab @@ -14,35 +14,31 @@ _crontab() ;; esac - local i opts=" -u -l -r -e" # leading space at start is significant... - [[ $OSTYPE == *linux* ]] && opts+=" -i" - [ -e /etc/selinux ] && opts+=" -s" + local -A opts=( [-u]= [-l]= [-r]= [-e]= ) + [[ $OSTYPE == *linux* ]] && opts[-i]= + [ -e /etc/selinux ] && opts[-s]= + + local i for (( i=0; i < ${#words[@]}-1; i++ )); do + [[ ${words[i]} ]] && unset opts[${words[i]}] case "${words[i]}" in -l) - opts=${opts// -l -r -e/} - opts=${opts// -i/} - opts=${opts// -s/} + unset opts[-r] opts[-e] opts[-i] opts[-s] ;; -e) - opts=${opts// -l -r -e/} - opts=${opts// -i/} + unset opts[-l] opts[-r] opts[-i] ;; -r) - opts=${opts// -l -r -e/} + unset opts[-l] opts[-e] ;; -u) - opts=${opts// -u/} - opts=${opts// -i/} - ;; - -i|-s) - opts=${opts// ${words[i]}/} + unset opts[-i] ;; esac done if [[ "$cur" == -* ]]; then - COMPREPLY=( $( compgen -W '$opts' -- "$cur" ) ) + COMPREPLY=( $( compgen -W '${!opts[@]}' -- "$cur" ) ) return 0 fi diff --git a/completions/findutils b/completions/findutils index 23260e47..cd1c4404 100644 --- a/completions/findutils +++ b/completions/findutils @@ -91,27 +91,23 @@ _find() -delete -exec -execdir -fls -fprint -fprint0 -fprintf -ls -ok -okdir \ -print -print0 -printf -prune -quit' -- "$cur" ) ) - # this removes any options from the list of completions that have - # already been specified somewhere on the command line, as long as - # these options can only be used once (in a word, "options", in - # opposition to "tests" and "actions", as in the find(1) manpage). - local onlyonce - onlyonce=' -daystart -depth -follow -help -ignore_readdir_race -maxdepth \ - -mindepth -mount -noignore_readdir_race -noleaf -nowarn -regextype \ - -version -warn -xdev ' - COMPREPLY=( $( \ - (while read -d ' ' i; do - [[ -z "$i" || "${onlyonce/ ${i%% *} / }" == "$onlyonce" ]] && - 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%% *} / } ) + if [[ ${#COMPREPLY[@]} -ne 0 ]]; then + # this removes any options from the list of completions that have + # already been specified somewhere on the command line, as long as + # these options can only be used once (in a word, "options", in + # opposition to "tests" and "actions", as in the find(1) manpage). + local -A onlyonce=( [-daystart]=1 [-depth]=1 [-follow]=1 [-help]=1 + [-ignore_readdir_race]=1 [-maxdepth]=1 [-mindepth]=1 [-mount]=1 + [-noignore_readdir_race]=1 [-noleaf]=1 [-nowarn]=1 [-regextype]=1 + [-version]=1 [-warn]=1 [-xdev]=1 ) + local j + for i in "${words[@]}"; do + [[ $i && ${onlyonce[$i]} ]] || continue + for j in ${!COMPREPLY[@]}; do + [[ ${COMPREPLY[j]} == $i ]] && unset COMPREPLY[j] done - printf '%s ' "${COMPREPLY[@]}") <<<"${words[@]}" - ) ) + done + fi _filedir