Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expand wildcards on tab #8593

Closed

Conversation

ridiculousfish
Copy link
Member

Prior to this change, if you tab-completed a token with a wildcard (glob), we would invoke ordinary completions. Instead, expand the wildcard, replacing the wildcard with the result of expansions. If the wildcard fails to expand, flash the command line to signal an error and do not modify it.

Example:

> touch file(seq 4)
> echo file*<tab>

becomes:

> echo file1 file2 file3 file4

whereas before the tab would have just added a space.

Some things to note:

  1. If the expansion would produce more than 256 items, we flash the command line and do nothing, since it would make the commandline overfull.
  2. The wildcard token can be brought back through Undo (ctrl-Z).

Fixes #954.

The handle_readline_command function is getting unwieldy, so factor it
better to reduce its length. No functional change here.
When fish expands a string that starts with a tilde, like `~/stuff/*`, it
first must resolve the tilde (e.g. to the user's home directory) before
passing it to wildcard expansion. The wildcard expansion will produce full
paths like `/home/user/stuff/file`. fish then "unexpands" the home directory
back to a tilde.

Previously this was only used during completions, but in the next commit
we plan to use it for string expansions as well.

Rationalize this behavior by adding an explicit flag to request it and
explain some subtleties about completions.
Prior to this change, if you tab-completed a token with a wildcard (glob), we
would invoke ordinary completions. Instead, expand the wildcard, replacing
the wildcard with the result of expansions. If the wildcard fails to expand,
flash the command line to signal an error and do not modify it.

Example:

    > touch file(seq 4)
    > echo file*<tab>

becomes:

    > echo file1 file2 file3 file4

whereas before the tab would have just added a space.

Some things to note:

1. If the expansion would produce more than 256 items, we flash the command
line and do nothing, since it would make the commandline overfull.

2. The wildcard token can be brought back through Undo (ctrl-Z).

Fixes fish-shell#954.
@krobelus
Copy link
Member

krobelus commented Dec 29, 2021

This is really powerful, but it disallows some scenarios,
Press tab on

ls ~/.config/*/conf

(The glob is useful in case there are multiple directories with interesting files.)

previously, we got a set of completions with entries like ~/.config/*/config.fish.
Now we get nothing (since there is no file named "conf").

Maybe ~/.config/*/conf should expand to ~/.config/fish/config.fish ~/.config/whatever/we.conf.
This is fixable: don't expand the last path component, but ask the completion engine instead.

Sadly that's still not perfect, because sometimes preserving the glob is nice.
Think of ls src/*/java/com/example/... - I want to tab-complete the java/com/example components but not expand the glob.
Of course that case is rare so I don't know how important it is; I'll try it for a while.

Maybe there is a criteria to guess if the user wants expansion or not. Hopefully we can avoid a separate key binding.

@krobelus
Copy link
Member

krobelus commented Jan 1, 2022

Maybe only expand * in the current path component. That'd cut this feature back so some useful completions keep working.

Here are some scenarios (where | is the cursor)

  1. echo R*|

    • Expand to README.rst
  2. echo *.r|

    • Glob fails, so offer completion (*.rst because README.rst exists).
  3. echo *.rst|

    • Expand to README.rst
  4. echo benchmarks/*|

    • Expand to benchmarks/benchmarks/ benchmarks/driver.sh
  5. echo benchmarks/*/|

    • No glob in current path component, so offer completion (benchmarks/*/aliases.fish etc.).
  6. echo ben*/*|

    • Expand to benchmarks/benchmarks/ benchmarks/driver.sh
    • Alternative: only expand the second *. That might be harder to implement.
  7. echo benchmarks/*|/

    • Expand to benchmarks/benchmarks/ (not driver.sh, because of the trailing slash)
  8. echo ben*|/nosuchfile

    • Glob fails, so offer completion, which also fails.
  9. echo ben*|/bench

    • Glob fails, so offer completion (bench*/benchmarks/) like we do now.
    • Alternative/future: expand parts of the glob, to benchmarks/bench and perhaps immediately complete to benchmarks/benchmarks/
  10. echo {benchmarks/*/,benchm}a|

  • No glob in current path component, so offer completion (not really important I guess).
  1. echo ben**/aliases.fish|
  • Expand to benchmarks/benchmarks/aliases.fish, even though ** is not in the current path component!
  1. echo ben**/aliases.|
  • Glob fails, so offer completion (this case is not really important, it doesn't work in master either).

I think these are acceptable because filename completion rarely does much when there is a * in the current path component (plus we can fall back to it, see 2).
So we'd need tweaks for 2 and 5 (I haven't looked at the source code yet).
I'm not entirely sure about 11, but that's not so important.

@ridiculousfish
Copy link
Member Author

ridiculousfish commented Apr 10, 2022

Shout-out to @krobelus for detailed thinking here. I successfully implemented 1 through 10 (and 12 is unchanged). For 6, I didn't implement "expand only one wildcard;" it's probably doable but can be saved for the future.

143757e

@ridiculousfish ridiculousfish deleted the expand-wildcards branch April 10, 2022 21:17
@krobelus krobelus added this to the fish 3.5.0 milestone Apr 10, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Apr 17, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Make tab-completion with wildcards make more sense
2 participants