diff --git a/cg b/cg index 08aaf22..901b9e5 100755 --- a/cg +++ b/cg @@ -22,6 +22,7 @@ # Show the version of the Cogito toolkit. Equivalent to the output # of `cg-version`. +# Auto-completion: cmds|opts; optparse --version USAGE="cg [--version | COMMAND [ARGS]...]" cmd="$1"; shift diff --git a/cg-Xlib b/cg-Xlib index 308d798..0070cc5 100644 --- a/cg-Xlib +++ b/cg-Xlib @@ -464,8 +464,8 @@ optparse() fi CUROPT="${ARGS[$ARGPOS]}" - local match="${1%=}" minmatch="${2:-1}" opt="$CUROPT" o="$CUROPT" val - [[ "$1" == *= ]] && val="$match" + local match="${1%=*}" minmatch="${2:-1}" opt="$CUROPT" o="$CUROPT" val + [[ "$1" == *=* ]] && val="$match" case "$match" in --*) [ "$val" ] && o="${o%%=*}" diff --git a/cg-add b/cg-add index c763530..879f01e 100755 --- a/cg-add +++ b/cg-add @@ -28,6 +28,7 @@ # ignore rules - see `cg-status` for a more detailed description of # those). See also above for more notes about cg-add vs. directories. +# Auto-completion: newfile|opts USAGE="cg-add [-N] [-r] FILE..." . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-admin-cat b/cg-admin-cat index 87e6424..c20dee4 100755 --- a/cg-admin-cat +++ b/cg-admin-cat @@ -21,13 +21,14 @@ # This solution based on posting from: torvalds@osdl.org # Polish and test by: ellson@research.att.com +# Auto-completion: file|opts USAGE="cg-admin-cat [-r TREE_ID] FILE..." . "${COGITO_LIB}"cg-Xlib || exit 1 rev=HEAD while optparse; do - if optparse -r=; then + if optparse -r=tree; then rev="$OPTARG" else optfail diff --git a/cg-admin-ls b/cg-admin-ls index fb5bc6c..70842e8 100755 --- a/cg-admin-ls +++ b/cg-admin-ls @@ -36,13 +36,14 @@ # # 100644 blob c7dacd0ea28994e3c754ca4eadb2e08c011ee3d3 README +# Auto-completion: file|opts USAGE="cg-admin-ls [-t TREE_ID] [PATH]" . "${COGITO_LIB}"cg-Xlib || exit 1 tree_id= while optparse; do - if optparse -t=; then + if optparse -t=tree; then tree_id="$OPTARG" else optfail diff --git a/cg-admin-lsobj b/cg-admin-lsobj index 9ae46bb..6a65e8b 100755 --- a/cg-admin-lsobj +++ b/cg-admin-lsobj @@ -38,6 +38,7 @@ # echo -e "\n==================\nme $i"; cat-file commit $i; # done +# Auto-completion: objtype|opts USAGE="cg-admin-lsobj [OBJECT_TYPE]" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-admin-setuprepo b/cg-admin-setuprepo index efc1d6e..6db5048 100755 --- a/cg-admin-setuprepo +++ b/cg-admin-setuprepo @@ -49,6 +49,7 @@ # #!/bin/sh # exec git-update-server-info +# Auto-completion: dir|opts USAGE="cg-admin-setuprepo [-g GROUP] DIRECTORY" _git_repo_unneeded=1 @@ -56,7 +57,7 @@ _git_repo_unneeded=1 unixgroup= while optparse; do - if optparse -g=; then + if optparse -g=groups; then unixgroup="$OPTARG" else optfail diff --git a/cg-admin-uncommit b/cg-admin-uncommit index 0021080..ea50d84 100755 --- a/cg-admin-uncommit +++ b/cg-admin-uncommit @@ -28,6 +28,7 @@ # push again after you uncommitted a pushed out commit, too. At the moment # you pushed the commit out it's etched to the history, live with that. +# Auto-completion: refs|opts USAGE="cg-admin-uncommit [-t] [COMMIT_ID]" _git_requires_root=1 diff --git a/cg-branch-add b/cg-branch-add index 899b934..01dc1f3 100755 --- a/cg-branch-add +++ b/cg-branch-add @@ -60,6 +60,7 @@ # # $ cg-diff -r repo-testing +# Auto-completion: 2=branches 3=location opts USAGE="cg-branch-add BRANCH_NAME LOCATION" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-branch-chg b/cg-branch-chg index 300d860..fe5dfd8 100755 --- a/cg-branch-chg +++ b/cg-branch-chg @@ -5,6 +5,7 @@ # # Takes the branch name and new source location as parameters. +# Auto-completion: 2=branches 3=location opts USAGE="cg-branch-chg BRANCH_NAME NEW_LOCATION" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-branch-ls b/cg-branch-ls index 44b0553..eeb19ce 100755 --- a/cg-branch-ls +++ b/cg-branch-ls @@ -13,6 +13,7 @@ # # origin http://www.kernel.org/pub/scm/cogito/cogito.git +# Auto-completion: opts USAGE="cg-branch-ls" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-clean b/cg-clean index b40b41b..67a1331 100755 --- a/cg-clean +++ b/cg-clean @@ -24,6 +24,7 @@ # -x:: Clean files ignored by cg-status # Also clean files ignored by cg-status, such as object files. +# Auto-completion: opts USAGE="cg-clean [-d] [-D] [-n] [-q] [-x]" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-clone b/cg-clone index afd9c05..d09c9cf 100755 --- a/cg-clone +++ b/cg-clone @@ -28,6 +28,7 @@ # Clone in the current directory instead of creating a new one. # Specifying both -s and a destination directory makes no sense. +# Auto-completion: location|opts USAGE="cg-clone [-l] [-s] LOCATION [DESTDIR]" _git_repo_unneeded=1 diff --git a/cg-commit b/cg-commit index e5e98b4..a82a1bf 100755 --- a/cg-commit +++ b/cg-commit @@ -129,6 +129,7 @@ # EDITOR:: # The editor used for entering revision log information. +# Auto-completion: <=file file|opts USAGE="cg-commit [-m MESSAGE]... [-e] [-c COMMIT_ID] [OTHER_OPTIONS] [FILE]... [< MESSAGE]" . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -187,7 +188,7 @@ while optparse; do signoff="$OPTARG" elif optparse -m=; then msgs[${#msgs[@]}]="$OPTARG" - elif optparse -c=; then + elif optparse -c=refs; then copy_commit="$(cg-object-id -c "$OPTARG")" || exit 1 else optfail diff --git a/cg-diff b/cg-diff index fabd16c..5bd779d 100755 --- a/cg-diff +++ b/cg-diff @@ -52,6 +52,7 @@ # things more comfortable to SVN users). See cogito(7) for more details # about revision specification. +# Auto-completion: file|opts USAGE="cg-diff [-c] [-m] [-s] [-p] [-r FROM_ID[..TO_ID]] [FILE]..." . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -119,7 +120,7 @@ while optparse; do parent=1 elif optparse -s; then opt_summary=1 - elif optparse -r=; then + elif optparse -r=refs; then if echo "$OPTARG" | fgrep -q '..'; then id2="${OPTARG#*..}" [ "$id2" ] || log_end="HEAD" diff --git a/cg-export b/cg-export index 7acc1a0..18da1d0 100755 --- a/cg-export +++ b/cg-export @@ -10,6 +10,7 @@ # for generating a tarball. Other destination specifiers are assumed # to be directory names, and the tree is exported to the given directory. +# Auto-completion: file|opts USAGE="cg-export [-r TREE_ID] DESTFILE" _git_requires_root=1 @@ -17,7 +18,7 @@ _git_requires_root=1 id= while optparse; do - if optparse -r=; then + if optparse -r=tree; then # We do not resolve to tree id since git-tar-tree can # utilize some commit information. id="$(cg-object-id -c "$OPTARG" 2>/dev/null)" || id="$OPTARG" diff --git a/cg-fetch b/cg-fetch index 3e37cd6..5ab187b 100755 --- a/cg-fetch +++ b/cg-fetch @@ -53,7 +53,7 @@ # use git-clone-pack instead of git-fetch-pack, since git-clone-pack # won't unpack the transferred pack. - +# Auto-completion: branches|opts USAGE="cg-fetch [-f] [-v] [BRANCH_NAME]" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-help b/cg-help index 89d0d9e..afcd9f6 100755 --- a/cg-help +++ b/cg-help @@ -17,6 +17,7 @@ # -c:: Colorize # Colorize the output. +# Auto-completion: cmds|opts USAGE="cg-help [-c] [cg-COMMAND | COMMAND]" _git_repo_unneeded=1 diff --git a/cg-init b/cg-init index 9cdbb48..9dc5593 100755 --- a/cg-init +++ b/cg-init @@ -37,6 +37,7 @@ # This is for special purposes when you might not actually _have_ any # object database. This option is normally not interesting. +# Auto-completion: opts USAGE="cg-init [-I] [-N] [-e EXCLUDEPATTERN]... [-m MESSAGE]..." _git_repo_unneeded=1 diff --git a/cg-log b/cg-log index e52323f..3d6ae74 100755 --- a/cg-log +++ b/cg-log @@ -98,6 +98,7 @@ # things more comfortable to SVN users). See cogito(7) for more details # about revision specification. +# Auto-completion: file|opts USAGE="cg-log [-d DATE] [-r FROM_ID[..TO_ID]] [-s] [--summary] [OTHER_OPTIONS] FILE..." . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -282,7 +283,7 @@ while optparse; do list_files=1 elif optparse -u=; then user="$OPTARG" - elif optparse -r=; then + elif optparse -r=refs; then if echo "$OPTARG" | fgrep -q '..'; then log_end="${OPTARG#*..}" [ "$log_end" ] || log_end="HEAD" diff --git a/cg-merge b/cg-merge index 3b6defd..d40452c 100755 --- a/cg-merge +++ b/cg-merge @@ -93,6 +93,7 @@ # is called right after fetch. This is used to do better decision # about whether to fast-forward or tree-merge. +# Auto-completion: branches|opts USAGE="cg-merge [-c] [-b BASE_COMMIT] [-j] [--squash] [-v] [BRANCH_NAME]" _git_requires_root=1 @@ -125,7 +126,7 @@ verbose= while optparse; do if optparse -c; then careful=1 - elif optparse -b=; then + elif optparse -b=refs; then base="$(cg-object-id -c "$OPTARG")" || exit 1 elif optparse -j; then join=1 diff --git a/cg-mkpatch b/cg-mkpatch index d0bb2c2..64dca03 100755 --- a/cg-mkpatch +++ b/cg-mkpatch @@ -62,6 +62,7 @@ # things more comfortable to SVN users). See cogito(7) for more details # about revision specification. +# Auto-completion: opts USAGE="cg-mkpatch [-m] [-s] [-r FROM_ID[..TO_ID] [-d DIRNAME]]" _git_requires_root=1 @@ -113,7 +114,7 @@ fileformat="%s/%02d-%s.patch" while optparse; do if optparse -s; then omit_header=1 - elif optparse -r=; then + elif optparse -r=refs; then if echo "$OPTARG" | fgrep -q '..'; then log_end="${OPTARG#*..}" [ "$log_end" ] || log_end="HEAD" @@ -129,7 +130,7 @@ while optparse; do fi elif optparse -m; then mergebase=1 - elif optparse -d=; then + elif optparse -d=dir; then outdir="$OPTARG" elif optparse -f=; then fileformat="$OPTARG" diff --git a/cg-mv b/cg-mv index c42853c..a5bdf7a 100755 --- a/cg-mv +++ b/cg-mv @@ -20,6 +20,7 @@ # -f:: Force overwriting of existing files # Remove the target file if it already exists. +# Auto-completion: file|opts USAGE="cg-mv [-f] FILE... DEST" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-object-id b/cg-object-id index f65b8a7..84a99af 100755 --- a/cg-object-id +++ b/cg-object-id @@ -29,6 +29,7 @@ # OBJECT_ID:: # An ID resolving to a commit. +# Auto-completion: refs|opts USAGE="cg-object-id [-c | -n | -p | -t] [OBJECT_ID]" . "${COGITO_LIB}"cg-Xlib diff --git a/cg-patch b/cg-patch index 8be13be..defbc97 100755 --- a/cg-patch +++ b/cg-patch @@ -17,6 +17,7 @@ # # Takes the diff on stdin. +# Auto-completion: <=file opts USAGE="cg-patch [-R] < patch on stdin" _git_requires_root=1 diff --git a/cg-push b/cg-push index 8c2a33f..658859b 100755 --- a/cg-push +++ b/cg-push @@ -28,6 +28,7 @@ # that even if you pass `cg-push` the '-t' arguments, your # HEAD is still pushed as well in addition to the tags. +# Auto-completion: branches|opts USAGE="cg-push [-r LOCAL_BRANCH] [REMOTE_BRANCH] [-t TAG]..." . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -44,10 +45,10 @@ send_pack_update() locbranch="$_git_head" tags=() while optparse; do - if optparse -r=; then + if optparse -r=heads; then locbranch="$OPTARG" [ "$(cg-object-id -c "$locbranch")" ] || exit 1 - elif optparse -t=; then + elif optparse -t=tags; then tags[${#tags[@]}]="refs/tags/$OPTARG" else optfail diff --git a/cg-reset b/cg-reset index db1f490..5cbafc6 100755 --- a/cg-reset +++ b/cg-reset @@ -22,6 +22,7 @@ # the file physically as well, that will not be undone - run # 'cg-restore' to restore it physically afterwards). +# Auto-completion: opts USAGE="cg-reset [--adds-removes]" _git_requires_root=1 diff --git a/cg-restore b/cg-restore index 20c55d2..d77615d 100755 --- a/cg-restore +++ b/cg-restore @@ -33,6 +33,7 @@ # Restore the file to the state appropriate to the given ID. # The list of files to recover is mandatory in this case. +# Auto-completion: file|opts USAGE="cg-restore [-f] [-r ID] [FILE]..." . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -42,7 +43,7 @@ objid= while optparse; do if optparse -f; then force=-f - elif optparse -r=; then + elif optparse -r=refs; then objid="$(cg-object-id -n "${OPTARG}")" || exit 1 else optfail diff --git a/cg-rm b/cg-rm index 5ab5dc8..b7986af 100755 --- a/cg-rm +++ b/cg-rm @@ -20,6 +20,7 @@ # If you pass cg-rm this flag and any directory names, it will try # to remove files in those directories recursively. +# Auto-completion: file|opts USAGE="cg-rm [-f] [-n] [-r] FILE..." . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-seek b/cg-seek index 3a28130..c9d9479 100755 --- a/cg-seek +++ b/cg-seek @@ -27,6 +27,7 @@ # # $ cg-switch -f -r COMMIT_ID CURRENT_HEAD_NAME +# Auto-completion: refs|opts USAGE="cg-seek [COMMIT_ID]" _git_requires_root=1 diff --git a/cg-status b/cg-status index 6abc52f..4bb54fc 100755 --- a/cg-status +++ b/cg-status @@ -68,6 +68,7 @@ # The excludes are applied from the project root approaching the # current subdirectory. +# Auto-completion: dir|opts USAGE="cg-status [-g] [[-n] -s STATUS] [-w] [-x] [DIRPATH]" . "${COGITO_LIB}"cg-Xlib || exit 1 @@ -88,7 +89,7 @@ while optparse; do gitstatus=1 elif optparse -n; then noflags=1 - elif optparse -s=; then + elif optparse -s=statflag; then flagfilter="$OPTARG" echo "$flagfilter" | grep -qx '[a-zA-Z?!]*' \ || die "invalid -s status flag" diff --git a/cg-switch b/cg-switch index e0e2b77..e3f9c16 100755 --- a/cg-switch +++ b/cg-switch @@ -53,6 +53,7 @@ # # $ cg-switch -f -r testing v1.x +# Auto-completion: refs|opts USAGE="cg-switch [-f] [-n] [-r COMMIT_ID] BRANCH" _git_requires_root=1 @@ -76,7 +77,7 @@ while optparse; do force=1 elif optparse -n; then seek= - elif optparse -r=; then + elif optparse -r=refs; then dstcommit="$(cg-object-id -c "$OPTARG")" || exit 1 else optfail diff --git a/cg-tag b/cg-tag index b96005d..8a97d85 100755 --- a/cg-tag +++ b/cg-tag @@ -28,6 +28,7 @@ # This is most usually the ID of the commit to tag. Tagging # other objects than commits is possible, but rather "unusual". +# Auto-completion: opts USAGE="cg-tag [-d DESCRIPTION] [-s [-k KEYNAME]] TAG_NAME [OBJECT_ID]" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-tag-ls b/cg-tag-ls index 43a9f5f..f8322e4 100755 --- a/cg-tag-ls +++ b/cg-tag-ls @@ -27,6 +27,7 @@ # fetch_from_pasky 11ed64c1b141c9ba397a1ca76aef2cd250976007 # $ +# Auto-completion: opts USAGE="cg-tag-ls" . "${COGITO_LIB}"cg-Xlib || exit 1 diff --git a/cg-update b/cg-update index 591f3c5..d768188 100755 --- a/cg-update +++ b/cg-update @@ -39,6 +39,7 @@ # CGFETCH_FLAGS:: # Additional flags to pass cg-fetch (useful e.g. for -v -v). +# Auto-completion: branches|opts USAGE="cg-update [-f] [--squash] [-v] [BRANCH_NAME]" _git_requires_root=1 diff --git a/cg-version.in b/cg-version.in index 54b1945..6b043ad 100644 --- a/cg-version.in +++ b/cg-version.in @@ -8,6 +8,7 @@ # is also shown if this information was available # at the build time. +# Auto-completion: opts USAGE="cg-version" _git_repo_unneeded=1 diff --git a/contrib/bash_completion b/contrib/bash_completion new file mode 100755 index 0000000..6be7acd --- /dev/null +++ b/contrib/bash_completion @@ -0,0 +1,196 @@ +#!/usr/bin/env bash +# +# Based on the programmed completion for bash to use quilt. +# Copyright 2003-2004 Martin Quinson (martin quinson#debian org) +# +# This file is part of the distribution of quilt, and is distributed under +# the same licence than quilt itself +# +# Apart from that it looks like it contains stuff from /etc/bash_completion. +# Adopted to Cogito by Jonas Fonseca , 2006-02-03 +# +# NOTES +# ----- +# Commands are completed based on the this tiny specification: +# +# Syntax Example Completes +# ------------------------------------------------------ +# - -r=refs refs after -r +# = 2=branches branches as 2nd arg +# ... file|opts file and opts +# +# The last one is the default completion combo. +# +# The completion script looks for the following line: +# +# # Auto-completion: [ ";" ] + +if type cg &> /dev/null ; then + +_cg() +{ + local __cg_path="$(type -P cg)" + local __cg_dir="$(git-rev-parse --git-dir)" || return 0 + local __cg_cmd= + local __cg_specs= + + local cur=${COMP_WORDS[COMP_CWORD]} + local prev=${COMP_WORDS[COMP_CWORD-1]} + + COMPREPLY=() + + __cg_cmd_lookup() + { + for words in ${COMP_WORDS[@]}; do + for cmd in $(__cg_cmds); do + if [ "$words" = "$cmd" ]; then + echo "$cmd" + return + fi + done + done + } + + # List options as specified by optparse usage and lastly completion + # info in the Auto-completion info line. + __cg_specs_lookup() + { + local path="$__cg_path${__cg_cmd:+-$__cg_cmd}" + local find_default_script=' + s/^# Auto-completion: \([^;]*\).*/\1/p + ' + local find_options_script=' + s/\(optparse -[A-Za-z0-9=_-]*\)/\n\1\n/g + p + ' + local list_options_script='s/^optparse \(-[A-Za-z0-9=_-]*\)/\1/p' + + LANG=C LC_ALL=C sed -ne "$find_options_script" < "$path" | \ + LANG=C LC_ALL=C sed -ne "$list_options_script" | \ + LANG=C LC_ALL=C sort -u + + LANG=C LC_ALL=C sed -ne "$find_default_script" < "$path" + } + + # Convert the argument synopsis from USAGE to argument list + __cg_opts() + { + echo "${__cg_specs}" | sed -n '/^-.*/p' | sed 's/=.*//' | sort -u + echo "-h --help" + } + + # List all Cogito commands + __cg_cmds() + { + ls "$__cg_path"-* | sed "s#$__cg_path-##"; + } + + # FIXME: Tilde expansion + __cg_dir() { compgen -d -- "$cur" | sed '/^.git$/d'; } + __cg_file() { compgen -f -- "$cur"; } + __cg_groups() { compgen -g -- "$cur"; } + __cg_objtype() { echo commit tree blob tag; } + __cg_statflag() { echo "A D M m \\\\? !"; } + + + # List files in the $GIT_DIR/ sub directory. + __cg_list() + { + local path="$__cg_dir/$1/" + + find "$path" -type f | while read line; do + echo ${line#$path} + done + } + + # List first line of files in $GIT_DIR/ sub directory. + __cg_list_content() + { + find "$__cg_dir/$1/" -type f | while read line; do + head -n 1 ${line} + done + } + + # All of these should maybe be rate limited but only tags + # is a problem for me. ;) --jonas + __cg_tags() { __cg_list refs/tags | head -n 15; } + __cg_heads() { __cg_list refs/heads; } + __cg_refs() { __cg_heads; __cg_tags; echo HEAD; } + __cg_branches() { __cg_list branches; } + + # FIXME: For interaction with GIT repos? + __cg_remotes() { __cg_list remotes; } + + __cg_location() + { + # FIXME needs work, maybe pull in _known_hosts + # if it is defined + echo "git:// git+ssh:// http:// rsync://" + __cg_dir + __cg_list_content branches + } + + __cg_newfile() + { + cg status -s '?' -n -w \ + | sed "s,\($cur[^/]*\)/.*,\1," | sort -u | while read i; do + compgen -f "$i" -- "$cur" + done + } + + __cg_complete() + { + for i in "$@"; do + COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W "$(__cg_$i)" -- $cur ) ) + done + } + + __cg_cmd="$(__cg_cmd_lookup)" + __cg_specs="$(__cg_specs_lookup)" + + # The completion "parser". + for spec in $__cg_specs; do + local -a comps + + # First match options, both exact and catch all. Then look for + # numeric position markers. Finally, just assume we hit the + # default completion. + case "$spec,$prev" in + -*=*,"${spec%=*}") + comps=("${spec#*=}") + ;; + -*) + continue + ;; + "<"*,"${spec%=*}") + comps=("${spec#*=}") + ;; + "<"*) + continue; + ;; + "$COMP_CWORD"=*) + comps=("${spec#*=}") + ;; + [0-9]*) + continue + ;; + *) + comps=(${spec//|/ }) + esac + + __cg_complete ${comps[@]} + return 0 + done + + return 0 +} + +fi + +# Enable proper file name completion if available. +[ ${BASH_VERSINFO[0]} '>' 2 -o \ + ${BASH_VERSINFO[0]} = 2 -a ${BASH_VERSINFO[1]} '>' 04 ] \ + && __cg_complete_opt="-o filenames" + +complete -F _cg $__cg_complete_opt cg +unset -v __cg_complete_opt