summaryrefslogtreecommitdiff
path: root/Completion/Unix/Command
diff options
context:
space:
mode:
Diffstat (limited to 'Completion/Unix/Command')
-rw-r--r--Completion/Unix/Command/_darcs508
1 files changed, 501 insertions, 7 deletions
diff --git a/Completion/Unix/Command/_darcs b/Completion/Unix/Command/_darcs
index 7aa57643b..fe5c9842f 100644
--- a/Completion/Unix/Command/_darcs
+++ b/Completion/Unix/Command/_darcs
@@ -1,11 +1,505 @@
#compdef darcs
-if (($CURRENT == 2)); then
- # We're completing the first word after "darcs" -- the command.
- _wanted command expl 'darcs command' \
- compadd -- $( darcs --commands )
+# EXTENDED_GLOB is required fr pattern backreferences.
+setopt EXTENDED_GLOB
+
+local DARCS=$words[1]
+
+# test whether to hide short options from completion
+autoload is-at-least
+local hide_short
+if zstyle -s ":completion:${curcontext}" hide-shortopts hide_short; then
+ case $hide_short in
+ true|yes|on|1) hide_short='!' ;;
+ *) hide_short='' ;;
+ esac
else
- # Find the options/files/URL/etc. for the current command by using darcs.
- _wanted args expl 'arg for darcs command' \
- compadd -- $( darcs ${words[2]} --list-option )
+ is-at-least 4.1 || hide_short='!'
fi
+
+
+
+_darcs_main() {
+# Based on section 6.8 of _A User's Guide to the Z-Shell_ by Peter Stephenson.
+# Also based on the tla completion module by Jason McCarty. How do I credit
+# this?
+local DARCS=$words[1]
+local arguments
+local curcontext="$curcontext"
+
+if (( CURRENT > 2 )); then
+ local cmd=${words[2]}
+ local var_cmd=cmd_${cmd//-/_}
+ curcontext="${curcontext%:*:*}:darcs-${cmd}:"
+ (( CURRENT-- ))
+ shift words
+
+ local short long arg desc action
+ short=()
+ long=()
+ arg=()
+ desc=()
+ action=()
+ arguments=()
+
+ # Collect all help lines which have a leading space.
+ local input
+ input=(${(f)"$($DARCS $cmd -h)"})
+ input=(${input:#[^\ ]*})
+ local i
+ for (( i=1 ; i <= ${#input} ; i++ )); do
+ # Assumption: the the argument descriptions from `darcs cmd -h`
+ # have the following format:
+ # [spaces]<-f>[spaces][--flag]<=<spaces>argument>[spaces][description]
+ [[ "$input[i]" = (#b)' '#(-?|)' '#([^' ']#|)' '#(--[^=' ']#)(=([^' ']#)|)' '#(*) ]] \
+ || _message -e messages "cannot parse command help output." || return 1
+
+ short[i]="$match[1]"
+ long[i]="$match[3]"
+ arg[i]="$match[5]"
+ desc[i]="$match[6]"
+ desc[i]="${${desc[i]//\[/\\[}//\]/\\]}" # escape brackets
+
+ case $arg[i] in
+ DIRECTORY)
+ action[i]='_files -/' ;;
+ FILE|FILENAME|IDFILE|KEYS)
+ action[i]='_files' ;;
+ USERNAME)
+ action[i]='_users' ;;
+ EMAIL|FROM)
+ action[i]='_email_addresses' ;;
+ *)
+ action[i]='' ;;
+ esac
+ done
+
+ # Compute the exludes for _arguments
+
+ local excluded short_excluded long_excluded k
+
+ for (( i=1 ; i <= ${#input} ; i++ )); do
+ excluded=()
+ for opt (${=excludes[$long[i]]}); do
+ k=$long[(i)$opt]
+ excluded=($excluded $short[k] $long[k])
+ done
+
+ # Generate arguments for _arguments.
+ # Make long and short options mutually exclusive.
+ short_excluded=($long[i] $excluded)
+ long_excluded=($short[i] $excluded)
+ [ $short[i] ] && arguments=("$arguments[@]"
+ "${hide_short}(${short_excluded})${short[i]}[${desc[i]}]${arg[i]:+:$arg[i]:$action[i]}")
+ [ $long[i] ] && arguments=("$arguments[@]"
+ "(${long_excluded})${long[i]}${arg[i]:+=}[${desc[i]}]${arg[i]:+:$arg[i]:$action[i]}")
+ done
+
+ arguments=("$arguments[@]" "${(@P)var_cmd-*:FILE:_files}")
+else
+ local hline
+ local -a cmdlist
+ _call_program help-commands darcs --help | while read -A hline; do
+ (( ${#hline} < 2 )) && continue
+ [[ $hline[1] == darcs ]] && continue
+ [[ $hline[1] == Usage: ]] && continue
+ [[ $hline[1] == Use ]] && continue
+ cmdlist=( $cmdlist "${hline[1]}:${hline[2,-1]}" )
+ done
+ arguments=(':commands:(($cmdlist))')
+fi
+
+_arguments -S -A '-*' \
+ "$arguments[@]"
+}
+
+
+
+#
+# Command argument definitions
+#
+local -a cmd_initialize cmd_get
+cmd_initialize=()
+cmd_get=(':repository:_files -/' ':new repository name:_files -/')
+
+local -a cmd_add cmd_remove cmd_move cmd_replace
+cmd_add=('*:new files:_darcs_new_file_or_tree')
+cmd_remove=('*:existing controlled files:_darcs_controlled_files -e')
+cmd_move=('*:existing controlled files:_darcs_controlled_files -e')
+cmd_replace=(':old token:' ':new token:' '*:existing controlled files:_darcs_controlled_files -e')
+
+local -a cmd_record cmd_pull cmd_push cmd_send cmd_apply
+cmd_record=('*:controlled files:_darcs_controlled_files')
+cmd_pull=(':repository:_darcs_repository_or_tree')
+cmd_push=(':repository:_darcs_repository_or_tree')
+cmd_send=(':repository:_darcs_repository_or_tree')
+cmd_apply=(':patch file:_files')
+
+local -a cmd_whatsnew cmd_changes
+cmd_whatsnew=('*:controlled files:_darcs_controlled_files')
+cmd_changes=('*:controlled files:_darcs_controlled_files')
+
+local -a cmd_tag cmd_setpref cmd_check cmd_optimize
+cmd_tag=()
+cmd_setpref=(':preference key:(test predist boringfile binaries)' ':value:_files')
+cmd_check=()
+cmd_optimize=()
+
+local -a cmd_amend_record cmd_rollback cmd_unrecord cmd_unpull cmd_revert cmd_unrevert
+cmd_amend_record=('*:controlled files:_darcs_controlled_files')
+cmd_rollback=()
+cmd_unrecord=()
+cmd_unpull=()
+cmd_revert=('*:controlled files:_darcs_controlled_files')
+cmd_unrevert=()
+
+local -a cmd_diff cmd_annotate
+cmd_diff=('*:controlled files:_darcs_controlled_files')
+cmd_annotate=('*:controlled files:_darcs_controlled_files')
+
+local -a cmd_resolve cmd_dist cmd_trackdown cmd_repair
+cmd_resolve=()
+cmd_dist=()
+cmd_trackdown=(':initialization:' ':command:')
+cmd_repair=()
+
+
+#
+# Completion functions
+#
+
+(( $+functions[_darcs_new_files] )) ||
+_darcs_new_files () {
+ local -a new_files
+ local -a local_files
+ local in_tree_head in_tree_tail
+ _darcs_make_tree_path in_tree_head in_tree_tail || return 1
+ new_files=(${(f)"$(cd $(_darcs_absolute_tree_root)/$in_tree_head; $DARCS whatsnew -sl .)"})
+ new_files=(${${new_files:#[^a]*}//a /})
+
+ local_files=()
+ for file ($new_files); do
+ [[ $file:h = $in_tree_head && $file:t = ${in_tree_tail}* ]] && local_files+=$file:t
+ done
+
+ compset -P '*/'
+ _description new_files expl "new files"
+ compadd "$expl[@]" "$local_files[@]"
+}
+
+
+
+
+# _darcs_controlled_files [-e|r] [-f|d]
+#
+# Adds controlled files to the completion. Can take either
+# -e or -r as flags which respectively only add the existing
+# files or the deleted files. Can take either -f or -d which
+# respectively add only the files or directories.
+(( $+functions[_darcs_controlled_files] )) ||
+_darcs_controlled_files() {
+ local abs_root=$(_darcs_absolute_tree_root)
+ local only_removed only_existing only_files only_dirs
+ zparseopts -E \
+ 'r=only_removed' 'e=only_existing' \
+ 'f=only_files' 'd=only_dirs'
+
+ local in_tree_head in_tree_tail
+ _darcs_make_tree_path in_tree_head in_tree_tail
+ local recorded_dir="$abs_root/_darcs/current/$in_tree_head"
+ local -a controlled_files controlled_dirs existing_files existing_dirs
+ local -a dir_display_strs removed_dir_display_strs
+ controlled_files=${(z)$(print $recorded_dir/$in_tree_tail*(.:t))}
+ controlled_dirs=${(z)$(print $recorded_dir/$in_tree_tail*(/:t))}
+ existing_files=() existing_dirs=()
+ removed_files=() removed_dirs=()
+ dir_display_strs=() removed_dir_display_strs=()
+ local dir file
+ for dir ($controlled_dirs); do
+ if [[ -e $abs_root/$in_tree_head/$dir ]]; then
+ existing_dirs+="$dir"
+ dir_display_strs+="$dir/"
+ else
+ removed_dirs+="$dir"
+ removed_dir_display_strs+="$dir/"
+ fi
+ done
+ for file ($controlled_files); do
+ if [[ -e $abs_root/$in_tree_head/$file ]]; then
+ existing_files+="$file"
+ else
+ removed_files+="$file"
+ fi
+ done
+
+ compset -P '*/'
+ if (( ! ${#only_removed} )); then
+ _description controlled_files expl "existing revision controlled files"
+ (( ! ${#only_dirs} )) && compadd "$expl[@]" $existing_files
+ (( ! ${#only_files} )) \
+ && compadd "$expl[@]" -q -S / -d dir_display_strs -a -- existing_dirs
+ fi
+ if (( ! ${#only_existing} )); then
+ _description removed_files expl "removed revision controlled files"
+ (( ! ${#only_dirs} )) && compadd "$expl[@]" $removed_files
+ (( ! ${#only_files} )) \
+ && compadd "$expl[@]" -q -S / -d removed_dir_display_strs -a -- removed_dirs
+ fi
+}
+
+(( $+functions[_darcs_repositories] )) ||
+_darcs_repositories() {
+ local local_repos_path="$(_darcs_absolute_tree_root)/_darcs/prefs/repos"
+ local global_repos_path="$HOME/.darcs/repos"
+ local -a local_repos global_repos
+ local -a global_repos
+ [[ -e $local_repos_path ]] && cat $local_repos_path | read -A local_repos
+ [[ -e $global_repos_path ]] && cat $global_repos_path | read -A global_repos
+ local_repos=${local_repos:# #}
+ global_repos=${global_repos:# #}
+ _description repositories expl "repositories"
+ (( ${#local_repos} )) && compadd "$expl[@]" -- "$local_repos[@]"
+ (( ${#global_repos} )) && compadd "$expl[@]" -- "$global_repos[@]"
+}
+
+
+
+# Combination completion functions
+
+(( $+functions[_darcs_new_file_or_tree] )) ||
+_darcs_new_file_or_tree() {
+ local base_dir=$( cd ${$(_darcs_repodir):-.}; pwd -P)
+ [[ -z $(_darcs_absolute_tree_root $base_dir) ]] && return 1
+ local -a ignored_files
+ ignored_files=(_darcs)
+ _alternative 'newfiles:new file:_darcs_new_files' \
+ "directories:tree:_path_files -/ -W$base_dir -Fignored_files"
+}
+
+(( $+functions[_darcs_repository_or_tree] )) ||
+_darcs_repository_or_tree() {
+ local -a ignored_files
+ ignored_files=(_darcs)
+ _alternative 'repository:repository:_darcs_repositories' \
+ "directories:directories:_path_files -/ -Fignored_files"
+}
+
+
+#
+# Mutually exclusive options
+#
+
+typeset -A excludes
+excludes=(
+# Output
+ --summary '--no-summary'
+ --no-summary '--summary'
+ --context ' --xml-output --human-readable --unified'
+ --xml-output '--context --human-readable --unified'
+ --human-readable '--context --xml-output --unified'
+ --unified '--context --xml-output --human-readable '
+
+# Verbosity
+ --verbose ' --quiet --standard-verbosity'
+ --quiet '--verbose --standard-verbosity'
+ --standard-verbosity '--verbose --quiet '
+
+# Traversal
+ --recursive '--not-recursive'
+ --not-recursive '--recursive'
+ --look-for-adds '--dont-look-for-adds'
+ --dont-look-for-adds '--look-for-adds'
+
+# Pattern
+ --from-match ' --from-patch --from-tag'
+ --from-patch '--from-match --from-tag'
+ --from-tag '--from-patch --from-match '
+ --to-match ' --to-patch -to-tag'
+ --to-patch '--to-match -to-tag'
+ --to-tag '--to-match --to-patch '
+
+# Repository Properties
+ --plain-pristine-tree '--no-pristine-tree'
+ --no-pristine-tree '--plain-pristine-tree'
+ --parial '--complete'
+ --complete '--partial'
+ --compress '--dont-compress'
+ --dont-compress '--compress'
+ --set-default '--no-set-default'
+ --no-set-default '--set-default'
+
+# Logs
+ --edit-long-comment '--skip-long-comment --leave-test-directory'
+ --skip-long-comment '--edit-long-comment --leave-test-directory'
+ --prompt-long-comment '--edit-long-comment --skip-long-comment'
+
+# Security
+ --sign ' --sign-as --sign-ssl --dont-sign'
+ --sign-as '--sign --sign-ssl --dont-sign'
+ --sign-ssl '--sign --sign-as --dont-sign'
+ --dont-sign '--sign --sign-as --sign-ssl '
+ --verify ' --verify-ssl --no-verify'
+ --verify-ssl '--verify --no-verify'
+ --no-verify '--verify --verify-ssl '
+ --apply-as '--apply-as-myself'
+ --apply-as-myself '--apply-as'
+
+# Conflicts
+ --mark-conflicts '--allow-conflicts --no-resolve-conflicts --dont-allow-conflicts'
+ --allow-conflicts '--mark-conflicts --no-resolve-conflicts --dont-allow-conflicts'
+ --no-resolve-conflicts '--mark-conflicts --allow-conflicts --dont-allow-conflicts'
+ --dont-allow-conflicts '--mark-conflicts --allow-conflicts --no-resolve-conflicts '
+
+# Test
+ --test '--no-test'
+ --no-test '--test'
+ --leave-test-directory '--remove-test-directory'
+ --remove-test-directory '--leave-test-directory'
+
+# Misc
+ --force '--no-force'
+ --no-force '--force'
+ --ask-deps '--no-ask-deps'
+ --no-ask-deps '--ask-deps'
+ --date-trick '--no-date-trick'
+ --no-date-trick '--date-trick'
+ --set-scripts-executable '--dont-set-scripts-executable'
+ --dont-set-scripts-executable '--set-scripts-executable'
+)
+
+
+
+#
+# Utility functions
+#
+
+# _darcs_make_tree_path in_tree_head_name in_tree_tail_name path
+# Set in_tree_head_name in_tree_tail_name to the corresponding path
+# parts from inside the current darcs tree.
+_darcs_make_tree_path () {
+ [[ -z $3 || $3 = '.' ]] && 3=${PREFIX:-./}
+ local _in_tree=$(_darcs_path_from_root ${$(_darcs_repodir):-.}/$3)
+ [[ -z $_in_tree ]] && return 1
+ 4='' 5=''
+ if [[ ${3[-1]} = / ]]; then
+ 4=$_in_tree
+ else
+ 4=$_in_tree:h
+ [[ $_in_tree:t != . ]] && 5=$_in_tree:t
+ fi
+ set -A "$1" "$4"
+ set -A "$2" "$5"
+}
+
+_darcs_repodir () {
+ local index=$words[(i)--repodir*]
+ if (( index < CURRENT )); then
+ if [[ $words[$index] = --repodir ]]; then
+ (( index++ ))
+ print $words[$index]
+ else
+ print ${words[$index]#*=}
+ fi
+ fi
+}
+
+_darcs_absolute_tree_root () {
+ local root=$(_darcs_repodir)
+ [[ -z $root ]] && root=$(pwd -P)
+ while [[ ! $root -ef / ]]; do
+ [[ -d $root/_darcs ]] && break
+ root="$root/.."
+ done
+ [[ $root -ef / ]] || print $(cd $root; pwd -P)
+}
+
+_darcs_tree_root () {
+ local abs=$(_darcs_absolute_tree_root)
+ local rel=$(_darcs_relative_path $abs $(pwd -P))
+ [[ -n $abs ]] && print $rel
+}
+
+# _darcs_paths_from_root name paths
+# Sets name to the paths relative to the darcs tree root.
+# If no argument is given then the current directory
+# is assumed.
+_darcs_paths_from_root () {
+ local name=$1
+ abs=$(_darcs_absolute_tree_root)
+ [[ -z $abs ]] && set -A "$name" && return 1
+ shift
+ 1=${1:=$PWD}
+ local -a subpaths
+ _darcs_filter_for_subpaths subpaths $abs $*
+ local i
+ for (( i=1; i<=${#subpaths}; i++ )); do
+ [[ $subpaths[$i] != '.' ]] && subpaths[$i]="./$subpaths[$i]"
+ done
+ set -A "$name" "$subpaths[@]"
+}
+
+_darcs_path_from_root() {
+ local path
+ _darcs_paths_from_root path $1
+ [[ -n $path ]] && print "$path"
+}
+
+# _darcs_filter_for_in_dir name dir paths
+# Sets name to the relative paths from dir to the given paths which
+# traverse dir. It ignores paths which are not in dir.
+_darcs_filter_for_subpaths () {
+ local name=$1 dir=$2
+ shift 2
+ local p rel
+ local -a accepted_paths
+ accepted_paths=()
+ for p; do
+ rel=$(_darcs_path_difference $p $dir)
+ [[ -n $rel ]] && accepted_paths+="$rel"
+ done
+ set -A "$name" "$accepted_paths[@]"
+}
+
+# _darcs_path_difference p1 p2
+# Print the path from p2 to p1. If p2 is not an ancestor of p1 then it
+# prints a blank string. If they point to the same directory then it returns
+# a single period. p2 needs to be a directory path.
+_darcs_path_difference () {
+ local diff=$(_darcs_relative_path $1 $2)
+ [[ ${diff%%/*} != .. ]] && print $diff || return 1
+}
+
+
+# Print the a relative path from the second directory to the first,
+# defaulting the second directory to $PWD if none is specified.
+# Taken from the zsh mailing list.
+_darcs_relative_path () {
+ 2=${2:=$PWD}
+ [[ -d $2 && -d $1:h ]] || return 1
+ [[ ! -d $1 ]] && 3=$1:t 1=$1:h
+ 1=$(cd $1; pwd -P)
+ 2=$(cd $2; pwd -P)
+ [[ $1 -ef $2 ]] && print ${3:-.} && return
+
+ local -a cur abs
+ cur=(${(s:/:)2}) # Split 'current' directory into cur
+ abs=(${(s:/:)1} $3) # Split target directory into abs
+
+ # Compute the length of the common prefix, or discover a subdiretory:
+ integer i=1
+ while [[ i -le $#abs && $abs[i] == $cur[i] ]]
+ do
+ ((++i > $#cur)) && print ${(j:/:)abs[i,-1]} && return
+ done
+
+ 2=${(j:/:)cur[i,-1]/*/..} # Up to the common prefix directory and
+ 1=${(j:/:)abs[i,-1]} # down to the target directory or file
+
+ print $2${1:+/$1}
+}
+
+# Code to make sure _darcs is run when we load it
+_darcs_main "$@"
+
+
+