diff --git a/src/main.rs b/src/main.rs index 95fa2b1..8a6a33b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,7 @@ -use nix::fcntl::{fcntl, OFlag, F_GETFL, F_SETFL}; -use nix::pty::{forkpty, ForkptyResult, PtyMaster}; -use nix::unistd::{execve, read, write}; +use nix::fcntl::{F_GETFL, F_SETFL, OFlag, fcntl}; +use nix::pty::{ForkptyResult, PtyMaster, forkpty}; +use nix::sys::wait::{WaitPidFlag, WaitStatus, waitpid}; +use nix::unistd::{Pid, execve, read, write}; use minifb::{Key, KeyRepeat, Window, WindowOptions}; @@ -74,20 +75,20 @@ impl Perform for Model { // draw a character to the screen and update states fn print(&mut self, c: char) { if self.cursor.col < self.buffer.width { - // scrolls - while self.cursor.row >= self.buffer.height { - for row in 0..(self.buffer.height - 1) { + // scrolls + while self.cursor.row >= self.buffer.height { + for row in 0..(self.buffer.height - 1) { + for col in 0..self.buffer.width { + self.buffer.set(col, row, self.buffer.get(col, row + 1)); + } + } for col in 0..self.buffer.width { - self.buffer.set(col, row, self.buffer.get(col, row + 1)); - }; - }; - for col in 0..self.buffer.width { - self.buffer.set(col, self.buffer.height - 1, None); + self.buffer.set(col, self.buffer.height - 1, None); + } + self.cursor.row -= 1; } - self.cursor.row -= 1; - }; - self.buffer.set(self.cursor.col, self.cursor.row, Some(c)); - self.cursor.col += 1; + self.buffer.set(self.cursor.col, self.cursor.row, Some(c)); + self.cursor.col += 1; } println!("[print] {:?}", c); } @@ -100,7 +101,7 @@ impl Perform for Model { 0x08 => { self.cursor.col = self.cursor.col - 1; self.buffer.set(self.cursor.col, self.cursor.row, None); - }, + } _ => (), } println!("[execute] {:02x}", byte); @@ -193,7 +194,7 @@ fn main() { // initialize window and its buffer let mut window = Window::new( - "rust-term", + "rustty", model.screenbuffer.width, model.screenbuffer.height, WindowOptions::default(), @@ -201,7 +202,7 @@ fn main() { .unwrap(); window.set_target_fps(60); - let pty = spawn_pty().unwrap(); + let (pty, child) = spawn_pty().unwrap(); fcntl( &pty, F_SETFL(OFlag::from_bits_truncate(fcntl(&pty, F_GETFL).unwrap()) | OFlag::O_NONBLOCK), @@ -211,7 +212,10 @@ fn main() { let mut statemachine = Parser::new(); let mut buf = [0u8; 2048]; - while window.is_open() && !window.is_key_down(Key::Escape) { + while window.is_open() + && !window.is_key_down(Key::Escape) + && waitpid(child, Some(WaitPidFlag::WNOHANG)) == Ok(WaitStatus::StillAlive) + { // mask to render into let mut mask = vec![0u8; model.screenbuffer.width * model.screenbuffer.height]; @@ -260,17 +264,20 @@ fn main() { }; let keys = window.get_keys_pressed(KeyRepeat::Yes); - let shift = window.is_key_down(Key::LeftShift) || window.is_key_down(Key::RightShift) || window.is_key_down(Key::CapsLock); + let shift = window.is_key_down(Key::LeftShift) + || window.is_key_down(Key::RightShift) + || window.is_key_down(Key::CapsLock); let ctrl = window.is_key_down(Key::LeftCtrl) || window.is_key_down(Key::RightCtrl); if !keys.is_empty() { let bytes: Vec = keys .iter() // TODO apply modifiers - .map(|key| key_to_u8( + .map(|key| { + key_to_u8( *key, // key - shift, - ctrl - )) + shift, ctrl, + ) + }) .filter(|v| *v != 0u8) .collect(); write(&pty, bytes.as_slice()); @@ -279,24 +286,26 @@ fn main() { } // forks a new pty and returns file descriptor of the master -fn spawn_pty() -> Option { +fn spawn_pty() -> Option<(PtyMaster, Pid)> { // SAFETY safe unless os out of PTYs; incredibly unlikely match unsafe { forkpty(None, None) } { Ok(fork_pty_res) => match fork_pty_res { - ForkptyResult::Parent { child: _, master } => { + ForkptyResult::Parent { child, master } => { // SAFETY `master` is a valid PtyMaster - return Some(unsafe { PtyMaster::from_owned_fd(master) }); + return Some((unsafe { PtyMaster::from_owned_fd(master) }, child)); } ForkptyResult::Child => { let _ = execve::( &CString::new("/usr/bin/env").unwrap(), - &[ CString::new("/usr/bin/env").unwrap(), + &[ + CString::new("/usr/bin/env").unwrap(), CString::new("-i").unwrap(), CString::new("sh").unwrap(), CString::new("--norc").unwrap(), - CString::new("--noprofile").unwrap() ], - &[ CString::new("TERM=dumb").unwrap() ], - ); + CString::new("--noprofile").unwrap(), + ], + &[CString::new("TERM=dumb").unwrap()], + ); return None; } },