kazhala / InquirerPy

:snake: Python port of Inquirer.js (A collection of common interactive command-line user interfaces)
https://inquirerpy.readthedocs.io
MIT License
357 stars 19 forks source link

FuzzyPrompt with Multiselect should return None without selected item #15

Closed theguy147 closed 3 years ago

theguy147 commented 3 years ago

FuzzyPrompt with Multiselect should return None without selected item

FuzzyPrompt with multiselect=True does not behave according to the documentation:

By default, when there are no choices after filter, user can still hit enter and the result will be a None value. To prevent this from happening, you can setup a simple validator.

But when no item is chosen/selected the one that was highlighted when hitting "Enter" is returned instead of None. This currently prevents the user from un-selecting all items in scenarios where this might be necessary (like e.g. ordering a pizza without extra toppings even if the fuzzy toppings prompt appears)

Test case to reproduce

# filename: test_case.py
from InquirerPy import inquirer
result = inquirer.fuzzy(message="", multiselect=True, choices=[1,2,3]).execute()
print(result)

And now when running the script just hit "Enter" without selecting any item. The result will be [1] instead of the expected None

kazhala commented 3 years ago

Hi @theguy147 ,

Thanks for pointing out. I guess the reason I decided to go with the current behavior is to sort of replicate the behavior from fzf.

I do wanna get some of the input tho. Currently we have #10 to track the progress of adding a special keybinding to skip a question, do you think that a multiselect without specific toggling a single choice should result None or the current choice if theres a keybinding to skip the question?

This would be a quite easy fix either way, reference.

Thanks, Kevin

theguy147 commented 3 years ago

Hm, that is a good question. IMO there are two ways of looking at it:

1) You enter a multiselection with nothing selected and you only want to select one of the options. Then doing so by highlighting it and pressing "Enter" seems reasonable. Also just selecting one option with <Tab> (or other keybinding) beforehand appears to be unnecessary in this scenario.

2) You enter a multiselection and start selecting stuff, then you change your mind and unselect them again. Now it feels odd that pressing "Enter" still selects the currently highlighted option. The same is true for pre-selected items that you unselect. Also an additional keybinding to skip/confirm that you really don't want to select anything feels strange and is not intuitive.

The problem is that the choice of these scenarios is often done by the end-user and not necessarily by the developer.

My personal, subjective, opinion is that scenario 2) should be supported without changing keybindings or using the raise_keyboard_interrupt option. But I do understand the reasons for not explicitly supporting it (most notably to mimic fzfs behavior). Also this would probably be a breaking change for some projects #using this library. So against my opinion the additional keybinding would probably be the best option. Although I'm still not 100% sure how this keybinding would be used. Is it a hard skip or is it like an "Enter" that skips the question if nothing has been chosen but keeps the items if they have been chosen?

As a side note: The raise_keyboard_interrupt=False option does not seem to work for me as described in the other issue.

kazhala commented 3 years ago

Hi @theguy147 ,

Might have been a bit misleading, I've been re-thinking this decision, atm the raise_keyboard_interrupt argument belongs to the execute function rather than the prompt itself. It would probably make sense to also add this argument to all prompts instead of just accepting it at the execute function.

action = inquirer.fuzzy(
    message="Select actions:",
    choices=["hello", "weather", "what", "whoa", "hey", "yo"],
).execute(raise_keyboard_interrupt=False)

Regarding the issue itself

Thanks for your input. I can't recall my initial intention of changing this behaviour (from what the doc says) but I think for backward compatibility and personal preference I personally prefer the first option you described.

I do understand the intention of the second behaviour and thus I think this might be beneficial if we add the search capability to the checkbox prompt which can fulfil your preference. This might take a bit longer to do because the architecture for checkbox is quite different from the fuzzy prompt.

For the skip itself, I'm planning to make a hard skip and just return None.

Thanks, Kevin

theguy147 commented 3 years ago

Thank you for the explanation. I'm looking forward to your final solution then :)