-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Dynamic completion support #1232
Comments
Sorry for the late reply, it's been a busy week! This is related to #568 and something I very much want. The implementation you've outlined is pretty close to what we're thinking in #568 and probably almost exactly what will end up being implemented. I haven't worked out the final details yet as I've had other issues as as priority and the v3 release is a prerequisite for me to implement this (although I want this, or an initial implementation in the v3-alpha1 release). |
hey, I was recently looking for such a feature and stumbled over clangs autocompletion feature (http://blog.llvm.org/2017/09/clang-bash-better-auto-completion-is.html). Maybe their solution is somehow inspiring. |
To reiterate a call for this, we'd love to have this in |
I'd also like to register interest in this. It's not as conceptually clean, but an approach that injects the results of a subshell would be sufficient for many CLIs. Borrowing the subcommand(
App::new("dump")
.arg(
Arg::with_name("thing")
.with_completion("foobar list")
)
) would go from something like this in the opts=" -h -V --help --version <thing> " to this: opts=" -h -V --help --version $(foobar list) " (N.B. that this approach applies to |
I must admit I like the "special option to autocomplete" approach very much, but I've also came up with a number of tricky questions. Let me summarize the prior discussion and outline the desired solution that should work and satisfy everybody. We want this facility somewhere in clap: fn dynamic_completion<F>(hook: F) -> Variants
where
F: FnOnce(Input) -> Variants; Where to squeeze the The How it works: presence of this kind of hook tells clap to generate a special How does clap supply the variants back to the shell so the later can use it? It doesn't. What it does is printing the values to stdin. This option is supposed to be called from inside the completions script, like that. The script will handle the rest in a shell-specific way. What does // we may want to extend the system in future
#[non_exhaustive]
enum Variants {
/// Return this when the completion hook couldn't decide on the completion.
/// This will fall back to the default completion system which should work sensibly.
Fallback,
/// Return when the hook did found some good options to complete.
Success(Vec<OsString>)
} Some examples: # What user does
cargo +<TAB>
# the call
cargo --autocompletion 1 '+'
# the output (OK, pack the values and return early)
SUCSESS
nightly
stable
beta
# ATTENTION! There's a space between `+` and `<TAB>
cargo + <TAB>
# the call
cargo --autocompletion 2 '+'
# the output (Oops, let's just cross fingers and let the script handle the rest)
FALLBACK The next question is: what is
fn dynamic_completion<F>(name: &str, hook: F) -> Variants
where
F: FnOnce(bool, &[OsString]) -> Variants;
.dynamic_completion(|has_space, args| { /* ... */ })
// alternatively, see |args, str| design in the first comment Does everybody agree with this design? Any unresolved questions? |
Yeah, this is essentially what I proposed above, with the small tweak that I was using I'm less fond of the
I think it should be all args except the one currently being tabbed. It should be okay to tab-complete in the middle of an arg list |
No quoting the entire string here (we simply don't know what the string was with most shells). We pass the args array as is, quoting each arg to guard against spaces. But using # what we do
app arg1 --flag --opt1 val1 'val 2' -- something <TAB>
# what we get
app --autocomplete 7 -- '--flag' '--opt' 'val1' 'val 2' '--' 'something'
User needs to reparse all args in any case. The "partial parsing" problem was reported as #1880, and I think this could work as a viable option. But anyway, the hook should work on top of bare strings and expect So, maybe: // or maybe index instead of has_space?
.dynamic_completion(|has_space, partially_parsed_matches, args_as_os_strings| { /* ... */ }) |
A few weeks ago I saw completion approaches of I agree with th CreepySkeleton's first observation. But, I vote Manishearth's point. I prefer the completion function live on the I expect normalization works for #1880 . Is there a case one have to parse raw string? Let me classify the cases. Simple cases.
More complex cases.
The code is here. Clap version will be done easily because parser will remove ambiguity of
The code is here. Consider the last case. Clap version will be done by querying subcommand's name and options from Seeing git's cases, I feel parsing by clap + |
Note that clap can automatically derive completion for short/long options in many cases, i.e., if one doesn't need special treatment. |
Is there progress on this issue? The approach suggested by @CreepySkeleton seems pretty good to me. If the issue is stalled for need of a contributor, I'd be interested in spending a few days on it (especially if I can get some mentoring). I'd really like to improve cargo's autocompletion. |
This is still in design phase. According to the current suggested design, this needs more foundational work regarding partial parsing (#1880). |
We have an initial version as For tracking stabilization, see #3166 |
Maintainers notes:
ArgMatches
for completing based on other data like in Compute argument possible values based on other arguments #1910Like with
PossibleValue::help
, we should support help textCurrently clap does basic completion of arguments, however it can't be used to do things like the dynamic completion of
git checkout <branch>
.It would be really neat if this could be handled by clap itself -- AFAICT nothing like this currently exists for any language and it would just be magical since you can then do everything in Rust code.
The rough idea is that the
Arg
/Subcommand
builder can take a.with_completion(|args, str| ... )
closure. We pass theclosure the partial parsed list of other args, and the partial string being completed for this arg (may be empty). The closure returns a list of completions.
When you attempt to do something like
git branch -D foo<tab>
, the completion script will callgit --secret-completion-param 10 -- branch -D foo
, where 10 is the index in the arguments of where<tab>
was pressed, and after the--
we pass all the arguments. Clap parses these arguments except the partial one, and passes this down to thewith_completion
closure, which will return a list of completions which we print out (and feed back to bash or whatever).A simpler version doesn't handle parsing all the other arguments, instead your closure just takes the partial string, so you just provide a closure operating on a string.
If this could be made to work neatly, it would be pretty great.
cc @killercup
The text was updated successfully, but these errors were encountered: