Open thallada opened 6 years ago
Hi!
Cursive currently sets up the terminal at creation (Cursive::new()
) and cleans up on drop. Though this rigid structure is already not ideal, as seen in #180 .
Being able to "pause" the cursive app while executing something else sounds like a good use-case, and shouldn't be too hard. Maybe something like Cursive::pause<F: FnOnce()>(&mut self, command: F)
, where command
would be run in a cursive-free context (and the app would resume when the closure exits).
I am interested in this functionality, too: for spawning vim from a cursive app.
@matthiasbeyer I'm building a terminal widget. It can't handle control codes yet but I am working on it.
This can give you a window you can attach an external command to.
It's currently buried in https://github.com/igbc/cue but I can break it into a crate as soon as someone want's it for something.
@IGBC I tried running your program but I get a whole bunch of errors if I try to run anything more complex than ls
. Looks like you are just piping the output of commands back into Cursive?
I tried messing with this some more but still got nowhere. I added this function to Cursive
:
pub fn pause(&mut self) {
self.running = false; // what quit() calls
self.backend.finish(); // what drop() calls
}
But, even if I called that before the Command
I mentioned above, nothing changed. The cursor is still not shown and I still have the weird stdin behavior where I have to hit keys multiple times before the child process registers them.
I thought it might have something to do with the separate thread termion.rs
spawns that processes stdin events, so I added a way to pause that as well:
fn init() -> Self {
...
let process_input = true;
thread::spawn(move || {
for key in ::std::io::stdin().events() {
if process_input {
if let Ok(key) = key {
sender.send(key)
}
}
}
});
...
}
...
fn pause(&mut self) {
self.process_input = false;
print!("{}", ToMainScreen); // what AlternateScreen's drop() calls
}
But calling self.backend.pause()
to trigger that didn't seem to fix the issue either.
It seems like Cursive doesn't really clean up after itself and return the terminal to normal until after the whole Rust program exits, and I can't get that same process to happen while the program is still running.
yes the output is passed back into cursive, the idea is to create an embedded terminal emulator inside of cursive. The errors you are encountering are because this is still a work in progress and not remotely shipable yet.
I am also interested by getting access to stdout, my use case is much simpler. I want to be able to get the output of cursive and use as part of some command, for example
vim `cursive-pick-file`
This doesn't work today because Cursive uses initscr
. I think that if Cursive were to use newterm
instead this use case would work.
https://www.linuxquestions.org/questions/linux-newbie-8/can-a-process-redirect-stdout-and-still-use-ncurses-in-a-terminal-4175411385/
Let me know what you think :)
Ah indeed, I didn't know about newterm
.
Latest master should now use this instead of initscr
; if this works for you, I'll use the same for pancurses. We'll see then how to bring this to the termion backend.
@gyscos the newterm()
approach seems to be working fine 👍 Many thanks!
We still print a few things to stdout, I still need to replace these with writing to the tty.
Ah yes, I was able to reproduce the issue with extra characters after going in circles for a while. The extra characters are not visible, gotta love it.
2729e77838b2312054251d95fe162e1ee7d092d1 should remove the last bits we were writing to stdout
.
For instance, cargo run --example colors | hexdump
should show no output.
In addition, stdin
is also untouched, making it easier to use cursive applications to pipe data in/out (could be used as a more interactive pv
for instance).
For the pancurses backend, we're waiting on a new release to make newterm
usable.
For the termion backend, we'll need to replace the calls to print!
with direct writes to /dev/tty
.
I confirm that back-tick use case works for me with the latest commit 👍 Looking forward to the next release - and maybe we can get also cursive_table_view to upgrade.
Just added the vpv
example - a visual pipe viewer - to showcase stdin/stdout usage. It uses moves data from stdin
(or directly a file) to stdout
and shows the progress visually.
Ex:
$ # Follows any pipe
$ cat /dev/urandom | cargo run --example vpv > /dev/null
$ # Can also open files directly - in this case we know the size and can show a progress bar
$ # `pv` is used here to limit the transfer speed
$ cargo run --example vpv -- target/debug/examples/vpv | pv -qL1M > /dev/null
Maybe just me, but much minimal - even artificial - example showing this feature would be also welcome. This example is very practical with logic shadowing the essence of feature?
Ah, sorry, the example only shows how stdin/stdout are now free for other usages, like piping data. This "feature" is more abstract and really simple, so I hope it won't be too confusing.
The core issue (pausing cursive to let something else handle the terminal, like running vim
) is not implemented yet.
Maybe a multiplexer-mode can be added? To make a terminal emulator inside cursive to allow other interactive terminal apps will be a killing feature. I think it can be implemented similar to this https://github.com/deadpixi/mtm
. (It is about 1000 lines of C code for simple terminal emulation). Or could the project borrow some codes from alacrity for its terminal processing?
There is already a multiplexer for cursive!
@matthiasbeyer They are different. I want to open other TUI app inside, not just another internal cursive view.
I understood that! You think of a terminal emulator that can be used to start, for example, vim inside a cursive app. There's no need for a tiling functionality, because there's the cursive-multiplex crate that can handle that part.
So there's a bunch of different needs here:
Cursive
root. Until then, the alternative is to tear down the Cursive
object, let it clean up the terminal, and re-create it after the "pause" when the other app exits. This seems to be the original intent for this issue.vim
or cursive-in-cursive applications.The last point seems to be what cursive-multiplex
solves, and the first point is not too difficult (it will probably come in the next month or two).
The middle point is the tricky one: it would need to create a pt
device (pseudoterminal) and handle a bunch of event translations. This is where a third-party library may make things a bit easier, but it would still be a fair amount of work.
@gyscos Indeed writing a terminal emulator properly is fair amount of work. Maybe alacrity_terminal
rust module from alacritty
can help and be used as a standalone terminal emulation layer.
I'd rather use a VTE binding library to implement one, tbh.
additional event loop implementation will be needed to terminal emulation if just using rust VTE crate.
The latest commit starts experimenting with the idea of pausable/resumable backends. More specifically:
As a result you should be able to run an event loop; when it exits, the terminal will be reset, and you can run another process (bash, vim, ...), and when that process completes, you can re-use the same Cursive
instance for another event loop.
It's quite a big change, and will likely take a major version bump. In particular, it moves the error handling from cursive creation to running the event loop.
A CursiveRunnable
wrapper is added to embed a Cursive
instance with a backend-initializing function, to bring back the same behaviour as previously (backend selected at creation time).
It's still experimental though: I'm not 100% sure yet if backends can be initialized again multiple times without issue. There may very well be memory leaks or possibly lost input - will need to test some more.
Added the pause
example to show how to run multiple event loops, potentially running other commands in between.
Added the
pause
example to show how to run multiple event loops, potentially running other commands in between.
The example seems to be located here now 😃.
I am new to Rust and this library so I'm not sure if this is currently possible.
Problem description
I'm trying to make a Cursive program that will launch another interactive program and then resume after the program exits. I'm using the Termion backend. I have tried this on the callback of a submit:
But it seems like Cursive in the background is still reacting to the stdin and the spawned program isn't working correctly (I have to hit tab multiple times before w3m responds and goes to the next link, there's no cursor, etc.). If I run that code above in a fresh main.rs without Cursive, the spawned program behaves fine.
blessed, a terminal UI library in Node.js has a function for this called spawn.
The cursor would have to be shown again and Cursive would need to stop processing stdin until the spawned program closes.
Environment
locale
in a terminal): en_US.UTF-8Thanks for creating this library. I've been able to get a lot done with it so far!