bash-completion icon indicating copy to clipboard operation
bash-completion copied to clipboard

Handle ambiguous globs gracefully

Open DabeDotCom opened this issue 9 years ago • 10 comments

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

DabeDotCom avatar Oct 04 '16 20:10 DabeDotCom

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)

scop avatar Oct 04 '16 21:10 scop

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... :-(

DabeDotCom avatar Oct 04 '16 23:10 DabeDotCom

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.

scop avatar Oct 05 '16 04:10 scop

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

DabeDotCom avatar Oct 05 '16 16:10 DabeDotCom

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.

scop avatar Oct 05 '16 16:10 scop

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

DabeDotCom avatar Oct 05 '16 17:10 DabeDotCom

Ah, thanks for the clarification. And yuck :)

scop avatar Oct 05 '16 17:10 scop

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»

DabeDotCom avatar Oct 05 '16 17:10 DabeDotCom

Awaiting this pull request for merge. I successfully use base-completion with this patch on a regular basis.

AleXoundOS avatar Apr 15 '20 18:04 AleXoundOS

The test suite has been considerably reworked in past few years, perhaps it would be easier to add some test cases now.

scop avatar Apr 22 '20 18:04 scop