Is it possible to host a REPL child process in rustyline?

This is a clone from my StackOverflow post. https://stackoverflow.com/questions/79707263/is-it-possible-to-host-a-repl-child-process-in-rustyline

I'm currently working on a rustyline program. My goal is to host another REPL program as a child process, and do something like auto complete its commands. However, I encountered a problem. The readline() function in rustyline::Editor would block, and if the child process wants to print something after the readline() call, it would not be shown before the user press enter to unblock it. This really destroys user experiences. Here's some code for clearer understanding.

loop {
        // rx is a receiver handled by the thread that runs the child process
        while let Ok(output_line) = rx.try_recv() {
            println!("{}", output_line);
        }

        let readline = rl.readline("> "); // This will block until user press enter
        match readline { // Code that do with readline
...
}

Spawning a thread that prints the child process's output continuously doesn't work, either. We can't know when to readline and display the > prompt.

Clarifying question: Are you trying to just stream the output from the child process to the REPL user's terminal? I.e. Do you care if the prompt > and whatever the user is in the middle of typing just disappears behind whatever other output comes from the child process?

Because, if you don't care, you could probably do something with your own process's stdout in another thread. But honestly that sounds like an ugly experience for the user.

If you're trying to integrate with your repl more cleanly, it doesn't look like Rustyline has an API for interactive editing. But if you defined one, maybe the maintainer(s) would take the PR (I've had success submitting a PR to rustyline in the past, and I know they are very open to work from the community)

The code that handles the update loop inside readline is here: rustyline/src/lib.rs at 535a9c21e017ffdb9bc1c5360e7cefbc74c1a22a · kkawakam/rustyline · GitHub

Thanks. I do care the disappearance behind the child process output, but creating a pull request seems far from me, and I have no idea how to implement this. As you mentioned, rustyline does not provide this feature. Do I have any alternative crates?

You may want to look at reedline as another similar crate. I've never used it personally but it looks to be well supported.

Slightly more afield, some very cool stuff has been made with ratatui It's less of a simple turnkey setup, but you have a lot of control over the layout. Unfortunately it's not designed specifically around prompt / REPL UI so you won't get things like history, auto-complete (done for you), etc. without some custom work. But it sounds like customizing that stuff is your aim anyway.

An ExternalPrinter may help. See this example.

1 Like

I thought `rustyline` is only responsible for the input line, but it seems that it does more than that.

I think this does the thing.

Also found this fork. What are the differences?

The difference is presumably right there in the title: support for async. If you are new to Rust I guess you might not yet have come across the async/await syntax. I don't know what a good beginner resource on that would be. The official async book is quite out of date and incomplete unfortunately.

So the difference is that, in rustyline we have to use multi-threading, but `rustyline-async can do the same thing in a single thread. The readline() call doesn’t block.

That would be my guess, but I only read the readme, not the docs.

Of course for async you need an async runtime (that is not built into rust). It appears that rustyline-async is agnostic to which one from a first glance at the dependencies.

Async in Rust is a whole thing, which you probably don't want to deal with yet if you are fairly new to the language. It has more rough edges than the rest of the language still to this day, though it is getting better slowly.

This actually appeared in here.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.