#compdef cd pushd # Handling of cd. # - Normally just completes directories. Uses cdpath if that's set # and the string doesn't begin with ~, /, ./ or ../. # - In the second argument to cd for the form `cd old new', completes # possible `new' strings by examining `old' and $PWD. # - After pushd - or pushd +, completes numbers, but the listing # gives you the list of directories to complete. This turns on # menu-completion and lists the possibilities automatically, otherwise # it's not a lot of use. If you don't type the + or - it will # complete directories as normal. local pushdminus [[ -o pushdminus ]] && pushdminus=1 emulate -LR zsh setopt extendedglob if [[ CURRENT -eq 3 ]]; then # cd old new: look for old in $PWD and see what can replace it local rep # Get possible completions using word in position 2 rep=(${~PWD/$words[2]/*}~$PWD(-/N)) # Now remove all the common parts of $PWD and the completions from this rep=(${${rep#${PWD%%$words[2]*}}%${PWD#*$words[2]}}) (( ! $#rep )) || compadd $rep elif [[ $words[1] = pu* && $PREFIX = [-+]* ]]; then # pushd: just complete the numbers, but show the full directory list with # numbers. # For - we do the same thing, but reverse the numbering (other # way round if pushdminus is set). # The test is for pu* because I have an alias pu since I'm too # lazy to type pushd. IPREFIX=$PREFIX[1] PREFIX=$PREFIX[2,-1] local list lines ret=1 # get the list of directories with their canonical number lines="$(dirs -v)" # turn the lines into an array, removing the current directory list=(${${(f)lines}##0*}) if [[ ( $IPREFIX = - && -z $pushdminus ) || ( $IPREFIX = + && -n $pushdminus ) ]]; then # reverse the numbering: it counts the last one as -0, which # is a little strange. integer tot i for (( i = 1, tot = $#list-1; tot >= 0; i++, tot-- )); do list[$i]="$tot${list[$i]##[0-9]#}" done fi # make sure -y treats this as a single string lines="${(F)list}" # get the array of numbers only list=(${list%%[ ]*}) compgen -y '$lines' -Q -k list && ret=0 [[ -z $compstate[list] ]] && compstate[list]=list && ret=0 [[ -n $compstate[insert] ]] && compstate[insert]=menu && ret=0 return ret elif [[ $PREFIX != (\~|/|./|../)* && $#cdpath -ne 0 ]]; then _path_files -W "(. $cdpath)" -/ else _path_files -/ fi