mikaelmello / inquire

A Rust library for building interactive prompts
https://docs.rs/inquire
MIT License
2.04k stars 76 forks source link

Provide access to the underlying crossterm Events. #129

Open 0xForerunner opened 1 year ago

0xForerunner commented 1 year ago

I have a project called interactive-parse that builds JsonSchema types interactively using inquire. It calls various inquire methods many times to eventually build out the structure, and I would like to implement an undo feature which allows the user to revert to a previous prompt and fix an error. As an example, upon receiving ctrl+z I would like to kill the current inquire prompt, clear the last line in the terminal, and re call the previous inquire prompt. So far with my experimentation on cross term, it seems impossible for me to intercept the key presses without accidentally stealing them from the inquire prompt. Admittedly my knowledge here is lacking so it's possible I'm asking for the wrong feature here. Another potential solution to my problem would be the ability to pass a map of certain crossterm events which correspond to a list of preprogrammed actions (aborting the current prompt for example).

mikaelmello commented 1 year ago

I'm currently working on #126 to make exactly this possible.

The idea is to provide APIs to all relevant layers and make inquire really extensible. What you described should be possible soon!

0xForerunner commented 1 year ago

I'm currently working on #126 to make exactly this possible.

The idea is to provide APIs to all relevant layers and make inquire really extensible. What you described should be possible soon!

Holy are you ever responsive. Thanks so much for your hard work. This is an awesome crate. Great to hear you've already got this in the works!

mikaelmello commented 1 year ago

Giving some more context, the primary goal is to enable testability, which will be achieved by adding a middleware layer between key events and the prompts handling them called an "Action". Think Submit, MoveUp, etc.

The API for that will be straightforward, I'll simply expose a prompt_with_actions(list) or something like that and, under a feature flag, interested users will be happy and everything.

For your use case, the API gets a little trickier. We must find a good way to:

  1. Make it easy for you to hook a Key handler, which you could match against Ctrl+Z.
  2. Wire something up so you can actually execute something on the Ctrl+Z.

In my mind the most common use-case for the custom Key handler (no. 1) would be to enable developers to implement their own keybindings if they didn't want inquire's defaults. This would not need any additional wiring on the Action side, since it could be achieved by accepting a fn(Key) -> Action only and not change prompt behaviour.

Now to achieve what you're looking for, I have an idea but it feels clunky I guess, so I was looking to get your thoughts on what would look good for you (and everyone else :) )

The initial idea would be to maybe add a new variant to the Action enum, e.g. UserAction(Key), which would call a fn(Key) -> InquireResult<()> callback? Something along that lines. It would be a lot of boilerplate code to make that possible and I'm also not sure if it's a good UX in general for the feature.

Let me know what you think

0xForerunner commented 1 year ago

The initial idea would be to maybe add a new variant to the Action enum, e.g. UserAction(Key), which would call a fn(Key) -> InquireResult<()> callback?

I actually think this sounds perfectly reasonable. It would be nice if there was a built in Action that could abort the prompt and clear the current line of output, but if that is too far out of scope that could be accomplished with the callback you mentioned. I'd be perfectly happy with that solution. And for the record I don't consider that to be too much boilerplate at all. Seems great!

polizz commented 7 months ago

I think this might be useful for something I'm trying to do as well. I'd like to get the select item changed event so I can run some other code to perform a preview of the selection before the user selects it.