about summary refs log tree commit diff
path: root/Completion
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2003-09-22 13:04:37 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2003-09-22 13:04:37 +0000
commitf27036858ae1b2e61b40d0467ba88566dc8863f6 (patch)
treec58b0a7014b992fbb955680271b60046474c7c54 /Completion
parentb598aba3687a07f554ad146771d4338aaa489f2f (diff)
downloadzsh-f27036858ae1b2e61b40d0467ba88566dc8863f6.tar.gz
zsh-f27036858ae1b2e61b40d0467ba88566dc8863f6.tar.xz
zsh-f27036858ae1b2e61b40d0467ba88566dc8863f6.zip
19112: several improvements and fixes for Perforce completion
Diffstat (limited to 'Completion')
-rw-r--r--Completion/Unix/Command/_perforce2098
1 files changed, 1109 insertions, 989 deletions
diff --git a/Completion/Unix/Command/_perforce b/Completion/Unix/Command/_perforce
index 6891d6ba6..a76b64f52 100644
--- a/Completion/Unix/Command/_perforce
+++ b/Completion/Unix/Command/_perforce
@@ -33,6 +33,19 @@
 # handled within Perforce, so the completion code may limit the number even
 # further.  If not set explicitly, the value is taken to be 20 to avoid a
 # huge database being output.  Set it to a larger number if necessary.
+# Setting it explicitly to zero removes the maximum.  Because you see only
+# the most recent, changes and jobs are shown in the order given by
+# Perforce without further sorting.
+#
+# Completion of jobs can also be controlled by the `jobview' style.
+# This uses the standard Perforce JobView syntax, and is applied
+# in connection with the `max' style.  In other words,
+# if you set
+#   zstyle ':completion:*:p4-*:jobs' max 0
+#   zstyle ':completion:*:p4-*:jobs' jobview 'user=pws'
+# then jobs to be completed will be those from the output of
+#   p4 jobs -e 'user=pws'
+# i.e. those assigned to Perforce user `pws'.
 #
 # The style `all-files' is used to tell the completion system to
 # complete any file in a given context.  This is for use in places
@@ -69,7 +82,9 @@
 #    zstyle ':completion:*:p4-*:at-suffix:*' tag-order changes '*'
 # will force all completion after `@' to show changes first.  Executing
 # _next_tags (usually ^x^n) will cycle between that and the remaining
-# tags (dates, labels, clients).
+# tags (dates, labels, clients).  I recommend, at least, keeping labels
+# later than changes since the former are less useful and can take a long
+# time to complete.
 #
 # A # is automatically quoted when handled in this way; if the file is
 # typed by hand or the completion didn't finish (e.g. you typed a character
@@ -197,7 +212,10 @@
 # says that the command `p4cvsmap' takes arguments like `p4 files'.
 # Often the options will be different; if this is a problem, you
 # will need to write your own completer which loads _perforce and
-# calls its functions directly.
+# calls its functions directly.  You can add -global to the end
+# of the service to say that the command also handles global
+# Perforce options, comme ca:
+#   compdef _perforce p4reopen=p4-job-global
 #
 # TODO
 # ====
