inquirer-rs icon indicating copy to clipboard operation
inquirer-rs copied to clipboard

Shortcuts for choices

Open killercup opened this issue 9 years ago • 4 comments

As mentioned in https://github.com/killercup/rustfix/issues/15 it would be nice to be able to use shortcuts to select a specific option.

While currently, the UI looks like

[?] Choose an option:
  > An option
    Another option
    Something else?

we could just prepend a shortcut key, like this (the second option is selected here):

[?] Choose an option:
    [a] An option
  > [n] Another option
    [s] Something else?

The behaviour should be that pressing e.g. o results in the same as choosing the second option and pressing enter.

If we want to be really fancy, we could look for the first word beginning with (or just the occurrence of) the shortcut character in the display text and highlight that one (e.g. A[n]other option).


Implementation-wise, I would add fn shortcut(&self) -> Option<char> { None } to the Choice trait introduced in #1 and implement it for triples (T, V, S) where S: Into<char>. (Or create a new struct for list items to keep things readable.)

killercup avatar Jul 14 '16 14:07 killercup

Indeed that would be nice. However, don't you think that use case could be covered by something like the expand method from Inquirer.js?

Of course, we have to decide whether we want to be an exact port of Inquirer.js, or if we want more freedom to do our own thing.

Munksgaard avatar Jul 14 '16 14:07 Munksgaard

I'm not really a fan of how the implemented "expand". It's far too complicated to use and I think it only makes sense when you have ≥10 options and don't want to render that many lines. But, if you have that many options, do you really want to select them with one letter? (You'll probably want a fuzzy matcher like fzf instead).

Of course, we have to decide whether we want to be an exact port of Inquirer.js, or if we want more freedom to do our own thing.

That's totally up to you :) Inquirer.js has some really cool stuff (confirm, checkboxes, basic inputs are all done pretty well), but I would probably not copy it as-is.

killercup avatar Jul 14 '16 14:07 killercup

I'm not really a fan of how the implemented "expand". It's far too complicated to use and I think it only makes sense when you have ≥10 options and don't want to render that many lines. But, if you have that many options, do you really want to select them with one letter? (You'll probably want a fuzzy matcher like fzf instead).

I guess that makes sense. Would you suggest extending the current implementation of list, or would it be okay for you with a separate function for "list menu with shortcuts"?

That's totally up to you :) Inquirer.js has some really cool stuff (confirm, checkboxes, basic inputs are all done pretty well), but I would probably not copy it as-is.

Good point. Let's improve where we can :)

Munksgaard avatar Jul 15 '16 07:07 Munksgaard

Would you suggest extending the current implementation of list, or would it be okay for you with a separate function for "list menu with shortcuts"?

I would try to extend the current list implementation to try and get shortcut names for its items. This way, it's just a matter of "Did I supply a shortcut name?" and not "Oh, now I have to this whole different function".

Let's assume we have an impl Choice for (T, V, char) and Choice gains a new fn shortcut(&self) -> Option<char> (which I think requires little adjustments). In list, you can then collect the shortcuts (e.g. using flat_map to filter out any None values) to handle the key presses, and additionally render them when printing the selection (turning None into en empty string).

Since the current function signature of list wants something like choices: &[C], all slice items have all the same type. Thus, if you want to render a list with shortcuts, you need to give every single item a shortcut. (I'm not sure if that's the best way to do it, but we can easily add an impl Choice for (T, V, Option<char>) later on.)

killercup avatar Jul 15 '16 10:07 killercup