lucc / khard

Console vcard client
https://khard.readthedocs.io/en/latest/
GNU General Public License v3.0
600 stars 65 forks source link

Add some explanation for c/s/q #320

Closed protist closed 1 year ago

protist commented 1 year ago

I'm using the (neo)mutt integration, which executes <pipe-message>khard add-email<return>. However, after attempting to add a new contact in (neo)mutt, I am shown:

Khard: Add email addresses to contacts
New address: "Foo Bar" <foo@bar.com>. Select? (y/N) y
Nothing found for 'Foo Bar' (c/s/q):

The meaning of c/s/q was not obvious to me, and I had to read the source.

                error_message = ('Please answer with "c" to create a new '
                                 'contact, "s" to search for an existing '
                                 'contact or "q" to quit')

It would be nice if there were hints in the CLI itself. (Even after reading it, "c" seemed a bit counter-intuitive to me. I would have expected n for "new".)

lucc commented 1 year ago

PRs to improve this are welcome. We could come up with a general scheme to make all these prompts easier to understand from the get go.

What are some possible requirements?

  1. short, we do not want to spam the user with several lines of text
  2. explicit (not cryptic like it is now)
  3. easy to understand the default value if I hit enter
  4. error messages with more explanation if the user hits an invalid key (I believe we already have that)

So my suggestion for these requirements are:

We could use upper case letters and brackets around stuff to mark the default and abbreviation, like so (capitals for abbreviation, brackets for default):

[Yes]/No  --> yes is the default, "y" and "n" can be used as abbreviation
Foo/Bar/baZ  --> no default "F" "B" and "Z" can be used as abbreviation

or like so (brackets for abbreviation, capitals for default):

[y]es/[n]o  --> no default, "y" and "n" as abbreviation
[F]OO/[b]ar/ba[z] --> foo is the default, "f","b", "z" can be used as abbreviation

other requirements, other ideas?

protist commented 1 year ago

Thanks for the detailed reply. I agree with all of it. I didn't read the source code enough to realised when the "error message" would be shown. Upon reflection, perhaps a more concise alternative would be another option (with suggestion) to bring up this "help" page, e.g. (c/s/q/?) or (c/s/q), ? for help.

It looks like there is no default at the moment, so I'm not sure if that informs the potential design. So apart from my suggestion above, with the c/s/q options it might look like this.

scheibler commented 1 year ago

Just to clarify:

I've chosen the very short approach to keep it simple. The idea was: press ENTER, if you don't know, what to pick and a help text provides some context. But obviously, that was not very intuitive by itself. Therefore I agree, that it should be improved.

I opt for "capitals for abbreviation, brackets for default".

[Yes]/No  --> yes is the default, "y" and "n" can be used as abbreviation

The other format is not so accessible to screen reader users (doable but inconvenient).

And yes, we should replace "create" with "new".

In the future we also should use that option format for all other prompts for consistency and update existing ones.

protist commented 1 year ago

The other format is not so accessible to screen reader users (doable but inconvenient).

I didn't think about that. This is a good point. I agree with your reasoning.

lucc commented 1 year ago

I will try to implement a new general query-the-user function in helpers.interactive. The function should print a message, get input from the user and compare that input against some allowed values. If the answer is allowed it is returned else the user is queried again. I am currently wondering about some design decisions:

  1. the name of the function: we already have select to let the user select an item from a list, we already have confirm for yes/no question. I came up with ask and query (which I don't like because we have a query module and class already that does something different).
  2. the signature: I want it to be simple and general in order to make it easier to understand and reuse.
    1. def ask(message: str, choices: Union[List[str], Dict[str, str]], default: str) -> str: ... the user has to type the keys of the dict or the strings in the list. If the answer is not valid, the values of the dict are used as explanation of the keys. This signature is more complex but the caller does not need to format anything. This can be seen in e2755c3
    2. def ask(message: str, long_message: Optionl[str], choices: List[str], default: str) -> str: ... the user has to type one of the values from the list, if they fail the long message is displayed. This signature is simpler but the caller has to think about formatting. This can be seen in 892b2e7

Does anybody of you have any ideas about the design of such a function? (the output formatting from discussed is already clear, I think)

EDIT: I opened #326 for this. Comments welcome!

lucc commented 1 year ago

326 is now ready for review.

protist commented 1 year ago

Thanks @lucc. From the UX side I think that looks pretty good to me!