@@ -209,106 +227,109 @@
 # context `:completion:*:p4[-:]*' should work.
 
 _perforce() {
-    # rely on localoptions
-    setopt nonomatch
-    local p4cmd==p4 match mbegin mend
-    integer i
-
-    if [[ $service = -value-* ]]; then
-	# Completing parameter value.
-	# Some of these --- in particular P4PORT --- don't need
-	# the perforce server.
-	case $compstate[parameter] in
-	    (P4PORT) _perforce_hosts_ports
-		     ;;
-	    (P4CLIENT) _perforce_clients
-		       ;;
-	    (P4MERGE) _command_names -e
-		      ;;
-	    (P4USER) _users
-		     ;;
-	esac
-	# We do not handle values anywhere else.
-	return
-    fi
-
-    if [[ $p4cmd = '=p4' ]]; then
-	_message "p4 executable not found: completion not available"
-	return
-    fi
+  # rely on localoptions
+  setopt nonomatch
+  local p4cmd==p4 match mbegin mend
+  integer _perforce_cmd_ind
+
+  if [[ $service = -value-* ]]; then
+    # Completing parameter value.
+    # Some of these --- in particular P4PORT --- don't need
+    # the perforce server.
+    case $compstate[parameter] in
+      (P4PORT)
+      _perforce_hosts_ports
+      ;;
+
+      (P4CLIENT)
+      _perforce_clients
+      ;;
+
+      (P4MERGE)
+      _command_names -e
+      ;;
+
+      (P4USER)
+      _perforce_users
+      ;;
+    esac
+    # We do not handle values anywhere else.
+    return
+  fi
+
+  if [[ $p4cmd = '=p4' ]]; then
+    _message "p4 executable not found: completion not available"
+    return
+  fi
+
+  # If we are at or after the command word, remember the
+  # global arguments to p4 as we will need to pass these down
+  # when generating completion lists.
+  # This is both an array and a function, but luckily I never
+  # get confused...
+  local -a _perforce_global_options
+  local -a _perforce_option_dispatch
+  _perforce_option_dispatch=(
+    '-c+[client]:client:_perforce_clients' \
+    '-C+[charset]:charset:_perforce_charsets' \
+    '-d+[current directory]:directory:_path_files -g "*(/)"' \
+    '-H+[hostname]:host:_hosts' \
+    '-G[python output]' \
+    '-L+[message language]:language: ' \
+    '-p+[server port]:port:_perforce_hosts_ports' \
+    '-P+[password on server]:password: ' \
+    '-s[output script tags]' \
+    '-u+[user]:user name:_perforce_users' \
+    '-x+[filename or -]:file:_perforce_files_or_minus' \
+  )
+
+  # If we are given a service of the form p4-cmd, treat this
+  # as if it was after `p4 cmd'.  This provides an easy way in
+  # for scripts and functions that emulate the behaviour of
+  # p4 subcommands.  Note we don't shorten the command line arguments.
+  if [[ $service = p4-(#b)(*) ]]; then
+    local curcontext="$curcontext"
+    local p4cmd=$words[1] cmd=$match[1] gbl
 
-    # If we are given a service of the form p4-cmd, treat this
-    # as if it was after `p4 cmd'.  This provides an easy way in
-    # for scripts and functions that emulate the behaviour of
-    # p4 subcommands.  Note we don't shorten the command line arguments.
-    if [[ $service = p4-(#b)(*) ]]; then
-        local curcontext="$curcontext"
-	if (( $+functions[_perforce_cmd_${match[1]}] )); then
-	    curcontext="${curcontext%:*:*}:p4-$match[1]:"
-	    _perforce_cmd_${match[1]}
-	else
-	    _message "unhandled _perforce service: $service"
-	fi
+    if [[ $cmd = (#b)(*)-global ]]; then
+      # Handles global options.
+      cmd=$match[1]
+      _perforce_global_options && gbl=1
     fi
-
-    # Options with arguments we need to pass down when calling
-    # p4 from completers.  There are no options without arguments
-    # we need to pass.  (Don't pass down -L language since we
-    # parse based on English output.)
-    local argopts_pass="cCdHpPu"
-    # Other options which have arguments but we shouldn't pass down.
-    # There are some debugging options, but they tend to get used
-    # with the argument in the same word as the option, in which
-    # case they will be handled OK anyway.
-    local argopts_ignore="Lx"
-
-    # If we are at or after the command word, remember the
-    # global arguments to p4 as we will need to pass these down
-    # when generating completion lists.
-    local -a _perforce_global_options
-
-    # We need to try and check if we are before or after the
-    # subcommand, since some of the options with arguments, in particular -c,
-    # work differently.  It didn't work if I just added '*::...' to the
-    # end of the arguments list, anyway.
-    for (( i = 2; i < CURRENT; i++ )); do
-	if [[ $words[i] = -[$argopts_pass$argopts_ignore] ]]; then
-	    # word with following argument --- check this
-	    # is less than the current word, else we are completing
-	    # this and shouldn't pass it down
-	    if [[ $(( i + 1 )) -lt $CURRENT && \
-		  $words[i] = -[$argopts_pass] ]]; then
-		_perforce_global_options+=(${words[i,i+1]})
-	    fi
-	    (( i++ ))
-	elif [[ $words[i] = -[$argopts_pass]* ]]; then
-	    # word including argument which we want to keep
-	    _perforce_global_options+=(${words[i]})
-	elif [[ $words[i] != -* ]]; then
-	    break
-	fi
-    done
-
-    if (( i >= CURRENT )); then
-	_arguments -s : \
-	    '-c+[client]:client:_perforce_clients' \
-	    '-C+[charset]:charset:_perforce_charsets' \
-	    '-d+[current directory]:directory:_path_files -g "*(/)"' \
-	    '-H+[hostname]:host:_hosts' \
-	    '-G[python output]' \
-	    '-L+[message language]:language: ' \
-	    '-p+[server port]:port:_perforce_hosts_ports' \
-	    '-P+[password on server]:password: ' \
-	    '-s[output script tags]' \
-	    '-u+[user]:user name:_users' \
-	    '-x+[filename or -]:file:_perforce_files_or_minus' \
-	    '1:perforce command:_perforce_commands'
+    if (( $+functions[_perforce_cmd_$cmd] )); then
+      curcontext="${curcontext%:*:*}:p4-${cmd}:"
+      if [[ -n $gbl ]]; then
+	# We are handling global Perforce options as well as the
+	# arguments to the specific command.
+	# To handle the latter, we need the command name, plus
+	# all the arguments for the command with the global options
+	# removed.  The function _perforce_service_dispatch handles
+	# this by unshifting the command ($p4cmd) into words,
+	# then dispatching for the Perforce subcommand $cmd.
+	#
+	# Has anyone noticed this is getting rather complicated?
+	_arguments -s : $_perforce_option_dispatch \
+	"*::p4-$cmd arguments: _perforce_service_dispatch $p4cmd $cmd"
+      else
+	_perforce_cmd_$cmd
+      fi
+      # Don't try to do full command handling.
+      return
     else
-	(( i-- ))
-	(( CURRENT -= i ))
-	shift $i words
-	_perforce_command_args
+      _message "unhandled _perforce service: $service"
+      return 1
     fi
+  fi
+
+  if _perforce_global_options; then
+    _arguments -s : $_perforce_option_dispatch \
+    '1:perforce command:_perforce_commands'
+  else
+    (( _perforce_cmd_ind-- ))
+    (( CURRENT -= _perforce_cmd_ind ))
+    shift $_perforce_cmd_ind words
+    _perforce_command_args
+  fi
 }
 
 
@@ -320,12 +341,12 @@ _perforce() {
 # passed to p4.
 (( $+functions[_perforce_call_p4] )) ||
 _perforce_call_p4() {
-    local cp_tag=$1
-    shift
-    # This is for our own use for parsing, and we need English output,
-    # so...
-    local +x P4LANGUAGE
-    _call_program $cp_tag p4 "${_perforce_global_options[@]}" "$@"
+  local cp_tag=$1
+  shift
+  # This is for our own use for parsing, and we need English output,
+  # so...
+  local +x P4LANGUAGE
+  _call_program $cp_tag p4 "${_perforce_global_options[@]}" "$@"
 }
 
 
@@ -333,36 +354,46 @@ _perforce_call_p4() {
 # only generate it via this function when we need it.
 (( $+functions[_perforce_gen_cmd_list] )) ||
 _perforce_gen_cmd_list() {
-    (( ${+_perforce_cmd_list} )) || typeset -ga _perforce_cmd_list
-    local hline
-    # Output looks like <tab>command-name<space>description in words...
-    # Ignore blank lines and the heading line beginning `Perforce...'
-    # Just gets run once, then cached, so don't bother optimising
-    # this to a grossly unreadable parameter substitution.
-    _perforce_call_p4 help-commands help commands | while read -A hline; do
-	(( ${#hline} < 2 )) && continue
-	[[ $hline[1] = (#i)perforce ]] && continue
-	_perforce_cmd_list+=("${hline[1]}:${hline[2,-1]}")
-    done
+  (( ${+_perforce_cmd_list} )) || typeset -ga _perforce_cmd_list
+  local hline
+  # Output looks like <tab>command-name<space>description in words...
+  # Ignore blank lines and the heading line beginning `Perforce...'
+  # Just gets run once, then cached, so don't bother optimising
+  # this to a grossly unreadable parameter substitution.
+  _perforce_call_p4 help-commands help commands | while read -A hline; do
+    (( ${#hline} < 2 )) && continue
+    [[ $hline[1] = (#i)perforce ]] && continue
+    _perforce_cmd_list+=("${hline[1]}:${hline[2,-1]}")
+  done
 }
 
 
 (( $+functions[_perforce_commands] )) ||
 _perforce_commands() {
-    (( ${#_perforce_cmd_list} )) || _perforce_gen_cmd_list
-    _describe -t p4-commands 'Perforce command' _perforce_cmd_list
+  (( ${#_perforce_cmd_list} )) || _perforce_gen_cmd_list
+  _describe -t p4-commands 'Perforce command' _perforce_cmd_list
 }
 
 
 (( $+functions[_perforce_command_args] )) ||
 _perforce_command_args() {
-    local curcontext="$curcontext" cmd=${words[1]}
-    if (( $+functions[_perforce_cmd_$cmd] )); then
-	 curcontext="${curcontext%:*:*}:p4-${cmd}:"
-	 _perforce_cmd_$cmd
-    else
-	 _message "unhandled perforce command: $cmd"
-    fi
+  local curcontext="$curcontext" cmd=${words[1]}
+  if (( $+functions[_perforce_cmd_$cmd] )); then
+    curcontext="${curcontext%:*:*}:p4-${cmd}:"
+    _perforce_cmd_$cmd
+  else
+    _message "unhandled perforce command: $cmd"
+  fi
+}
+
+
+(( $+functions[_perforce_service_dispatch] )) ||
+_perforce_service_dispatch() {
+  # Put the original command name back, then dispatch for
+  # our Perforce handler.
+  words=($1 "$words[@]")
+  (( CURRENT++ ))
+  _perforce_cmd_$2
 }
 
 
@@ -370,202 +401,250 @@ _perforce_command_args() {
 # Helper functions
 #
 
+(( $+functions[_perforce_global_options] )) ||
+_perforce_global_options() {
+  # Options with arguments we need to pass down when calling
+  # p4 from completers.  There are no options without arguments
+  # we need to pass.  (Don't pass down -L language since we
+  # parse based on English output.)
+  local argopts_pass="cCdHpPu"
+  # Other options which have arguments but we shouldn't pass down.
+  # There are some debugging options, but they tend to get used
+  # with the argument in the same word as the option, in which
+  # case they will be handled OK anyway.
+  local argopts_ignore="Lx"
+
+  integer i
+
+  # We need to try and check if we are before or after the
+  # subcommand, since some of the options with arguments, in particular -c,
+  # work differently.  It didn't work if I just added '*::...' to the
+  # end of the arguments list, anyway.
+  for (( i = 2; i < CURRENT; i++ )); do
+    if [[ $words[i] = -[$argopts_pass$argopts_ignore] ]]; then
+      # word with following argument --- check this
+      # is less than the current word, else we are completing
+      # this and shouldn't pass it down
+      if [[ $(( i + 1 )) -lt $CURRENT && \
+	$words[i] = -[$argopts_pass] ]]; then
+	_perforce_global_options+=(${words[i,i+1]})
+      fi
+      (( i++ ))
+    elif [[ $words[i] = -[$argopts_pass]* ]]; then
+      # word including argument which we want to keep
+      _perforce_global_options+=(${words[i]})
+    elif [[ $words[i] != -* ]]; then
+      break
+    fi
+  done
+
+  (( _perforce_cmd_ind = i ))
+  (( _perforce_cmd_ind >= CURRENT ))
+}
+
 (( $+functions[_perforce_branches] )) ||
 _perforce_branches() {
-    local bline match mbegin mend
-    local -a bl
-    bl=(${${${(f)"$(_perforce_call_p4 branches branches 2>/dev/null)"}##Branch }/ /:})
-    [[ $#bl -eq 1 && $bl[1] = '' ]] && bl=()
-    (( $#bl )) && _describe -t branches 'Perforce branch' bl
+  local bline match mbegin mend
+  local -a bl
+  bl=(${${${(f)"$(_perforce_call_p4 branches branches 2>/dev/null)"}##Branch }/ /:})
+  [[ $#bl -eq 1 && $bl[1] = '' ]] && bl=()
+  (( $#bl )) && _describe -t branches 'Perforce branch' bl
 }
 
 
 (( $+functions[_perforce_changes] )) ||
 _perforce_changes() {
-    local cline match mbegin mend max ctype num comma file
-    local -a cl cstatus
-
-    zstyle -s ":completion:${curcontext}:" max max
-    if [[ ${NUMERIC:-0} -lt 0 && -z $compstate[insert] ]]; then
-	 # Not inserting (i.e. just listing) and given a negative
-	 # prefix argument.  Instead of listing possible completions,
-	 # show the full description for the change number on the line at
-	 # the moment.
-	 [[ $PREFIX = (|*[^[:digit:]])(#b)(<->) ]] && num+=$match[1]
-	 [[ $SUFFIX = (#b)(<->)* ]] && num+=$match[1]
-	 if [[ -n $num ]]; then
-	     _message -r "$(_perforce_call_p4 describe describe $num)"
-	     return 0
-	 fi
-    elif [[ ${NUMERIC:-0} -gt 0 ]]; then
-	 max=$NUMERIC
+  local cline match mbegin mend max ctype num comma file
+  local -a cl cstatus amax
+
+  zstyle -s ":completion:${curcontext}:changes" max max || max=20
+  if [[ ${NUMERIC:-0} -lt 0 && -z $compstate[insert] ]]; then
+    # Not inserting (i.e. just listing) and given a negative
+    # prefix argument.  Instead of listing possible completions,
+    # show the full description for the change number on the line at
+    # the moment.
+    [[ $PREFIX = (|*[^[:digit:]])(#b)(<->) ]] && num+=$match[1]
+    [[ $SUFFIX = (#b)(<->)* ]] && num+=$match[1]
+    if [[ -n $num ]]; then
+      _message -r "$(_perforce_call_p4 describe describe $num)"
+      return 0
     fi
-
-    # Hack: assume the arguments we want are at the end.
-    while [[ $argv[-1] = -t? ]]; do
-	 case $argv[-1] in
-	     # Change embedded in filename; extract that and remove
-	     # the corresponding prefix.  Remove possible `#'s, too,
-	     # in case we are looking at a range.
-	     (-tf) file=${${(Q)PREFIX}%%[\#@]*}
-		   compset -P '*@'
-		   ;;
-	     # Changes already submitted
-	     (-ts) cstatus=(-s submitted)
-		   ctype="submitted "
-		   ;;
-	     # Changes still pending
-	     (-tp)
-		   cstatus=(-s pending)
-		   ctype="pending "
-		   ;;
-	     # Range allowed: append comma and supply rules for
-	     # removing and handling subsequent `#'.
-	     (-tR) comma=(-S, -R _perforce_file_suffix)
-	 esac
-	 argv=($argv[1,-2])
-    done
-    # Limit to the 20 most recent changes by default to avoid huge
-    # output.
-    cl=(
-${${${${(f)"$(_perforce_call_p4 changes changes -m ${max:-20} $cstatus \$file)"}##Change\ }//\ on\ /:}/\ by\ /\ }
+  elif [[ ${NUMERIC:-0} -gt 0 ]]; then
+    max=$NUMERIC
+  fi
+
+  (( max )) && amax=(-m $max)
+
+  # Hack: assume the arguments we want are at the end.
+  while [[ $argv[-1] = -t? ]]; do
+    case $argv[-1] in
+      # Change embedded in filename; extract that and remove
+      # the corresponding prefix.  Remove possible `#'s, too,
+      # in case we are looking at a range.
+      (-tf)
+      file=${${(Q)PREFIX}%%[\#@]*}
+      compset -P '*@'
+      ;;
+
+      # Changes already submitted
+      (-ts)
+      cstatus=(-s submitted)
+      ctype="submitted "
+      ;;
+
+      # Changes still pending
+      (-tp)
+      cstatus=(-s pending)
+      ctype="pending "
+      ;;
+
+      # Range allowed: append comma and supply rules for
+      # removing and handling subsequent `#'.
+      (-tR)
+      comma=(-S, -R _perforce_file_suffix)
+    esac
+    argv=($argv[1,-2])
+  done
+  # Limit to the 20 most recent changes by default to avoid huge
+  # output.
+  cl=(
+${${${${(f)"$(_perforce_call_p4 changes changes $amax $cstatus \$file)"}##Change\ }//\ on\ /:}/\ by\ /\ }
 "default:change not yet numbered")
-    [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
-    _describe -t changes "${ctype}change" cl $comma
+  [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
+  _describe -t changes "${ctype}change" cl -V changes-unsorted $comma
 }
 
 
 (( $+functions[_perforce_charsets] )) ||
 _perforce_charsets() {
-    local expl
-    _wanted charset expl 'character set' \
-	 compadd eucjp iso8859-1 shiftjis utf8 winansi
+  local expl
+  _wanted charset expl 'character set' \
+    compadd eucjp iso8859-1 shiftjis utf8 winansi
 }
 
 
 (( $+functions[_perforce_clients] )) ||
 _perforce_clients() {
-    local cline match mbegin mend 
-    local -a slash cl
+  local -a slash cl
 
-    # Are we completing after an @, or a client view in a filespec?
-    if ! compset -P '*@'; then
-	compset -P '//' && slash=(-S/ -q)
-    fi
+  # Are we completing after an @, or a client view in a filespec?
+  if ! compset -P '*@'; then
+    compset -P '//' && slash=(-S/ -q)
+  fi
 
-    cl=(${${${(f)"$(_perforce_call_p4 clients clients)"}##Client\ }/\ /:})
-    [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
-    _describe -t clients 'Perforce client' cl $slash
+  cl=(${${${(f)"$(_perforce_call_p4 clients clients)"}##Client\ }/\ /:})
+  [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
+  _describe -t clients 'Perforce client' cl $slash
 }
 
 
 (( $+functions[_perforce_counters] )) ||
 _perforce_counters() {
-    local cline match mbegin mend
-    local -a cl
+  local cline match mbegin mend
+  local -a cl
 
-    cl=(${${${(f)"$(_perforce_call_p4 counters counters)"}/\ /:}/\=/current value})
-    [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
-    _describe -t counters 'Perforce counter' cl
+  cl=(${${${(f)"$(_perforce_call_p4 counters counters)"}/\ /:}/\=/current value})
+  [[ $#cl -eq 1 && $cl[1] = '' ]] && cl=()
+  _describe -t counters 'Perforce counter' cl
 }
 
 
 (( $+functions[_perforce_counter_values] )) ||
 _perforce_counter_values() {
-    if [[ -n $words[CURRENT-1] ]]; then
-	 local value="$(_perforce_call_p4 counter counter $words[CURRENT-1] 2>/dev/null)"
-	 if [[ -n $value ]]; then
-	     # No space.  This allows stuff like incarg and decarg.
-	     compstate[insert]=1
-	     _wanted value expl 'counter value' compadd $value
-	 fi
+  if [[ -n $words[CURRENT-1] ]]; then
+    local value="$(_perforce_call_p4 counter counter $words[CURRENT-1] 2>/dev/null)"
+    if [[ -n $value ]]; then
+      # No space.  This allows stuff like incarg and decarg.
+      compstate[insert]=1
+      _wanted value expl 'counter value' compadd $value
     fi
+  fi
 }
 
 
 (( $+functions[_perforce_dates] )) ||
 _perforce_dates() {
-    # Only useful in a file spec after `@'.
-    compset -P '*@'
-
-    # Date/time now in format required by Perforce.
-    local now="$(date +%Y:%m:%d:%T)" name prefix
-    local -a nowarray offer opts matchpats suffixes names
-    nowarray=(${(s.:.)now})
-
-    names=(   year month day\ of\ month hour minute second)
-    suffixes=(  /    /    :               :     :     ''  )
-
-    integer i
-    prefix=${(Q)PREFIX}
-    for (( i = 6; i >= 1; i-- )); do
-	# Match from the most specific back.
-	# The following is one of those occasions where zsh
-	# substitution skips to the right answer without ever
-	# passing through the real world on the way.
-	if [[ $prefix = *${(j.*.)~suffixes[1,i-1]}* ]]; then
-	    (( i > 1 )) && compset -P "*$suffixes[i-1]"
-	    # If what's there already is the right length,
-	    # just accept it and add the suffix.
-	    prefix=${(Q)PREFIX}
-	    if [[ ${#prefix} = ${#nowarray[i]} ]]; then
-		offer=($prefix)
-	    else
-		offer=($nowarray[i])
-	    fi
-	    [[ -n $suffixes[i] ]] && opts=(-S $suffixes[i] -q)
-	    name=$names[i]
-	    break
-	fi
-    done
+  # Only useful in a file spec after `@'.
+  compset -P '*@'
+
+  # Date/time now in format required by Perforce.
+  local now="$(date +%Y:%m:%d:%T)" name prefix
+  local -a nowarray offer opts matchpats suffixes names
+  nowarray=(${(s.:.)now})
+
+  names=(   year month day\ of\ month hour minute second)
+  suffixes=(  /    /    :               :     :     ''  )
+
+  integer i
+  prefix=${(Q)PREFIX}
+  for (( i = 6; i >= 1; i-- )); do
+    # Match from the most specific back.
+    # The following is one of those occasions where zsh
+    # substitution skips to the right answer without ever
+    # passing through the real world on the way.
+    if [[ $prefix = *${(j.*.)~suffixes[1,i-1]}* ]]; then
+      (( i > 1 )) && compset -P "*$suffixes[i-1]"
+      # If what's there already is the right length,
+      # just accept it and add the suffix.
+      prefix=${(Q)PREFIX}
+      if [[ ${#prefix} = ${#nowarray[i]} ]]; then
+	offer=($prefix)
+      else
+	offer=($nowarray[i])
+      fi
+      [[ -n $suffixes[i] ]] && opts=(-S $suffixes[i] -q)
+      name=$names[i]
+      break
+    fi
+  done
 
-    _describe -t dates $name offer $opts
+  _describe -t dates $name offer $opts
 }
 
 
 (( $+functions[_perforce_depots] )) ||
 _perforce_depots() {
-    local dline match mbegin mend max
-    local -a dl
+  local dline match mbegin mend
+  local -a dl
 
-    dl=(${${${(f)"$(_perforce_call_p4 depots depots)"}##Depot\ }/\ /:})
-    [[ $#dl -eq 1 && $dl[1] = '' ]] && dl=()
-    _describe -t depots 'depot name' dl
+  dl=(${${${(f)"$(_perforce_call_p4 depots depots)"}##Depot\ }/\ /:})
+  [[ $#dl -eq 1 && $dl[1] = '' ]] && dl=()
+  _describe -t depots 'depot name' dl
 }
 
 
 (( $+functions[_perforce_files_or_minus] )) ||
 _perforce_files_or_minus() {
-    _alternative 'minus:minus sign:(-)' 'files:file name:_files'
+  _alternative 'minus:minus sign:(-)' 'files:file name:_files'
 }
 
 
 (( $+functions[_perforce_file_suffix] )) ||
 _perforce_file_suffix() {
-    # Used with compadd -R to handle @ or # after a file name.
-    # Differs from compadd -r '...' in that it quotes `#' if typed.
-    [[ $1 = 1 ]] || return
-
-    if [[ $LBUFFER[-1] = [\ ,] ]]; then
-	 if [[ $KEYS = '#' ]]; then
-	     if [[ $LBUFFER[-1] = , ]]; then
-		 # Range: no suffix removal but add a backslash
-		 LBUFFER+=\\
-	     else
-		 # Suffix removal with an added backslash
-		 LBUFFER="$LBUFFER[1,-2]\\"
-	     fi
-	 elif [[ $KEYS = (*[^[:print:]]*|[[:blank:]\;\&\|]) || \
-		 ( $KEYS = @ && $LBUFFER[-1] = ' ' ) ]] ; then
-	     # Normal suffix removal
-	     LBUFFER="$LBUFFER[1,-2]"
-	 fi
-    elif [[ $LBUFFER[-1] = / ]]; then
-	# Normal suffix removal for directories.
-	if [[ $KEYS = (*[^[:print:]]*|[[:blank:]\;\&\|/]) ]]; then
-	    LBUFFER="$LBUFFER[1,-2]"
-	fi
+  # Used with compadd -R to handle @ or # after a file name.
+  # Differs from compadd -r '...' in that it quotes `#' if typed.
+  [[ $1 = 1 ]] || return
+
+  if [[ $LBUFFER[-1] = [\ ,] ]]; then
+    if [[ $KEYS = '#' ]]; then
+      if [[ $LBUFFER[-1] = , ]]; then
+	# Range: no suffix removal but add a backslash
+	LBUFFER+=\\
+	  else
+	# Suffix removal with an added backslash
+	LBUFFER="$LBUFFER[1,-2]\\"
+      fi
+    elif [[ $KEYS = (*[^[:print:]]*|[[:blank:]\;\&\|]) || \
+      ( $KEYS = @ && $LBUFFER[-1] = ' ' ) ]] ; then
+      # Normal suffix removal
+      LBUFFER="$LBUFFER[1,-2]"
+    fi
+  elif [[ $LBUFFER[-1] = / ]]; then
+    # Normal suffix removal for directories.
+    if [[ $KEYS = (*[^[:print:]]*|[[:blank:]\;\&\|/]) ]]; then
+      LBUFFER="$LBUFFER[1,-2]"
     fi
+  fi
 }
 
 
@@ -577,297 +656,315 @@ _perforce_file_suffix() {
 
 (( $+functions[_perforce_integrated_files] )) ||
 _perforce_integrated_files() {
-    local pfx=${(Q)PREFIX} type
-    local -a files
+  local pfx=${(Q)PREFIX} type
+  local -a files
 
-    compset -P '*/'
-    files=(${${${(f)"$(_perforce_call_p4 integrated integrated \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
-    [[ $#files -eq 1 && $files[1] = '' ]] && files=()
-    compadd "$@" -a files
+  compset -P '*/'
+  files=(${${${(f)"$(_perforce_call_p4 integrated integrated \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
+  [[ $#files -eq 1 && $files[1] = '' ]] && files=()
+  compadd "$@" -a files
 }
 
 
 (( $+functions[_perforce_opened_files] )) ||
 _perforce_opened_files() {
-    local pfx=${(Q)PREFIX} type
-    local -a files
+  local pfx=${(Q)PREFIX} type
+  local -a files
 
-    compset -P '*/'
-    files=(${${${(f)"$(_perforce_call_p4 opened opened \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
-    [[ $#files -eq 1 && $files[1] = '' ]] && files=()
-    compadd "$@" -a files
+  compset -P '*/'
+  files=(${${${(f)"$(_perforce_call_p4 opened opened \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
+  [[ $#files -eq 1 && $files[1] = '' ]] && files=()
+  compadd "$@" -a files
 }
 
 
 (( $+functions[_perforce_resolved_files] )) ||
 _perforce_resolved_files() {
-    local pfx=${(Q)PREFIX} type
-    local -a files
+  local pfx=${(Q)PREFIX} type
+  local -a files
 
-    compset -P '*/'
-    files=(${${${(f)"$(_perfroce_call_p4 resolved resolved \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
-    [[ $#files -eq 1 && $files[1] = '' ]] && files=()
-    compadd "$@" -a files
+  compset -P '*/'
+  files=(${${${(f)"$(_perfroce_call_p4 resolved resolved \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
+  [[ $#files -eq 1 && $files[1] = '' ]] && files=()
+  compadd "$@" -a files
 }
 
 (( $+functions[_perforce_subdirs] )) ||
 _perforce_subdirs() {
-    # This has no other function than to offer to add the `...' used
-    # by Perforce to indicate a recursive search of directories.
-    # Bit pathetic, really.
-    compset -P '*/'
-    compadd "$@" '...'
+  # This has no other function than to offer to add the `...' used
+  # by Perforce to indicate a recursive search of directories.
+  # Bit pathetic, really.
+  compset -P '*/'
+  compadd "$@" '...'
 }
 
 (( $+functions[_perforce_depot_dirs] )) ||
 _perforce_depot_dirs() {
-    # Normal completion of directories in depots
-    local pfx=${(Q)PREFIX} expl
-    local -a files
+  # Normal completion of directories in depots
+  local pfx=${(Q)PREFIX} expl
+  local -a files
 
-    compset -P '*/'
-    files=(${"${(f)$(_perforce_call_p4 dirs dirs \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)}"##*/})
-    [[ $#files -eq 1 && $files[1] = '' ]] && files=()
-    compadd "$@" -S / -q -a files
+  compset -P '*/'
+  files=(${"${(f)$(_perforce_call_p4 dirs dirs \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)}"##*/})
+  [[ $#files -eq 1 && $files[1] = '' ]] && files=()
+  compadd "$@" -S / -q -a files
 }
 
 (( $+functions[_perforce_depot_files] )) ||
 _perforce_depot_files() {
-    # Normal completion of files in depots
-    local pfx=${(Q)PREFIX} expl
-    local -a files
+  # Normal completion of files in depots
+  local pfx=${(Q)PREFIX} expl
+  local -a files
 
-    compset -P '*/'
-    files=(${${${(f)"$(_perforce_call_p4 files files \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
-    [[ $#files -eq 1 && $files[1] = '' ]] && files=()
-    compadd "$@" -R _perforce_file_suffix -a files
+  compset -P '*/'
+  files=(${${${(f)"$(_perforce_call_p4 files files \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/})
+  [[ $#files -eq 1 && $files[1] = '' ]] && files=()
+  compadd "$@" -R _perforce_file_suffix -a files
 }
 
 (( $+functions[_perforce_client_dirs] )) ||
 _perforce_client_dirs() {
-    # This is a slightly odd addition which isn't often necessary.
-    # When completing directories in a client specification, Perforce
-    # doesn't tell you about intermediate directories which are in
-    # the client, but not in the depot.  (Well... sometimes.  I've
-    # had some odd results with this.  I suspect there may be a bug
-    # but I don't really know enough to be sure.)
-    #
-    # For example, if my view contains
-    #   //depot/branches/rev1.2/...   //pws_client/branches/rev1.2/...
-    # then `p4 dirs "//pws_client/*"' won't mention the `branches'
-    # directory because the view actually starts lower down.  So
-    # we add it by hand when necessary.
-    #
-    # We don't want to waste time on this, since it's not the usual
-    # case, so we cache the results where necessary.  This means
-    # recording all the clients that we can later ask about if necessary.
-    # To flush the cache, `unset _perforce_client_list _perforce_client_dirs'.
-    if (( ! ${+_perforce_client_list} )); then
-	# Retrieve the list of clients.
-	typeset -gA _perforce_client_list
-	local -a tmplist
-	local tmpelt
-	tmplist=(${${${(f)"$(_perforce_call_p4 clients clients)"}##Client\ }%%\ *})
-	[[ $#tmplist -eq 1 && $tmplist[1] = '' ]] && tmplist=()
-	for tmpelt in $tmplist; do
-	    _perforce_client_list[$tmpelt]=1
-	done
-    fi
-
-    # See if the first path element is a client.  Very often it
-    # will actually be a depot, so we test this as quickly as possible.
-    local client=${${PREFIX##//}%%/*}
-    [[ -z ${_perforce_client_list[$client]} ]] && return 1
-
-    local oldifs=$IFS IFS= type dir line dirs
-
-    (( ${+_perforce_client_dirs} )) || typeset -gA _perforce_client_dirs
-
-    if (( ${+_perforce_client_dirs[$client]} )); then
-	# Already cached, although may be empty.
-	dirs=${_perforce_client_dirs[$client]}
-    else
-	# We need to look at the View stanza of the client record
-	# to see what directories exist in the client view.
-	_perforce_call_p4 client "client -o $client" 2>/dev/null | while read line; do
-	    case $line in
-		([[:blank:]]##) type=
-			        ;;
-		((#b)([[:alpha:]]##):*) type=${match[1]}
-				        ;;
-		(*) if [[ $type = View ]]; then
-	                dir=${${line##[[:blank:]]##//*[[:blank:]]//$client}%%/...(/*|)}
-			if [[ $#dir -gt 1 ]]; then
-			    dirs+="${dirs:+ }${(q)dir##/}"
-			fi
-		    fi
-		    ;;
-	    esac
-	done
-    fi
-
-    (( ${#dirs} )) || return 1
-
-    # Turn our string of space-separated backquoted elements into an array.
-    dirs=(${(z)dirs})
-    # Get the current prefix also as an array of elements
-    compset -P '//[^/]##/'
-    pfx=(${(s./.)${(Q)PREFIX}})
-
-    local -a ndirs
-    local match mbegin mend
-    # Check matching path segments
-    while (( ${#pfx} > 1 )); do
-	ndirs=()
-	for dir in $dirs; do
-	    if [[ $dir = $pfx/(#b)(*) ]]; then
-		ndirs+=($match[1])
-	    fi
-	done
-	(( ${#ndirs} )) || return 1
-	dirs=($ndirs)
-	shift pfx
-	compset -P '[^/]'
+  # This is a slightly odd addition which isn't often necessary.
+  # When completing directories in a client specification, Perforce
+  # doesn't tell you about intermediate directories which are in
+  # the client, but not in the depot.  (Well... sometimes.  I've
+  # had some odd results with this.  I suspect there may be a bug
+  # but I don't really know enough to be sure.)
+  #
+  # For example, if my view contains
+  #   //depot/branches/rev1.2/...   //pws_client/branches/rev1.2/...
+  # then `p4 dirs "//pws_client/*"' won't mention the `branches'
+  # directory because the view actually starts lower down.  So
+  # we add it by hand when necessary.
+  #
+  # We don't want to waste time on this, since it's not the usual
+  # case, so we cache the results where necessary.  This means
+  # recording all the clients that we can later ask about if necessary.
+  # To flush the cache, `unset _perforce_client_list _perforce_client_dirs'.
+  if (( ! ${+_perforce_client_list} )); then
+    # Retrieve the list of clients.
+    typeset -gA _perforce_client_list
+    local -a tmplist
+    local tmpelt
+    tmplist=(${${${(f)"$(_perforce_call_p4 clients clients)"}##Client\ }%%\ *})
+    [[ $#tmplist -eq 1 && $tmplist[1] = '' ]] && tmplist=()
+    for tmpelt in $tmplist; do
+      _perforce_client_list[$tmpelt]=1
+    done
+  fi
+
+  # See if the first path element is a client.  Very often it
+  # will actually be a depot, so we test this as quickly as possible.
+  local client=${${PREFIX##//}%%/*}
+  [[ -z ${_perforce_client_list[$client]} ]] && return 1
+
+  local oldifs=$IFS IFS= type dir line dirs
+
+  (( ${+_perforce_client_dirs} )) || typeset -gA _perforce_client_dirs
+
+  if (( ${+_perforce_client_dirs[$client]} )); then
+    # Already cached, although may be empty.
+    dirs=${_perforce_client_dirs[$client]}
+  else
+    # We need to look at the View stanza of the client record
+    # to see what directories exist in the client view.
+    _perforce_call_p4 client "client -o $client" 2>/dev/null | while read line
+    do
+      case $line in
+	([[:blank:]]##)
+	type=
+	;;
+
+	((#b)([[:alpha:]]##):*)
+	type=${match[1]}
+	;;
+
+	(*)
+	if [[ $type = View ]]; then
+	  dir=${${line##[[:blank:]]##//*[[:blank:]]//$client}%%/...(/*|)}
+	  if [[ $#dir -gt 1 ]]; then
+	    dirs+="${dirs:+ }${(q)dir##/}"
+	  fi
+	fi
+	;;
+      esac
     done
-    compadd -S / -q "$@" -- ${dirs%%/*}
+  fi
+
+  (( ${#dirs} )) || return 1
+
+  # Turn our string of space-separated backquoted elements into an array.
+  dirs=(${(z)dirs})
+  # Get the current prefix also as an array of elements
+  compset -P '//[^/]##/'
+  pfx=(${(s./.)${(Q)PREFIX}})
+
+  local -a ndirs
+  local match mbegin mend
+  # Check matching path segments
+  while (( ${#pfx} > 1 )); do
+    ndirs=()
+    for dir in $dirs; do
+      if [[ $dir = $pfx/(#b)(*) ]]; then
+	ndirs+=($match[1])
+      fi
+    done
+    (( ${#ndirs} )) || return 1
+    dirs=($ndirs)
+    shift pfx
+    compset -P '[^/]'
+  done
+  compadd -S / -q "$@" -- ${dirs%%/*}
 }
 
 (( $+functions[_perforce_files] )) ||
 _perforce_files() {
-    local pfx fline expl opt match mbegin mend range type
-    local -a files types
-
-    local dodirs unmaintained
-    # Suffix operations can modify context
-    local curcontext="$curcontext"
-
-    while (( $# )); do
-	if [[ $1 = -t(#b)(?) ]]; then
-	    case $match[1] in
-		(d) dodirs=-/
-		    ;;
-		(u) unmaintained=1
-		    ;;
-		(i) types+=(integrated)
-		    ;;
-		(o) types+=(opened)
-		    ;;
-		(r) types+=(resolved)
-		    ;;
-		(R) range="-tR"
-		    ;;
-	    esac
-	fi
-	shift
-    done
-
-    # Remove the quotes present in the word on the command line,
-    # since we will treat this as a literal string from now on.
-    # We might get into problems with characters recognised as
-    # special by p4 files and p4 dirs, but worry about that later.
-    pfx=${(Q)PREFIX}
-    if [[ -prefix *@ ]]; then
-	# Modify context to indicate we are in a suffix.
-	curcontext="${curcontext%:*}:at-suffix"
-	# Check for existing range syntax
-	[[ $PREFIX = *[@\#]*,* ]] && range=
-	# After @ you can specify changes, clients, labels or dates.
-	# Note we don't remove the prefix here; we leave it to the
-	# subcommand.  This is in case it needs information from
-	# the prefix; _perforce_changes uses this to limit the
-	# output to relevant changes.
-	_alternative \
-	    "changes:change:_perforce_changes $range -tf" \
-	    clients:client:_perforce_clients \
-	    labels:label:_perforce_labels \
-	    'dates:date (+ time):_perforce_dates'
-    elif [[ -prefix *\# ]]; then
-	# Modify context to indicate we are in a suffix.
-	curcontext="${curcontext%:*}:hash-suffix"
-	# Check for existing range syntax
-	[[ $PREFIX = *[@\#]*,* ]] && range=
-	# Remove longest possible tail match to get name --- this
-	# automatically handles filenames in ranges e.g. `foo#1,#3'.
-	# (Note the compset removes the maximum possible head match,
-	# so we only complete the second part of the range in that case.)
-	_perforce_revisions $range
-    elif [[ $PREFIX = //* ]]; then
-	# This specifies files already handled by Perforce, so there's
-	# no point trying to look for unmaintained files.  Assume
-	# the user knows what they're doing.
-	local -a altfiles
-
-	if [[ $PREFIX = //[^/]# ]]; then
-	    # Complete //clientname spec.  Don't complete non-directories...
-	    # I don't actually know if they are valid here.
-	    altfiles+=("clients:Perforce client:_perforce_clients")
+  local pfx fline expl opt match mbegin mend range type
+  local -a files types
+
+  local dodirs unmaintained
+  # Suffix operations can modify context
+  local curcontext="$curcontext"
+
+  while (( $# )); do
+    if [[ $1 = -t(#b)(?) ]]; then
+      case $match[1] in
+	(d)
+	dodirs=-/
+	;;
+
+	(u)
+	unmaintained=1
+	;;
+
+	(i)
+	types+=(integrated)
+	;;
+
+	(o)
+	types+=(opened)
+	;;
+
+	(r)
+	types+=(resolved)
+	;;
+
+	(R)
+	range="-tR"
+	;;
+      esac
+    fi
+    shift
+  done
+
+  # Remove the quotes present in the word on the command line,
+  # since we will treat this as a literal string from now on.
+  # We might get into problems with characters recognised as
+  # special by p4 files and p4 dirs, but worry about that later.
+  pfx=${(Q)PREFIX}
+  if [[ -prefix *@ ]]; then
+    # Modify context to indicate we are in a suffix.
+    curcontext="${curcontext%:*}:at-suffix"
+    # Check for existing range syntax
+    [[ $PREFIX = *[@\#]*,* ]] && range=
+    # After @ you can specify changes, clients, labels or dates.
+    # Note we don't remove the prefix here; we leave it to the
+    # subcommand.  This is in case it needs information from
+    # the prefix; _perforce_changes uses this to limit the
+    # output to relevant changes.
+    _alternative \
+      "changes:change:_perforce_changes $range -tf" \
+      clients:client:_perforce_clients \
+      labels:label:_perforce_labels \
+      'dates:date (+ time):_perforce_dates'
+  elif [[ -prefix *\# ]]; then
+    # Modify context to indicate we are in a suffix.
+    curcontext="${curcontext%:*}:hash-suffix"
+    # Check for existing range syntax
+    [[ $PREFIX = *[@\#]*,* ]] && range=
+    # Remove longest possible tail match to get name --- this
+    # automatically handles filenames in ranges e.g. `foo#1,#3'.
+    # (Note the compset removes the maximum possible head match,
+    # so we only complete the second part of the range in that case.)
+    _perforce_revisions $range
+  elif [[ $PREFIX = //* ]]; then
+    # This specifies files already handled by Perforce, so there's
+    # no point trying to look for unmaintained files.  Assume
+    # the user knows what they're doing.
+    local -a altfiles
+
+    if [[ $PREFIX = //[^/]# ]]; then
+      # Complete //clientname spec.  Don't complete non-directories...
+      # I don't actually know if they are valid here.
+      altfiles+=("clients:Perforce client:_perforce_clients")
+    else
+      local donefiles=1
+      if [[ -z $dodirs ]]; then
+	if [[ ${#types} -gt 0 ]] &&
+	  ! zstyle -t ":completion:${curcontext}:" all-files; then
+	  for type in $types; do
+	    altfiles+=("$type-files:$type file:_perforce_${type}_files")
+	  done
 	else
-	    local donefiles=1
-	    if [[ -z $dodirs ]]; then
-		if [[ ${#types} -gt 0 ]] &&
-		    ! zstyle -t ":completion:${curcontext}:" all-files; then
-		    for type in $types; do
-			altfiles+=("$type-files:$type file:_perforce_${type}_files")
-		    done
-		else
-		    altfiles+=("depot-files:file in depot:_perforce_depot_files")
-		fi
-	    fi
-	    # Intermediate directories in a client view.
-	    # See function for notes.
-	    altfiles+=("client-dirs:client directory:_perforce_client_dirs")
+	  altfiles+=("depot-files:file in depot:_perforce_depot_files")
 	fi
-	altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
-	    "subdirs:subdirectory search:_perforce_subdirs")
-	_alternative $altfiles
-    elif [[ -n $unmaintained && -z $dodirs ]]; then
-	# a la _cvs_nonentried_files: directories are never maintained,
-	# so skip 'em.  Unmaintained files can't be integrated, opened
-	# or resolved, so treat as exclusive (just as well, since
-	# this bit's messy).
-	local MATCH MBEGIN MEND
-	local -a omitpats
-
-	match=()
-	: ${PREFIX:#(#b)(*/)(*)}
-	pfx="$match[1]"
-	pfx=${(e)~pfx}
-	omitpats=(
-	    ${${${${(f)"$(_perforce_call_p4 files files \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/}//(#m)[][*?()<|^~#\\]/\\$MATCH}
+      fi
+      # Intermediate directories in a client view.
+      # See function for notes.
+      altfiles+=("client-dirs:client directory:_perforce_client_dirs")
+    fi
+    altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
+      "subdirs:subdirectory search:_perforce_subdirs")
+    _alternative $altfiles
+  elif [[ -n $unmaintained && -z $dodirs ]]; then
+    # a la _cvs_nonentried_files: directories are never maintained,
+    # so skip 'em.  Unmaintained files can't be integrated, opened
+    # or resolved, so treat as exclusive (just as well, since
+    # this bit's messy).
+    local MATCH MBEGIN MEND
+    local -a omitpats
+
+    match=()
+    : ${PREFIX:#(#b)(*/)(*)}
+    pfx="$match[1]"
+    pfx=${(e)~pfx}
+    omitpats=(
+      ${${${${(f)"$(_perforce_call_p4 files files \"\$pfx\*\$\{\(Q\)SUFFIX\}\" 2>/dev/null)"}%\#*}##*/}//(#m)[][*?()<|^~#\\]/\\$MATCH}
 	)
 
-	[[ $#omitpats -eq 1 && $omitpats[1] = '' ]] && omitpats=()
-	if (( ${#omitpats} )); then
-	    _path_files -g "*~(*/|)(${(j:|:)~omitpats})(D.)"
-	else
-	    _path_files
-	fi
-	# Don't handle suffixes for non-entried files
-    elif (( ${#types} )) && ! zstyle -t ":completion:${curcontext}:" all-files
+    [[ $#omitpats -eq 1 && $omitpats[1] = '' ]] && omitpats=()
+    if (( ${#omitpats} )); then
+      _path_files -g "*~(*/|)(${(j:|:)~omitpats})(D.)"
+    else
+      _path_files
+    fi
+    # Don't handle suffixes for non-entried files
+  elif (( ${#types} )) && ! zstyle -t ":completion:${curcontext}:" all-files
     then
-	local -a altfiles
+    local -a altfiles
 
-	for type in $types; do
-	    altfiles+=("$type-files:$type file:_perforce_${type}_files")
-	done
-
-	altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
-	    "subdirs:subdirectory search:_perforce_subdirs")
-	_alternative $altfiles
-    elif zstyle -t ":completion:${curcontext}:" depot-files; then
-	local -a altfiles
-	if [[ -z $dodirs ]]; then
-	    altfiles+=("depot-files:file in depot:_perforce_depot_files")
-	fi
-	altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
-	    "subdirs:subdirectory search:_perforce_subdirs")
-	_alternative $altfiles
-    else
-	# Look locally.
-	_alternative \
-	    "files:file:_path_files -R _perforce_file_suffix $dodirs" \
-	    "subdirs:subdirectory search:_perforce_subdirs"
+    for type in $types; do
+      altfiles+=("$type-files:$type file:_perforce_${type}_files")
+    done
+
+    altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
+      "subdirs:subdirectory search:_perforce_subdirs"
+      "directories:directory:_path_files -/")
+    _alternative $altfiles
+  elif zstyle -t ":completion:${curcontext}:" depot-files; then
+    local -a altfiles
+    if [[ -z $dodirs ]]; then
+      altfiles+=("depot-files:file in depot:_perforce_depot_files")
     fi
+    altfiles+=("depot-dirs:directory in depot:_perforce_depot_dirs"
+      "subdirs:subdirectory search:_perforce_subdirs")
+    _alternative $altfiles
+  else
+    # Look locally.
+    _alternative \
+      "files:file:_path_files -R _perforce_file_suffix $dodirs" \
+      "subdirs:subdirectory search:_perforce_subdirs"
+  fi
 }
 
 
@@ -877,154 +974,166 @@ _perforce_files() {
 
 (( $+functions[_perforce_filetypes] )) ||
 _perforce_filetypes() {
-    local -a values
-    if compset -P '*+*'; then
-	# That second `*' is deliberate --- only complete the last
-	# letter since we can have a whole string of them.
-	values=(
-	    "m:always set modtime on client"
-	    "w:always writeable on client"
-	    "x:set exec bit on client"
-	    "k:full RCS keyword expansion"
-	    "k:RCS expansion only for Id, Header"
-	    "l:exclusive open, disallow multiple opens"
-	    "C:server stores compress file per revision"
-	    "D:server stores deltas in RCS format"
-	    "F:server stores full file per revision"
-	    "S:server stores only head revision")
-	_describe -t file-modifiers 'Perforce file modifier' values
-    else
-	values=(
-	    "text:text, translate newlines"
-	    "binary:raw bytes"
-	    "symlink:symbolic link"
-	    "apple:Mac resource + data"
-	    "unicode:text, translate newlines, store as UTF-8")
-	_describe -t file-types 'Perforce file type' values -S+ -q
-    fi
+  local -a values
+  if compset -P '*+*'; then
+    # That second `*' is deliberate --- only complete the last
+    # letter since we can have a whole string of them.
+    values=(
+      "m:always set modtime on client"
+      "w:always writeable on client"
+      "x:set exec bit on client"
+      "k:full RCS keyword expansion"
+      "k:RCS expansion only for Id, Header"
+      "l:exclusive open, disallow multiple opens"
+      "C:server stores compress file per revision"
+      "D:server stores deltas in RCS format"
+      "F:server stores full file per revision"
+      "S:server stores only head revision")
+    _describe -t file-modifiers 'Perforce file modifier' values
+  else
+    values=(
+      "text:text, translate newlines"
+      "binary:raw bytes"
+      "symlink:symbolic link"
+      "apple:Mac resource + data"
+      "unicode:text, translate newlines, store as UTF-8")
+    _describe -t file-types 'Perforce file type' values -S+ -q
+  fi
 }
 
 
 (( $+functions[_perforce_groups] )) ||
 _perforce_groups() {
-    _describe -t groups 'Perforce group' $(_perforce_call_p4 groups groups)
+  _describe -t groups 'Perforce group' $(_perforce_call_p4 groups groups)
 }
 
 
 (( $+functions[_perforce_hosts_ports] )) ||
 _perforce_hosts_ports() {
-    if compset -P '*:'; then
-	_ports
-	local expl
-	_wanted ports expl port compadd "$@" 1666
-    else
-	# is this -q-able?
-	_hosts -S :
-    fi
+  if compset -P '*:'; then
+    _ports
+    local expl
+    _wanted ports expl port compadd "$@" 1666
+  else
+    # is this -q-able?
+    _hosts -S :
+  fi
 }
 
 (( $+functions[_perforce_jobs] )) ||
 _perforce_jobs() {
-    local jline match mbegin mend max
-    local -a jl
-
-    zstyle -s ":completion:${curcontext}:" max max
-    if [[ ${NUMERIC:-0} -lt 0 && -z $compstate[insert] ]]; then
-	# Not inserting (i.e. just listing) and given a negative
-	# prefix argument.  Instead of listing possible completions,
-	# show the full description for the job which is on the line at
-	# the moment.
-	_message -r "$(_perforce_call_p4 jobs jobs -e \"Job=\$PREFIX\$SUFFIX\" -l 2>/dev/null)"
-	return 0
-    elif [[ ${NUMERIC:-0} -gt 0 ]]; then
-	max=$NUMERIC
+  local jline match mbegin mend max jobview
+  local -a jl amax ajobview
+
+  zstyle -s ":completion:${curcontext}:jobs" max max || max=20
+  zstyle -s ":completion:${curcontext}:jobs" jobview jobview &&
+  ajobview=(-e $jobview)
+  if [[ ${NUMERIC:-0} -lt 0 && -z $compstate[insert] ]]; then
+  # Not inserting (i.e. just listing) and given a negative
+  # prefix argument.  Instead of listing possible completions,
+  # show the full description for the job which is on the line at
+  # the moment.
+    _message -r "$(_perforce_call_p4 jobs jobs -e \"Job=\$PREFIX\$SUFFIX\" -l 2>/dev/null)"
+    return 0
+  elif [[ ${NUMERIC:-0} -gt 0 ]]; then
+    max=$NUMERIC
+  fi
+
+  (( max )) && amax=(-m $max)
+
+  _perforce_call_p4 jobs jobs $ajobview $amax | while read jline; do
+    if [[ $jline = (#b)([^[:blank:]]##)' '[^[:blank:]]##' '(*) ]]; then
+      jl+=("${match[1]}:${match[2]}")
     fi
-
-    _perforce_call_p4 jobs jobs -m ${max:-20} | while read jline; do
-	if [[ $jline = (#b)([^[:blank:]]##)' '[^[:blank:]]##' '(*) ]]; then
-	    jl+=("${match[1]}:${match[2]}")
-	fi
-    done
-    _describe -t jobs 'Perforce job' jl
+  done
+  _describe -t jobs 'Perforce job' jl -V jobs-unsorted
 }
 
 (( $+functions[_perforce_jobviews] )) ||
 _perforce_jobviews() {
-    # Jobviews (see `p4 help jobview') are ways of interrogating the
-    # jobs/fixes database.  It's basically either a set of strings,
-    # or a set of key=value pairs, or some combination, separated
-    # by various logical operators.  The `=' could be a comparison,
-    # but we don't currently bother with that here; it's a bit cumbersome
-    # to complete.
-    local line type oldifs=$IFS IFS= key value slash=/
-    local match mbegin mend
-    # This is simply to split out two space-delimited words a backreferences.
-    local m2words
-    m2words='(#b)[[:blank:]]##([[:alnum:]]##)[[:blank:]]##([^[:blank:]]##)'
-
-    local -a valuespec
-    local -A p4fields p4values
-
-    # All the characters which can separate multiple match attempts.
-    # Ignore up to the last one.  We don't try to complete these.
-    compset -P '*[[:blank:]\^\&\|\(\)]'
-
-    # According to the manual, `p4 jobspec' requires admin privileges.
-    # If this is true even of `p4 jobspec -o', we are a bit screwed.
-    _perforce_call_p4 jobspec jobspec -o 2>/dev/null | while read line; do
-	case $line in
-	    ([[:blank:]]##) type=
-			    ;;
-	    ((#b)([[:alpha:]]##):*) type=${match[1]}
-				    ;;
-	    (*) case $type in
-	        # This stanza tells us all the allowed fields.
-	        (Fields) if [[ $line = [[:blank:]]##<->${~m2words}* ]]
-	                 then
-			     p4fields[${(L)match[1]}]=${match[2]}
-			 fi
-			 ;;
-	        # This stanza gives allowed values for the `select' types.
-		(Values) if [[ $line = ${~m2words}* ]]; then
-			     p4values[${(L)match[1]}]=${match[2]}
-			 fi
-			 ;;
-	        esac
-	        ;;
-	esac
-    done
-
-    IFS=$oldifs
+  # Jobviews (see `p4 help jobview') are ways of interrogating the
+  # jobs/fixes database.  It's basically either a set of strings,
+  # or a set of key=value pairs, or some combination, separated
+  # by various logical operators.  The `=' could be a comparison,
+  # but we don't currently bother with that here; it's a bit cumbersome
+  # to complete.
+  local line type oldifs=$IFS IFS= key value slash=/
+  local match mbegin mend
+  # This is simply to split out two space-delimited words a backreferences.
+  local m2words
+  m2words='(#b)[[:blank:]]##([[:alnum:]]##)[[:blank:]]##([^[:blank:]]##)'
+
+  local -a valuespec
+  local -A p4fields p4values
+
+  # All the characters which can separate multiple match attempts.
+  # Ignore up to the last one.  We don't try to complete these.
+  compset -P '*[[:blank:]\^\&\|\(\)]'
+
+  # According to the manual, `p4 jobspec' requires admin privileges.
+  # If this is true even of `p4 jobspec -o', we are a bit screwed.
+  _perforce_call_p4 jobspec jobspec -o 2>/dev/null | while read line; do
+    case $line in
+      ([[:blank:]]##)
+      type=
+      ;;
+
+      ((#b)([[:alpha:]]##):*)
+      type=${match[1]}
+      ;;
+
+      (*)
+      case $type in
+	# This stanza tells us all the allowed fields.
+	(Fields)
+	if [[ $line = [[:blank:]]##<->${~m2words}* ]]; then
+	  p4fields[${(L)match[1]}]=${match[2]}
+	fi
+	;;
 
-    if (( ! ${#p4fields} )); then
-	# We didn't get anything; add the defaults.
-	p4fields=(
-	    date	date
-	    description text
-	    job		word
-	    status	select
-	    user	word
-	)
-	p4values=(
+	# This stanza gives allowed values for the `select' types.
+	(Values)
+	if [[ $line = ${~m2words}* ]]; then
+	  p4values[${(L)match[1]}]=${match[2]}
+	fi
+	;;
+      esac
+
+      ;;
+    esac
+  done
+
+  IFS=$oldifs
+
+  if (( ! ${#p4fields} )); then
+    # We didn't get anything; add the defaults.
+    p4fields=(
+      date		date
+      description	text
+      job		word
+      status		select
+      user		word
+    )
+    p4values=(
 	    status	open/suspended/closed
 	)
+  fi
+
+  for key in ${(k)p4fields}; do
+    if [[ -n ${p4values[$key]} ]]; then
+      valuespec+=("${key}:${p4fields[$key]}:(${p4values[$key]//$slash/ })")
+    elif [[ $key = job ]]; then
+      # Nothing special for jobs; add our own completion.
+      valuespec+=("${key}:Perforce job:_perforce_jobs")
+    elif [[ $key = user ]]; then
+      # Nothing provided for user; add our own completion.
+      valuespec+=("${key}:user:_perforce_users")
+    else
+      valuespec+=("${key}:${p4fields[$key]}: ")
     fi
+  done
 
-    for key in ${(k)p4fields}; do
-	if [[ -n ${p4values[$key]} ]]; then
-	    valuespec+=("${key}:${p4fields[$key]}:(${p4values[$key]//$slash/ })")
-	elif [[ $key = job ]]; then
-	    # Nothing special for jobs; add our own completion.
-	    valuespec+=("${key}:Perforce job:_perforce_jobs")
-	elif [[ $key = user ]]; then
-	    # Nothing provided for user; add our own completion.
-	    valuespec+=("${key}:user:_users")
-	else
-	    valuespec+=("${key}:${p4fields[$key]}: ")
-	fi
-    done
-
-    _values 'Job specification parameter' $valuespec
+  _values 'Job specification parameter' $valuespec
 }
 
 (( $+functions[_perforce_labels] )) ||
@@ -1046,75 +1155,86 @@ _perforce_labels() {
 
 (( $+functions[_perforce_revisions] )) ||
 _perforce_revisions() {
-    # Doesn't handle standard completion options; requires space
-    # in front if used as action in _arguments.
+  # Doesn't handle standard completion options; requires space
+  # in front if used as action in _arguments.
 
-    local rline match mbegin mend comma expl pfx
-    local -a rl
+  local rline match mbegin mend comma expl pfx
+  local -a rl
 
-    if [[ $1 = -tR ]]; then
-	# handle ranges
-	comma=(-S, -R _perforce_file_suffix)
+  if [[ $1 = -tR ]]; then
+    # handle ranges
+    comma=(-S, -R _perforce_file_suffix)
 	shift
-    fi
-
-    # Beware of @foo,#bar; stupid but probably valid.
-    pfx=${${(Q)PREFIX}%%[\#@]*}
-    compset -P '*\#'
-
-    # Numerical revision numbers, possibly with text.
-    if [[ -z $PREFIX || $PREFIX = <-> ]]; then
-	# always allowed (same as none)
-	rl+=(0)
-	_perforce_call_p4 filelog 'filelog $pfx' 2>/dev/null | while read rline; do
-	    if [[ $rline = (#b)'... #'(<->)' change '(*) ]]; then
-		rl+=("${match[1]}:${match[2]}")
-	    fi
-	done
-    fi
-    # Non-numerical (special) revision names.
-    if [[ -z $PREFIX || $PREFIX != <-> ]]; then
-	rl+=('head:head revision' 'none:empty revision'
-		'have:current synced revision')
-    fi
-    _describe -t revisions 'revision' rl $comma
+  fi
+
+  # Beware of @foo,#bar; stupid but probably valid.
+  pfx=${${(Q)PREFIX}%%[\#@]*}
+  compset -P '*\#'
+
+  # Numerical revision numbers, possibly with text.
+  if [[ -z $PREFIX || $PREFIX = <-> ]]; then
+    # always allowed (same as none)
+    rl+=(0)
+    _perforce_call_p4 filelog 'filelog $pfx' 2>/dev/null | while read rline; do
+      if [[ $rline = (#b)'... #'(<->)' change '(*) ]]; then
+	rl+=("${match[1]}:${match[2]}")
+      fi
+    done
+  fi
+  # Non-numerical (special) revision names.
+  if [[ -z $PREFIX || $PREFIX != <-> ]]; then
+    rl+=('head:head revision' 'none:empty revision'
+      'have:current synced revision')
+  fi
+  _describe -t revisions 'revision' rl -V revisions-unsorted $comma
 }
 
 
 (( $+functions[_perforce_statuses] )) ||
 _perforce_statuses() {
-    # Perforce statuses are usually limited to a set of values
-    # given by the jobspec.
-    local jline match mbegin mend
-    local -a statuses
-
-    _perforce_call_p4 jobspec jobspec -o | while read jline; do
-	if [[ $jline = (#b)Status[[:blank:]]##(*/*) ]]; then
-	    statuses=(${(s./.)match[1]})
-	    break
-	fi
-    done
-    if (( !${#statuses} )); then
-	# Couldn't find anything from the jobspec; add defaults.
-	statuses=(closed open suspended)
+  # Perforce statuses are usually limited to a set of values
+  # given by the jobspec.
+  local jline match mbegin mend
+  local -a statuses
+
+  _perforce_call_p4 jobspec jobspec -o | while read jline; do
+    if [[ $jline = (#b)Status[[:blank:]]##(*/*) ]]; then
+      statuses=(${(s./.)match[1]})
+      break
     fi
-    _describe -t statuses 'job status' statuses
-    return 1
+  done
+  if (( !${#statuses} )); then
+    # Couldn't find anything from the jobspec; add defaults.
+    statuses=(closed open suspended)
+  fi
+  _describe -t statuses 'job status' statuses
+}
+
+
+
+(( $+functions[_perforce_users] )) ||
+_perforce_users() {
+  local -a ul
+
+  ul=(${${(f)"$(_perforce_call_p4 users users)"}/\ /:})
+  [[ $#ul -eq 1 && $ul[1] = '' ]] && ul=()
+  _describe -t clients 'Perforce client' ul
 }
 
 
 (( $+functions[_perforce_variables] )) ||
 _perforce_variables() {
-    local line match mbegin mend expl
-    local -a vars
+  local line match mbegin mend expl
+  local -a vars
 
-    _perforce_call_p4 help-environment help environment | while IFS= read line; do
-	if [[ $line = $'\t'(#b)([A-Z][A-Z0-9_]##)* ]]; then
-	   vars+=($match[1])
-	fi
-    done
+  _perforce_call_p4 help-environment help environment | while IFS= read line
+  do
+    if [[ $line = $'\t'(#b)([A-Z][A-Z0-9_]##)* ]]; then
+      vars+=($match[1])
+    fi
+  done
 
-    _wanted variable expl 'environment variable' compadd -S= -q $vars
+  _wanted variable expl 'environment variable' compadd -S= -q $vars
 }
 
 #
@@ -1123,605 +1243,605 @@ _perforce_variables() {
 
 (( $+functions[_perforce_cmd_add] )) ||
 _perforce_cmd_add() {
-    _arguments -s : \
-	'-c+[select by change]:change:_perforce_changes -tp' \
-	'-t+[set file type]:file type:_perforce_filetypes' \
-	'*:file:_perforce_files -tu'
+  _arguments -s : \
+    '-c+[select by change]:change:_perforce_changes -tp' \
+    '-t+[set file type]:file type:_perforce_filetypes' \
+    '*:file:_perforce_files -tu'
 }
 
 
 (( $+functions[_perforce_cmd_admin] )) ||
 _perforce_cmd_admin() {
-    if (( CURRENT == 2 )); then
-	local -a adcmds
-	adcmds=(
-	    "checkpoint:checkpoint, save copy of journal file"
-	    "journal:save and truncate journal file"
-	    "stop:stop the server")
-        _describe -t commands 'Perforce admin command' adcmds
-    elif [[ $words[2] == (checkpoint|journal) ]]; then
-	shift words
-	(( CURRENT-- ))
-	_arguments -s : \
-	    '-z[gzip journal file]' \
-	    '1::journal file prefix: '
-    fi
+  if (( CURRENT == 2 )); then
+    local -a adcmds
+    adcmds=(
+      "checkpoint:checkpoint, save copy of journal file"
+      "journal:save and truncate journal file"
+      "stop:stop the server")
+    _describe -t commands 'Perforce admin command' adcmds
+  elif [[ $words[2] == (checkpoint|journal) ]]; then
+    shift words
+    (( CURRENT-- ))
+    _arguments -s : \
+      '-z[gzip journal file]' \
+      '1::journal file prefix: '
+  fi
 }
 
 
 (( $+functions[_perforce_cmd_annotate] )) ||
 _perforce_cmd_annotate() {
-    # If you don't have this, it's new in release 2002.2.
-    _arguments -s : \
-	'-a[all, show both added and deleted lines]' \
-	'-q[quiet, suppress one-line file header]' \
-	'*::file:_perforce_files -tR'
+  # If you don't have this, it's new in release 2002.2.
+  _arguments -s : \
+    '-a[all, show both added and deleted lines]' \
+    '-q[quiet, suppress one-line file header]' \
+    '*::file:_perforce_files -tR'
 }
 
 (( $+functions[_perforce_cmd_branch] )) ||
 _perforce_cmd_branch() {
-    _arguments -s : \
-	'(-o)-f[force operation by superuser]' \
-	'(-o -i)-d[delete branch]' \
-	'(-d -i -f)-o[write specification to standard output]' \
-	'(-d -o)-i[read specification from standard input]' \
-	'(-i)*::branch name:_perforce_branches'
+  _arguments -s : \
+    '(-o)-f[force operation by superuser]' \
+    '(-o -i)-d[delete branch]' \
+    '(-d -i -f)-o[write specification to standard output]' \
+    '(-d -o)-i[read specification from standard input]' \
+    '(-i)*::branch name:_perforce_branches'
 }
 
 
 (( $+functions[_perforce_cmd_branches] )) ||
 _perforce_cmd_branches() {
-    # No arguments.
-    _arguments -s :
+  # No arguments.
+  _arguments -s :
 }
 
 
 (( $+functions[_perforce_cmd_change] )) ||
 _perforce_cmd_change() {
-    local ctype
-    # Unless forcing or outputting, we don't
-    # complete committed changes since they can't be altered.
-    [[ ${words[(I)-*(f|o)*]} -eq 0 ]] && ctype=" -tp"
-    _arguments -s : \
-	'(-o)-f[allow force by superuser]' \
-	'-s[joblist includes the fix status]' \
-	'(-o -i)-d[discard newly created pending change]' \
-	'(-d -i -f)-o[output specification to standard output]' \
-	'(-d -o)-i[read specification from standard input]' \
-	"(-i)1::change:_perforce_changes$ctype"
+  local ctype
+  # Unless forcing or outputting, we don't
+  # complete committed changes since they can't be altered.
+  [[ ${words[(I)-*(f|o)*]} -eq 0 ]] && ctype=" -tp"
+  _arguments -s : \
+    '(-o)-f[allow force by superuser]' \
+    '-s[joblist includes the fix status]' \
+    '(-o -i)-d[discard newly created pending change]' \
+    '(-d -i -f)-o[output specification to standard output]' \
+    '(-d -o)-i[read specification from standard input]' \
+    "(-i)1::change:_perforce_changes$ctype"
 }
 
 
 (( $+functions[_perforce_cmd_changes] )) ||
 _perforce_cmd_changes() {
-    _arguments -s : \
-      '-i[include integrated changes]' \
-      '-l[long output]' \
-      '-c[select by client]:client:_perforce_clients' \
-      '-m[most recent N changes]:max changes: ' \
-      '-s[select by status]:status:(pending submitted)' \
-      '-u[select by user]:user:_users' \
-      '*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-i[include integrated changes]' \
+    '-l[long output]' \
+    '-c+[select by client]:client:_perforce_clients' \
+    '-m+[most recent N changes]:max changes: ' \
+    '-s+[select by status]:status:(pending submitted)' \
+    '-u+[select by user]:user:_perforce_users' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_client] )) ||
 _perforce_cmd_client() {
-    _arguments -s : \
-	'-f[force modification by superuser]' \
-	'-t[use template]:template client:_perforce_clients' \
-	'(-o -i -t)-d[delete client]' \
-	'(-d -i -f)-o[print to standard output]' \
-	'(-d -o -t)-i[read from standard input]' \
-	'1::file:_perforce_clients'
+  _arguments -s : \
+    '-f[force modification by superuser]' \
+    '-t[use template]:template client:_perforce_clients' \
+    '(-o -i -t)-d[delete client]' \
+    '(-d -i -f)-o[print to standard output]' \
+    '(-d -o -t)-i[read from standard input]' \
+    '1::file:_perforce_clients'
 }
 
 
 (( $+functions[_perforce_cmd_clients] )) ||
 _perforce_cmd_clients() {
-    # No arguments.
-    _arguments -s :
+  # No arguments.
+  _arguments -s :
 }
 
 
 (( $+functions[_perforce_cmd_counter] )) ||
 _perforce_cmd_counter() {
-    _arguments -s : \
-	'-d[delete counter]' \
-	'-f[force setting of internal counter]' \
-	'1:counter:_perforce_counters' \
-	'(-d)2::numeric value:_perforce_counter_values'
+  _arguments -s : \
+    '-d[delete counter]' \
+    '-f[force setting of internal counter]' \
+    '1:counter:_perforce_counters' \
+    '(-d)2::numeric value:_perforce_counter_values'
 }
 
 
 (( $+functions[_perforce_cmd_counters] )) ||
 _perforce_cmd_counters() {
-    # No arguments
-    _arguments -s :
+  # No arguments
+  _arguments -s :
 }
 
 
 (( $+functions[_perforce_cmd_delete] )) ||
 _perforce_cmd_delete() {
-    _arguments -s : \
-	'-c[select change for deletion]:change:_perforce_changes -tp' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-c[select change for deletion]:change:_perforce_changes -tp' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_depot] )) ||
 _perforce_cmd_depot() {
-    _arguments -s : \
-	'-d[delete depot]' \
-	'-o[print to stdout]' \
-	'-i[read name from stdin]' \
-	'(-i)*::depot name:_perforce_depots'
+  _arguments -s : \
+    '-d[delete depot]' \
+    '-o[print to stdout]' \
+    '-i[read name from stdin]' \
+    '(-i)*::depot name:_perforce_depots'
 }
 
 
 (( $+functions[_perforce_cmd_depots] )) ||
 _perforce_cmd_depots() {
-    # No arguments
-    _arguments -s :
+  # No arguments
+  _arguments -s :
 }
 
 
 (( $+functions[_perforce_cmd_describe] )) ||
 _perforce_cmd_describe() {
-    _arguments -s : \
-	'-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
-	'-s[short form]' \
-	'*::change:_perforce_changes'
+  _arguments -s : \
+    '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
+    '-s[short form]' \
+    '*::change:_perforce_changes'
 }
 
 
 (( $+functions[_perforce_cmd_diff] )) ||
 _perforce_cmd_diff() {
-    local limit
-    [[ ${words[(I)-(f|sd|se)]} -eq 0 ]] && limit=" -to"
-    _arguments -s : \
-	'-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
-	'-f[diff every file]' \
-	'(-sd -se -sr)-sa[opened files, different or missing]' \
-	'(-sa -se -sr)-sd[unopened files, missing]' \
-	'(-sa -sd -sr)-se[unopened files, different]' \
-	'(-sa -sd -se)-sr[opened files, same as depot]' \
-	'-t[include non-text files]' \
-	"*::file:_perforce_files$limit"
+  local limit
+  [[ ${words[(I)-(f|sd|se)]} -eq 0 ]] && limit=" -to"
+  _arguments -s : \
+    '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
+    '-f[diff every file]' \
+    '(-sd -se -sr)-sa[opened files, different or missing]' \
+    '(-sa -se -sr)-sd[unopened files, missing]' \
+    '(-sa -sd -sr)-se[unopened files, different]' \
+    '(-sa -sd -se)-sr[opened files, same as depot]' \
+    '-t[include non-text files]' \
+    "*::file:_perforce_files$limit"
 }
 
 
 (( $+functions[_perforce_cmd_diff2] )) ||
 _perforce_cmd_diff2() {
-    _arguments -s : \
-	'-b[specify branch view]:branch name:_perforce_branches' \
-	'-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
-	'-q[only list different files]' \
-	'-t[include non-text files]' \
-	'-u[use patch-friendly output]' \
-	'1::first file:_perforce_files' \
-	'2::second file:_perforce_files'
+  _arguments -s : \
+    '-b[specify branch view]:branch name:_perforce_branches' \
+    '-d-[select diff option]:diff option:((b\:ignore\ blanks c\:context n\:RCS s\:summary u\:unified w\:ignore\ all\ whitespace))' \
+    '-q[only list different files]' \
+    '-t[include non-text files]' \
+    '-u[use patch-friendly output]' \
+    '1::first file:_perforce_files' \
+    '2::second file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_dirs] )) ||
 _perforce_cmd_dirs() {
-    _arguments -s : \
-	'-C[only dirs on current client]' \
-	'-D[include dirs with deleted files]' \
-	'-H[only dirs on the `have'\'' list]' \
-	'*::directory:_perforce_files -td'
+  _arguments -s : \
+    '-C[only dirs on current client]' \
+    '-D[include dirs with deleted files]' \
+    '-H[only dirs on the `have'\'' list]' \
+    '*::directory:_perforce_files -td'
 }
 
 
 (( $+functions[_perforce_cmd_edit] )) ||
 _perforce_cmd_edit() {
-    _arguments -s : \
-	'-c[set change for edit]:change:_perforce_changes -tp' \
-	'-t[set filetype]:filetype:_perforce_filetypes' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-c[set change for edit]:change:_perforce_changes -tp' \
+    '-t[set filetype]:filetype:_perforce_filetypes' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_filelog] )) ||
 _perforce_cmd_filelog() {
-    _arguments -s : \
-	'-i[follow branches]' \
-	'-l[long output, full change text]' \
-	'-m[set maximum number of revisions to show]:max revisions: ' \
-	'-t[include time with date]' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-i[follow branches]' \
+    '-l[long output, full change text]' \
+    '-m[set maximum number of revisions to show]:max revisions: ' \
+    '-t[include time with date]' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_files] )) ||
 _perforce_cmd_files() {
-    _arguments -s : \
-	'-a[display all revisions in given range]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-a[display all revisions in given range]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_fix] )) ||
 _perforce_cmd_fix() {
-    _arguments -s : \
-	'-d[delete the fix]' \
-	'-s[set job status]:status:_perforce_statuses' \
-	'1::-c required:(-c)' \
-	'2::change:_perforce_changes' \
-	'3::job:_perforce_jobs'
+  _arguments -s : \
+    '-d[delete the fix]' \
+    '-s[set job status]:status:_perforce_statuses' \
+    '1::-c required:(-c)' \
+    '2::change:_perforce_changes' \
+    '3::job:_perforce_jobs'
 }
 
 
 (( $+functions[_perforce_cmd_fixes] )) ||
 _perforce_cmd_fixes() {
-    _arguments -s : \
-	'-i[include integrated changes]' \
-	'-j[select by job]:job:_perforce_jobs' \
-	'-c[select by change]:change:_perforce_changes' \
-	'*::fixed file:_perforce_files -tR'
+  _arguments -s : \
+    '-i[include integrated changes]' \
+    '-j[select by job]:job:_perforce_jobs' \
+    '-c[select by change]:change:_perforce_changes' \
+    '*::fixed file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_flush] )) ||
 _perforce_cmd_flush() {
-    _arguments -s : \
-	'-f[force resynchronisation]' \
-	'-n[show operations but don'\''t perform them]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-f[force resynchronisation]' \
+    '-n[show operations but don'\''t perform them]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_fstat] )) ||
 _perforce_cmd_fstat() {
-    _arguments -s : \
-	'-c+[select by change]:change:_perforce_changes -ts' \
-	'-C[select mapped files]' \
-	'-H[select synced files]' \
-	'-W[select opened files]' \
-	'-l[include fileSize, possibly slow]' \
-	'-P[output clientFile in full Perforce syntax]' \
-	'-s[shorten, no client-related data]' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-c+[select by change]:change:_perforce_changes -ts' \
+    '-C[select mapped files]' \
+    '-H[select synced files]' \
+    '-W[select opened files]' \
+    '-l[include fileSize, possibly slow]' \
+    '-P[output clientFile in full Perforce syntax]' \
+    '-s[shorten, no client-related data]' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_group] )) ||
 _perforce_cmd_group() {
-    _arguments -s : \
-	'-d[delete group]' \
-	'-o[output to stdout]' \
-	'-i[read from stdin]' \
-	'1::perforce group:_perforce_groups'
+  _arguments -s : \
+    '-d[delete group]' \
+    '-o[output to stdout]' \
+    '-i[read from stdin]' \
+    '1::perforce group:_perforce_groups'
 }
 
 
 (( $+functions[_perforce_cmd_groups] )) ||
 _perforce_cmd_groups() {
-    _arguments -s : \
-	'1::user name:_users'
+  _arguments -s : \
+    '1::user name:_perforce_users'
 }
 
 
 (( $+functions[_perforce_cmd_have] )) ||
 _perforce_cmd_have() {
-    _perforce_files
+  _perforce_files
 }
 
 
 (( $+functions[_perforce_cmd_help] )) ||
 _perforce_cmd_help() {
-    local hline
-    if (( ! ${#_perforce_help_list} )); then
-	(( ${+_perforce_help_list} )) || typeset -ga _perforce_help_list
-	# All commands have help.
-	(( ${#_perforce_cmd_list} )) || _perforce_gen_cmd_list
-	_perforce_help_list=($_perforce_cmd_list)
-	_perforce_call_p4 help help | while read -A hline; do
-	    if [[ $hline[1] = p4 && $hline[2] = help ]]; then
-		_perforce_help_list+=("$hline[3]:${hline[4,-1]}")
-	    fi
-	done
-    fi
-    _describe -t help-options 'Perforce help option' _perforce_help_list
+  local hline
+  if (( ! ${#_perforce_help_list} )); then
+    (( ${+_perforce_help_list} )) || typeset -ga _perforce_help_list
+    # All commands have help.
+    (( ${#_perforce_cmd_list} )) || _perforce_gen_cmd_list
+    _perforce_help_list=($_perforce_cmd_list)
+    _perforce_call_p4 help help | while read -A hline; do
+      if [[ $hline[1] = p4 && $hline[2] = help ]]; then
+	_perforce_help_list+=("$hline[3]:${hline[4,-1]}")
+      fi
+    done
+  fi
+  _describe -t help-options 'Perforce help option' _perforce_help_list
 }
 
 
 (( $+functions[_perforce_cmd_info] )) ||
 _perforce_cmd_info() {
-    # No arguments
-    _arguments -s :
+  # No arguments
+  _arguments -s :
 }
 
 
 (( $+functions[_perforce_cmd_integrate] )) ||
 _perforce_cmd_integrate() {
-    local range
-    # If -s is present, the first normal argument can't have revRange.
-    [[ ${words[(I)-s]} -eq 0 ]] && range=" -tR"
-    _arguments -s : \
-	'-b[select branch]:branch:_perforce_branches' \
-	'-c[select change for integration]:change:_perforce_changes -tp' \
-	'-f[force reintegration]' \
-	'-d[reintegrated deleted files]' \
-	'-h[integrate to revision had on client]' \
-	'-i[integrate if no common file base]' \
-	'-n[no action, dummy run]' \
-	'-r[reverse direction of integration with branch]' \
-	'-s[select source]:source file:_perforce_files -tR' \
-	'-t[propagate type changes]' \
-	'-v[leave newly branched files uncopied till sync]' \
-	"1:file:_perforce_files$range" \
-	'*::file:_perforce_files'
+  local range
+  # If -s is present, the first normal argument can't have revRange.
+  [[ ${words[(I)-s]} -eq 0 ]] && range=" -tR"
+  _arguments -s : \
+    '-b[select branch]:branch:_perforce_branches' \
+    '-c[select change for integration]:change:_perforce_changes -tp' \
+    '-f[force reintegration]' \
+    '-d[reintegrated deleted files]' \
+    '-h[integrate to revision had on client]' \
+    '-i[integrate if no common file base]' \
+    '-n[no action, dummy run]' \
+    '-r[reverse direction of integration with branch]' \
+    '-s[select source]:source file:_perforce_files -tR' \
+    '-t[propagate type changes]' \
+    '-v[leave newly branched files uncopied till sync]' \
+    "1:file:_perforce_files$range" \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_integrated] )) ||
 _perforce_cmd_integrated() {
-    _perforce_files -ti
+  _perforce_files -ti
 }
 
 
 (( $+functions[_perforce_cmd_job] )) ||
 _perforce_cmd_job() {
-    _arguments -s : \
-	'(-d -o -i)-f[force setting of readonly fields]' \
-	'(-f -o -i)-d[delete job]' \
-	'(-f -d -i)-o[print to stdout]' \
-	'(-d -o)-i[read from stdin]' \
-	'(-i)1::job:_perforce_jobs'
+  _arguments -s : \
+    '(-d -o -i)-f[force setting of readonly fields]' \
+    '(-f -o -i)-d[delete job]' \
+    '(-f -d -i)-o[print to stdout]' \
+    '(-d -o)-i[read from stdin]' \
+    '(-i)1::job:_perforce_jobs'
 }
 
 
 (( $+functions[_perforce_cmd_jobs] )) ||
 _perforce_cmd_jobs() {
-    _arguments -s : \
-	'-e[select by jobview]:jobview:_perforce_jobviews' \
-	'-i[included integrated changes]' \
-	'-l[long output, full job descriptions]' \
-	'-r[reverse order of job names]' \
-	'-m[limit to most recent N jobs]:most recent jobs: ' \
-	'(-e -i -l -m)-R[]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-e[select by jobview]:jobview:_perforce_jobviews' \
+    '-i[included integrated changes]' \
+    '-l[long output, full job descriptions]' \
+    '-r[reverse order of job names]' \
+    '-m[limit to most recent N jobs]:most recent jobs: ' \
+    '(-e -i -l -m)-R[]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_jobspec] )) ||
 _perforce_cmd_jobspec() {
-    _arguments -s : \
-	'-i[read form from stdin]' \
-	'-o[write form from to stdout]'
+  _arguments -s : \
+    '-i[read form from stdin]' \
+    '-o[write form from to stdout]'
 }
 
 
 (( $+functions[_perforce_cmd_label] )) ||
 _perforce_cmd_label() {
-    _arguments -s : \
-	'-f[force operation]' \
-	'-t+[copy template]:template: ' \
-	'(-o -i -t)-d[delete label]' \
-	'(-d -f -i)-o[write to standard output]' \
-	'(-o -d -t)-i[read from standard input]' \
-	'*::label:_perforce_labels'
+  _arguments -s : \
+    '-f[force operation]' \
+    '-t+[copy template]:template: ' \
+    '(-o -i -t)-d[delete label]' \
+    '(-d -f -i)-o[write to standard output]' \
+    '(-o -d -t)-i[read from standard input]' \
+    '*::label:_perforce_labels'
 }
 
 
 (( $+functions[_perforce_cmd_labels] )) ||
 _perforce_cmd_labels() {
-    _arguments -s : \
-	'1::file or revisions which must contain label:_perforce_files -tR'
+  _arguments -s : \
+    '1::file or revisions which must contain label:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_labelsync] )) ||
 _perforce_cmd_labelsync() {
-    _arguments -s : \
-	'-a[add files to label]' \
-	'-d[delete files from label]' \
-	'-n[no effect, dummy run]' \
-	'-l[specify label]:label:_perforce_labels' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-a[add files to label]' \
+    '-d[delete files from label]' \
+    '-n[no effect, dummy run]' \
+    '-l[specify label]:label:_perforce_labels' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_lock] )) ||
 _perforce_cmd_lock() {
-    _arguments -s : \
-	'-c[select by change]:change:_perforce_changes -tp' \
-	'*::file:_perforce_files -to'
+  _arguments -s : \
+    '-c[select by change]:change:_perforce_changes -tp' \
+    '*::file:_perforce_files -to'
 }
 
 
 (( $+functions[_perforce_cmd_logger] )) ||
 _perforce_cmd_logger() {
-    _arguments -s : \
-	'-c[limit by counter no]:number: ' \
-	'-t[use counter instead of logger]:counter:_perforce_counters'
+  _arguments -s : \
+    '-c[limit by counter no]:number: ' \
+    '-t[use counter instead of logger]:counter:_perforce_counters'
 }
 
 
 (( $+functions[_perforce_cmd_obliterate] )) ||
 _perforce_cmd_obliterate() {
-    _message "obliterate is dangerous: you're on your own here."
+  _message "obliterate is dangerous: you're on your own here."
 }
 
 
 (( $+functions[_perforce_cmd_opened] )) ||
 _perforce_cmd_opened() {
-    _arguments -s : \
-	'-a[list for all clients]' \
-	'-c+[select by change]:change:_perforce_changes -tp' \
-	'*::file:_perforce_files -to'
+  _arguments -s : \
+    '-a[list for all clients]' \
+    '-c+[select by change]:change:_perforce_changes -tp' \
+    '*::file:_perforce_files -to'
 }
 
 
 (( $+functions[_perforce_cmd_passwd] )) ||
 _perforce_cmd_passwd() {
-    _arguments -s : : \
-	'-O[explicit old password]:old password: ' \
-	'-P[explicit new password]:new password: ' \
-	'1::user name:_users'
+  _arguments -s : : \
+    '-O[explicit old password]:old password: ' \
+    '-P[explicit new password]:new password: ' \
+    '1::user name:_perforce_users'
 }
 
 
 (( $+functions[_perforce_cmd_print] )) ||
 _perforce_cmd_print() {
-    _arguments -s : \
-	'-a[display all revisions in a range]' \
-	'-o[select output file]:output file:_files' \
-	'-q[suppress header]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-a[display all revisions in a range]' \
+    '-o[select output file]:output file:_files' \
+    '-q[suppress header]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_protect] )) ||
 _perforce_cmd_protect() {
-    _arguments -s : \
-	'-o[write spec to stdout]' \
-	'-i[read spec from stdin]'
+  _arguments -s : \
+    '-o[write spec to stdout]' \
+    '-i[read spec from stdin]'
 }
 
 
 (( $+functions[_perforce_cmd_reopen] )) ||
 _perforce_cmd_reopen() {
-    _arguments -s : \
-	'-c+[select change to reopen on]:change:_perforce_changes -tp' \
-	'-t+[set file type]:file type:_perforce_filetypes' \
-	'*::file:_perforce_files -to'
+  _arguments -s : \
+    '-c+[select change to reopen on]:change:_perforce_changes -tp' \
+    '-t+[set file type]:file type:_perforce_filetypes' \
+    '*::file:_perforce_files -to'
 }
 
 
 (( $+functions[_perforce_cmd_resolve] )) ||
 _perforce_cmd_resolve() {
-    _arguments -s : \
-	'-a-[select automatic merge type]:automation type:((f\:force\ acceptance m\:skip\ conflicts s\:safe t\:use\ theirs y\:use\ yours))' \
-	'-d-[select diff option]:diff option:((b\:ignore\ blanks w\:ignore\ all\ whitespace))' \
-	'-f[force re-resolution]' \
-	'-n[no action, just list]' \
-	'-t[force textual merge on binary files]' \
-	'-v[verbose, mark all changes]' \
-	'*::file:_perforce_files -to'
+  _arguments -s : \
+    '-a-[select automatic merge type]:automation type:((f\:force\ acceptance m\:skip\ conflicts s\:safe t\:use\ theirs y\:use\ yours))' \
+    '-d-[select diff option]:diff option:((b\:ignore\ blanks w\:ignore\ all\ whitespace))' \
+    '-f[force re-resolution]' \
+    '-n[no action, just list]' \
+    '-t[force textual merge on binary files]' \
+    '-v[verbose, mark all changes]' \
+    '*::file:_perforce_files -to'
 }
 
 
 (( $+functions[_perforce_cmd_resolved] )) ||
 _perforce_cmd_resolved() {
-    _perforce_files -tr
+  _perforce_files -tr
 }
 
 
 (( $+functions[_perforce_cmd_revert] )) ||
 _perforce_cmd_revert() {
-    _arguments -s : \
-	'-a[revert unaltered files]' \
-	'-c[limit reversions to change]:change:_perforce_changes -tp' \
-	'-n[no action, show effect only]' \
-	'*::file:_perforce_files -to'
+  _arguments -s : \
+    '-a[revert unaltered files]' \
+    '-c[limit reversions to change]:change:_perforce_changes -tp' \
+    '-n[no action, show effect only]' \
+    '*::file:_perforce_files -to'
 }
 
 
 (( $+functions[_perforce_cmd_review] )) ||
 _perforce_cmd_review() {
-    _arguments -s : \
-	'-c[select change for counter]:change:_perforce_changes -ts' \
-	'-t[limit change number by counter]:counter:_perforce_counters'
+  _arguments -s : \
+    '-c[select change for counter]:change:_perforce_changes -ts' \
+    '-t[limit change number by counter]:counter:_perforce_counters'
 }
 
 
 (( $+functions[_perforce_cmd_reviews] )) ||
 _perforce_cmd_reviews() {
-    _arguments -s : \
-	'-c[show users by change]:change:_perforce_changes -ts' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-c[show users by change]:change:_perforce_changes -ts' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_set] )) ||
 _perforce_cmd_set() {
-    # Only works under Windoze but maybe we are on Cygwin.
-    _arguments -s : \
-	'-s[set for whole system]' \
-	'-S[set for specified service]:service: ' \
-	"*::environment variable:_perforce_variables"
+  # Only works under Windoze but maybe we are on Cygwin.
+  _arguments -s : \
+    '-s[set for whole system]' \
+    '-S[set for specified service]:service: ' \
+    "*::environment variable:_perforce_variables"
 }
 
 
 (( $+functions[_perforce_cmd_submit] )) ||
 _perforce_cmd_submit() {
-    _arguments -s : \
-	'-r[files open for add or edit remain open]' \
-	'-s[include fix status in list]' \
-	'(-s -i)-c[submit specific change]:change:_perforce_changes -tp' \
-	'(-c)-i[read change spec from stdin]' \
-	'*::file:_perforce_files -to -tr' \
+  _arguments -s : \
+    '-r[files open for add or edit remain open]' \
+    '-s[include fix status in list]' \
+    '(-s -i)-c[submit specific change]:change:_perforce_changes -tp' \
+    '(-c)-i[read change spec from stdin]' \
+    '*::file:_perforce_files -to -tr'
 }
 
 
 (( $+functions[_perforce_cmd_sync] )) ||
 _perforce_cmd_sync() {
-    _arguments -s : \
-	'-f[force resynchronisation]' \
-	'-n[show operations but don'\''t perform them]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-f[force resynchronisation]' \
+    '-n[show operations but don'\''t perform them]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_triggers] )) ||
 _perforce_cmd_triggers() {
-    _arguments -s : \
-	'-o[output form to stdout]' \
-	'-i[read from from stdin]'
+  _arguments -s : \
+    '-o[output form to stdout]' \
+    '-i[read from from stdin]'
 }
 
 
 (( $+functions[_perforce_cmd_typemap] )) ||
 _perforce_cmd_typemap() {
-    _arguments -s : \
-	'-o[output table to stdout]' \
-	'-i[read table from stdin]'
+  _arguments -s : \
+    '-o[output table to stdout]' \
+    '-i[read table from stdin]'
 }
 
 
 (( $+functions[_perforce_cmd_unlock] )) ||
 _perforce_cmd_unlock() {
-    _arguments -s : \
-	'-c[non-default change to unlock]:change:_perforce_changes -tp' \
-	'-f[allow superuser to unlock any file]' \
-	'*::file:_perforce_files'
+  _arguments -s : \
+    '-c[non-default change to unlock]:change:_perforce_changes -tp' \
+    '-f[allow superuser to unlock any file]' \
+    '*::file:_perforce_files'
 }
 
 
 (( $+functions[_perforce_cmd_user] )) ||
 _perforce_cmd_user() {
-    _arguments -s : \
-	'(-o)-f[force edit by superuser]' \
-	'(-o -i)-d[delete user]' \
-	'(-o -d)-i[read form from stdin]' \
-	'(-f -i -d)-o[write form to stdout]' \
-	'(-i)1::username:_users'
+  _arguments -s : \
+    '(-o)-f[force edit by superuser]' \
+    '(-o -i)-d[delete user]' \
+    '(-o -d)-i[read form from stdin]' \
+    '(-f -i -d)-o[write form to stdout]' \
+    '(-i)1::username:_perforce_users'
 }
 
 
 (( $+functions[_perforce_cmd_users] )) ||
 _perforce_cmd_users() {
-    _arguments -s : \
-	'*::username:_users'
+  _arguments -s : \
+    '*::username:_perforce_users'
 }
 
 
 (( $+functions[_perforce_cmd_verify] )) ||
 _perforce_cmd_verify() {
-    _arguments -s : \
-	'-q[operate quietly]' \
-	'-u[compute and save digest if missing]' \
-	'-v[compute and save all digets]' \
-	'*::file:_perforce_files -tR'
+  _arguments -s : \
+    '-q[operate quietly]' \
+    '-u[compute and save digest if missing]' \
+    '-v[compute and save all digets]' \
+    '*::file:_perforce_files -tR'
 }
 
 
 (( $+functions[_perforce_cmd_where] )) ||
 _perforce_cmd_where() {
-    _perforce_files
+  _perforce_files
 }