#autoload

local state=qual expl char delim
local -a alts

while [[ -n $PREFIX ]]; do
  char=$PREFIX[1]
  compset -p 1
  case $char in
    ([-/F.@=p*rwxAIERWXsStUG^MTNDn,])
    # no argument
    ;;

    (%)
    # optional b, c
    if [[ $PREFIX[1] = [bc] ]]; then
      compset -p 1
    fi
    ;;

    (f)
    if ! compset -P "[-=+][0-7?]##"; then
      if [[ -z $PREFIX ]]; then
	_delimiters qualifier-f
	return
      elif ! _globqual_delims; then
	# still completing mode spec
	_message "mode spec"
	return
      fi
    fi
    ;;

    (e)
    # complete/skip delimited command line
    if [[ -z $PREFIX ]]; then
      _delimiters qualifer-e
      return
    elif ! _globqual_delims; then
      # still completing command to eval
      compset -q
      _normal
      return
    fi
    ;;

    (+)
    # complete/skip command name (no delimiters)
    if [[ $PREFIX = [[:IDENT:]]# ]]; then
      # either nothing there yet, or still on name
      _command_names
      return
    fi
    compset -P '[[:IDENT:]]##'
    ;;

    (d)
    # complete/skip device
    if ! compset -p '[[:digit:]]##'; then
      _message "device ID"
      return
    fi
    ;;

    (l)
    # complete/skip link count
    if ! compset -P '([-+]|)[[:digit:]]##'; then
      _message "link count"
      return
    fi
    ;;

    (u)
    # complete/skip UID or delimited user
    if ! compset -P '[[:digit:]]##'; then
      if [[ -z $PREFIX ]]; then
	_delimiters qualifier-u
	return
      elif ! _globqual_delims; then
	# still completing user
	_users -S $delim
	return
      fi
    fi
    ;;

    (g)
    # complete/skip GID or delimited group
    if ! compset -P '[[:digit:]]##'; then
      if [[ -z $PREFIX ]]; then
	_delimiter qualifier-g
	return
      elif ! _globqual_delims; then
	# still completing group
	_groups -S $delim
	return
      fi
    fi
    ;;

    ([amc])
    if ! compset -P '([Mwhms]|)([-+]|)<->'; then
      # complete/skip relative time spec
      alts=()
      if ! compset -P '[Mwhms]' && [[ -z $PREFIX ]]; then
	alts+=(
	  "time-specifiers:time specifier:\
((M\:months w\:weeks h\:hours m:\minutes s\:seconds))")
      fi
      if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then
	alts+=("senses:sense:((-\:less\ than +\:more\ than))")
      fi
      alts+=('digits:digit: ')
      _alternative $alts
      return
    fi
    ;;

    (L)
    # complete/skip file size
    if ! compset -P '([kKmMpP]|)([-+]|)<->'; then
      # complete/skip size spec
      alts=()
      if ! compset -P '[kKmMpP]' && [[ -z $PREFIX ]]; then
	alts+=(
	  "size-specifiers:size specifier:\
((k\:kb m\:mb p\:512-byte\ blocks))")
      fi
      if ! compset -P '[-+]' && [[ -z $PREFIX ]]; then
	alts+=("senses:sense:((-\:less\ than +\:more\ than))")
      fi
      alts+=('digits:digit: ')
      _alternative $alts
      return
    fi
    ;;
    
    ([oO])
    # complete/skip sort spec
    if ! compset -P "?"; then
      alts=(
	"n:lexical order of name"
	"L:size of file"
	"l:number of hard links"
	"a:last access time"
	"m:last modification time"
	"c:last inode change time"
	"d:directory depth"
	)
      _describe -t sort-specifiers "sort specifier" alts -Q -S ''
      return
    fi
    ;;

    (\[)
    # complete/skip range: check for closing bracket
    if ! compset -P "(-|)[[:digit:]]##(,(-|)[[:digit:]]##|)]"; then
      if compset -P "(-|)[[:digit:]]##,"; then
	_message "end of range"
      else
	_message "start of range"
      fi
      return
    fi
    ;;

    (:)
    # complete modifiers and don't stop completing them
    _history_modifiers q
    return
    ;;
  esac
done

case $state in
  (qual)
  local -a quals
  quals=(
    "/:directories"
    "F:non-empty directories"
    ".:plain files"
    "@:symbolic links"
    "=:sockets"
    "p:name pipes (FIFOS)"
    "*:executable plain files"
    "%:device files"
    "r:owner-readable"
    "w:owner-writeable"
    "x:owner-executable"
    "A:group-readable"
    "I:group-writeable"
    "E:group-executable"
    "R:world-readable"
    "W:world-writeable"
    "X:world-executable"
    "s:setuid"
    "S:setgid"
    "t:sticky bit set"
    "f:+ access rights"
    "e:execute code"
    "+:+ command name"
    "d:+ device"
    "l:+ link count"
    "U:owned by EUID"
    "G:owned by EGID"
    "u:+ owning user"
    "g:+ owning group"
    "a:+ access time"
    "m:+ modification time"
    "c:+ inode change time"
    "L:+ size"
    "^:negate qualifiers"
    "-:follow symlinks toggle"
    "M:mark directories"
    "T:mark types"
    "N:use NULL_GLOB"
    "D:glob dots"
    "n:numeric glob sort"
    "o:+ sort order, up"
    "O:+ sort order, down"
    "[:+ range of files"
    "):end of qualifiers"
    "\::modifier"
    )
  _describe -t globquals "glob qualifier" quals -Q -S ''
  ;;
esac
