2021-09-15 17:47:40 +02:00
|
|
|
|
|
|
|
use {
|
2021-11-17 22:32:04 +01:00
|
|
|
std::sync::{Arc, Mutex},
|
2021-09-15 17:47:40 +02:00
|
|
|
termion::event::{Key, Event},
|
2021-11-17 22:32:04 +01:00
|
|
|
cgmath::Vector2,
|
2021-09-15 17:47:40 +02:00
|
|
|
nested::{
|
|
|
|
core::{InnerViewPort},
|
2021-11-11 22:29:37 +01:00
|
|
|
singleton::{SingletonView, SingletonBuffer},
|
|
|
|
terminal::{TerminalView, TerminalEvent, TerminalEditorResult}
|
2021-09-15 17:47:40 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
pub use portable_pty::CommandBuilder;
|
|
|
|
|
|
|
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
|
|
|
2021-11-17 22:32:04 +01:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub enum PTYStatus {
|
|
|
|
Running{ pid: u32 },
|
|
|
|
Done{ status: portable_pty::ExitStatus }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for PTYStatus {
|
|
|
|
fn default() -> Self {
|
|
|
|
PTYStatus::Running {
|
|
|
|
pid: 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
|
|
|
|
|
2021-09-15 17:47:40 +02:00
|
|
|
pub struct PTY {
|
2021-11-17 22:32:04 +01:00
|
|
|
master: Mutex<Box<dyn portable_pty::MasterPty + Send>>,
|
|
|
|
child: Arc<Mutex<Box<dyn portable_pty::Child + Send + Sync>>>
|
2021-09-15 17:47:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl PTY {
|
|
|
|
pub fn new(
|
|
|
|
cmd: portable_pty::CommandBuilder,
|
2021-11-17 22:32:04 +01:00
|
|
|
max_size: Vector2<i16>,
|
2021-11-11 22:29:37 +01:00
|
|
|
term_port: InnerViewPort<dyn TerminalView>,
|
2021-11-17 22:32:04 +01:00
|
|
|
status_port: InnerViewPort<dyn SingletonView<Item = PTYStatus>>
|
2021-09-15 17:47:40 +02:00
|
|
|
) -> Option<Self> {
|
|
|
|
|
|
|
|
// Create a new pty
|
|
|
|
let mut pair = portable_pty::native_pty_system().openpty(portable_pty::PtySize {
|
2021-11-17 22:32:04 +01:00
|
|
|
rows: max_size.y as u16,
|
|
|
|
cols: max_size.x as u16,
|
2021-09-15 17:47:40 +02:00
|
|
|
|
|
|
|
// Not all systems support pixel_width, pixel_height,
|
|
|
|
// but it is good practice to set it to something
|
|
|
|
// that matches the size of the selected font. That
|
|
|
|
// is more complex than can be shown here in this
|
|
|
|
// brief example though!
|
|
|
|
pixel_width: 0,
|
|
|
|
pixel_height: 0,
|
|
|
|
}).unwrap();
|
|
|
|
|
2021-11-11 22:29:37 +01:00
|
|
|
if let Ok(mut child) = pair.slave.spawn_command(cmd) {
|
2021-09-15 17:47:40 +02:00
|
|
|
let mut reader = pair.master.try_clone_reader().unwrap();
|
2021-11-17 22:32:04 +01:00
|
|
|
let mut status_buf = SingletonBuffer::new(PTYStatus::Running{ pid: child.process_id().expect("") }, status_port);
|
|
|
|
|
|
|
|
let child = Arc::new(Mutex::new(child));
|
2021-09-15 17:47:40 +02:00
|
|
|
|
|
|
|
async_std::task::spawn_blocking(
|
|
|
|
move || {
|
2021-11-18 22:55:32 +01:00
|
|
|
nested::terminal::ansi_parser::read_ansi_from(&mut reader, max_size, term_port);
|
2021-09-15 17:47:40 +02:00
|
|
|
});
|
2021-11-11 22:29:37 +01:00
|
|
|
|
2021-11-17 22:32:04 +01:00
|
|
|
async_std::task::spawn_blocking({
|
|
|
|
let child = child.clone();
|
2021-11-11 22:29:37 +01:00
|
|
|
move || {
|
2021-11-17 22:32:04 +01:00
|
|
|
loop {
|
|
|
|
if let Ok(Some(status)) = child.lock().unwrap().try_wait() {
|
|
|
|
status_buf.set(PTYStatus::Done{ status });
|
|
|
|
break;
|
|
|
|
}
|
2021-11-18 22:55:32 +01:00
|
|
|
|
|
|
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
2021-11-11 22:29:37 +01:00
|
|
|
}
|
|
|
|
}
|
2021-11-17 22:32:04 +01:00
|
|
|
});
|
2021-11-11 22:29:37 +01:00
|
|
|
|
2021-09-15 17:47:40 +02:00
|
|
|
Some(PTY {
|
2021-11-17 22:32:04 +01:00
|
|
|
master: Mutex::new(pair.master),
|
|
|
|
child
|
2021-09-15 17:47:40 +02:00
|
|
|
})
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 22:32:04 +01:00
|
|
|
pub fn kill(&mut self) {
|
|
|
|
self.child.lock().unwrap().kill();
|
|
|
|
}
|
|
|
|
|
2021-11-11 22:29:37 +01:00
|
|
|
pub fn handle_terminal_event(&mut self, event: &TerminalEvent) -> TerminalEditorResult {
|
2021-09-15 17:47:40 +02:00
|
|
|
match event {
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEvent::Input(Event::Key(Key::Char('\n'))) => {
|
|
|
|
self.master.lock().unwrap().write(&[13]).unwrap();
|
|
|
|
TerminalEditorResult::Continue
|
|
|
|
},
|
2021-09-15 17:47:40 +02:00
|
|
|
TerminalEvent::Input(Event::Key(Key::Char(c))) => {
|
2021-09-24 23:31:09 +02:00
|
|
|
write!(self.master.lock().unwrap(), "{}", c);
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Continue
|
|
|
|
},
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Esc)) => {
|
|
|
|
self.master.lock().unwrap().write(&[0x1b]).unwrap();
|
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Backspace)) => {
|
|
|
|
self.master.lock().unwrap().write(&[0x8]).unwrap();
|
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::F(n))) => {
|
|
|
|
self.master.lock().unwrap().write(&[
|
|
|
|
0x1b,
|
|
|
|
0x0a,
|
|
|
|
match n {
|
|
|
|
11 => 133,
|
|
|
|
12 => 134,
|
|
|
|
n => 58 + n
|
|
|
|
}
|
|
|
|
]).unwrap();
|
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Up)) => {
|
2021-11-17 22:32:04 +01:00
|
|
|
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'A']).unwrap();
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Down)) => {
|
2021-11-17 22:32:04 +01:00
|
|
|
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'B']).unwrap();
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Right)) => {
|
2021-11-17 22:32:04 +01:00
|
|
|
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'C']).unwrap();
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Continue
|
|
|
|
}
|
|
|
|
TerminalEvent::Input(Event::Key(Key::Left)) => {
|
2021-11-17 22:32:04 +01:00
|
|
|
self.master.lock().unwrap().write(&[b'\x1B', b'[', b'D']).unwrap();
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Continue
|
2021-09-15 17:47:40 +02:00
|
|
|
}
|
|
|
|
_ => {
|
2021-11-11 22:29:37 +01:00
|
|
|
TerminalEditorResult::Exit
|
2021-09-15 17:47:40 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|