|
|
# bash completion for the Mercurial distributed SCM
|
|
|
|
|
|
# Docs:
|
|
|
#
|
|
|
# If you source this file from your .bashrc, bash should be able to
|
|
|
# complete a command line that uses hg with all the available commands
|
|
|
# and options and sometimes even arguments.
|
|
|
#
|
|
|
# Mercurial allows you to define additional commands through extensions.
|
|
|
# Bash should be able to automatically figure out the name of these new
|
|
|
# commands and their options. See below for how to define _hg_opt_foo
|
|
|
# and _hg_cmd_foo functions to fine-tune the completion for option and
|
|
|
# non-option arguments, respectively.
|
|
|
#
|
|
|
#
|
|
|
# Notes about completion for specific commands:
|
|
|
#
|
|
|
# - the completion function for the email command from the patchbomb
|
|
|
# extension will try to call _hg_emails to get a list of e-mail
|
|
|
# addresses. It's up to the user to define this function. For
|
|
|
# example, put the addresses of the lists that you usually patchbomb
|
|
|
# in ~/.patchbomb-to and the addresses that you usually use to send
|
|
|
# the patchbombs in ~/.patchbomb-from and use something like this:
|
|
|
#
|
|
|
# _hg_emails()
|
|
|
# {
|
|
|
# if [ -r ~/.patchbomb-$1 ]; then
|
|
|
# cat ~/.patchbomb-$1
|
|
|
# fi
|
|
|
# }
|
|
|
#
|
|
|
#
|
|
|
# Writing completion functions for additional commands:
|
|
|
#
|
|
|
# If it exists, the function _hg_cmd_foo will be called without
|
|
|
# arguments to generate the completion candidates for the hg command
|
|
|
# "foo". If the command receives some arguments that aren't options
|
|
|
# even though they start with a "-", you can define a function called
|
|
|
# _hg_opt_foo to generate the completion candidates. If _hg_opt_foo
|
|
|
# doesn't return 0, regular completion for options is attempted.
|
|
|
#
|
|
|
# In addition to the regular completion variables provided by bash,
|
|
|
# the following variables are also set:
|
|
|
# - $hg - the hg program being used (e.g. /usr/bin/hg)
|
|
|
# - $cmd - the name of the hg command being completed
|
|
|
# - $cmd_index - the index of $cmd in $COMP_WORDS
|
|
|
# - $cur - the current argument being completed
|
|
|
# - $prev - the argument before $cur
|
|
|
# - $global_args - "|"-separated list of global options that accept
|
|
|
# an argument (e.g. '--cwd|-R|--repository')
|
|
|
# - $canonical - 1 if we canonicalized $cmd before calling the function
|
|
|
# 0 otherwise
|
|
|
#
|
|
|
|
|
|
shopt -s extglob
|
|
|
|
|
|
_hg_commands()
|
|
|
{
|
|
|
local commands
|
|
|
commands="$("$hg" debugcomplete "$cur" 2>/dev/null)" || commands=""
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_paths()
|
|
|
{
|
|
|
local paths="$("$hg" paths 2>/dev/null | sed -e 's/ = .*$//')"
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_repos()
|
|
|
{
|
|
|
local i
|
|
|
for i in $(compgen -d -- "$cur"); do
|
|
|
test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i")
|
|
|
done
|
|
|
}
|
|
|
|
|
|
_hg_status()
|
|
|
{
|
|
|
local files="$("$hg" status -n$1 . 2>/dev/null)"
|
|
|
local IFS=$'\n'
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_tags()
|
|
|
{
|
|
|
local tags="$("$hg" tags -q 2>/dev/null)"
|
|
|
local IFS=$'\n'
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$tags' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_branches()
|
|
|
{
|
|
|
local branches="$("$hg" branches -q 2>/dev/null)"
|
|
|
local IFS=$'\n'
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$branches' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
# this is "kind of" ugly...
|
|
|
_hg_count_non_option()
|
|
|
{
|
|
|
local i count=0
|
|
|
local filters="$1"
|
|
|
|
|
|
for ((i=1; $i<=$COMP_CWORD; i++)); do
|
|
|
if [[ "${COMP_WORDS[i]}" != -* ]]; then
|
|
|
if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then
|
|
|
continue
|
|
|
fi
|
|
|
count=$(($count + 1))
|
|
|
fi
|
|
|
done
|
|
|
|
|
|
echo $(($count - 1))
|
|
|
}
|
|
|
|
|
|
_hg()
|
|
|
{
|
|
|
local cur prev cmd cmd_index opts i
|
|
|
# global options that receive an argument
|
|
|
local global_args='--cwd|-R|--repository'
|
|
|
local hg="$1"
|
|
|
local canonical=0
|
|
|
|
|
|
COMPREPLY=()
|
|
|
cur="$2"
|
|
|
prev="$3"
|
|
|
|
|
|
# searching for the command
|
|
|
# (first non-option argument that doesn't follow a global option that
|
|
|
# receives an argument)
|
|
|
for ((i=1; $i<=$COMP_CWORD; i++)); do
|
|
|
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
|
|
if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
|
|
|
cmd="${COMP_WORDS[i]}"
|
|
|
cmd_index=$i
|
|
|
break
|
|
|
fi
|
|
|
fi
|
|
|
done
|
|
|
|
|
|
if [[ "$cur" == -* ]]; then
|
|
|
if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
opts=$("$hg" debugcomplete --options "$cmd" 2>/dev/null)
|
|
|
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur"))
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
# global options
|
|
|
case "$prev" in
|
|
|
-R|--repository)
|
|
|
_hg_paths
|
|
|
_hg_repos
|
|
|
return
|
|
|
;;
|
|
|
--cwd)
|
|
|
# Stick with default bash completion
|
|
|
return
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then
|
|
|
_hg_commands
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
# try to generate completion candidates for whatever command the user typed
|
|
|
local help
|
|
|
if _hg_command_specific; then
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
# canonicalize the command name and try again
|
|
|
help=$("$hg" help "$cmd" 2>/dev/null)
|
|
|
if [ $? -ne 0 ]; then
|
|
|
# Probably either the command doesn't exist or it's ambiguous
|
|
|
return
|
|
|
fi
|
|
|
cmd=${help#hg }
|
|
|
cmd=${cmd%%[$' \n']*}
|
|
|
canonical=1
|
|
|
_hg_command_specific
|
|
|
}
|
|
|
|
|
|
_hg_command_specific()
|
|
|
{
|
|
|
if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then
|
|
|
"_hg_cmd_$cmd"
|
|
|
return 0
|
|
|
fi
|
|
|
|
|
|
if [ "$cmd" != status ] && [ "$prev" = -r ] || [ "$prev" == --rev ]; then
|
|
|
if [ $canonical = 1 ]; then
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
return 0
|
|
|
elif [[ status != "$cmd"* ]]; then
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
return 0
|
|
|
else
|
|
|
return 1
|
|
|
fi
|
|
|
fi
|
|
|
|
|
|
case "$cmd" in
|
|
|
help)
|
|
|
_hg_commands
|
|
|
;;
|
|
|
export)
|
|
|
if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then
|
|
|
return 0
|
|
|
fi
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
;;
|
|
|
manifest|update)
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
;;
|
|
|
pull|push|outgoing|incoming)
|
|
|
_hg_paths
|
|
|
_hg_repos
|
|
|
;;
|
|
|
paths)
|
|
|
_hg_paths
|
|
|
;;
|
|
|
add)
|
|
|
_hg_status "u"
|
|
|
;;
|
|
|
merge)
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
;;
|
|
|
commit)
|
|
|
_hg_status "mar"
|
|
|
;;
|
|
|
remove)
|
|
|
_hg_status "d"
|
|
|
;;
|
|
|
forget)
|
|
|
_hg_status "a"
|
|
|
;;
|
|
|
diff)
|
|
|
_hg_status "mar"
|
|
|
;;
|
|
|
revert)
|
|
|
_hg_status "mard"
|
|
|
;;
|
|
|
clone)
|
|
|
local count=$(_hg_count_non_option)
|
|
|
if [ $count = 1 ]; then
|
|
|
_hg_paths
|
|
|
fi
|
|
|
_hg_repos
|
|
|
;;
|
|
|
debugindex|debugindexdot)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur"))
|
|
|
;;
|
|
|
debugdata)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur"))
|
|
|
;;
|
|
|
*)
|
|
|
return 1
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
return 0
|
|
|
}
|
|
|
|
|
|
complete -o bashdefault -o default -F _hg hg 2>/dev/null \
|
|
|
|| complete -o default -F _hg hg
|
|
|
|
|
|
|
|
|
# Completion for commands provided by extensions
|
|
|
|
|
|
# bookmarks
|
|
|
_hg_bookmarks()
|
|
|
{
|
|
|
local bookmarks="$("$hg" bookmarks --quiet 2>/dev/null )"
|
|
|
local IFS=$'\n'
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$bookmarks' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_cmd_bookmarks()
|
|
|
{
|
|
|
if [[ "$prev" = @(-d|--delete|-m|--rename) ]]; then
|
|
|
_hg_bookmarks
|
|
|
return
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
# mq
|
|
|
_hg_ext_mq_patchlist()
|
|
|
{
|
|
|
local patches
|
|
|
patches=$("$hg" $1 2>/dev/null)
|
|
|
if [ $? -eq 0 ] && [ "$patches" ]; then
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur"))
|
|
|
return 0
|
|
|
fi
|
|
|
return 1
|
|
|
}
|
|
|
|
|
|
_hg_ext_mq_queues()
|
|
|
{
|
|
|
local root=$("$hg" root 2>/dev/null)
|
|
|
local n
|
|
|
for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do
|
|
|
# I think we're usually not interested in the regular "patches" queue
|
|
|
# so just filter it.
|
|
|
if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} "$n")
|
|
|
fi
|
|
|
done
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qpop()
|
|
|
{
|
|
|
if [[ "$prev" = @(-n|--name) ]]; then
|
|
|
_hg_ext_mq_queues
|
|
|
return
|
|
|
fi
|
|
|
_hg_ext_mq_patchlist qapplied
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qpush()
|
|
|
{
|
|
|
if [[ "$prev" = @(-n|--name) ]]; then
|
|
|
_hg_ext_mq_queues
|
|
|
return
|
|
|
fi
|
|
|
_hg_ext_mq_patchlist qunapplied
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qgoto()
|
|
|
{
|
|
|
if [[ "$prev" = @(-n|--name) ]]; then
|
|
|
_hg_ext_mq_queues
|
|
|
return
|
|
|
fi
|
|
|
_hg_ext_mq_patchlist qseries
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qdelete()
|
|
|
{
|
|
|
local qcmd=qunapplied
|
|
|
if [[ "$prev" = @(-r|--rev) ]]; then
|
|
|
qcmd=qapplied
|
|
|
fi
|
|
|
_hg_ext_mq_patchlist $qcmd
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qsave()
|
|
|
{
|
|
|
if [[ "$prev" = @(-n|--name) ]]; then
|
|
|
_hg_ext_mq_queues
|
|
|
return
|
|
|
fi
|
|
|
}
|
|
|
|
|
|
_hg_cmd_strip()
|
|
|
{
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qcommit()
|
|
|
{
|
|
|
local root=$("$hg" root 2>/dev/null)
|
|
|
# this is run in a sub-shell, so we can't use _hg_status
|
|
|
local files=$(cd "$root/.hg/patches" 2>/dev/null &&
|
|
|
"$hg" status -nmar 2>/dev/null)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qfold()
|
|
|
{
|
|
|
_hg_ext_mq_patchlist qunapplied
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qrename()
|
|
|
{
|
|
|
_hg_ext_mq_patchlist qseries
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qheader()
|
|
|
{
|
|
|
_hg_ext_mq_patchlist qseries
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qclone()
|
|
|
{
|
|
|
local count=$(_hg_count_non_option)
|
|
|
if [ $count = 1 ]; then
|
|
|
_hg_paths
|
|
|
fi
|
|
|
_hg_repos
|
|
|
}
|
|
|
|
|
|
_hg_ext_mq_guards()
|
|
|
{
|
|
|
"$hg" qselect --series 2>/dev/null | sed -e 's/^.//'
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qselect()
|
|
|
{
|
|
|
local guards=$(_hg_ext_mq_guards)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_cmd_qguard()
|
|
|
{
|
|
|
local prefix=''
|
|
|
|
|
|
if [[ "$cur" == +* ]]; then
|
|
|
prefix=+
|
|
|
elif [[ "$cur" == -* ]]; then
|
|
|
prefix=-
|
|
|
fi
|
|
|
local ncur=${cur#[-+]}
|
|
|
|
|
|
if ! [ "$prefix" ]; then
|
|
|
_hg_ext_mq_patchlist qseries
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
local guards=$(_hg_ext_mq_guards)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur"))
|
|
|
}
|
|
|
|
|
|
_hg_opt_qguard()
|
|
|
{
|
|
|
local i
|
|
|
for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
|
|
|
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
|
|
if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
|
|
|
_hg_cmd_qguard
|
|
|
return 0
|
|
|
fi
|
|
|
elif [ "${COMP_WORDS[i]}" = -- ]; then
|
|
|
_hg_cmd_qguard
|
|
|
return 0
|
|
|
fi
|
|
|
done
|
|
|
return 1
|
|
|
}
|
|
|
|
|
|
|
|
|
# hbisect
|
|
|
_hg_cmd_bisect()
|
|
|
{
|
|
|
local i subcmd
|
|
|
|
|
|
# find the sub-command
|
|
|
for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do
|
|
|
if [[ ${COMP_WORDS[i]} != -* ]]; then
|
|
|
if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then
|
|
|
subcmd="${COMP_WORDS[i]}"
|
|
|
break
|
|
|
fi
|
|
|
fi
|
|
|
done
|
|
|
|
|
|
if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then
|
|
|
COMPREPLY=(${COMPREPLY[@]:-}
|
|
|
$(compgen -W 'bad good help init next reset' -- "$cur"))
|
|
|
return
|
|
|
fi
|
|
|
|
|
|
case "$subcmd" in
|
|
|
good|bad)
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
return
|
|
|
}
|
|
|
|
|
|
|
|
|
# patchbomb
|
|
|
_hg_cmd_email()
|
|
|
{
|
|
|
case "$prev" in
|
|
|
-c|--cc|-t|--to|-f|--from|--bcc)
|
|
|
# we need an e-mail address. let the user provide a function
|
|
|
# to get them
|
|
|
if [ "$(type -t _hg_emails)" = function ]; then
|
|
|
local arg=to
|
|
|
if [[ "$prev" == @(-f|--from) ]]; then
|
|
|
arg=from
|
|
|
fi
|
|
|
local addresses=$(_hg_emails $arg)
|
|
|
COMPREPLY=(${COMPREPLY[@]:-}
|
|
|
$(compgen -W '$addresses' -- "$cur"))
|
|
|
fi
|
|
|
return
|
|
|
;;
|
|
|
-m|--mbox)
|
|
|
# fallback to standard filename completion
|
|
|
return
|
|
|
;;
|
|
|
-s|--subject)
|
|
|
# free form string
|
|
|
return
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
return
|
|
|
}
|
|
|
|
|
|
|
|
|
# gpg
|
|
|
_hg_cmd_sign()
|
|
|
{
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
}
|
|
|
|
|
|
|
|
|
# transplant
|
|
|
_hg_cmd_transplant()
|
|
|
{
|
|
|
case "$prev" in
|
|
|
-s|--source)
|
|
|
_hg_paths
|
|
|
_hg_repos
|
|
|
return
|
|
|
;;
|
|
|
--filter)
|
|
|
# standard filename completion
|
|
|
return
|
|
|
;;
|
|
|
esac
|
|
|
|
|
|
# all other transplant options values and command parameters are revisions
|
|
|
_hg_tags
|
|
|
_hg_branches
|
|
|
return
|
|
|
}
|
|
|
|
|
|
# shelve
|
|
|
_hg_shelves()
|
|
|
{
|
|
|
local shelves="$("$hg" unshelve -l . 2>/dev/null)"
|
|
|
local IFS=$'\n'
|
|
|
COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur"))
|
|
|
}
|
|
|
|
|
|
_hg_cmd_shelve()
|
|
|
{
|
|
|
_hg_status "mard"
|
|
|
}
|
|
|
|
|
|
_hg_cmd_unshelve()
|
|
|
{
|
|
|
_hg_shelves
|
|
|
}
|
|
|
|