#autoload # To use this, put _next_tags at the beginning of the completer style, # define it as a completion widget and bind it to a key, e.g.: # # zle -C _next_tags complete-word _next_tags # bindkey '^Xn' _next_tags # # Makes it be bound to ^Xn. # Main widget/completer. _next_tags() { if [[ $#funcstack -gt 1 ]]; then # Called as completer, probably `remove' our helper function. A better # test would be nice, but I think one should still be able to edit the # current word between attempts to complete it. [[ $_next_tags_pre != ${LBUFFER%${PREFIX}} ]] && unset _sort_tags return 1 else local comp if [[ -z $compstate[old_list] ]]; then comp=() else comp=(_next_tags _complete) fi (( $+_sort_tags )) || _next_tags_not= _sort_tags=_next_tags_sort _next_tags_pre="${LBUFFER%${PREFIX}}" _next_tags_not="$_next_tags_not $_lastcomp[tags]" _main_complete "$comp[@]" [[ $compstate[insert] = automenu ]] && compstate[insert]=automenu-unambiguous compstate[insert]='' compstate[list]='list force' fi } # Helper function for sorting tags. Most of this is copied from _tags. _next_tags_sort() { local order tags tag nodef if ! zstyle -a ":completion:${curcontext}:" tag-order order; then if (( $+_comp_default_tags )); then order=( "$_comp_default_tags[@]" ) else order=( 'arguments values' options ) fi fi # But we also remove the tags we've already tried... tags=( "${(@)order:#(${(j:|:)~${=_next_tags_not}})}" ) # ... unless that would remove all offered tags. [[ $#tags -ne $#order && "$tags" != *(${(j:|:)~argv})* ]] && tags=( $order ) _next_tags_not= for tag in $tags; do case $tag in -) nodef=yes;; *\(\)) "${${tag%%[ ]#\(\)}##[ ]#}" "$@";; \!*) comptry "${(@)argv:#(${(j:|:)~${=tag[2,-1]}})}";; ?*) comptry ${=tag};; esac done [[ -z "$nodef" ]] && comptry "$@" } [[ -o kshautoload ]] || _next_tags "$@"