From f3ebc7b919933f554bd7f47fefbd137d1d4e76a3 Mon Sep 17 00:00:00 2001 From: Michael Sippel Date: Wed, 17 Nov 2021 22:32:04 +0100 Subject: [PATCH] process launcher: PTYStatus & kill process --- shell/src/process.rs | 16 ++++++++---- shell/src/pty.rs | 60 +++++++++++++++++++++++++++++++++----------- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/shell/src/process.rs b/shell/src/process.rs index 13e0219..ebb64fb 100644 --- a/shell/src/process.rs +++ b/shell/src/process.rs @@ -17,7 +17,8 @@ use { tree_nav::{TreeNav, TreeNavResult, TerminalTreeEditor, TreeCursor}, list::{ListCursorMode, ListEditor, ListEditorStyle, sexpr::ListDecoration}, string_editor::CharEditor, - } + }, + crate::pty::{PTY, PTYStatus} }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>> @@ -77,7 +78,7 @@ pub struct ProcessLauncher { suspended: bool, pty_port: ViewPort, - status_port: ViewPort>>, + status_port: ViewPort>, comp_port: ViewPort, compositor: Arc> @@ -156,7 +157,7 @@ impl ProcessLauncher { 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 { // 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.suspended = false; } match event { 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.suspended = false; self.cmd_editor.goto(TreeCursor { @@ -222,7 +228,7 @@ impl TreeNav for ProcessLauncher { fn goto(&mut self, cur: TreeCursor) -> TreeNavResult { 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; } diff --git a/shell/src/pty.rs b/shell/src/pty.rs index b0b5f88..c264b3f 100644 --- a/shell/src/pty.rs +++ b/shell/src/pty.rs @@ -1,7 +1,8 @@ use { + std::sync::{Arc, Mutex}, termion::event::{Key, Event}, - std::sync::Mutex, + cgmath::Vector2, nested::{ core::{InnerViewPort}, 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 { - master: Mutex> + master: Mutex>, + child: Arc>> } impl PTY { pub fn new( cmd: portable_pty::CommandBuilder, + max_size: Vector2, term_port: InnerViewPort, - status_port: InnerViewPort>> + status_port: InnerViewPort> ) -> Option { // Create a new pty let mut pair = portable_pty::native_pty_system().openpty(portable_pty::PtySize { - rows: 25, - cols: 120, + rows: max_size.y as u16, + cols: max_size.x as u16, // Not all systems support pixel_width, pixel_height, // 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) { 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( move || { 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 || { - let mut status_buf = SingletonBuffer::new(None, status_port); - if let Ok(status) = child.wait() { - status_buf.set(Some(status)); + loop { + if let Ok(Some(status)) = child.lock().unwrap().try_wait() { + status_buf.set(PTYStatus::Done{ status }); + break; + } } } - ); + }); Some(PTY { - master: Mutex::new(pair.master) + master: Mutex::new(pair.master), + child }) } else { None } } + pub fn kill(&mut self) { + self.child.lock().unwrap().kill(); + } + pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult { match event { TerminalEvent::Input(Event::Key(Key::Char('\n'))) => { @@ -94,19 +124,19 @@ impl PTY { TerminalEditorResult::Continue } 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 } 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 } 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 } 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 } _ => {