contrib/zsh_completion
author mason@suse.com
Tue, 04 Apr 2006 16:47:12 -0400
changeset 2079 ee96ca273f32
parent 1544 b3184bea3eb3
child 3487 46958e428fcd
permissions -rw-r--r--
New lazy index code for revlogs. This tunes for large repositories. It does not read the whole index file in one big chunk, but tries to buffer reads in more reasonable chunks instead. Search speeds are improved in two ways. When trying to find a specific sha hash, it searches from the end of the file backward. More recent entries are more likely to be relevant, especially the tip. Also, this can load only the mapping of nodes to revlog index number. Loading the map uses less cpu (no struct.unpack) and much less memory than loading both the map and the index. This cuts down the time for hg tip on the 80,000 changeset kernel repo from 1.8s to 3.69s. Most commands the pull a single rev out of a big index get roughly the same benefit. Commands that read the whole index are not slower.

#compdef hg

# Zsh completion script for mercurial.  Rename this file to _hg and copy
# it into your zsh function path (/usr/share/zsh/site-functions for
# instance)
#
# Copyright (C) 2005 Steve Borho
#
# This is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your
# option) any later version.
#

local curcontext="$curcontext" state line
typeset -A opt_args
local subcmds repos tags newFiles addedFiles includeExclude

tags=($(hg tags 2> /dev/null | sed -e 's/[0-9]*:[a-f0-9]\{40\}$//; s/ *$//'))
subcmds=($(hg -v help | sed -e '1,/^list of commands:/d' \
      -e '/^global options:/,$d' -e '/^ [^ ]/!d; s/[,:].*//g;'))

# A lot of commands have these arguments
includeExclude=(
        '*-I-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
        '*--include-[include names matching the given patterns]:dir:_files -W $(hg root) -/'
        '*-X-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/'
        '*--exclude-[exclude names matching the given patterns]:dir:_files -W $(hg root) -/')

if [[ $service == "hg" ]]; then
    _arguments -C -A "-*" \
    '(--repository)-R[repository root directory]:root:_files -/' \
    '(-R)--repository[repository root directory]:root:_files -/' \
    '--cwd[change working directory]:new working directory:_files -/' \
    '(--noninteractive)-y[do not prompt, assume yes for any required answers]' \
    '(-y)--noninteractive[do not prompt, assume yes for any required answers]' \
    '(--verbose)-v[enable additional output]' \
    '(-v)--verbose[enable additional output]' \
    '(--quiet)-q[suppress output]' \
    '(-q)--quiet[suppress output]' \
    '(--help)-h[display help and exit]' \
    '(-h)--help[display help and exit]' \
    '--debug[debug mode]' \
    '--debugger[start debugger]' \
    '--traceback[print traceback on exception]' \
    '--time[time how long the command takes]' \
    '--profile[profile]' \
    '--version[output version information and exit]' \
    '*::command:->subcmd' && return 0

    if (( CURRENT == 1 )); then
        _wanted commands expl 'hg command' compadd -a subcmds
        return
    fi
    service="$words[1]"
    curcontext="${curcontext%:*}=$service:"
fi

case $service in
    (add)
        newFiles=(${(ps:\0:)"$(hg status -0un .)"})
        _arguments $includeExclude \
        '*:file:->unknown'
        _wanted files expl 'unknown files' compadd -a newFiles
    ;;

    (addremove)
        _arguments $includeExclude \
        '*:directories:_files -/'  # assume they want to add/remove a dir
    ;;

    (forget)
        addedFiles=(${(ps:\0:)"$(hg status -0an .)"})
        _arguments $includeExclude  \
        '*:file:->added'
        _wanted files expl 'newly added files' compadd -a addedFiles
    ;;

    (remove|rm)
        _arguments $includeExclude \
        '*:file:_files'
    ;;

    (copy|cp)
        _arguments $includeExclude \
        '(--after)-A[record a copy that has already occurred]' \
        '(-A)--after[record a copy that has already occurred]' \
        '(--force)-f[forcibly copy over an existing managed file]' \
        '(-f)--force[forcibly copy over an existing managed file]' \
        '(--parents)-p[append source path to dest]' \
        '(-p)--parents[append source path to dest]' \
        '*:files:_files'
    ;;

    (rename|mv)
        if (( CURRENT == 2 )); then
            _arguments $includeExclude \
            '(--after)-A[record a rename that has already occurred]' \
            '(-A)--after[record a rename that has already occurred]' \
            '(--force)-f[replace destination if it exists]' \
            '(-F)--force[replace destination if it exists]' \
            '(--parents)-p[append source path to dest]' \
            '(-p)--parents[append source path to dest]' \
            '*:files:_files'
        else
            _arguments '*:destination:_files'
        fi
    ;;

    (diff)
        _arguments $includeExclude \
        '*-r[revision]:revision:($tags)' \
        '*--rev[revision]:revision:($tags)' \
        '(--text)-a[treat all files as text]' \
        '(-a)--text[treat all files as text]' \
        '*:file:_files'
    ;;

    (status|st)
        _arguments $includeExclude \
        '(--no-status)-n[hide status prefix]' \
        '(-n)--no-status[hide status prefix]' \
        '(--print0)-0[end filenames with NUL, for use with xargs]' \
        '(-0)--print0[end filenames with NUL, for use with xargs]' \
        '(--modified)-m[show only modified files]' \
        '(-m)--modified[show only modified files]' \
        '(--added)-a[show only added files]' \
        '(-a)--added[show only added files]' \
        '(--removed)-r[show only removed files]' \
        '(-r)--removed[show only removed files]' \
        '(--unknown)-u[show only unknown files]' \
        '(-u)--unknown[show only unknown files]' \
        '*:search pattern, then files:_files'
    ;;

    (revert)
        addedFiles=(${(ps:\0:)"$(hg status -0amrn .)"})
        _arguments \
        '(--rev)-r[revision to revert to]:revision:($tags)' \
        '(-r)--rev[revision to revert to]:revision:($tags)' \
        '(--nonrecursive)-n[do not recurse into subdirectories]' \
        '(-n)--nonrecursive[do not recurse into subdirectories]' \
        '*:file:->modified'
        _wanted files expl 'mofified files' compadd -a addedFiles
    ;;

    (commit|ci)
        addedFiles=(${(ps:\0:)"$(hg status -0amrn .)"})
        _arguments $includeExclude \
        '(--addremove)-A[run addremove during commit]' \
        '(-A)--addremove[run addremove during commit]' \
        '(--message)-m[use <txt> as commit message]:string:' \
        '(-m)--message[use <txt> as commit message]:string:' \
        '(--logfile)-l[read commit message from <file>]:.log file:_file -g \*.txt' \
        '(-l)--logfile[read commit message from <file>]:.log file:_file -g \*.txt' \
        '(--date)-d[record datecode as commit date]:date code:' \
        '(-d)--date[record datecode as commit date]:date code:' \
        '(--user)-u[record user as commiter]:user:' \
        '(-u)--user[record user as commiter]:user:' \
        '*:file:->modified'
        _wanted files expl 'mofified files' compadd -a addedFiles
    ;;

    (cat)
        _arguments $includeExclude \
        '(--output)-o[print output to file with formatted name]:filespec:' \
        '(-o)--output[print output to file with formatted name]:filespec:' \
        '(--rev)-r[revision]:revision:($tags)' \
        '(-r)--rev[revision]:revision:($tags)' \
        '*:file:_files'
    ;;

    (annotate)
        _arguments $includeExclude \
        '(--rev)-r[annotate the specified revision]:revision:($tags)' \
        '(-r)--rev[annotate the specified revision]:revision:($tags)' \
        '(--text)-a[treat all files as text]' \
        '(-a)--text[treat all files as text]' \
        '(--user)-u[list the author]' \
        '(-u)--user[list the author]' \
        '(--changeset)-c[list the changeset]' \
        '(-c)--changeset[list the changeset]' \
        '(--number)-n[list the revision number (default)]' \
        '(-n)--number[list the revision number (default)]' \
        '*:files:_files'
    ;;

    (grep)
        _arguments $includeExclude \
        '*-r[search in given revision range]:revision:($tags)' \
        '*--rev[search in given revision range]:revision:($tags)' \
        '--all[print all revisions with matches]' \
        '(-print0)-0[end filenames with NUL, for use with xargs]' \
        '(-0)--print0[end filenames with NUL, for use with xargs]' \
        '(--ignore-case)-i[ignore case when matching]' \
        '(-i)--ignore-case[ignore case when matching]' \
        '(--files-with-matches)-l[print names of files and revs that match]' \
        '(-l)--files-with-matches[print names of files and revs that match]' \
        '(--line-number)-n[print matching line numbers]' \
        '(-n)--line-number[print matching line numbers]' \
        '(--user)-u[print user who committed change]' \
        '(-u)--user[print user who committed change]' \
        '*:search pattern:'
    ;;

    (locate)
        _arguments $includeExclude \
        '(--rev)-r[search repository as it stood at revision]:revision:($tags)' \
        '(-r)--rev[search repository as it stood at revision]:revision:($tags)' \
        '(--print0)-0[end filenames with NUL, for use with xargs]' \
        '(-0)--print0[end filenames with NUL, for use with xargs]' \
        '(--fullpath)-f[print complete paths]' \
        '(-f)--fullpath[print complete paths]' \
        '*:search pattern:'
    ;;

    (log|history)
        _arguments $includeExclude \
        '*-r[show the specified revision or range]:revision:($tags)' \
        '*--rev[show the specified revision or range]:revision:($tags)' \
        '(--no-merges -M --only-merges)-m[show only merge revisions]' \
        '(--no-merges -M -m)--only-merges[show only merge revisions]' \
        '(--only-merges -m --no-merges)-M[do not show merge revisions]' \
        '(--only-merges -m -M)--no-merges[do not show merge revisions]' \
        '(--keyword)-k[search for a keyword]:keyword:' \
        '(-k)--keyword[search for a keyword]:keyword:' \
        '(--branch)-b[show branches]' \
        '(-b)--branch[show branches]' \
        '(--patch)-p[show patch]' \
        '(-p)--patch[show patch]' \
        '*:file:_files'
    ;;

    (update|checkout|co)
        _arguments \
        '(--branch)-b[checkout the head of a specific branch]' \
        '(-b)--branch[checkout the head of a specific branch]' \
        '(-C --clean --merge)-m[allow merging of branches]' \
        '(-C --clean -m)--merge[allow merging of branches]' \
        '(-m --merge --clean)-C[overwrite locally modified files]' \
        '(-m --merge -C)--clean[overwrite locally modified files]' \
        '*:revision or tag:($tags)'
    ;;

    (tag)
        _arguments \
        '(--local)-l[make the tag local]' \
        '(-l)--local[make the tag local]' \
        '(--message)-m[message for tag commit log entry]:string:' \
        '(-m)--message[message for tag commit log entry]:string:' \
        '(--date)-d[record datecode as commit date]:date code:' \
        '(-d)--date[record datecode as commit date]:date code:' \
        '(--user)-u[record user as commiter]:user:' \
        '(-u)--user[record user as commiter]:user:' \
        '*:name, then revision:($tags)'
    ;;

    (clone)
        if (( CURRENT == 2 )); then
            repos=( $(hg paths | sed -e 's/^.*= //') )
            _arguments \
            '(--no-update)-U[do not update the new working directory]' \
            '(-U)--no-update[do not update the new working directory]' \
            '(--ssh)-e[specify ssh command to use]:string:' \
            '(-e)--ssh[specify ssh command to use]:string:' \
            '--pull[use pull protocol to copy metadata]' \
            '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
            '*:local repo:_files -/'
            _wanted source expl 'source repository' compadd -a repos
        elif (( CURRENT == 3 )); then
            _arguments '*:dest repo:_files -/'
        fi
    ;;

    (rawcommit)
        _arguments \
        '(--parent)-p[parent revision]:revision:($tags)' \
        '(-p)--parent[parent revision]:revision:($tags)' \
        '(--date)-d[record datecode as commit date]:date code:' \
        '(-d)--date[record datecode as commit date]:date code:' \
        '(--user)-u[record user as commiter]:user:' \
        '(-u)--user[record user as commiter]:user:' \
        '(--message)-m[use <txt> as commit message]:string:' \
        '(-m)--message[use <txt> as commit message]:string:' \
        '(--logfile)-l[read commit message from <file>]:.log file:_file -g \*.txt' \
        '(-l)--logfile[read commit message from <file>]:.log file:_file -g \*.txt' \
        '(--files)-F[file list]:file list:_files' \
        '(-F)--files[file list]:file list:_files' \
        '*:files to commit:_files'
    ;;

    (bundle)
        if (( CURRENT == 2 )); then
            _arguments '*:changegroup file:_files -g \*.hg'
        elif (( CURRENT == 3 )); then
            _arguments '*:other repo:_files -/'
        fi
    ;;

    (unbundle)
        _arguments '*:changegroup .hg file:_files -g \*.hg'
    ;;

    (incoming)
        _arguments \
        '(--patch)-p[show patch]' \
        '(-p)--patch[show patch]' \
        '(--no-merges)-M[do not show merge revisions]' \
        '(-M)--no-merges[do not show merge revisions]' \
        '(--newest-first)-n[show newest record first]' \
        '(-n)--newest-first[show newest record first]' \
        '*:mercurial repository:_files -/'
    ;;

    (import|patch)
        _arguments \
        '(--strip)-p[directory strip option for patch (default: 1)]:count:' \
        '(-p)--strip[directory strip option for patch (default: 1)]:count:' \
        '(--force)-f[skip check for outstanding uncommitted changes]' \
        '(-f)--force[skip check for outstanding uncommitted changes]' \
        '(--base)-b[base directory to read patches from]:file:_files -W $(hg root) -/' \
        '(-b)--base[base directory to read patches from]:file:_files -W $(hg root) -/' \
        '*:patch file:_files'
    ;;

    (pull)
        repos=( $(hg paths | sed -e 's/^.*= //') )
        _arguments \
        '(--update)-u[update working directory to tip after pull]' \
        '(-u)--update[update working directory to tip after pull]' \
        '(--ssh)-e[specify ssh command to use]:ssh command:' \
        '(-e)--ssh[specify ssh command to use]:ssh command:' \
        '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
        '*:local repo:_files -/'
        _wanted source expl 'source repository' compadd -a repos
    ;;

    (outgoing)
        _arguments \
        '(--patch)-p[show patch]' \
        '(-p)--patch[show patch]' \
        '(--no-merges)-M[do not show merge revisions]' \
        '(-M)--no-merges[do not show merge revisions]' \
        '(--newest-first)-n[show newest record first]' \
        '(-n)--newest-first[show newest record first]' \
        '*:local repo:_files -/'
        _wanted source expl 'source repository' compadd -a repos
    ;;

    (export)
        _arguments \
        '(--outout)-o[print output to file with formatted name]:filespec:' \
        '(-o)--output[print output to file with formatted name]:filespec:' \
        '(--text)-a[treat all files as text]' \
        '(-a)--text[treat all files as text]' \
        '*:revision:->revs'
        _wanted revs expl 'revision or tag' compadd -a tags
    ;;

    (push)
        repos=( $(hg paths | sed -e 's/^.*= //') )
        _arguments \
        '(--force)-f[force push]' \
        '(-f)--force[force push]' \
        '(--ssh)-e[specify ssh command to use]:ssh command:' \
        '(-e)--ssh[specify ssh command to use]:ssh command:' \
        '--remotecmd[specify hg command to run on the remote side]:remote hg:' \
        '*:local repo:_files -/'
        _wanted source expl 'source repository' compadd -a repos
    ;;

    (serve)
        _arguments \
        '(--accesslog)-A[name of access log file]:log file:_files' \
        '(-A)--accesslog[name of access log file]:log file:_files' \
        '(--errorlog)-E[name of error log file]:log file:_files' \
        '(-E)--errorlog[name of error log file]:log file:_files' \
        '(--port)-p[listen port]:listen port:' \
        '(-p)--port[listen port]:listen port:' \
        '(--address)-a[interface address]:interface address:' \
        '(-a)--address[interface address]:interface address:' \
        '(--name)-n[name to show in web pages]:repository name:' \
        '(-n)--name[name to show in web pages]:repository name:' \
        '(--templates)-t[web template directory]:template dir:_files -/' \
        '(-t)--templates[web template directory]:template dir:_files -/' \
        '--style[web template style]:style' \
        '--stdio[for remote clients]' \
        '(--ipv6)-6[use IPv6 in addition to IPv4]' \
        '(-6)--ipv6[use IPv6 in addition to IPv4]'
    ;;

    (help)
        _wanted commands expl 'hg command' compadd -a subcmds
    ;;

    (heads)
        _arguments \
        '(--branches)-b[find branch info]' \
        '(-b)--branches[find branch info]'
    ;;

    (paths)
        _arguments '*:symbolic name:(default default-push)'
    ;;

    (init)
        _arguments '*:new repo directory:_files -/'
    ;;

    (manifest)
        _arguments '*:revision:($tags)'
    ;;

    (parents)
        _arguments '*:revision:($tags)'
    ;;

    (identify|recover|root|undo|view|verify|version|ct|tags)
        # no arguments for these commands
    ;;

    (*)
        _message "unknown hg command completion: $service"
    ;;
esac