bash-completion
bash-completion copied to clipboard
Handle ambiguous globs gracefully
Fall back to bash's default glob handling (i.e., list multiple matches) See: http://superuser.com/a/1022284/541376
if [[ ${#toks[@]} -ne 0 ]]; then
#2>/dev/null for direct invocation, e.g. in the _filedir unit test
compopt -o filenames 2>/dev/null
COMPREPLY+=( "${toks[@]}" )
+ else
+ compopt -o bashdefault 2>/dev/null
fi
Adding compopt -o bashdefault after failed matches lets you eat your cake and have it, too: you can keep your shopt -s progcomp bash_completion AND if that doesn't find a match, it will fall back to bash's default glob handling:
prompt% ls ~/.bash*<TAB> # Bell
prompt% ls ~/.bash*<TAB><TAB>
.bash_alias .bash_history .bash_logout .bash_profile .bashrc
While for some completions that may be desirable, for some others it explicitly isn't. We already have the COMP_FILEDIR_FALLBACK option that users who disagree with our default non-completion behavior can set to get the bash default one (see documentation)
While for some completions that may be desirable, for some others it explicitly isn't.
I'm sure there's been extensive discussion — the issue has been around for over a year! — but it didn't show up when I searched... :-\
We already have the COMP_FILEDIR_FALLBACK option that users who disagree with our default non-completion behavior can set to get the bash default one (see documentation)
I'm not sure I understand what COMP_FILEDIR_FALLBACK is supposed to do (I'm not talking about .extensions — just regular globs) but it doesn't seem to do what I mean...
From the PR, here's what I _want_ to have happen:
prompt% ls ~/.bash*<TAB> # Bell
prompt% ls ~/.bash*<TAB><TAB>
.bash_alias .bash_history .bash_logout .bash_profile .bashrc
prompt% ls ~/.bash*o*<TAB><TAB>
.bash_history .bash_logout .bash_profile
Regardless of whether COMP_FILEDIR_FALLBACK is set, I never get the partial alternatives... :-(
Ah, I misunderstood somewhat. The problem is valid - glob completion doesn't work at all with bash-completion. But the implementation may not be as I think it might interfere with for example the explicitly wanted filename extension non-completion cases, as well as possibly turning cases where we want only dirs completed into completing files if no dirs are found. (Haven't checked yet.) But in any case, this will require a slew of test cases for our test suite to ensure it works exactly as desired with no anticipated side effects.
Ah, I misunderstood somewhat. The problem is valid - glob completion doesn't work at all with bash-completion.
Thanks for looking into this!
But the implementation may not be as I think it might interfere with for example the explicitly wanted filename extension non-completion cases, as well as possibly turning cases where we want only dirs completed into completing files if no dirs are found. (Haven't checked yet.)
If it helps minimize collateral damage, one possible (simple) way to limit the scope of the change might be to use [[ $COMP_TYPE -eq 63 ]] to verify we're in a secondary tab completion: «shrug»
if [[ ${#toks[@]} -ne 0 ]]; then
# 2>/dev/null for direct invocation, e.g. in the _filedir unit test
compopt -o filenames 2>/dev/null
COMPREPLY+=( "${toks[@]}" )
+ elif [[ $COMP_TYPE -eq 63 ]]; then
+ compopt -o bashdefault 2>/dev/null
fi
(Another thought would be to explicitly search $cur for glob characters, but that feels kind of gross... And you'd have to make sure they weren't \quoted, and maybe check whether shopt -s extglob is in effect, to know if you need to look for +(...) and @(...), etc.)
But in any case, this will require a slew of test cases for our test suite to ensure it works exactly as desired with no anticipated side effects.
I did look into adding some tests, but couldn't figure out exactly how/where to indicate that I wanted to operate on the SECOND <Tab>. (I'm totally in favor of TDD, though!)
My guess is I would have to crack open test/lib/library.exp and either duplicate the "assert_complete_many"-type procedures to send $cmd\t\t — or perhaps just add something like a -send-two-tabs argument, then use that to trigger sending the second \t.
But thanks for helping me look into it! :-D
Hm, testing for a magic value like 63 for COMP_TYPE sounds kind of ugly to me too. My bash (4.3.42) man page doesn't document any numeric values for it whatsoever, but just TAB, ?, !, @, and %.
Also, I think the first vs second tab thing is a user preference. I would personally actually want the completions to appear on first tab, just like I want them for all other cases. For other, usual cases I'm setting set show-all-if-ambiguous on in ~/.inputrc to get that.
So I guess I'm suggesting to forget about the 1st vs 2nd tab issue until the base functionality has been otherwise validated.
Hm, testing for a magic value like 63 for COMP_TYPE sounds kind of ugly to me too. My bash (4.3.42) man page doesn't document any numeric values for it whatsoever, but just TAB, ?, !, @, and %.
Yeah, it says:
Set to an _integer_ value corresponding to the type of completion attempted that caused a completion function to be called: TAB, for normal completion, ?, for listing completions after successive tabs, !, for listing alternatives on partial word completion, @, to list completions if the word is not unmodified, or %, for menu completion.
Which is dumb, since TAB is ASCII 9, ? is ASCII 63, ! is ASCII 33, and @ is ASCII 64, and % is 37.
I figured hard-coding the 63 was better than something like [[ $COMP_TYPE -eq $(echo -n \? | od -d | awk '{print $2}') ]] ;-D
Ah, thanks for the clarification. And yuck :)
PS — It's not much better [I don't expect the lower 7-bit ASCII characters to change any time soon... and if they do, we're in a lot more trouble than just shell completion not working] but I do feel compelled to provide a slightly* less obfuscated version:
[[ $COMP_TYPE -eq $(printf %d "'?") ]]
* Note the single quote inside the double quotes... From the bash(1) manpage:
... if the leading character is a single or double quote, the value is the ASCII value of the following character
(I learned something new today!)
Regardless, you raise a good point about show-all-if-ambiguous. I knew there would be some edge cases to consider, but _yikes!_ «grin»
Awaiting this pull request for merge. I successfully use base-completion with this patch on a regular basis.
The test suite has been considerably reworked in past few years, perhaps it would be easier to add some test cases now.