Re: broken bash completion
Hi Rolf,
On Sat, May 05, 2012 at 12:24:38PM +0800, Rolf Leggewie wrote:
> After all is said and done, though, the bash-completion remains
> inconsistent and thus broken. It's great that your life is
> currently more convenient but in the end you are relying on broken
> behaviour.
Well, git's completion script is consistent with itself: whenever there is no matching subcommand, option, parameter for an option, or ref, it falls back to filename completion. I wouldn't consider this behavior as broken.
Show 5 quoted lines
> Affected commands:
> git log
> git diff
> git whatchanged
> git branch (why offer tags OR files here at all)
While files and tags make no sense for 'git branch' itself, completing them can be helpful to construct the name of a new branch. I did the following at dayjob just the other day:
# there are route_calculation.c and .h files in that project, and # there were some nasty bugs in there $ git branch ro<TAB> # which gave me $ git branch route_calculation. # just deleted the '.' and completed the new branch name by hand $ git branch route_calculation_fixes
Anyway, I see two ways to fix this if we want to be anal, but none of them is actually applicable:
- When registering _git() as the completion function for the git
command, we specify some options to tell Bash to do filename
completion when we can't find any matches to the word to be
completed. Recent Bash versions provide the 'compopt' builtin to
allow modifying completion options for the currently executed
completion. We could do a 'compopt +o bashdefault +o default'
to disable the filename completion fallback wherever we deem it
inappropriate.
'compopt' was introduced in Bash 4.0, but unfortunately msysgit
still includes an older version, so this is a no go.
- We don't specify the options to ask Bash to fall back to filename
completion when registering _git(). This will disable filename
completion for the whole git completion script, so we must roll our
own helper functions to do filename completion, which we would
invoke wherever filename completion is explicitly desired.
This should work on any Bash version, but would inherently include
some fork()+exec()s, adding significant delays especially on
msysgit.
> Unaffected programs, i.e. working correctly:
> git commit
> [...]
You haven't tried it hard enough ;)
$ git commit --fixup=e<TAB> editor.c entry.c environment.c exec_cmd.c exec_cmd.o editor.o entry.o environment.o exec_cmd.h
although at that point only a commit is accepted.
> Some consistency would be great. In a perfect world bash-completion
> ought to work on all possible completion targets but at the same
> time it should exclude all that make no sense, too. Neither of the
> two seems to be currently the case.
Yeah, in that perfect world 'git rm <TAB>', 'git bisect -- <TAB>', and 'git log -- <TAB>' whould offer only tracked files, 'git (add|commit) <TAB>' only modified or untracked files, and 'git diff <TAB>' would read your mind to find out whether you want to diff a ref or a file, etc. etc.
But you miss an important point here: users expect the completion to be pretty fast, because delays are quite noticeable and annoying while typing a command. So there's a trade-off between correctness and usability. Unfortunately, in the real world all that filtering costs a great deal, so git's completion script does that only if it can be done cheaply (e.g. 'git rebase --<TAB>' won't offer you '--abort' and '--continue' if you're not in the middle of an ongoing rebase). And as pointed out above, something might be nonsense for a command, but still be useful for the user.
Best, Gábor