3 # This script implements zsh completions for StGit (stg).
5 # To use these completions, copy to a directory in $fpath as _stgit.
9 # $ cp completion/stgit.zsh ~/.zsh.d/_stgit
12 # fpath=("$HOME/.zsh.d" $fpath)
13 # autoload -U compinit
20 '--list[list branches]'
22 '--merge[merge worktree changes into other branch]'
23 ':branch:__stg_branch_stgit'
25 '--create[create and switch to new branch]'
29 '--clone[clone current branch to new branch]'
32 '(-r --rename)'{-r,--rename}'[rename existing branch]'
33 ':branch:__stg_branch_stgit'
36 '(-p --protect)'{-p,--protect}'[prevent stg from modifying branch]'
37 ':branch:__stg_branch_stgit'
39 '(-u --unprotect)'{-u,--unprotect}'[allow stg to modify branch]'
40 ':branch:__stg_branch_stgit'
42 '--delete[delete branch]'
43 '--force[force delete when series is non-empty]'
44 ':branch:__stg_branch_stgit'
46 '--cleanup[cleanup stg metadata for branch]'
47 '--force[force cleanup when series is non-empty]'
48 ':branch:__stg_branch_stgit'
50 '(-d --description)'{-d,--description}'[set branch description]:description'
51 ':branch:__stg_branch_stgit'
53 _arguments
-s -S $subcmd_args
59 '(-a --applied)'{-a,--applied}'[delete empty applied patches]'
60 '(-u --unapplied)'{-u,--unapplied}'[delete empty unapplied patches]'
62 _arguments
-s -S $subcmd_args
71 _arguments
-s $subcmd_args
78 '(-a --all)'{-a,--all}'[commit all unapplied patches]'
80 '(-n --number)'{-n+,--number=}'[commit specified number of patches]:number'
82 '*:applied patches:__stg_patches_applied'
84 _arguments
-s -S $subcmd_args
91 '--spill[spill patch contents to worktree and index]'
93 '(-t --top)'{-t,--top}'[delete top patch]'
95 '*:patches:__stg_patches_all'
97 _arguments
-s -S $subcmd_args
102 __stg_add_args_diffopts
104 '(-r --range)'{-r,--range=}'[show diff between revisions]: :__stg_patches_all'
105 '(-s --stat)'{-s,--stat}'[show stat instead of diff]'
106 '*:files:__stg_changed_files'
108 _arguments
-s -S $subcmd_args
113 __stg_add_args_author
114 __stg_add_args_diffopts
117 __stg_add_args_savetemplate
120 '(-d --diff)'{-d,--diff}'[edit patch diff]'
121 '(-t --set-tree)'{-t,--set-tree=}'[set git tree of patch]:treeish'
122 ':patch:__stg_patches_all'
124 __stg_add_args_message
125 _arguments
-s -S $subcmd_args
130 __stg_add_args_branch
131 __stg_add_args_diffopts
133 '(-d --dir)'{-d,--dir}'[export patches to directory]: :_directories'
134 '(-n --numbered)'{-n,--numbered}'[prefix patch names with order numbers]'
135 '(-s --stdout)'{-s,--stdout}'[dump patches to standard output]'
136 '(-t --template)'{-t,--template=}'[use template file]: :_files'
137 '*:patches:__stg_patches_unhidden'
139 '(-e --extension)'{-e,--extension=}'[extension to append to patch names]:extension'
140 '(-p --patch)'{-p,--patch}'[append .patch to patch names]'
142 _arguments
-s -S $subcmd_args
147 __stg_add_args_diffopts
149 '--bare[bare file names]'
150 '(-s --stat)'{-s,--stat}'[show diff stat]'
151 ':patches:__stg_patches_all'
153 _arguments
-s -S $subcmd_args
160 '(-s --series)'{-s,--series=}'[arrange according to series file]: :_files'
161 '*:patches:__stg_patches_all'
163 _arguments
-s -S $subcmd_args
169 '(-b --base)'{-b,--base=}'[apply on base commit instead of HEAD]:commit'
170 '(-p --strip)'{-p+,--strip=}'[remove N leading directories from diff paths]:num'
171 '-C=[ensure N lines of surrounding context for each change]:num'
172 '--reject[leave rejected hunks in .rej files]'
175 _arguments
-s -S $subcmd_args
181 __stg_add_args_merged
183 ':patches:__stg_patches_all'
185 _arguments
-s -S $subcmd_args
189 _arguments
-s ':commands:__stg_subcommands'
194 __stg_add_args_branch
196 ':patches:__stg_patches_unhidden'
198 _arguments
-s -S $subcmd_args
204 ':references:__stg_patches_all'
206 _arguments
-s -S $subcmd_args
211 __stg_add_args_author
215 '(-n --name)'{-n,--name}'[name for imported patch]'
216 '(-p --strip)'{-p+,--strip=}'[remove N leading directories from diff paths]:num'
217 '(-t --stripname)'{-t,--stripname}'[strip number and extension from patch name]'
218 '-C=[ensure N lines of surrounding context for each change]:num'
219 '(-i --ignore)'{-i,--ignore}'[ingore applied patches in series]'
220 '--replace[replace unapplied patches in series]'
221 '--reject[leave rejected hunks in .rej files]'
222 '--keep-cr[do not remove CR from email lines ending with CRLF]'
223 '(-d --showdiff)'{-d,--showdiff}'[show patch content in editor buffer]'
226 '(-m --mail)'{-m,--mail}'[import from standard email file]'
227 '(-M --mbox)'{-M,--mbox}'[import from mbox file]'
228 '(-s --series)'{-s,--series}'[import from series file]'
229 '(-u --url)'{-u,--url}'[import patch from URL]'
231 _arguments
-s -S $subcmd_args
236 _arguments
-s $subcmd_args
241 __stg_add_args_branch
243 '--clear[clear log history]'
244 '(-d --diff)'{-d,--diff}'[show refresh diffs]'
245 '(-f --full)'{-f,--full}'[show full commit ids]'
246 '(-g --graphical)'{-g,--graphical}'[show log in gitk]'
247 '(-n --number)'{-n+,--number=}'[limit to number of commits]'
248 '*:patches:__stg_patches_all'
250 _arguments
-s -S $subcmd_args
255 __stg_add_args_branch
256 __stg_add_args_diffopts
258 '--to=[add address to To: list]:address'
259 '--cc=[add address to Cc: list]:address'
260 '--bcc=[add address to Bcc: list]:address'
261 '--auto[automatically cc patch signers]'
262 '--no-thread[do not send subsequent messages as replies]'
263 '--unrelated[send patches without sequence numbers]'
264 '(-v --version)'{-v,--version=}'[add version to subject prefix]:version'
265 '--prefix=[add prefix to subject]:prefix'
266 '(-c --cover)'{-c,--cover=}'[cover message file]: :_files'
267 '(-e --edit-cover)'{-e,--edit-cover}'[edit cover message before sending]'
268 '(-E --edit-patches)'{-E,--edit-patches}'[edit patches before sending]'
269 '(-s --sleep)'{-s,--sleep=}'[seconds to sleep between sending emails]:seconds'
270 '--in-reply-to=[reply reference id]:refid'
271 '--domain=[domain to use for message ID]:domain'
272 '(-u --user)'{-u,--user=}'[username for SMTP authentication]:user'
273 '(-p --password)'{-p,--password=}'[password for SMTP authentication]:password'
274 '(-T --smtp-tls)'{-t,--smtp-tls}'[use TLS for SMTP authentication]'
276 '--git[use `git send-email`]'
277 '(-m --mbox)'{-m,--mbox}'[generate mbox file instead of sending]'
278 '--smtp-server=[server or command for sending email]'
280 '--attach[send patch as attachment]'
281 '--attach-inline[send patch as inline attachment]'
282 '(-t --template)'{-t,--template=}'[message template file]: :_files'
284 '(-a --all)'{-a,--all}'[email all applied patches]'
285 '*:patches:__stg_patches_all'
287 _arguments
-s -S $subcmd_args
292 __stg_add_args_author
295 __stg_add_args_savetemplate
297 '(-v --verbose)'{-v,--verbose}'[show diff of file changes]'
298 ':: :_guard "([^-]?#|)" name'
300 __stg_add_args_message
301 _arguments
-s -S $subcmd_args
306 __stg_add_args_branch
307 _arguments
-s -S $subcmd_args
312 __stg_add_args_branch
313 __stg_add_args_diffopts
315 '(-d --diff)'{-d,--diff}'[show diffs of given files]'
316 '*:files:__stg_files_known'
318 _arguments
-s -S $subcmd_args
322 # TODO: complete --parent commit id
325 '(-n --name)'{-n,--name=}'[name for picked patch]:name'
326 '(-B --ref-branch)'{-B,--ref-branch=}'[pick patches from branch]: :__stg_branch_stgit'
327 '(-r --revert)'{-r,--revert}'[revert given commit object]'
328 '(-p --parent=)'{-p,--parent}'[use commit id as parent]:commit'
329 '(-x --expose)'{-x,--expose}'[append imported commit id to patch log]'
330 '--unapplied[keep patch unapplied]'
331 '*'{-f,--file=}'[only fold given file]: :_files'
332 '*:patches:__stg_patches_refbranch'
334 '--fold[fold the commit into current patch]'
335 '--update[fold limited to current patch files]'
337 _arguments
-s -S $subcmd_args
344 '(-s --spill)'{-s,--spill}'[pop a patch keeping its modifications in the tree]'
346 '(-n --number)'{-n+,--number=}'[push specified number of patches]:number'
348 '(-a --all)'{-a,--all}'[push all unapplied patches]'
350 '*:applied patches:__stg_patches_applied'
352 _arguments
-s -S $subcmd_args
357 __stg_add_args_branch
358 _arguments
-s -S $subcmd_args
363 __stg_add_args_merged
365 '(-n --nopush)'{-n,--nopush}'[do not push patches after rebasing]'
366 ':repository:__stg_remotes'
368 _arguments
-s -S $subcmd_args
374 __stg_add_args_merged
376 '--reverse[push patches in reverse order]'
377 '--set-tree[push patch with the original tree]'
379 '(-a --all)'{-a,--all}'[push all unapplied patches]'
381 '(-n --number)'{-n+,--number=}'[push specified number of patches]:number'
383 '*:unapplied patches:__stg_patches_unapplied'
385 _arguments
-s -S $subcmd_args
390 __stg_add_args_merged
392 '(-n --nopush)'{-n,--nopush}'[do not push patches after rebasing]'
393 ':new-base-id:__stg_heads'
395 _arguments
-s -S $subcmd_args
401 '--hard[discard changes in index/worktree]'
402 '(-n --number)'{-n+,--number=}'[number of undos to redo]:number'
404 _arguments
-s -S $subcmd_args
409 __stg_add_args_author
413 __stg_add_args_diffopts
415 '(-a --annotate)'{-a,--annotate=}'[annotate patch log entry]:note'
416 '(-d --diff)'{-d,--diff}'[show diff when editing patch message]'
417 '(-F --force)'{-F,--force}'[force refresh even if index is dirty]'
418 '(-i --index)'{-i,--index}'[refresh from index instead of worktree]'
419 '(-p --patch)'{-p,--patch=}'[refresh patch other than top patch]: :__stg_patches_applied'
420 '--spill[Spill patch contents to worktree and index, and erase patch content]'
422 '(-u --update)'{-u,--update}'[only update current patch files]'
423 '*:files:__stg_changed_files'
425 '(-s --submodules)'{-s,--submodules}'[include submodules in refresh]'
426 '--no-submodules[exclude submodules from refresh]'
428 __stg_add_args_message
429 _arguments
-s -S $subcmd_args
434 __stg_add_args_branch
436 ':old-patch:__stg_patches_all'
438 _arguments
-s -S $subcmd_args
443 _arguments
-s $subcmd_args
449 '--hard[discard changes in index/worktree]'
451 '*:patches:__stg_patches_all'
453 _arguments
-s -S $subcmd_args
458 __stg_add_args_branch
460 '--author[show the author name for each patch]'
461 '(-c --count)'{-c,--count}'[print number of patches]'
462 '(-d --description)'{-d,--description}'[show short descriptions]'
463 '--no-description[do not show patch descriptions]'
464 '(-e --empty)'{-e,--empty}'[identify empty patches]'
465 '(-m --missing)'{-m,--missing=}'[show patches from branch missing in current]: :__stg_branch_stgit'
466 '--noprefix[do not show the patch status prefix]'
467 '(-s --short)'{-s,--short}'[list just patches around the topmost patch]'
468 '--showbranch[show branch name of listed patches]'
470 '(-A --applied)'{-A,--applied}'[show applied patches]'
471 '(-H --hidden)'{-H,--hidden}'[show hidden patches]'
472 '(-U --unapplied)'{-U,--unapplied}'[show unapplied patches]'
474 '(-a --all)'{-a,--all}'[show all patches including hidden]'
476 ':patches:__stg_patches_all'
478 _arguments
-s -S $subcmd_args
483 __stg_add_args_branch
484 __stg_add_args_diffopts
486 '(-s --stat)'{-s,--stat}'[show diff stat]'
487 '*:patches:__stg_patches_all'
488 + '(patch-selection)'
489 '(-a --applied)'{-a,--applied}'[show applied patches]'
490 '(-u --unapplied)'{-u,--unapplied}'[show unapplied patches]'
492 _arguments
-s -S $subcmd_args
499 '(-n --nopush)'{-n,--nopush}'[do not push patches after sinking]'
500 '(-t --to)'{-t,--to=}'[sink patches below target patch]: :__stg_patches_applied'
501 ':patches:__stg_patches_all'
503 _arguments
-s -S $subcmd_args
509 __stg_add_args_savetemplate
511 '(-n --name)'{-n,--name=}'[name for squashed patch]: :__stg_patches_all'
512 '*:patches:__stg_patches_all_allow_dups'
514 __stg_add_args_message
515 _arguments
-s -S $subcmd_args
522 '(-a --all)'{-a,--all}'[synchronize all applied patches]'
523 '*:patches:__stg_patches_refbranch'
525 '(-B --ref-branch)'{-B,--ref-branch}'[synchronize patches with branch]: :__stg_branch_stgit'
526 '(-s --series)'{-s,--series=}'[synchronize patches with series]: :_files'
528 _arguments
-s -S $subcmd_args
533 __stg_add_args_branch
534 _arguments
-s -S $subcmd_args
541 '(-n --number)'{-n+,--number=}'[push specified number of patches]:number'
544 '(-t --to)'{-t,--to=}'[uncommit to the specified commit]:commit'
545 '(-x --exclusive)'{-x,--exclusive}'[exclude the commit specified by --to]'
547 '*: :_guard "([^-]?#|)" names'
549 _arguments
-s -S $subcmd_args
555 '--hard[discard changes in index/worktree]'
556 '(-n --number)'{-n+,--number=}'[number commands to undo]:number'
558 _arguments
-s -S $subcmd_args
563 __stg_add_args_branch
565 ':patches:__stg_patches_hidden'
567 _arguments
-s -S $subcmd_args
570 __stg_add_args_author
() {
572 '--author=[set author details]'
573 '--authdate=[set author date]:date'
574 '--authemail=[set author email]:email'
575 '--authname=[set author name]:name'
579 __stg_add_args_branch
() {
581 '(-b --branch)'{-b,--branch=}'[specify another branch]: :__stg_branch_stgit'
585 __stg_add_args_diffopts
() {
586 # TODO: complete diff-opts values (with separators?)
588 '(-O --diff-opts)'{-O+,--diff-opts=}'[extra options for git diff]:opts'
592 __stg_add_args_edit
() {
594 '(-e --edit)'{-e,--edit}'[invoke interactive editor]'
598 __stg_add_args_help
() {
600 '(- *)'{-h,--help}'[show help message and exit]'
604 __stg_add_args_hook
() {
606 '--no-verify[disable commit-msg hook]'
610 __stg_add_args_keep
() {
612 '(-k --keep)'{-k,--keep}'[keep local changes]'
616 __stg_add_args_merged
() {
618 '(-m --merged)'{-m,--merged}'[check for patches merged upstream]'
622 __stg_add_args_message
() {
625 '(-f --file)'{-f,--file=}'[use message file instead of invoking editor]: :_files'
626 '(-m --message)'{-m,--message=}'[specify message instead of invoking editor]:message'
630 __stg_add_args_savetemplate
() {
632 '--save-template=[save message template to file and exit]: :_files'
636 __stg_add_args_sign
() {
638 '--ack[add Acked-by trailer]'
639 '--ack-by[add Acked-by trailer]:value'
640 '--review[add Reviewed-by trailer]'
641 '--review-by[add Reviewed-by trailer]:value'
642 '--sign[add Signed-off-by trailer]'
643 '--sign-by[add Signed-off-by trailer]:value'
648 _alternative
'heads-local::__stg_heads_local' 'heads-remote::__stg_heads_remote'
651 __stg_heads_local
() {
655 heads
=(${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname:short)"' refs/heads 2>/dev/null)"})
656 gitdir
=$
(_call_program gitdir git rev-parse
--git-dir 2>/dev
/null
)
657 if __stg_git_command_successful
$pipestatus; then
658 for f
in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD
; do
659 [[ -f $gitdir/$f ]] && heads
+=$f
661 [[ -f $gitdir/refs
/stash
]] && heads
+=stash
662 [[ -f $gitdir/refs
/bisect
/bad
]] && heads
+=bisect
/bad
665 __stg_git_describe_commit heads heads-local
"local head" "$@"
668 __stg_heads_remote
() {
671 heads
=(${(f)"$(_call_program headrefs git for-each-ref --format='"%(refname:short)"' refs/remotes 2>/dev/null)"})
673 __stg_git_describe_commit heads heads-remote
"remote head" "$@"
676 __stg_git_command_successful
() {
677 if (( ${#*:#0} > 0 )); then
678 _message
'not a git repository'
684 __stg_git_describe_commit
() {
685 __stg_git_describe_branch
$1 $2 $3 -M 'r:|/=* r:|=*' "${(@)argv[4,-1]}"
688 __stg_git_describe_branch
() {
689 local __commits_in
=$1
695 if zstyle
-s :completion
:$curcontext: max-verbose maxverbose
&&
696 (( ${compstate[nmatches]} <= maxverbose
)); then
699 for __c
in ${(P)__commits_in}; do
700 __commits
+=("${__c}:${$(_call_program describe git rev-list -1 --oneline $__c)//:/\\:}")
702 _describe
-t $__tag $__desc __commits
"$@"
705 _wanted
$__tag expl
$__desc compadd
"$@" -a - $__commits_in
709 __stg_branch_stgit
() {
710 declare -a stg_branches
712 ${${(f)"$(_call_program branchrefs git for-each-ref --format='"%(refname)"' refs/stacks 2>/dev/null)"}#refs/stacks/}
715 _wanted
-V branches expl
"branch" compadd
$stg_branches
718 __stg_files_relative
() {
720 prefix
=$
(_call_program gitprefix git rev-parse
--show-prefix 2>/dev
/null
)
721 if (( $#prefix == 0 )); then
730 # Collapse "//" and "/./" into "/". Strip any remaining "/." and "/".
731 for file in ${${${${${(0)1}//\/\///}//\
/.\
///}%/.
}%/}; do
733 (( n
= $#file > $#prefix ?
$#file : $#prefix ))
734 for (( i
= 1; i
<= n
; i
++ )); do
735 if [[ $file[i
] != $prefix[i
] ]]; then
736 while (( i
> 0 )) && [[ $file[i-1
] != / ]]; do
743 files
+=${(l@${#prefix[i,-1]//[^\/]}*3@@../@)}${file[i,-1]}
746 print
${(pj:\0:)files}
749 __stg_diff-index_files
() {
750 local tree
=$1 description
=$2 tag
=$3; shift 3
753 # $tree needs to be escaped for _call_program; matters for $tree = "HEAD^"
754 files
=$
(_call_program files git diff-index
-z --name-only --no-color --cached ${(q)tree} 2>/dev
/null
)
755 __stg_git_command_successful
$pipestatus ||
return 1
756 files
=(${(0)"$(__stg_files_relative $files)"})
757 __stg_git_command_successful
$pipestatus ||
return 1
759 _wanted
$tag expl
$description _multi_parts $@
- / files
762 __stg_changed-in-index_files
() {
763 __stg_diff-index_files HEAD
'changed in index file' changed-in-index-files
"$@"
766 __stg_changed-in-working-tree_files
() {
769 files
=$
(_call_program changed-in-working-tree-files git
diff -z --name-only --no-color 2>/dev
/null
)
770 __stg_git_command_successful
$pipestatus ||
return 1
771 files
=(${(0)"$(__stg_files_relative $files)"})
772 __stg_git_command_successful
$pipestatus ||
return 1
774 _wanted changed-in-working-tree-files expl
'changed in working tree file' _multi_parts $@
-f - / files
777 __stg_changed_files
() {
779 'changed-in-index-files::__stg_changed-in-index_files' \
780 'changed-in-working-tree-files::__stg_changed-in-working-tree_files'
783 __stg_files_known
() {
784 declare -a known_files
786 ${(f)"$(_call_program known-files git ls-files 2>/dev/null)"}
789 _wanted
-V known-files expl
"known files" _multi_parts
- / known_files
792 __stg_get_branch_opt
() {
795 long
=${2:-'--branch'}
796 i
=${words[(I)$short|$long(=*|)]}
799 if (( i
< $#words )); then
800 echo "--branch=${words[i + 1]}"
804 echo "--branch=${words[i]#*=}"
809 __stg_want_patches
() {
813 ${(f)"$(_call_program want-patches stg series --no-description --noprefix $@ 2>/dev/null)"}
815 _wanted
-V all expl
"patch" compadd
${patches:|words}
819 __stg_patches_all
() {
820 __stg_want_patches $
(__stg_get_branch_opt
) --all
823 __stg_patches_all_allow_dups
() {
825 local expl branch_opt
826 branch_opt
=$
(__stg_get_branch_opt
)
828 ${(f)"$(_call_program all-patches stg series $branch_opt --no-description --noprefix --all 2>/dev/null)"}
830 _wanted
-V all expl
"patch" compadd
${patches}
833 __stg_patches_applied
() {
834 __stg_want_patches $
(__stg_get_branch_opt
) --applied
837 __stg_patches_hidden
() {
838 __stg_want_patches $
(__stg_get_branch_opt
) --hidden
841 __stg_patches_unapplied
() {
842 __stg_want_patches $
(__stg_get_branch_opt
) --unapplied
845 __stg_patches_unhidden
() {
846 __stg_want_patches $
(__stg_get_branch_opt
) --applied --unapplied
849 __stg_patches_refbranch
() {
850 __stg_want_patches $
(__stg_get_branch_opt
-B --ref-branch) --all
855 remotes
=(${(f)"$(_call_program remotes git remote 2>/dev/null)"})
856 _wanted remotes expl remote compadd
"$@" -a - remotes
859 __stg_subcommands
() {
860 _describe
-t commands
'stgit command' _stg_cmds
863 __stg_caching_policy
() {
864 [[ =$service -nt $1 ]]
868 local curcontext
="$curcontext" state line expl ret
=1
871 # Special cases for git aliases
881 if [ "$words[1]" = git
]; then
887 zstyle
-s ":completion:*:*:stg:*" cache-policy update_policy
888 if [[ -z "$update_policy" ]]; then
889 zstyle
":completion:*:*:stg:*" cache-policy __stg_caching_policy
892 _arguments
-C -A "-*" \
893 '(-)--help[print help information]' \
894 '(*)--version[display version information]' \
896 '*:: :->args' && ret
=0
898 if [[ -n $state ]] && (( ! $
+_stg_cmds
)); then
900 if _cache_invalid stg-cmds ||
! _retrieve_cache stg-cmds
; then
902 ${${${(M)${(f)"$(stg help 2> /dev/null)"}## *}# }/#(#b)([^[:space:]]##)[[:space:]]##(*)/$match[1]:$match[2]}
904 if (( $?
== 0 )); then
905 _store_cache stg-cmds _stg_cmds
914 __stg_subcommands
&& ret
=0
918 local subcmd
=$words[1]
919 curcontext
="${curcontext%:*:*}:stg-$subcmd:"
920 if ! _call_function ret _stg-
$subcmd; then
921 _message
"unknown sub-command: $subcmd"