-
Notifications
You must be signed in to change notification settings - Fork 0
Dynamic completion support #92
Comments
Comment by kbknapp 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). |
Comment by sportfloh 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. |
Comment by kinnison To reiterate a call for this, we'd love to have this in |
Comment by woodruffw 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 |
Comment by CreepySkeleton 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? |
Comment by Manishearth 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 |
Comment by CreepySkeleton
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 clap-rs/clap#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| { /* ... */ }) |
Comment by kenoss 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 + |
Comment by kenoss Note that clap can automatically derive completion for short/long options in many cases, i.e., if one doesn't need special treatment. |
Comment by PoignardAzur 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. |
Comment by pksunkara This is still in design phase. According to the current suggested design, this needs more foundational work regarding partial parsing (#1880). |
Comment by kolloch @CreepySkeleton I've been playing around with the code and I think we could get it to work to support dynamic completion of a simple flag value. I haven't looked at the shell completion logic but I am thinking in the direction of only calling It would be super cool, to reduce all shell autocomplete logic to calling out to your prog with the Anyways, if we use the |
Comment by blaggacao how cobra does it:
and here is the 'hidden' command: looks like this is becoming a 'copy paste' task |
Comment by nrdxp I would really appreciate this feature. Right now my app has a Struct describing what are basically inputs to all of my cli subcommands. It would be super great to use this information in completions. I was a bit surprised when I found out it may not be possible 😞 |
Comment by sergiimk As a long-time watcher of this issue thought I'd share my solution. The CLI tool I'm working on deals with a lot of different kinds of entities that have long names (think The solution pieces are:
It's not perfect (e.g. has troubles with multiple positional arguments of different kinds, and I struggled to make it work with For Rust apps that are very fast to start I really can't think of a good reason to generate completion scripts instead of delegating the entire work to the app itself in all cases. Dealing with completion differences between various shells is no fun. |
Comment by chisui Haskells |
Comment by woodruffw This isn't a catch-all solution, but: perhaps What I'm thinking of is something like This would be a reasonable solution for many CLIs, and requires relatively little complexity on Thoughts? |
Comment by epage #3022 was a tipping point for me in realizing that maybe our current approach to completions doesn't work. We effectively have to implement a mostly-untested parser within each shell. Examples of other problems that seem to stem from this:
If we take the approach of argcomplete where we do the parsing in our core code, rather than in each completion script, this will help us share parsing logic between shell, share some or all parsing logic with clap itself, and make a subset of the logic more testable. In my mind, this is raising the priority of this issue. This doesn't mean we'll work on it immediately though. We need to first get clap3 out and some work that is spilling out of clap3. We also need to decide whether to morph the existing parser into supporting this or create a custom parser (since the needs are pretty special). If we do a custom parser, we should probably do clap-rs/clap#2915 first so we can reuse lexing logic between clap and the completion generation. I've also been considering clap-rs/clap#2912 which would allow reusing the completion logic with any CLI parser. |
Issue by Manishearth
Monday Mar 26, 2018 at 21:39 GMT
Originally opened as clap-rs/clap#1232
Currently 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: