7

i use alias which adds some parameters to some program.

for example:

alias git.home='git --git-dir=$HOME/.git.home/'

complete -o bashdefault -o default -o nospace -F _git git.home \
  2>/dev/null || complete -o default -o nospace -F _git git.home

it works with bash-completion v.1:2.0-1 ("debian 7 wheezy"):
tab completes parameters and options for alias git.home as well as for "original" git.

but with bash-completion v.1:2.1-4 ("debian 8 jessie") after typing git.home and pressing tab i get this error:

bash: completion: function `_git' not found

how to re-use existing completion (for example for git) with recent versions of package bash-completion?


update

found partial solution: do source /usr/share/bash-completion/completions/git before complete ...

but i get another error - git.home log + space + tab results in:

fatal: Not a git repository (or any of the parent directories): .git HEAD

3 Answers 3

8

how to re-use existing completion (for example for git) with recent versions of package bash-completion

Add the following lines to your ~/.bashrc:

_completion_loader git
eval $(complete -p git | perl -pe 's/(\s)git$/$1git.home/')

Explanation:

bash-completion uses a dynamic loading of completions since 1.90. So, the git compspec unavailable before your typing git,Space,Tab.

Try:

bash
complete -p git # bash: complete: git: no completion specification
git<space><tab>
complete -p git # complete -o bashdefault -o default -o nospace -F __git_wrap__git_main git

_completion_loader git imitates git,Space,Tab (i.e. loads a compspec for git)

complete -p git | perl -pe 's/(\s)git$/$1git.home/' builds a compspec for git.home (replaces git to git.home in a git's compspec)

eval execute the resulting compspec.

Type git.home,Space,pTab. You should see:

popt   pull   push

But git.home log,Space,Tab produces:

fatal: Not a git repository (or any of the parent directories): .git HEAD

This message is a result of the git completion bug. There is a fix in the upstream: completion: silence "fatal: Not a git repository" error

Looks like another question:)

_githome(){ 
   GIT_DIR=$HOME/.git.home
   complete -o default -o nospace -F _git git.home
 }

doesn't work as expected. You set GIT_DIR for current session. Try with your solution:

bash
git clone git://git.debian.org/git/bash-completion/bash-completion.git ~/bash-completion
cd ~/bash-completion
git log<space><tab> # completion for current repo
git.home log<space><tab> # completion for GIT_DIR
git log<space><tab> # completion for GIT_DIR
9
  • doesn't work as expected — it works for me as expected. f.e., git log shows history for the repo in ./.git/, and git.home log shows history for the repo in ~/.git.home/. and completion of branches in both cases is working correctly. Commented Jul 18, 2015 at 10:20
  • hm, I can't reproduce. What do you see after last git log<space><tab>? What do you see for git --git-dir=.git log<space><tab> in ~/bash_completion?
    – Evgeny
    Commented Jul 18, 2015 at 10:33
  • 1. use jessie and "official" package bash-completion. 2. append these lines to ~/.bashrc and re-login. 3. cp -a /some/repo/.git ~/.git.home. 4. cd. 5. try git.home log, git.home status etc. Commented Jul 18, 2015 at 10:47
  • What do you see after last git log<space><tab> — hmm. in home dir this should cause the error, but i see branches from ~/.git.home Commented Jul 18, 2015 at 10:52
  • yes, cd, git.home log, git.home status works fine. but git log<space><tab> always shows git --git-dir=$HOME/.git.home for-each-ref '--format=%(refname:short)' refs/tags refs/heads refs/remotes and HEAD. i.e. git.home completion affects git completion
    – Evgeny
    Commented Jul 18, 2015 at 11:03
2

updated

solution for alias git.home, which operates with ~/.git.home as repo.

partially based on this answer.

add to ~/.bashrc:

alias git.home='git --git-dir=$HOME/.git.home/'

_completion_loader git
eval "$(complete -p git | sed -r 's/(\s)git$/\1git.home/')"

eval "$(type __gitdir | 
  sed '1d;1,/if/s|if|if [[ "$COMP_LINE" == "git.home "* ]]; then\necho "$HOME/.git.home"\nelif|')"

explanation of last eval (for other lines see answer):

we are patching the function __gitdir(), which returns a path to the git repo dir. from:

$ type __gitdir | head -n 4
__gitdir is a function
__gitdir () 
{ 
    if [ -z "${1-}" ]; then

to:

$ type __gitdir | head -n 7
__gitdir is a function
__gitdir () 
{ 
    if [[ "$COMP_LINE" == "git.home "* ]]; then
        echo "$HOME/.git.home";
    else
        if [ -z "${1-}" ]; then

i.e., if command starts with a "git.home ", function returns $HOME/.git.home.

0

This is a general answer that should work for any completion function. I'm concerned about the insecurity of the other answers assuming a single line output to be parsed by sed or perl and I can implement that without an external call.

# Usage: complete_as TARGET COMMAND [COMMAND...]
# Tab-complete one or more COMMANDs like TARGET
complete_as() {
  _completion_loader "$1"
  local completion="$(complete -p "$1")"
  completion="${completion%[[:space:]]$1}"
  shift
  eval "$completion $@"
}
complete_as git git.home

Just like the sed and perl code in the older answers, this replaces the last instance of the target command ($1) with the new command ($2), but I'm using parameter substitution, which views the whole content rather than running on each line of the output. This is important because the end of the output of the completion function sometimes has line breaks (as is the case with complete -W "$(_parse_help foo)" foo). Removing external calls also makes this much faster, which you may notice if you're doing a lot of these.

You could similarly build such safeties (and use bash substitution) to fix the __gitdir function like aleksandr barakin's answer does.

See also this zsh solution to the same question.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .