petereon / beaupy

A Python library of interactive CLI elements you have been looking for
https://petereon.github.io/beaupy/
MIT License
200 stars 13 forks source link

feat: Support multi-line input in prompts #36

Closed MatanRubin closed 2 months ago

MatanRubin commented 1 year ago

This commit adds an optional multiline flag to prompt, allowing users to input multi-line strings. To confirm the input, users may use alt-enter.

Caveats:

  1. I don't have Linux and Windows setups to test this on, possible bugs there due to OS-dependent line-separators, as well as ALT_ENTER.
  2. I haven't implemented up/down keys when in multiline strings, as it's non-trivial. I might implement it in a separate PR.
petereon commented 1 year ago

Hey, @MatanRubin , it seems to be one indent too deep here.

I have set up some tasks. You could try running poetry run poe lint for formatting and linting to basically run exactly what runs in the GitHub Actions. Alternatively to have continuous testing and linting after each save you can do poetry run poe test:watch and poetry run poe lint:watch.

MatanRubin commented 1 year ago

I fixed the lint issues, let me know what you think of this change.

I think the prompt() function can be refactored to make the code clearer and easier to maintain, but I didn't want to do it in this PR so that reviewing the change would be easier.

petereon commented 1 year ago

@MatanRubin Splendid, thanks! I am aware some refactoring is warranted, if you find time I am definitely happy to accept a PR.

Anyways, seems like multiline input is failing on Windows. I suppose that might be line-breaks (I believe Windows uses \r\n rather than \n as we have on darwin and linux, so it's probably just that tests will have to have some condition to figure out the platform and expect respective line-break character).

You are doing a lot of work here, I would not like to bother you with compatibility issues. I could close this and undertake that myself, unless you want to have a go at it. Please do let me know.

petereon commented 1 year ago

Okay, I have checked, it expects \r\n as a line break on Windows. However it seems click.getchar is a tremendous mess on Windows (or maybe it's Windows that is the mess).

Anyways, I've checked by hand and my Mac reads ALT+Enter as \r so the same as just Enter. I think we need different shortcut for confirmation with multiline input, I've checked CTRL+Enter and Enter which are different on Windows but not on my Mac either. I guess I need to give this a more proper thought.

petereon commented 1 year ago

So this seems to be a major pain-point. I've tried several solutions, from purely Pythonic to C extensions. Generally all fail to tell the difference between Ctrl+Enter and Enter.

petereon commented 1 year ago

@MatanRubin I don't think I can merge this as is. We either would need a different handling on Windows for the end of multiline prompt, or this could be marked as not implemented on Windows. Former being preferred. I can also leave this open until I figure out a better way to receive keyboard input in Python.

MatanRubin commented 1 year ago

I agree we shouldn't merge this before making sure it works on all platforms. It's weird that your mac doesn't interpret alt-enter differently than enter. Mine does...

In any case, another option would be to use an enter after the last line for confirmation (i.e. pressing enter twice would confirm the input. WDYT?

I also tried taking a look at other libraries that support this feature, but couldn't yet find anything useful.

petereon commented 1 year ago

I agree we shouldn't merge this before making sure it works on all platforms. It's weird that your mac doesn't interpret alt-enter differently than enter. Mine does...

In any case, another option would be to use an enter after the last line for confirmation (i.e. pressing enter twice would confirm the input. WDYT?

I also tried taking a look at other libraries that support this feature, but couldn't yet find anything useful.

@MatanRubin, agreed, situation is abyssmal with libraries that support this sort of keyboard-handling functionality, so much so I actually started looking at JavaScript ones I could migrate for Python.

As for the issue at hand, I suppose double ENTER makes sense, or even ESC followed by some sort of confirmation. I am hoping to get around to start working on some sort of library handling the keyboard input sometime soon, so if you just thought this would be a nice feature but don't use it per-se it might even stay open.

I leave this up to you, if you decide to implement this in some way that is platform independent and works I am happy to merge.

MatanRubin commented 1 year ago

@petereon, I've updated the PR to use double-enter for confirmation, instead of alt-enter. Again, I don't have a Windows machine to test on, so I can't verify this works well on Windows. It does on Mac.

I use "\r" in a few conditions there, and I suspect that won't work in Windows as expected. Can you try it yourself and let me know if it works? Feel free to contribute any change to the PR to make it work on Windows/Linux as well.

petereon commented 1 year ago

@MatanRubin went ahead to try it now but it turns out I can no longer boot my testing Windows. I will need to get myself a new instance of Windows, I'll try my best to get to it over the weekend.

MatanRubin commented 1 year ago

No problem.

Thinking about this some more, I don't think the solution I have here is good. Some people want to enter multiline text which actually includes a blank line between paragraphs.

What do you think about using some other key for confirmation? ctrl-g, F10, something... I don't know. Any idea how other applications solve this issue? Maybe we can do vim-style ESC to exit edit mode and then enter to confirm? WDYT?

petereon commented 1 year ago

@MatanRubin Looking to other solutions might be a good idea. Beaupy is actually fairly heavily influenced by charmbracelet/gum in conceptual terms. Basing of gum they just use raw ESC to get out of the gum write functionality without any confirmation or anything.

Now, that leaves some sort of confirmation to be desired. But with some sort of confirmation to make distinction between "using the text" or "abandoning the prompt" that sounds like a good design.

petereon commented 1 year ago

This has been further discussed here: #46

Vim-like modal editing sounds like a viable approach to having a multi-line input.