Adds support for kill and restart
This commit is contained in:
parent
692d38869a
commit
18bc80ee8e
33
src/lib.rs
33
src/lib.rs
|
@ -136,11 +136,34 @@ impl<W: Write> Multiview<W> {
|
||||||
pub fn push_stderr(&mut self, (i, j): (u16, u16), content: String) {
|
pub fn push_stderr(&mut self, (i, j): (u16, u16), content: String) {
|
||||||
self.push_stdout((i, j), content);
|
self.push_stdout((i, j), content);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Restarts the selected tile.
|
||||||
|
pub fn restart(&mut self) -> io::Result<()> {
|
||||||
|
let tile = self.tile_mut(self.selected);
|
||||||
|
tile.restart()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restarts all tiles.
|
||||||
|
pub fn restart_all(&mut self) -> io::Result<()> {
|
||||||
|
for row in &mut self.tiles {
|
||||||
|
for tile in row {
|
||||||
|
tile.restart()?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<W: Write> Drop for Multiview<W> {
|
impl<W: Write> Drop for Multiview<W> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
write!(self.stdout, "{}", cursor::Show).unwrap();
|
write!(self.stdout, "{}", cursor::Show).unwrap();
|
||||||
|
|
||||||
|
for row in &mut self.tiles {
|
||||||
|
for tile in row {
|
||||||
|
tile.kill().ok();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -155,6 +178,12 @@ pub enum Msg {
|
||||||
/// A click occured.
|
/// A click occured.
|
||||||
Click(u16, u16),
|
Click(u16, u16),
|
||||||
|
|
||||||
|
/// Restarts the selected tile.
|
||||||
|
Restart,
|
||||||
|
|
||||||
|
/// Restarts all tiles.
|
||||||
|
RestartAll,
|
||||||
|
|
||||||
/// Scroll up one line.
|
/// Scroll up one line.
|
||||||
ScrollUp,
|
ScrollUp,
|
||||||
|
|
||||||
|
@ -233,6 +262,8 @@ pub fn main() -> io::Result<()> {
|
||||||
let evt = c.unwrap();
|
let evt = c.unwrap();
|
||||||
match evt {
|
match evt {
|
||||||
Event::Key(Key::Char('q')) => sender.send(Msg::Exit).unwrap(),
|
Event::Key(Key::Char('q')) => sender.send(Msg::Exit).unwrap(),
|
||||||
|
Event::Key(Key::Char('r')) => sender.send(Msg::Restart).unwrap(),
|
||||||
|
Event::Key(Key::Char('R')) => sender.send(Msg::RestartAll).unwrap(),
|
||||||
Event::Key(Key::Down) => sender.send(Msg::ScrollDown).unwrap(),
|
Event::Key(Key::Down) => sender.send(Msg::ScrollDown).unwrap(),
|
||||||
Event::Key(Key::Up) => sender.send(Msg::ScrollUp).unwrap(),
|
Event::Key(Key::Up) => sender.send(Msg::ScrollUp).unwrap(),
|
||||||
Event::Key(Key::End) => sender.send(Msg::ScrollFullDown).unwrap(),
|
Event::Key(Key::End) => sender.send(Msg::ScrollFullDown).unwrap(),
|
||||||
|
@ -255,6 +286,8 @@ pub fn main() -> io::Result<()> {
|
||||||
Ok(Msg::Stderr(coords, line)) => multiview.push_stderr(coords, line),
|
Ok(Msg::Stderr(coords, line)) => multiview.push_stderr(coords, line),
|
||||||
Ok(Msg::Click(x, y)) => multiview.select_tile((x, y), term_size),
|
Ok(Msg::Click(x, y)) => multiview.select_tile((x, y), term_size),
|
||||||
Ok(Msg::ScrollDown) => multiview.scroll_down(),
|
Ok(Msg::ScrollDown) => multiview.scroll_down(),
|
||||||
|
Ok(Msg::Restart) => multiview.restart()?,
|
||||||
|
Ok(Msg::RestartAll) => multiview.restart_all()?,
|
||||||
Ok(Msg::ScrollUp) => multiview.scroll_up(),
|
Ok(Msg::ScrollUp) => multiview.scroll_up(),
|
||||||
Ok(Msg::ScrollFullDown) => multiview.scroll_full_down(),
|
Ok(Msg::ScrollFullDown) => multiview.scroll_full_down(),
|
||||||
Ok(Msg::ScrollFullUp) => multiview.scroll_full_up(),
|
Ok(Msg::ScrollFullUp) => multiview.scroll_full_up(),
|
||||||
|
|
139
src/tile.rs
139
src/tile.rs
|
@ -1,7 +1,7 @@
|
||||||
//! This module contains everything related to tiles.
|
//! This module contains everything related to tiles.
|
||||||
|
|
||||||
use std::io::Read;
|
use std::io::{self, Read};
|
||||||
use std::process::Stdio;
|
use std::process::{Child, Stdio};
|
||||||
use std::sync::mpsc::Sender;
|
use std::sync::mpsc::Sender;
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
||||||
|
@ -96,12 +96,12 @@ impl TileBuilder {
|
||||||
number_lines: 1,
|
number_lines: 1,
|
||||||
counting: true,
|
counting: true,
|
||||||
column_number: 0,
|
column_number: 0,
|
||||||
|
child: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A tile with a command running inside it.
|
/// A tile with a command running inside it.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Tile {
|
pub struct Tile {
|
||||||
/// The command that should be executed in the tile.
|
/// The command that should be executed in the tile.
|
||||||
pub command: Vec<String>,
|
pub command: Vec<String>,
|
||||||
|
@ -145,6 +145,9 @@ pub struct Tile {
|
||||||
|
|
||||||
/// The number of the current column.
|
/// The number of the current column.
|
||||||
pub column_number: u16,
|
pub column_number: u16,
|
||||||
|
|
||||||
|
/// The PTY and the child process of the command running in the tile.
|
||||||
|
pub child: Option<(Pty, Child)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tile {
|
impl Tile {
|
||||||
|
@ -161,83 +164,63 @@ impl Tile {
|
||||||
let size = self.inner_size;
|
let size = self.inner_size;
|
||||||
let sender = self.sender.clone();
|
let sender = self.sender.clone();
|
||||||
|
|
||||||
thread::spawn(move || {
|
let pty = Pty::new().unwrap();
|
||||||
let pty = Pty::new().unwrap();
|
pty.resize(pty_process::Size::new(size.1, size.0)).unwrap();
|
||||||
pty.resize(pty_process::Size::new(size.1, size.0)).unwrap();
|
|
||||||
|
|
||||||
let mut child = Command::new(&clone[0])
|
let mut child = Command::new(&clone[0])
|
||||||
.args(&clone[1..])
|
.args(&clone[1..])
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn(&pty.pts().unwrap())
|
.spawn(&pty.pts().unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut stdout = child.stdout.take().unwrap();
|
let mut stdout = child.stdout.take().unwrap();
|
||||||
let mut stderr = child.stderr.take().unwrap();
|
let mut stderr = child.stderr.take().unwrap();
|
||||||
let stderr_sender = sender.clone();
|
let stderr_sender = sender.clone();
|
||||||
|
|
||||||
let coords = coords;
|
let coords = coords;
|
||||||
|
|
||||||
thread::spawn(move || loop {
|
thread::spawn(move || loop {
|
||||||
let mut buffer = [0; 4096];
|
let mut buffer = [0; 4096];
|
||||||
let result = stderr.read(&mut buffer);
|
let result = stdout.read(&mut buffer);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(0) => break,
|
Ok(0) => break,
|
||||||
|
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
stderr_sender
|
sender
|
||||||
.send(Msg::Stderr(
|
.send(Msg::Stderr(
|
||||||
coords,
|
coords,
|
||||||
String::from_utf8_lossy(&buffer[0..n]).to_string(),
|
String::from_utf8_lossy(&buffer[0..n]).to_string(),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
loop {
|
Err(_) => break,
|
||||||
let mut buffer = [0; 4096];
|
|
||||||
let result = stdout.read(&mut buffer);
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(0) => break,
|
|
||||||
|
|
||||||
Ok(n) => {
|
|
||||||
sender
|
|
||||||
.send(Msg::Stderr(
|
|
||||||
coords,
|
|
||||||
String::from_utf8_lossy(&buffer[0..n]).to_string(),
|
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sender
|
|
||||||
.send(Msg::Stdout(coords, String::from("\n")))
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let code = child.wait().unwrap().code().unwrap();
|
|
||||||
|
|
||||||
let exit_string = format!(
|
|
||||||
"{}{}Command exited with return code {}{}\n",
|
|
||||||
style::Bold,
|
|
||||||
if code == 0 {
|
|
||||||
color::Green.fg_str()
|
|
||||||
} else {
|
|
||||||
color::Red.fg_str()
|
|
||||||
},
|
|
||||||
code,
|
|
||||||
style::Reset,
|
|
||||||
);
|
|
||||||
|
|
||||||
sender.send(Msg::Stdout(coords, exit_string)).unwrap();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
thread::spawn(move || loop {
|
||||||
|
let mut buffer = [0; 4096];
|
||||||
|
let result = stderr.read(&mut buffer);
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(0) => break,
|
||||||
|
|
||||||
|
Ok(n) => {
|
||||||
|
stderr_sender
|
||||||
|
.send(Msg::Stderr(
|
||||||
|
coords,
|
||||||
|
String::from_utf8_lossy(&buffer[0..n]).to_string(),
|
||||||
|
))
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(_) => break,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.child = Some((pty, child));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Push content into the stdout of the tile.
|
/// Push content into the stdout of the tile.
|
||||||
|
@ -456,4 +439,20 @@ impl Tile {
|
||||||
self.scroll = 0;
|
self.scroll = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Kill the child command.
|
||||||
|
pub fn kill(&mut self) -> io::Result<()> {
|
||||||
|
if let Some((_, child)) = self.child.as_mut() {
|
||||||
|
child.kill()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Restarts the child command.
|
||||||
|
pub fn restart(&mut self) -> io::Result<()> {
|
||||||
|
self.kill()?;
|
||||||
|
self.start();
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue