Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rfc: multiline input #1673

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

dwmkerr
Copy link

@dwmkerr dwmkerr commented Feb 18, 2025

Hi! I'd love to get your thoughts on this. Essentially this should allow for multi-line input. The use case is an application like mine, where a user may want to "Shift+Enter" to start a newline in an input prompt, or paste content that contains newlines. For example, in my ai app I want to write a message, "Shift+Enter" to put in a newline, then Paste from my clipboard a code sample. You can roughly see the app in use here: https://github.com/dwmkerr/terminal-ai?tab=readme-ov-file#terminal-ai

The methodology is:

  1. Add a new 'multiline' parameter. None of the changed logic should run unless this parameter is set, i.e. this is a 'noop' change for most users, unless the opt-in.
  2. (When in multiline mode) Shift+Enter inserts a \r character.
  3. (When in multiline mode) \r is rendered as \n
  4. (When in multiline mode) in the final result, \r is rendered as \n

However I'm having a few issues with the PR:

  1. Where is ctrl set on Keypress? I want to add a shift
  2. When I try yarn dev I get this forever:
image

Finally, my use case is that hitting 'paste' when in the input would have some kind of event I can listen to so that in multiline mode I can transform the \n to \r. I'm not sure if this is possible.

Before I continue I'd love to know if this seems like a useful feature, if possible a hint on the yarn dev issue and a couple of pointers. Thanks in advance

I'm more than happy to take on the work for this just need a couple of hints!

Alternatives

  • If input that contains newlines is received, e.g. by the user hitting 'paste' with multiline text on the clipboard, then we could assume they want to work with multiline text and use the editor input (or offer the option to switch to the editor automatically)

Potential Limitations

  • In multiline mode, \r characters will not be handled properly, as they essentially become a placeholder for a 'non-input ending newline'

Related Issues

Copy link

codecov bot commented Feb 18, 2025

Codecov Report

Attention: Patch coverage is 66.66667% with 2 lines in your changes missing coverage. Please review.

Please upload report for BASE (main@27c8859). Learn more about missing BASE report.

Files with missing lines Patch % Lines
packages/input/src/index.ts 66.66% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1673   +/-   ##
=======================================
  Coverage        ?   97.97%           
=======================================
  Files           ?       39           
  Lines           ?     2467           
  Branches        ?      658           
=======================================
  Hits            ?     2417           
  Misses          ?       43           
  Partials        ?        7           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@SBoudrias
Copy link
Owner

Hi, I think this is a great idea and approach to this problem. It's also been requested fairly often, and so is definitively a handy addition to the core!

All in all, I would prefer not to add a multiline option, and have this be a default behaviour.

A question on the approach, why using \r instead of \n directly and skipping the replaceAll calls? (and, do you happen to know if \n by itself works on Windows' terminals?)

To your questions:

Where is ctrl set on Keypress? I want to add a shift

Inquirer uses the default Node.js keypress events on a stream. I have a small utility in the repo (node tools/keys.mjs to log keypresses.) Weirdly enough, it seems to ignore shift/ctrl/cmd when enter is pressed 🫤

When I try yarn dev I get this forever

I saw yarn dev was broken, but I forgot about it 🤦🏻. What I've done last is yarn tsc to build, then yarn demo. You do loose the rebuild watcher unfortunately.

@dwmkerr
Copy link
Author

dwmkerr commented Feb 22, 2025

Thanks for the response and glad you like the idea? I might have stumbled onto a challenge (which currently seems insurmountable) though - it looks like it is potentially not possible in NodeJS to detect whether the shift key is pressed when 'Enter' is pressed. Combinations of the following haven't worked:

// no joy..
const readline = require("readline");
readline.emitKeypressEvents(process.stdin);
if (process.stdin.setRawMode != null) {
  process.stdin.setRawMode(true);
}
process.stdin.on("keypress", (str, key) => {
  console.log(key);
});

And:

process.stdin.setRawMode(true);
process.stdin.on('data', (key) => {
  if (key === '\u0003') process.exit(); // ctrl+c to exit
  console.log(key);
  if (key.toString() === '\r' && process.stdout.isShiftKeyDown) {
    console.log('Shift+Enter detected');
  }
});

Some googling suggested it might not be possible and that it could be terminal/os specific. I'm scratching my head as to what to do - unforunately it doesn't seem to even be possible to read the OS state of the keyboard, at least without using another language:

Both of these examples are bundled with a jar file and require java to be installed. I guess it might be possible with C, building for different distributions but it seems that'd be a lot of work and very brittle.

Any thoughts? It might just be that this won't work (I can't think of any REPLs or terminal apps that handle Shft+Enter either).

@dwmkerr
Copy link
Author

dwmkerr commented Feb 22, 2025

(note: looking at this comment it seems that at least on iTerm2 on MacOS 'Ctrl+o' seems to open a newline (works on my mac). I wonder if we could just inform the user and use Ctrl+o (and then something similar to the implementation above? However I don't know if we would be able to handle a clipboard paste as it may just stream the content into stdin and I don't know if we can identify that it is pasted content (if we can read all the content rather than byte by byte we could potentially at least handle newlines in the content at least up to the last one)

@SBoudrias
Copy link
Owner

Interesting, ctrl-O doesn't work for me, but ctrl-j does. However when sending this key combination, Node detect is as an enter keypress - so looks like we couldn't catch it.

I'm not too sure where to go from now. My thinking starts going into a switch for multiline/single, like press ESC then we don't submit on enter. But that's pretty much copying vim keybindings, and at that point is there value versus yielding to the editor prompt 🤷🏻

@SBoudrias
Copy link
Owner

(Side note, I figured out why yarn dev launched in an infinite loop - and it's fixed on latest main. Basically when I moved to tshy, it generates temporary files which were throwing off turborepo watcher.)

@dwmkerr
Copy link
Author

dwmkerr commented Feb 23, 2025

Great news on yarn dev! Yes I'm also at a loss - at the moment I pivot into the editor. Maybe one final thought - what about the down arrow? If we can catch this we could open a new line? And last question, when someone presses 'paste' - do we get the full bytestream of what is coming in (e.g. line one\nline two\nline three so that we can see that there are multiple lines and deal with them, or is it byte-by-byte (meaning ctrl+v will never work and maybe this is just not meant to be!)

(FYI I'm playing with both of these ideas in my fork now will let you know!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants