scop / bash-completion

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

Native bash-completion 2 loader using complete -D #1220

Open kislyuk opened 5 months ago

kislyuk commented 5 months ago

Argcomplete uses complete -D to register its loader as a general purpose loader that can match any command name:

https://github.com/kislyuk/argcomplete/blob/develop/argcomplete/bash_completion.d/_python-argcomplete#L245

This works fine in bash-completion 1, and in the compatibility mode directory (BASH_COMPLETION_COMPAT_DIR) in bash-completion 2, but not in native mode bash-completion 2 (since the main completion loader, _comp_load(), matches commands to completer filenames by name to implement lazy loading, so registering a completer to match any name seems impossible).

Is there a way to use the bash-completion 2 lazy loader to register a wildcard completer? I'm worried that if I stick with the bash-completion 1 style completer, it will eventually get deprecated.

Thanks 😄

akinomyoga commented 5 months ago

I think the current way is fine. Currently, bash-completion doesn't provide a way to register the wildcard completion, but you can overwrite bash-completion's complete -D to set up your own complete -D, and you can attempt _completion_loader (as already done) inside your own complete -D setting if you want bash-completion's dynamic completion.

kislyuk commented 5 months ago

@akinomyoga I don't think this answers my question. I'm looking for a way to use a bash-completion 2 style loader (instead of the old bash-completion 1 style loader, which is what you linked to) to register a "fallback" completer that is called to complete any command that doesn't have a completer set. I know this is possible with bash-completion 1, since that's what argcomplete has relied on for many years. What I don't know is whether there's a way to do this with bash-completion 2, short of using the compatibility mode directory - and if not, I'm looking for opinions from @scop on whether this functionality could be added.

akinomyoga commented 5 months ago

OK, to directly answer the original question,

Is there a way to use the bash-completion 2 lazy loader to register a wildcard completer?

No, and even if there was a way, I doubt that that is the right solution. However, it actually depends on what is your true purpose.

Within my previous reply, I assumed you wanted an official way to hook into bash-completion without affecting bash-completion's setting for complete -D.

If you want to delay the initialization of the argcomplete setting, I'm interested in the reason. Even if the loading of the default completion is delayed, it would soon be loaded on the first attempt of the completion anyway. We delay the completions of specific commands because loading all the completions (including the one for the commands not going to be used in the current session) would consume time and memory. However, the default completion would be used anyway, so a motivation to delay the initialization of the default completion seems weak.

If you just need a way to eagerly load completion settings, you can continue to put a file in compatdir (such as /etc/bash_completion.d). AFAIK, it won't go away because we continue to use bash_completion.d for managing compatibility interfaces. It is deprecated as a location for completion settings for specific commands, but it is still valid for the completion settings that want to be loaded eagerly. If you don't like it, you can simply source the file after loading bash-completion. The fzf completion is a similar completion setting that wants to overwrite complete -D, where the users are expected to first source bash-completion and later source the fzf completion file (or eval "$(fzf --bash)" in the latest version). Some of the distribution packages of fzf put its completion setting in compatdir or /etc/profile.d. The latter (/etc/profile.d) works because fzf.sh comes after bash_completion.sh in the collation order in typical locales, though I'm not sure if it is robust.

I'm worried that if I stick with the bash-completion 1 style completer, it will eventually get deprecated.

The API for bash-completion 1 style completions will be removed in the future (or some have already been removed), but as far as I see argcomplete, it doesn't rely on "v1 API" (such as _get_cword, _get_pword, _split_longopt, have, quote, and dequote).

akinomyoga commented 5 months ago

@akinomyoga I don't think this answers my question. I'm looking for a way to use a bash-completion 2 style loader (instead of the old bash-completion 1 style loader, which is what you linked to)

_completion_loader is the bash-completion v2 loader.

to register a "fallback" completer that is called to complete any command that doesn't have a completer set.

Then, again I'd suggest https://github.com/scop/bash-completion/issues/1220#issuecomment-2174884440.

We've recently upgraded the internal API for the next version, but we will keep the older v2 API for at least several years or maybe ten years. We haven't discussed at which point we'd bump the major version of bash-completion, but I think it should finally be "v3" API since deprecating the older v2 API means a breaking change. Let us call the new one "v3 API" hereafter.

Even though we internally updated the API, we still expect the external completions to use the v2 API for now. This is because it is generally hard to match the API version of bash-completion and the external completions if the versions of bash-completion with two different APIs coexist in the market. We decided to first replace the internal API while continuing to provide v2 API, and wait for bash-completion packages in the market to be entirely replaced with the versions that contain both v2 and v3 APIs (we estimate it to take several to ten years). After that, we will recommend the external completion writer switch from v2 to v3 and make v2-API functions output warning messages. After external completions are updated, we can safely remove the v2 API. This way, the external completion doesn't need to support two different APIs at the same time.

Nevertheless, if you wish, you can support both v2 and v3 APIs with an appropriate test (e.g. if declare -F _comp_load >/dev/null; then <use v3>; else <use v2>; fi).

I know this is possible with bash-completion 1, since that's what argcomplete has relied on for many years.

argcomplete appears to be using bash-completion 2 compatdir (equivalent to bash-completion 1) plus bash-completion 2 loader (_completion_loader). Then, this will continue to work with v3 API. You just need to switch from _completion_loader to _comp_load or _comp_load -D (and return 124 if necessary).

What I don't know is whether there's a way to do this with bash-completion 2, short of using the compatibility mode directory

You don't have to take an action for now. When switching to v3 is prompted, you can just switch from _completion_loader to _comp_load. /etc/bash_completiond.d will not go away in v3 API since we maintain it for managing our compatibility interfaces.

and if not, I'm looking for opinions from @scop on whether this functionality could be added.

@scop I think the current situation of BASH_COMPLETION_COMPAT_DIR is unclear. Although its name looks like it will be deprecated and should not be used, we added 000_bash_completion_compat.bash which I guess we need to maintain perpetually. The description in README is also not so clear about whether its use is encouraged or discouraged: "Q. How can I override a completion shipped by bash-completion?" seems to suggest using compatdir while "Q. I author/maintain package X and would like to maintain ..." (which is a question for the completion for a specific command) seems to deprecate compatdir. I've been thinking we would continue to offer compatdir for eagerly loaded settings while deprecating it for the completion settings for specific commands, but it is not so obvious. Maybe another option would be, as suggested, to prepare another directory where the eagerly loaded files can be put, though it is functionally equivalent to the current compatdir.

kislyuk commented 5 months ago

Thanks. That's helpful.

Even if the loading of the default completion is delayed, it would soon be loaded on the first attempt of the completion anyway. We delay the completions of specific commands because loading all the completions (including the one for the commands not going to be used in the current session) would consume time and memory. However, the default completion would be used anyway, so a motivation to delay the initialization of the default completion seems weak.

Agreed, I'm not looking to delay the loading. The motivation for my question was two-fold:

If you just need a way to eagerly load completion settings, you can continue to put a file in compatdir (such as /etc/bash_completion.d). AFAIK, it won't go away because we continue to use bash_completion.d for managing compatibility interfaces. It is deprecated as a location for completion settings for specific commands, but it is still valid for the completion settings that want to be loaded eagerly.

That's great, I'll stick to that for now.

scop commented 1 week ago

Sorry about the huuuuuuuuge delay on my part. I agree there's no rush to switch away from the bash_completion.d based approach for now, or for a long time.

Then again, regarding our own completion backward compatibility stuff, to me the intention is to eventually remove that. But I have no timeline in mind for that either, as far as I'm concerned, it can stay until it starts to create actual problems.

Closing as there is no plan to take any action based on this discussion in the foreseeable future.