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

Integration with termion (or any other terminal abstraction) #199

Closed
mandx opened this issue Jan 31, 2019 · 4 comments
Closed

Integration with termion (or any other terminal abstraction) #199

mandx opened this issue Jan 31, 2019 · 4 comments

Comments

@mandx
Copy link

mandx commented Jan 31, 2019

I absolutely love how RustyLine works; by itself it's pretty much perfect. However, I have no clue on how to integrate it with termion or any other terminal abstraction utilities.

The application I'm developing uses termion to create an AlternateScreen (so the previous screen is preserved after my app exits); my idea is to have RustyLine take over the bottom/top section of that screen (whatever number of lines it needs, as long as I can tell how many lines it's taking), and have another thread asynchronously render something else on the rest of the screen, mostly some processing results using rustyline's output as its input.

Blindly creating an editor instance and launching it produces no crash, but the screen is a mess, (the prompt always renders fine, though).

Should I be synchronizing writes to stdout? FWIW, rustyline would be the only element taking input, there is no "widget focus" management at all.

@gwenn
Copy link
Collaborator

gwenn commented Jan 31, 2019

I regret to say that rustyline does not support async mode.
You can give a try to linefeed.

May also be related to how the screen is refreshed by rustyline !
Is the display fine when the input is only on one line ?
Can you share some code/example ?

You can also try to replace the current Terminal implementation on unix by your own using termion.
What about liner which already uses termion ?

@mandx
Copy link
Author

mandx commented Feb 4, 2019

Oh sorry, I didn't get the notification of you edit!

Ok so, both rustyline and linefeed behave the same way when I try to use them within the context of a termion::AlternateScreen. This struct simply provides an easy way to get Vim's screen behaviour: your program uses an "alternate screen" for all output operations, and the original screen will be restored when the alternate is dropped. I'm creating this AlternateScreen instance with a handle to /dev/tty in "raw" mode.

The "problems" both libraries have are:

  • No way to "position" the editor/buffer, both go right to the bottom
  • While all input works just fine, rendering of the editor/buffer itself is erratic. Now I'm pretty sure this is something closely related to how my app is structured:

The Helper associated with my Editor has the "sender" end of a crossbeam channel, so I'm using the hinting mechanism to get the current contents of the editor in realtime and send it over the channel. A separate thread has the receiver end of the channel, and with each input received, it performs some operations and displays the output to the alternate screen using termion's style and movement commands. The only special characteristics about the output is that it might contain color codes and it will be multiline text.

Most of the time the editor's contents renders fine, but the position of the cursor (caret) is never where expected. I'm using Termion's commands to "save" and "restore" the cursor position (all of my custom rendering happens in between those two codes), but this doesn't appear to have any effect. If I just don't print anything from my worker thread, then everything works fine (well, except the positioning issue, but that's not a deal breaker).

I'm also using std::io::::Stdin::lock with little effect. My reasoning is that access to stdout should be protected behind a lock/mutex or somthing, but I can't tell if rustyline is also using it or not (I see some usage of io::stdout() instead of io::stdout().lock()).

I'm going to checkout liner, and try to put together a minimal example.

@gwenn
Copy link
Collaborator

gwenn commented Feb 4, 2019

@mandx std::io::Stdin::lock cannot be used because std::io::Stdin is buffered and there is no way to know if some data are available. So rustyline is using libc::STDIN_FILENO directly.
And std::Stdout::lock is used indirectly here: see https://doc.rust-lang.org/src/std/io/stdio.rs.html#461

I don't know how to synchronise multiple outputs.
I guess you want something like this or this.

@mandx
Copy link
Author

mandx commented Feb 4, 2019

Yes, this makes sense.

Well, then I guess that what's left for my to try is something like this, which involves switching to linefeed :(

In any case, thanks you for your replies. I was insisting on Rustyline, because it has all the nice features I would want for a proper REPL and a nice API. I will definitely use it in the future for "less crazy" stuff.

Thanks for all your work!

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

No branches or pull requests

2 participants