#compdef git-forgit -p forgit::* #description Utility tool for using git interactively # # forgit completions for zsh # # Place this file in your $fpath (e.g. /usr/share/zsh/site-functions) to enable # tab completions for forgit. _git-branches() { _alternative "branches:branchname:($(git branch -a --format '%(refname:short)'))" } _git-checkout-file() { _alternative "files:filename:($(git ls-files --modified))" } _git-stash-show() { _alternative "files:filename:($(git stash list | sed -n -e 's/:.*//p'))" } _git-worktrees() { local -a wt_list local field while IFS= read -r -d '' field; do [[ "$field" == worktree\ * ]] && wt_list+=("${field#worktree }") done < <(git worktree list --porcelain -z 2>/dev/null) _alternative "worktrees:worktree:(${(@q)wt_list})" } # The completions for git already define a _git-diff completion function, but # it provides the wrong results when called from _git-forgit because it heavily # depends on the context it's been called from (usage of $curcontext and # $CURRENT), so we use a simplified version here which always provides the same # results independent of the context. _git-forgit-diff() { _alternative \ 'commit-ranges::__git_commit_ranges' \ 'blobs-and-trees-in-treeish::__git_blobs_and_trees_in_treeish' \ 'files::__git_changed-in-working-tree_files' \ 'blobs::__git_blobs ' } _git-staged() { _alternative "files:filename:($(git diff --name-only --staged))" } _git-forgit-reflog() { declare -a cmds cmds=('expire:prune old reflog entries' 'delete:delete entries from reflog' 'show:show log of ref' 'exists:check whether a ref has a reflog') _alternative 'cmds:: _describe -t cmds cmd cmds' 'refs:: __git_references' } _git-forgit() { local subcommand cmd subcommand="${words[1]}" if [[ "$subcommand" != "forgit"* ]]; then # Forgit is obviously called via a git alias. Get the original # aliased subcommand and proceed as if it was the previous word. cmd=$(git config --get "alias.$subcommand" | cut -d ' ' -f 2) else # The last word is the relevant command cmd=${words[(( ${#words} - 1 ))]} fi case ${cmd} in forgit) local -a subcommands subcommands=( 'add:git add selector' 'attributes:git attributes generator' 'blame:git blame viewer' 'branch_delete:git branch deletion selector' 'checkout_branch:git checkout branch selector' 'checkout_commit:git checkout commit selector' 'checkout_file:git checkout-file selector' 'checkout_file_from_commit:git checkout-file from commit selector' 'checkout_tag:git checkout tag selector' 'cherry_pick:git cherry-picking' 'cherry_pick_from_branch:git cherry-picking with interactive branch selection' 'clean:git clean selector' 'diff:git diff viewer' 'fixup:git fixup' 'ignore:git ignore generator' 'log:git commit viewer' 'reflog:git reflog viewer' 'rebase:git rebase' 'reset_head:git reset HEAD (unstage) selector' 'restore:git restore file selector' 'revert_commit:git revert commit selector' 'reword:git fixup=reword' 'show:git show viewer' 'squash:git squash' 'stash_show:git stash viewer' 'stash_push:git stash push selector' 'switch_branch:git switch branch selector' 'worktree:git worktree browser' 'worktree_add:git worktree add selector' 'worktree_delete:git worktree remove selector' ) _describe -t commands 'git forgit' subcommands ;; add) _git-add ;; attributes) ;; blame) ;; branch_delete) _git-branches ;; checkout_branch) _git-branches ;; checkout_commit) __git_recent_commits ;; checkout_file) _git-checkout-file ;; checkout_file_from_commit) _git-branches ;; checkout_tag) __git_tags ;; cherry_pick) _git-cherry-pick ;; cherry_pick_from_branch) _git-branches ;; clean) _git-clean ;; diff) _git-forgit-diff ;; fixup) _git-log ;; ignore) ;; log) _git-log ;; reflog) _git-forgit-reflog ;; rebase) _git-rebase ;; reset_head) _git-staged ;; restore) _git-restore ;; revert_commit) __git_recent_commits ;; reword) _git-log ;; squash) _git-log ;; stash_show) _git-stash-show ;; stash_push) _git-add ;; show) _git-show ;; switch_branch) _git-switch ;; worktree) _git-worktree ;; worktree_delete) _git-worktrees ;; esac } # We're reusing existing completion functions, so load those first # if not already loaded and check if completion function exists afterwards. (( $+functions[_git-add] )) || _git (( $+functions[_git-add] )) || return 1 # Completions for forgit plugin shell functions (also works for aliases) compdef _git-add forgit::add compdef _git-branches forgit::branch::delete compdef _git-branches forgit::checkout::branch compdef _git-switch forgit::switch::branch compdef __git_recent_commits forgit::checkout::commit compdef _git-checkout-file forgit::checkout::file compdef _git-branches forgit::checkout::file::from::commit compdef __git_tags forgit::checkout::tag compdef _git-cherry-pick forgit::cherry::pick compdef _git-branches forgit::cherry::pick::from::branch compdef _git-clean forgit::clean compdef _git-forgit-diff forgit::diff compdef _git-log forgit::fixup compdef _git-log forgit::log compdef _git-reflog forgit::reflog compdef _git-rebase forgit::rebase compdef _git-staged forgit::reset::head compdef _git-restore forgit::restore compdef __git_recent_commits forgit::revert::commit compdef _git-log forgit::reword compdef _git-log forgit::squash compdef _git-stash-show forgit::stash::show compdef _git-add forgit::stash::push compdef _git-show forgit::show compdef _git-worktree forgit::worktree compdef _git-worktrees forgit::worktree::delete # this is the case of calling the command and pressing tab # the very first time of a shell session, we have to manually # call the dispatch function if [[ $funcstack[1] == "_git-forgit" ]]; then _git-forgit "$@" fi