From 02f14a9cb152561a5e44062aac79f3b700403b40 Mon Sep 17 00:00:00 2001 From: navewindre Date: Sun, 13 Jul 2025 06:42:05 +0200 Subject: omz --- home/.oh-my-zsh/plugins/gitfast/MANUAL.adoc | 40 + home/.oh-my-zsh/plugins/gitfast/README.md | 9 + home/.oh-my-zsh/plugins/gitfast/_git | 274 ++ .../.oh-my-zsh/plugins/gitfast/git-completion.bash | 3562 ++++++++++++++++++++ home/.oh-my-zsh/plugins/gitfast/git-prompt.sh | 594 ++++ home/.oh-my-zsh/plugins/gitfast/gitfast.plugin.zsh | 11 + 6 files changed, 4490 insertions(+) create mode 100644 home/.oh-my-zsh/plugins/gitfast/MANUAL.adoc create mode 100644 home/.oh-my-zsh/plugins/gitfast/README.md create mode 100644 home/.oh-my-zsh/plugins/gitfast/_git create mode 100644 home/.oh-my-zsh/plugins/gitfast/git-completion.bash create mode 100644 home/.oh-my-zsh/plugins/gitfast/git-prompt.sh create mode 100644 home/.oh-my-zsh/plugins/gitfast/gitfast.plugin.zsh (limited to 'home/.oh-my-zsh/plugins/gitfast') diff --git a/home/.oh-my-zsh/plugins/gitfast/MANUAL.adoc b/home/.oh-my-zsh/plugins/gitfast/MANUAL.adoc new file mode 100644 index 0000000..5333f5a --- /dev/null +++ b/home/.oh-my-zsh/plugins/gitfast/MANUAL.adoc @@ -0,0 +1,40 @@ +This project is a friendly fork of the official Git completion +(`contrib/completion`) and prompt scripts for Bash, Zsh, and possibly other +shells. + +Most Git developers use the Bash shell, for which the completion scripts work +rather well, however, Zsh is typically neglected. I've sent many patches to fix +the issues, many have been merged, but many have been ignored, thus the need for +a canonical location of a good, working Zsh completion. + +There are advantages for Bash users too. Currently the scripts under `contrib` are tied to the +specific Git version, for example the completion scripts of version v2.40 +(https://git.kernel.org/pub/scm/git/git.git/plain/contrib/completion/git-completion.bash?h=v2.40.0[git-completion.bash]) +have issues with older versions of Git (e.g. v2.33); the ones in +this project don't. + +With `git-completion` you can be sure you are using the latest completion that +works in both shells, and any Git version. + +This is a sister project of the +https://github.com/ohmyzsh/ohmyzsh/tree/master/plugins/gitfast[Oh My Zsh +gitfast] plugin (that I also maintain), which has similar needs. + +== Installation == + +* https://github.com/felipec/git-completion/wiki/Bash[Bash instructions] +* https://github.com/felipec/git-completion/wiki/Zsh[Zsh instructions] + +== Improvements from upstream == + +This is a short list of the benefits you get: + +* Easier installation +* Tons of bug fixes +* Works with older versions of git +* Zsh: much more options +* Zsh: quoting works properly +* Zsh: automatic suffix removal + +For a full list of all the patches on top of upstream git check +https://github.com/felipec/git-completion/wiki/Patches[Patches]. diff --git a/home/.oh-my-zsh/plugins/gitfast/README.md b/home/.oh-my-zsh/plugins/gitfast/README.md new file mode 100644 index 0000000..60b84a2 --- /dev/null +++ b/home/.oh-my-zsh/plugins/gitfast/README.md @@ -0,0 +1,9 @@ +# Gitfast plugin + +This plugin adds completion for Git, using the zsh completion from git.git folks, which is much faster than the official one from zsh. A lot of zsh-specific features are not supported, like descriptions for every argument, but everything the bash completion has, this one does too (as it is using it behind the scenes). Not only is it faster, it should be more robust, and updated regularly to the latest git upstream version. + +To use it, add `gitfast` to the plugins array in your zshrc file: + +```zsh +plugins=(... gitfast) +``` diff --git a/home/.oh-my-zsh/plugins/gitfast/_git b/home/.oh-my-zsh/plugins/gitfast/_git new file mode 100644 index 0000000..1283c71 --- /dev/null +++ b/home/.oh-my-zsh/plugins/gitfast/_git @@ -0,0 +1,274 @@ +#compdef git gitk + +# zsh completion wrapper for git +# +# Copyright (c) 2012-2024 Felipe Contreras +# +# The recommended way to use this script is to prepend its location to your $fpath: +# +# fpath=($git_completion_srcdir $fpath) +# + +zstyle -T ':completion:*:*:git:*' tag-order && \ + zstyle ':completion:*:*:git:*' tag-order 'common-commands' + +zstyle -s ":completion:*:*:git:*" script script +if [ -z "$script" ]; then + local -a locations + local e bash_completion + + bash_completion=$(pkg-config --variable=completionsdir bash-completion 2>/dev/null) || + bash_completion='/usr/share/bash-completion/completions/' + + locations=( + "${${funcsourcetrace[1]%:*}:A:h}"/git-completion.bash + "$HOME/.local/share/bash-completion/completions/git" + '/usr/local/share/bash-completion/completions/git' + "$bash_completion/git" + '/etc/bash_completion.d/git' # old debian + ) + for e in $locations; do + test -f $e && script="$e" && break + done +fi + +local old_complete="$functions[complete]" +functions[complete]=: +COMP_WORDBREAKS=':' +GIT_SOURCING_ZSH_COMPLETION=y . "$script" +functions[complete]="$old_complete" + +__gitcompadd () +{ + compadd -p "${2-}" -S "${3- }" -q -- ${=1} && _ret=0 +} + +__gitcomp () +{ + emulate -L zsh + + IFS=$' \t\n' __gitcompadd "$1" "${2-}" "${4- }" +} + +__gitcomp_opts () +{ + emulate -L zsh + + local cur_="${3-$cur}" + + [[ "$cur_" == *= ]] && return + + local c IFS=$' \t\n' sfx + for c in ${=1}; do + if [[ $c == "--" ]]; then + [[ "$cur_" == --no-* ]] && continue + __gitcompadd "--no-..." + break + fi + + if [[ -z "${4+set}" ]]; then + case $c in + *=) c="${c%=}"; sfx="=" ;; + *.) sfx="" ;; + *) sfx=" " ;; + esac + else + sfx="$4" + fi + __gitcompadd "$c" "${2-}" "$sfx" + done +} + +__gitcomp_nl () +{ + emulate -L zsh + + # words that don't end up in space + compadd -p "${2-}" -S "${4- }" -q -- ${${(f)1}:#*\ } && _ret=0 + # words that end in space + compadd -p "${2-}" -S " ${4- }" -q -- ${${(M)${(f)1}:#*\ }% } && _ret=0 +} + +__gitcomp_file () +{ + emulate -L zsh + + compadd -f -p "${2-}" -- ${(f)1} && _ret=0 +} + +__gitcomp_direct () +{ + __gitcomp_nl "$1" "" "" "" +} + +__gitcomp_file_direct () +{ + __gitcomp_file "$1" "" +} + +__git_complete_command () +{ + emulate -L zsh + + compset -P '*[=:]' + + local command="$1" + local completion_func="_git_${command//-/_}" + if (( $+functions[$completion_func] )); then + emulate ksh -c $completion_func + return 0 + elif emulate ksh -c "__git_support_parseopt_helper $command"; then + emulate ksh -c "__git_complete_common $command" + return 0 + else + return 1 + fi +} + +__git_zsh_bash_func () +{ + emulate -L ksh + + local command=$1 + + __git_complete_command "$command" && return + + local expansion=$(__git_aliased_command "$command") + if [ -n "$expansion" ]; then + words[1]=$expansion + __git_complete_command "$expansion" + fi +} + +__git_zsh_cmd_common () +{ + local -a list + list=( + add:'add file contents to the index' + bisect:'find by binary search the change that introduced a bug' + branch:'list, create, or delete branches' + checkout:'checkout a branch or paths to the working tree' + clone:'clone a repository into a new directory' + commit:'record changes to the repository' + diff:'show changes between commits, commit and working tree, etc' + fetch:'download objects and refs from another repository' + grep:'print lines matching a pattern' + init:'create an empty Git repository or reinitialize an existing one' + log:'show commit logs' + merge:'join two or more development histories together' + mv:'move or rename a file, a directory, or a symlink' + pull:'fetch from and merge with another repository or a local branch' + push:'update remote refs along with associated objects' + rebase:'forward-port local commits to the updated upstream head' + reset:'reset current HEAD to the specified state' + restore:'restore working tree files' + rm:'remove files from the working tree and from the index' + show:'show various types of objects' + status:'show the working tree status' + switch:'switch branches' + tag:'create, list, delete or verify a tag object signed with GPG') + _describe -t common-commands 'common commands' list && _ret=0 +} + +__git_zsh_cmd_alias () +{ + local -a list + list=(${${(0)"$(git config -z --get-regexp '^alias\.*')"}#alias.}) + list=(${(f)"$(printf "%s:alias for '%s'\n" ${(f@)list})"}) + _describe -t alias-commands 'aliases' list && _ret=0 +} + +__git_zsh_cmd_all () +{ + local -a list + emulate ksh -c __git_compute_all_commands + list=( ${=__git_all_commands} ) + _describe -t all-commands 'all commands' list && _ret=0 +} + +__git_zsh_main () +{ + local curcontext="$curcontext" state state_descr line + typeset -A opt_args + local -a __git_C_args + + _arguments -C \ + '(-p --paginate -P --no-pager)'{-p,--paginate}'[pipe all output into ''less'']' \ + '(-p --paginate -P --no-pager)'{-P,--no-pager}'[do not pipe git output into a pager]' \ + '(--bare)--git-dir=[set the path to the repository]: :_directories' \ + '(--git-dir)--bare[treat the repository as a bare repository]' \ + '(- :)--version[prints the git suite version]' \ + '--exec-path=[path to where your core git programs are installed]: :_directories' \ + '(- :)--exec-path[print the path where your core git programs are installed]' \ + '(- :)--html-path[print the path where git''s HTML documentation is installed]' \ + '(- :)--info-path[print the path where the Info files are installed]' \ + '(- :)--man-path[print the manpath (see `man(1)`) for the man pages]' \ + '--work-tree=[set the path to the working tree]: :_directories' \ + '--namespace=[set the git namespace]:' \ + '--no-replace-objects[do not use replacement refs to replace git objects]' \ + '(- :)--help[prints the synopsis and a list of the most commonly used commands]: :->arg' \ + '*-C[run as if git was started in the given path]: :_directories' \ + '*-c[pass a configuration parameter to the command]: :->config' \ + '(-): :->command' \ + '(-)*:: :->arg' && return + + case $state in + (command) + _tags common-commands alias-commands all-commands + while _tags; do + _requested common-commands && __git_zsh_cmd_common + _requested alias-commands && __git_zsh_cmd_alias + _requested all-commands && __git_zsh_cmd_all + let _ret || break + done + ;; + (config) + compset -P '*[=:]' + emulate ksh -c __git_complete_config_variable_name_and_value + ;; + (arg) + local command="${words[1]}" __git_dir __git_cmd_idx=1 + + if (( $+opt_args[--bare] )); then + __git_dir='.' + else + __git_dir=${~opt_args[--git-dir]} + fi + + for x in ${(s.:.)opt_args[-C]}; do + __git_C_args+=('-C' ${~x}) + done + + (( $+opt_args[--help] )) && command='help' + + words=( git ${words[@]} ) + + __git_zsh_bash_func $command + ;; + esac +} + +_git () +{ + local _ret=1 + local cur cword prev __git_cmd_idx=0 + + cur=${words[CURRENT]} + prev=${words[CURRENT-1]} + let cword=CURRENT-1 + + if (( $+functions[__${service}_zsh_main] )); then + __${service}_zsh_main + elif (( $+functions[__${service}_main] )); then + emulate ksh -c __${service}_main + elif (( $+functions[_${service}] )); then + emulate ksh -c _${service} + elif (( $+functions[_${service//-/_}] )); then + emulate ksh -c _${service//-/_} + fi + + let _ret && _default && _ret=0 + return _ret +} + +_git diff --git a/home/.oh-my-zsh/plugins/gitfast/git-completion.bash b/home/.oh-my-zsh/plugins/gitfast/git-completion.bash new file mode 100644 index 0000000..8a790ca --- /dev/null +++ b/home/.oh-my-zsh/plugins/gitfast/git-completion.bash @@ -0,0 +1,3562 @@ +# bash/zsh completion support for core Git. +# +# Copyright (C) 2006,2007 Shawn O. Pearce +# Copyright (c) 2012-2024 Felipe Contreras +# +# Conceptually based on gitcompletion (http://gitweb.hawaga.org.uk/). +# Distributed under the GNU General Public License, version 2.0. +# +# The contained completion routines provide support for completing: +# +# *) local and remote branch names +# *) local and remote tag names +# *) .git/remotes file names +# *) git 'subcommands' +# *) git email aliases for git-send-email +# *) tree paths within 'ref:path/to/file' expressions +# *) file paths within current working directory and index +# *) common --long-options +# +# To use these routines: +# +# 1) Copy this file to somewhere (e.g. ~/.git-completion.bash). +# 2) Add the following line to your .bashrc/.zshrc: +# source ~/.git-completion.bash +# 3) Consider changing your PS1 to also show the current branch, +# see git-prompt.sh for details. +# +# If you use complex aliases of form '!f() { ... }; f', you can use the null +# command ':' as the first command in the function body to declare the desired +# completion style. For example '!f() { : git commit ; ... }; f' will +# tell the completion to use commit completion. This also works with aliases +# of form "!sh -c '...'". For example, "!sh -c ': git commit ; ... '". +# +# If you have a command that is not part of git, but you would still +# like completion, you can use __git_complete: +# +# __git_complete gl git_log +# +# Or if it's a main command (i.e. git or gitk): +# +# __git_complete gk gitk +# +# Compatible with bash 3.2.57. +# +# You can set the following environment variables to influence the behavior of +# the completion routines: +# +# GIT_COMPLETION_CHECKOUT_NO_GUESS +# +# When set to "1", do not include "DWIM" suggestions in git-checkout +# and git-switch completion (e.g., completing "foo" when "origin/foo" +# exists). +# +# GIT_COMPLETION_SHOW_ALL_COMMANDS +# +# When set to "1" suggest all commands, including plumbing commands +# which are hidden by default (e.g. "cat-file" on "git ca"). +# +# GIT_COMPLETION_SHOW_ALL +# +# When set to "1" suggest all options, including options which are +# typically hidden (e.g. '--allow-empty' for 'git commit'). +# +# GIT_COMPLETION_IGNORE_CASE +# +# When set, uses for-each-ref '--ignore-case' to find refs that match +# case insensitively, even on systems with case sensitive file systems +# (e.g., completing tag name "FOO" on "git checkout f"). + +# The following functions are meant to modify COMPREPLY, which should not be +# modified directly. The purpose is to localize the modifications so it's +# easier to emulate it in Zsh. Every time a new __gitcomp* function is added, +# the corresponding function should be added to Zsh. + +__gitcompadd () +{ + local x i=${#COMPREPLY[@]} + for x in $1; do + if [[ "$x" == "$3"* ]]; then + COMPREPLY[i++]="$2$x$4" + fi + done +} + +# Creates completion replies. +# It accepts 1 to 4 arguments: +# 1: List of possible completion words. +# 2: A prefix to be added to each possible completion word (optional). +# 3: Generate possible completion matches for this word (optional). +# 4: A suffix to be appended to each possible completion word (optional). +__gitcomp () +{ + local IFS=$' \t\n' + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" +} + +# Generates completion reply from newline-separated possible completion words +# by appending a space to all of them. The result is appended to COMPREPLY. +# It accepts 1 to 4 arguments: +# 1: List of possible completion words, separated by a single newline. +# 2: A prefix to be added to each possible completion word (optional). +# 3: Generate possible completion matches for this word (optional). +# 4: A suffix to be appended to each possible completion word instead of +# the default space (optional). If specified but empty, nothing is +# appended. +__gitcomp_nl () +{ + local IFS=$'\n' + __gitcompadd "$1" "${2-}" "${3-$cur}" "${4- }" +} + +# Appends prefiltered words to COMPREPLY without any additional processing. +# Callers must take care of providing only words that match the current word +# to be completed and adding any prefix and/or suffix (trailing space!), if +# necessary. +# 1: List of newline-separated matching completion words, complete with +# prefix and suffix. +__gitcomp_direct () +{ + local IFS=$'\n' + + COMPREPLY+=($1) +} + +# Generates completion reply with compgen from newline-separated possible +# completion filenames. +# It accepts 1 to 3 arguments: +# 1: List of possible completion filenames, separated by a single newline. +# 2: A directory prefix to be added to each possible completion filename +# (optional). +# 3: Generate possible completion matches for this word (optional). +__gitcomp_file () +{ + local IFS=$'\n' + + # XXX does not work when the directory prefix contains a tilde, + # since tilde expansion is not applied. + # This means that COMPREPLY will be empty and Bash default + # completion will be used. + __gitcompadd "$1" "${2-}" "${3-$cur}" "" + + # use a hack to enable file mode in bash < 4 + compopt -o filenames +o nospace 2>/dev/null || + compgen -f /non-existing-dir/ >/dev/null || + true +} + +# Fills the COMPREPLY array with prefiltered paths without any additional +# processing. +# Callers must take care of providing only paths that match the current path +# to be completed and adding any prefix path components, if necessary. +# 1: List of newline-separated matching paths, complete with all prefix +# path components. +__gitcomp_file_direct () +{ + local IFS=$'\n' + + COMPREPLY+=($1) + + # use a hack to enable file mode in bash < 4 + compopt -o filenames +o nospace 2>/dev/null || + compgen -f /non-existing-dir/ >/dev/null || + true +} + +# Creates completion replies, reorganizing options and adding suffixes as needed. +# It accepts 1 to 4 arguments: +# 1: List of possible completion words. +# 2: A prefix to be added to each possible completion word (optional). +# 3: Generate possible completion matches for this word (optional). +# 4: A suffix to be appended to each possible completion word (optional). +__gitcomp_opts () +{ + local cur_="${3-$cur}" + + if [[ "$cur_" == *= ]]; then + return + fi + + local c i=0 IFS=$' \t\n' sfx + for c in $1; do + if [[ $c == "--" ]]; then + if [[ "$cur_" == --no-* ]]; then + continue + fi + + if [[ --no == "$cur_"* ]]; then + COMPREPLY[i++]="--no-... " + fi + break + fi + if [[ $c == "$cur_"* ]]; then + if [[ -z "${4+set}" ]]; then + case $c in + *=|*.) sfx="" ;; + *) sfx=" " ;; + esac + else + sfx="$4" + fi + COMPREPLY[i++]="${2-}$c$sfx" + fi + done +} + +# __gitcomp functions end here +# ============================================================================== + +# Discovers the path to the git repository taking any '--git-dir=' and +# '-C ' options into account and stores it in the $__git_repo_path +# variable. +__git_find_repo_path () +{ + if [ -n "${__git_repo_path-}" ]; then + # we already know where it is + return + fi + + if [ -n "${__git_C_args-}" ]; then + __git_repo_path="$(git "${__git_C_args[@]}" \ + ${__git_dir:+--git-dir="$__git_dir"} \ + rev-parse --absolute-git-dir 2>/dev/null)" + elif [ -n "${__git_dir-}" ]; then + test -d "$__git_dir" && + __git_repo_path="$__git_dir" + elif [ -n "${GIT_DIR-}" ]; then + test -d "$GIT_DIR" && + __git_repo_path="$GIT_DIR" + elif [ -d .git ]; then + __git_repo_path=.git + else + __git_repo_path="$(git rev-parse --git-dir 2>/dev/null)" + fi +} + +# Deprecated: use __git_find_repo_path() and $__git_repo_path instead +# __gitdir accepts 0 or 1 arguments (i.e., location) +# returns location of .git repo +__gitdir () +{ + if [ -z "${1-}" ]; then + __git_find_repo_path || return 1 + echo "$__git_repo_path" + elif [ -d "$1/.git" ]; then + echo "$1/.git" + else + echo "$1" + fi +} + +# Runs git with all the options given as argument, respecting any +# '--git-dir=' and '-C ' options present on the command line +__git () +{ + git ${__git_C_args:+"${__git_C_args[@]}"} \ + ${__git_dir:+--git-dir="$__git_dir"} "$@" 2>/dev/null +} + +# Removes backslash escaping, single quotes and double quotes from a word, +# stores the result in the variable $dequoted_word. +# 1: The word to dequote. +__git_dequote () +{ + local rest="$1" len ch + + dequoted_word="" + + while test -n "$rest"; do + len=${#dequoted_word} + dequoted_word="$dequoted_word${rest%%[\\\'\"]*}" + rest="${rest:$((${#dequoted_word}-$len))}" + + case "${rest:0:1}" in + \\) + ch="${rest:1:1}" + case "$ch" in + $'\n') + ;; + *) + dequoted_word="$dequoted_word$ch" + ;; + esac + rest="${rest:2}" + ;; + \') + rest="${rest:1}" + len=${#dequoted_word} + dequoted_word="$dequoted_word${rest%%\'*}" + rest="${rest:$((${#dequoted_word}-$len+1))}" + ;; + \") + rest="${rest:1}" + while test -n "$rest" ; do + len=${#dequoted_word} + dequoted_word="$dequoted_word${rest%%[\\\"]*}" + rest="${rest:$((${#dequoted_word}-$len))}" + case "${rest:0:1}" in + \\) + ch="${rest:1:1}" + case "$ch" in + \"|\\|\$|\`) + dequoted_word="$dequoted_word$ch" + ;; + $'\n') + ;; + *) + dequoted_word="$dequoted_word\\$ch" + ;; + esac + rest="${rest:2}" + ;; + \") + rest="${rest:1}" + break + ;; + esac + done + ;; + esac + done +} + +# Clear the variables caching builtins' options when (re-)sourcing +# the completion script. +if [[ -n ${ZSH_VERSION-} ]]; then + unset ${(M)${(k)parameters[@]}:#__gitcomp_builtin_*} 2>/dev/null +else + unset $(compgen -v __gitcomp_builtin_) +fi + +# This function is equivalent to +# +# __gitcomp_opts "$(git xxx --git-completion-helper) ..." +# +# except that the output is cached. Accept 1-3 arguments: +# 1: the git command to execute, this is also the cache key +# 2: extra options to be added on top (e.g. negative forms) +# 3: options to be excluded +__gitcomp_builtin () +{ + # spaces must be replaced with underscore for multi-word + # commands, e.g. "git remote add" becomes remote_add. + local cmd="$1" + local incl="${2-}" + local excl="${3-}" + + local var=__gitcomp_builtin_"${cmd//-/_}" + local options + eval "options=\${$var-}" + + if [ -z "$options" ]; then + local completion_helper + if [ "${GIT_COMPLETION_SHOW_ALL-}" = "1" ]; then + completion_helper="--git-completion-helper-all" + else + completion_helper="--git-completion-helper" + fi + # leading and trailing spaces are significant to make + # option removal work correctly. + options=" $incl $(__git ${cmd/_/ } $completion_helper) " || return + + for i in $excl; do + options="${options/ $i / }" + done + eval "$var=\"$options\"" + fi + + __gitcomp_opts "$options" +} + +# Execute 'git ls-files', unless the --committable option is specified, in +# which case it runs 'git diff-index' to find out the files that can be +# committed. It return paths relative to the directory specified in the first +# argument, and using the options specified in the second argument. +__git_ls_files_helper () +{ + if [ "$2" = "--committable" ]; then + __git -C "$1" -c core.quotePath=false diff-index \ + --name-only --relative HEAD -- "${3//\\/\\\\}*" + else + # NOTE: $2 is not quoted in order to support multiple options + __git -C "$1" -c core.quotePath=false ls-files \ + --exclude-standard $2 -- "${3//\\/\\\\}*" + fi +} + + +# __git_index_files accepts 1 or 2 arguments: +# 1: Options to pass to ls-files (required). +# 2: A directory path (optional). +# If provided, only files within the specified directory are listed. +# Sub directories are never recursed. Path must have a trailing +# slash. +# 3: List only paths matching this path component (optional). +__git_index_files () +{ + local root="$2" match="$3" + + __git_ls_files_helper "$root" "$1" "${match:-?}" | + awk -F / -v pfx="${2//\\/\\\\}" '{ + paths[$1] = 1 + } + END { + for (p in paths) { + if (substr(p, 1, 1) != "\"") { + # No special characters, easy! + print pfx p + continue + } + + # The path is quoted. + p = dequote(p) + if (p == "") + continue + + # Even when a directory name itself does not contain + # any special characters, it will still be quoted if + # any of its (stripped) trailing path components do. + # Because of this we may have seen the same directory + # both quoted and unquoted. + if (p in paths) + # We have seen the same directory unquoted, + # skip it. + continue + else + print pfx p + } + } + function dequote(p, bs_idx, out, esc, esc_idx, dec) { + # Skip opening double quote. + p = substr(p, 2) + + # Interpret backslash escape sequences. + while ((bs_idx = index(p, "\\")) != 0) { + out = out substr(p, 1, bs_idx - 1) + esc = substr(p, bs_idx + 1, 1) + p = substr(p, bs_idx + 2) + + if ((esc_idx = index("abtvfr\"\\", esc)) != 0) { + # C-style one-character escape sequence. + out = out substr("\a\b\t\v\f\r\"\\", + esc_idx, 1) + } else if (esc == "n") { + # Uh-oh, a newline character. + # We cannot reliably put a pathname + # containing a newline into COMPREPLY, + # and the newline would create a mess. + # Skip this path. + return "" + } else { + # Must be a \nnn octal value, then. + dec = esc * 64 + \ + substr(p, 1, 1) * 8 + \ + substr(p, 2, 1) + out = out sprintf("%c", dec) + p = substr(p, 3) + } + } + # Drop closing double quote, if there is one. + # (There is not any if this is a directory, as it was + # already stripped with the trailing path components.) + if (substr(p, length(p), 1) == "\"") + out = out substr(p, 1, length(p) - 1) + else + out = out p + + return out + }' +} + +# __git_complete_index_file requires 1 argument: +# 1: the options to pass to ls-file +# +# The exception is --committable, which finds the files appropriate commit. +__git_complete_index_file () +{ + local dequoted_word pfx="" cur_ + + __git_dequote "$cur" + + case "$dequoted_word" in + ?*/*) + pfx="${dequoted_word%/*}/" + cur_="${dequoted_word##*/}" + ;; + *) + cur_="$dequoted_word" + esac + + __gitcomp_file_direct "$(__git_index_files "$1" "$pfx" "$cur_")" +} + +# Lists branches from the local repository. +# 1: A prefix to be added to each listed branch (optional). +# 2: List only branches matching this word (optional; list all branches if +# unset or empty). +# 3: A suffix to be appended to each listed branch (optional). +__git_heads () +{ + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + + __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "refs/heads/$cur_*" "refs/heads/$cur_*/**" +} + +# Lists branches from remote repositories. +# 1: A prefix to be added to each listed branch (optional). +# 2: List only branches matching this word (optional; list all branches if +# unset or empty). +# 3: A suffix to be appended to each listed branch (optional). +__git_remote_heads () +{ + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + + __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "refs/remotes/$cur_*" "refs/remotes/$cur_*/**" +} + +# Lists tags from the local repository. +# Accepts the same positional parameters as __git_heads() above. +__git_tags () +{ + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + + __git for-each-ref --format="${pfx//\%/%%}%(refname:strip=2)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "refs/tags/$cur_*" "refs/tags/$cur_*/**" +} + +# List unique branches from refs/remotes used for 'git checkout' and 'git +# switch' tracking DWIMery. +# 1: A prefix to be added to each listed branch (optional) +# 2: List only branches matching this word (optional; list all branches if +# unset or empty). +# 3: A suffix to be appended to each listed branch (optional). +__git_dwim_remote_heads () +{ + local pfx="${1-}" cur_="${2-}" sfx="${3-}" + local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers + + # employ the heuristic used by git checkout and git switch + # Try to find a remote branch that cur_es the completion word + # but only output if the branch name is unique + __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + --sort="refname:strip=3" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "refs/remotes/*/$cur_*" "refs/remotes/*/$cur_*/**" | \ + uniq -u +} + +# Lists refs from the local (by default) or from a remote repository. +# It accepts 0, 1 or 2 arguments: +# 1: The remote to list refs from (optional; ignored, if set but empty). +# Can be the name of a configured remote, a path, or a URL. +# 2: In addition to local refs, list unique branches from refs/remotes/ for +# 'git checkout's tracking DWIMery (optional; ignored, if set but empty). +# 3: A prefix to be added to each listed ref (optional). +# 4: List only refs matching this word (optional; list all refs if unset or +# empty). +# 5: A suffix to be appended to each listed ref (optional; ignored, if set +# but empty). +# +# Use __git_complete_refs() instead. +__git_refs () +{ + local i hash dir track="${2-}" + local list_refs_from=path remote="${1-}" + local format refs + local pfx="${3-}" cur_="${4-$cur}" sfx="${5-}" + local match="${4-}" + local umatch="${4-}" + local fer_pfx="${pfx//\%/%%}" # "escape" for-each-ref format specifiers + + __git_find_repo_path + dir="$__git_repo_path" + + if [ -z "$remote" ]; then + if [ -z "$dir" ]; then + return + fi + else + if __git_is_configured_remote "$remote"; then + # configured remote takes precedence over a + # local directory with the same name + list_refs_from=remote + elif [ -d "$remote/.git" ]; then + dir="$remote/.git" + elif [ -d "$remote" ]; then + dir="$remote" + else + list_refs_from=url + fi + fi + + if test "${GIT_COMPLETION_IGNORE_CASE:+1}" = "1" + then + # uppercase with tr instead of ${match,^^} for bash 3.2 compatibility + umatch=$(echo "$match" | tr a-z A-Z 2>/dev/null || echo "$match") + fi + + if [ "$list_refs_from" = path ]; then + if [[ "$cur_" == ^* ]]; then + pfx="$pfx^" + fer_pfx="$fer_pfx^" + cur_=${cur_#^} + match=${match#^} + umatch=${umatch#^} + fi + case "$cur_" in + refs|refs/*) + format="refname" + refs=("$match*" "$match*/**") + track="" + ;; + *) + for i in HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD REBASE_HEAD CHERRY_PICK_HEAD; do + case "$i" in + $match*|$umatch*) + if [ -e "$dir/$i" ]; then + echo "$pfx$i$sfx" + fi + ;; + esac + done + format="refname:strip=2" + refs=("refs/tags/$match*" "refs/tags/$match*/**" + "refs/heads/$match*" "refs/heads/$match*/**" + "refs/remotes/$match*" "refs/remotes/$match*/**") + ;; + esac + __git_dir="$dir" __git for-each-ref --format="$fer_pfx%($format)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "${refs[@]}" + if [ -n "$track" ]; then + __git_dwim_remote_heads "$pfx" "$match" "$sfx" + fi + return + fi + case "$cur_" in + refs|refs/*) + __git ls-remote "$remote" "$match*" | \ + while read -r hash i; do + case "$i" in + *^{}) ;; + *) echo "$pfx$i$sfx" ;; + esac + done + ;; + *) + if [ "$list_refs_from" = remote ]; then + case "HEAD" in + $match*|$umatch*) echo "${pfx}HEAD$sfx" ;; + esac + __git for-each-ref --format="$fer_pfx%(refname:strip=3)$sfx" \ + ${GIT_COMPLETION_IGNORE_CASE+--ignore-case} \ + "refs/remotes/$remote/$match*" \ + "refs/remotes/$remote/$match*/**" + else + local query_symref + case "HEAD" in + $match*|$umatch*) query_symref="HEAD" ;; + esac + __git ls-remote "$remote" $query_symref \ + "refs/tags/$match*" "refs/heads/$match*" \ + "refs/remotes/$match*" | + while read -r hash i; do + case "$i" in + *^{}) ;; + refs/*) echo "$pfx${i#refs/*/}$sfx" ;; + *) echo "$pfx$i$sfx" ;; # symbolic refs + esac + done + fi + ;; + esac +} + +# Completes refs, short and long, local and remote, symbolic and pseudo. +# +# Usage: __git_complete_refs [