How would one go about emulating the behaviour of io::stdin().read_line?

51 Views Asked by At

This is a mostly abstract question. I'm asking for a basic description of an implementation, not 'fix my code pls'.

I'm using crossterm, working on a project that would ideally have a command line with multi-line support. This is really easy to do with read_line(). However, I would like to process some key events myself (mainly arrow up and down for consistent command history support, and gracefully handling CTRL+C). There's a basic crossterm example illustrating how to read lines character by character.

The problem I'm having is displaying this output back to the user. I believe my issue is that when I print the input back to the user, it isn't wrapped with newlines. This means the terminal wraps it when it goes over width. When I move my cursor up to erase the line and reprint it, it dutifully goes up, erases, and reprints. However, this erases previous terminal lines because my output lines didn't actually move the terminal content.

So the fundamental question is: how would I go about inserting newlines into my output to emulate the behaviour of io::stdin().read_line()? A basic pointer is fine, I'm just a bit lost on how other multiline inputs of this nature handle line wrapping (e.g rustyline)

1

There are 1 best solutions below

0
Kevin Reid On

how would I go about inserting newlines into my output to emulate the behaviour of io::stdin().read_line()?

That behavior is actually built into the operating system — on Unix it's part of the pseudo-tty device that all terminal applications use. It also only works as well as it does because it is single-line — the cursor can be moved backwards in a consistently wrapping way with backspace characters, as long as you never print a carriage return and cause the cursor to forget its previous horizontal position. As soon as you start moving vertically, you need to calculate with explicit consideration of wrapping, and so you need to know the terminal size and string widths, and so on.

For a multi-line editable input, I strongly recommend that you just use rustyline or another library that provides an editor (I have no specific recommendation in this space), unless you specifically want to explore the very particular and quirky problem space of interactive UI in a terminal from scratch.