scop / bash-completion

Programmable completion functions for bash
GNU General Public License v2.0
2.92k stars 380 forks source link

adding an alias completion helper #521

Open calestyo opened 3 years ago

calestyo commented 3 years ago

Hey there.

A recurring question seems to be how to automatically get completions for aliases. Numerous code snippets and helper functions can be found, e.g. here:

It seems that getting it right and especially covering all cases, like support for git or to get aliases completed that already contained arguments, is trickier than a one liner.

I think it would be nice if bash-completion could provide a proper helper for this, i.e. one that covers all cases and solves it reasonably cleanly. Shipping this with bash-completion would have the great benefit, that sooner or later most distros would get it out-of-the box, while a separate small project has often only little chances to really find its way into all distros.

Cheers, Chris.

scop commented 3 years ago

I can have a look if someone submits one, however if it doesn't come with a promise to help maintain it (well to take ownership to be fair), it needs to be one that doesn't make my head hurt (and come with a bunch of test cases). I'm afraid the ones quickly visible from the links all do inflict that ache.

Failing that, I could add a FAQ entry for this and point towards https://github.com/cykerway/complete-alias, that one seems a cleanly installable thing that works for all cases if it works as advertised. But I'd need to take a closer look at it before doing so.

calestyo commented 3 years ago

Should I ask the maintainer of complete-alias whether he'd consider to merge it into bash-completion?

scop commented 3 years ago

If the test cases and offer for long term maintainership within bash-completion are in order, sure.

cykerway commented 3 years ago

I think a FAQ entry is good for now, and take your time to review complete-alias if you are interested in merging.

Long answer.

akinomyoga commented 1 year ago

Ref: PR #104

calestyo commented 1 year ago

Nice... how does it come that this seems so much smaller in terms of of code than cykerway/complete-alias?

akinomyoga commented 1 year ago

104 is the version 7 years before. I just today realized that @cykerway has already submitted the very initial version of cykerway/complete-alias in bash-completion as a PR, so I thought it'd be good to mention it for reference.

No one has yet started to work on the migration of the latest version of complete-alias to bash-completion, but if it would finally be merged, it should replace #104 (or we might work on it by adding commits in #104, but I haven't checked in detail how much the latest version has been changed since #104).

jw013 commented 1 year ago

I found that bash has a progcomp_alias shopt that is close to doing the desired behavior of expanding aliases for completions, but it is only used as a last resort if complete -D is not active which makes it incompatible with dynamically loaded completions. If the relative priorities could be flipped around I believe that would solve everything and architecturally that seems much cleaner than a reimplementation of alias parsing and expansion in shell functions. It seems like this idea has been raised at least once in the past but not met with much enthusiasm.

One workaround I have been using is to simply expand the alias manually before attempting to trigger completion. By default bash binds the key chord Alt-Control-e to the command shell-expand-line, which will expand the alias. It will also expand any $variables in the input line so if so if this is not desirable one may prefer a binding to the alias-expand-line command instead.

akinomyoga commented 1 year ago

I remember there were similar discussions about complete -D and progcomp_alias in the past. FWIW, these are the discussions that I can find now:

calestyo commented 1 month ago

Is there a proper way to have completions for some command (e.g. systemctl, as given in /usr/share/bash-completion/completions/systemctl) be loaded for some other (alias) command name (like sc)?

I'd basically like to use:

alias sc=systemctl
complete -F _systemctl sc

but _systemctl is only loaded when /usr/share/bash-completion/completions/systemctl is loaded (which happens only dynamically.

I can of course add another:

_comp_load -D -- 'systemctl' && return 124

to trigger the loading unconditionally, but then I always have the functions from the dynamic completions for systemctl around, even if not used.

I also tried making ~/.local/share/bash-completion/completions/sc a symlink to /usr/share/bash-completion/completions/systemctl, but that doesn't seem to do the job.

Thanks, Chris.

beavailable commented 1 month ago

@calestyo Here is the command I use:

sed -E 's/^(\s*complete -F _systemctl )systemctl$/\1sc/' /usr/share/bash-completion/completions/systemctl >~/.local/share/bash-completion/completions/sc

For other commands, you just need to substitute the command name, the completion function name and the aliases, then execute it. But I'm not sure if it works for all commands.

calestyo commented 1 month ago

@beavailable Thanks, that works :-) but has IMO two downsides:

I played a bit and came up with the following for ~/.local/share/bash-completion/completions/sc:

#load `systemctl`’s completion code, if the completion for `systemctl` has not been defined yet
# The latter could have happened by previously completing `systemctl`. If `sc`
# would have been previously completed, this script would not be sourced again
# (see the `-D`-option of bash’s `complete`-built-in-utility and the definition
# of the completion for `sc` below).
if ! complete -p systemctl 2>/dev/null; then
    _comp_complete_load systemctl
fi

complete -F _systemctl sc

That should do the following:

The only thing I don't know right now is whether one should call _comp_complete_load or rather _comp_load directly... @akinomyoga @scop... what would you recommend? :-)

akinomyoga commented 1 month ago

The only thing I don't know right now is whether one should call _comp_complete_load or rather _comp_load directly... @akinomyoga @scop... what would you recommend? :-)

Use _comp_load. See Naming: _comp_complete_* are the functions to be specified to complete -F. They are not intended to be called by scripts. While the exit status of _comp_complete_load follows a specific way of Bash's programmable completion scheme, the exit status of _comp_load returns whether a dynamic completion setting is found. In case a corresponding completion setting is not found in the system, you should write it in the following way:

if complete -p systemctl 2>/dev/null || _comp_load systemctl; then
    complete -F _systemctl sc
fi
calestyo commented 1 month ago

Thanks... :-)

And nice that this doesn't even define the completion for sc, when that for systemctl couldn’t be loaded!

beavailable commented 1 month ago

@calestyo You're right, I haven't thought that much, because it just works. But your solution is indeed better and I'm gonna use it too.