process launcher: PTYStatus & kill process

This commit is contained in:
Michael Sippel 2021-11-17 22:32:04 +01:00
parent c9c6958a62
commit f3ebc7b919
Signed by: senvas
GPG key ID: F96CF119C34B64A6
2 changed files with 56 additions and 20 deletions

View file

@ -17,7 +17,8 @@ use {
tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor}, tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor},
list::{ListCursorMode, ListEditor, ListEditorStyle, sexpr::ListDecoration}, list::{ListCursorMode, ListEditor, ListEditorStyle, sexpr::ListDecoration},
string_editor::CharEditor, string_editor::CharEditor,
} },
crate::pty::{PTY, PTYStatus}
}; };
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
@ -77,7 +78,7 @@ pub struct ProcessLauncher {
suspended: bool, suspended: bool,
pty_port: ViewPort<dyn TerminalView>, pty_port: ViewPort<dyn TerminalView>,
status_port: ViewPort<dyn SingletonView<Item = Option<portable_pty::ExitStatus>>>, status_port: ViewPort<dyn SingletonView<Item = PTYStatus>>,
comp_port: ViewPort<dyn TerminalView>, comp_port: ViewPort<dyn TerminalView>,
compositor: Arc<RwLock<nested::terminal::TerminalCompositor>> compositor: Arc<RwLock<nested::terminal::TerminalCompositor>>
@ -156,7 +157,7 @@ impl ProcessLauncher {
tree_addr: vec![] tree_addr: vec![]
}); });
self.pty = crate::pty::PTY::new(cmd, self.pty_port.inner(), self.status_port.inner()); self.pty = PTY::new(cmd, cgmath::Vector2::new(120, 40), self.pty_port.inner(), self.status_port.inner());
} }
} }
@ -173,13 +174,18 @@ impl TerminalEditor for ProcessLauncher {
fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
// todo: move to observer of status view // todo: move to observer of status view
if let Some(status) = self.status_port.outer().get_view().get() { if let PTYStatus::Done{ status } = self.status_port.outer().get_view().get() {
self.pty = None; self.pty = None;
self.suspended = false; self.suspended = false;
} }
match event { match event {
TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => { TerminalEvent::Input(Event::Key(Key::Ctrl('c'))) => {
// todo: sigterm instead of kill?
if let Some(mut pty) = self.pty.as_mut() {
pty.kill();
}
self.pty = None; self.pty = None;
self.suspended = false; self.suspended = false;
self.cmd_editor.goto(TreeCursor { self.cmd_editor.goto(TreeCursor {
@ -222,7 +228,7 @@ impl TreeNav for ProcessLauncher {
fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { fn goto(&mut self, cur: TreeCursor) -> TreeNavResult {
self.suspended = false; self.suspended = false;
if let Some(status) = self.status_port.outer().get_view().get() { if let PTYStatus::Done{status} = self.status_port.outer().get_view().get() {
self.pty = None; self.pty = None;
} }

View file

@ -1,7 +1,8 @@
use { use {
std::sync::{Arc, Mutex},
termion::event::{Key, Event}, termion::event::{Key, Event},
std::sync::Mutex, cgmath::Vector2,
nested::{ nested::{
core::{InnerViewPort}, core::{InnerViewPort},
singleton::{SingletonView, SingletonBuffer}, singleton::{SingletonView, SingletonBuffer},
@ -13,21 +14,39 @@ pub use portable_pty::CommandBuilder;
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
#[derive(Clone)]
pub enum PTYStatus {
Running{ pid: u32 },
Done{ status: portable_pty::ExitStatus }
}
impl Default for PTYStatus {
fn default() -> Self {
PTYStatus::Running {
pid: 0
}
}
}
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
pub struct PTY { pub struct PTY {
master: Mutex<Box<dyn portable_pty::MasterPty + Send>> master: Mutex<Box<dyn portable_pty::MasterPty + Send>>,
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>
} }
impl PTY { impl PTY {
pub fn new( pub fn new(
cmd: portable_pty::CommandBuilder, cmd: portable_pty::CommandBuilder,
max_size: Vector2<i16>,
term_port: InnerViewPort<dyn TerminalView>, term_port: InnerViewPort<dyn TerminalView>,
status_port: InnerViewPort<dyn SingletonView<Item = Option<portable_pty::ExitStatus>>> status_port: InnerViewPort<dyn SingletonView<Item = PTYStatus>>
) -> Option<Self> { ) -> Option<Self> {
// Create a new pty // Create a new pty
let mut pair = portable_pty::native_pty_system().openpty(portable_pty::PtySize { let mut pair = portable_pty::native_pty_system().openpty(portable_pty::PtySize {
rows: 25, rows: max_size.y as u16,
cols: 120, cols: max_size.x as u16,
// Not all systems support pixel_width, pixel_height, // Not all systems support pixel_width, pixel_height,
// but it is good practice to set it to something // but it is good practice to set it to something
@ -40,29 +59,40 @@ impl PTY {
if let Ok(mut child) = pair.slave.spawn_command(cmd) { if let Ok(mut child) = pair.slave.spawn_command(cmd) {
let mut reader = pair.master.try_clone_reader().unwrap(); let mut reader = pair.master.try_clone_reader().unwrap();
let mut status_buf = SingletonBuffer::new(PTYStatus::Running{ pid: child.process_id().expect("") }, status_port);
let child = Arc::new(Mutex::new(child));
async_std::task::spawn_blocking( async_std::task::spawn_blocking(
move || { move || {
nested::terminal::ansi_parser::read_ansi_from(&mut reader, term_port); nested::terminal::ansi_parser::read_ansi_from(&mut reader, term_port);
}); });
async_std::task::spawn_blocking( async_std::task::spawn_blocking({
let child = child.clone();
move || { move || {
let mut status_buf = SingletonBuffer::new(None, status_port); loop {
if let Ok(status) = child.wait() { if let Ok(Some(status)) = child.lock().unwrap().try_wait() {
status_buf.set(Some(status)); status_buf.set(PTYStatus::Done{ status });
break;
}
} }
} }
); });
Some(PTY { Some(PTY {
master: Mutex::new(pair.master) master: Mutex::new(pair.master),
child
}) })
} else { } else {
None None
} }
} }
pub fn kill(&mut self) {
self.child.lock().unwrap().kill();
}
pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
match event { match event {
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
@ -94,19 +124,19 @@ impl PTY {
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
TerminalEvent::Input(Event::Key(Key::Up)) => { TerminalEvent::Input(Event::Key(Key::Up)) => {
self.master.lock().unwrap().write(&[0, b'\x1B', b'[', b'A']).unwrap(); self.master.lock().unwrap().write(&[b'\x1B', b'[', b'A']).unwrap();
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
TerminalEvent::Input(Event::Key(Key::Down)) => { TerminalEvent::Input(Event::Key(Key::Down)) => {
self.master.lock().unwrap().write(&[0, b'\x1B', b'[', b'B']).unwrap(); self.master.lock().unwrap().write(&[b'\x1B', b'[', b'B']).unwrap();
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
TerminalEvent::Input(Event::Key(Key::Right)) => { TerminalEvent::Input(Event::Key(Key::Right)) => {
self.master.lock().unwrap().write(&[0, b'\x1B', b'[', b'C']).unwrap(); self.master.lock().unwrap().write(&[b'\x1B', b'[', b'C']).unwrap();
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
TerminalEvent::Input(Event::Key(Key::Left)) => { TerminalEvent::Input(Event::Key(Key::Left)) => {
self.master.lock().unwrap().write(&[0, b'\x1B', b'[', b'D']).unwrap(); self.master.lock().unwrap().write(&[b'\x1B', b'[', b'D']).unwrap();
TerminalEditorResult::Continue TerminalEditorResult::Continue
} }
_ => { _ => {