fmt, use waitpid to exit

This commit is contained in:
andromeda
2026-01-18 12:47:12 +01:00
parent aecca6f229
commit d2ed0e974b

View File

@@ -1,6 +1,7 @@
use nix::fcntl::{fcntl, OFlag, F_GETFL, F_SETFL}; use nix::fcntl::{F_GETFL, F_SETFL, OFlag, fcntl};
use nix::pty::{forkpty, ForkptyResult, PtyMaster}; use nix::pty::{ForkptyResult, PtyMaster, forkpty};
use nix::unistd::{execve, read, write}; use nix::sys::wait::{WaitPidFlag, WaitStatus, waitpid};
use nix::unistd::{Pid, execve, read, write};
use minifb::{Key, KeyRepeat, Window, WindowOptions}; use minifb::{Key, KeyRepeat, Window, WindowOptions};
@@ -79,13 +80,13 @@ impl Perform for Model {
for row in 0..(self.buffer.height - 1) { for row in 0..(self.buffer.height - 1) {
for col in 0..self.buffer.width { for col in 0..self.buffer.width {
self.buffer.set(col, row, self.buffer.get(col, row + 1)); self.buffer.set(col, row, self.buffer.get(col, row + 1));
}; }
}; }
for col in 0..self.buffer.width { 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.buffer.set(self.cursor.col, self.cursor.row, Some(c));
self.cursor.col += 1; self.cursor.col += 1;
} }
@@ -100,7 +101,7 @@ impl Perform for Model {
0x08 => { 0x08 => {
self.cursor.col = self.cursor.col - 1; self.cursor.col = self.cursor.col - 1;
self.buffer.set(self.cursor.col, self.cursor.row, None); self.buffer.set(self.cursor.col, self.cursor.row, None);
}, }
_ => (), _ => (),
} }
println!("[execute] {:02x}", byte); println!("[execute] {:02x}", byte);
@@ -193,7 +194,7 @@ fn main() {
// initialize window and its buffer // initialize window and its buffer
let mut window = Window::new( let mut window = Window::new(
"rust-term", "rustty",
model.screenbuffer.width, model.screenbuffer.width,
model.screenbuffer.height, model.screenbuffer.height,
WindowOptions::default(), WindowOptions::default(),
@@ -201,7 +202,7 @@ fn main() {
.unwrap(); .unwrap();
window.set_target_fps(60); window.set_target_fps(60);
let pty = spawn_pty().unwrap(); let (pty, child) = spawn_pty().unwrap();
fcntl( fcntl(
&pty, &pty,
F_SETFL(OFlag::from_bits_truncate(fcntl(&pty, F_GETFL).unwrap()) | OFlag::O_NONBLOCK), 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 statemachine = Parser::new();
let mut buf = [0u8; 2048]; 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 // mask to render into
let mut mask = vec![0u8; model.screenbuffer.width * model.screenbuffer.height]; 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 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); let ctrl = window.is_key_down(Key::LeftCtrl) || window.is_key_down(Key::RightCtrl);
if !keys.is_empty() { if !keys.is_empty() {
let bytes: Vec<u8> = keys let bytes: Vec<u8> = keys
.iter() .iter()
// TODO apply modifiers // TODO apply modifiers
.map(|key| key_to_u8( .map(|key| {
key_to_u8(
*key, // key *key, // key
shift, shift, ctrl,
ctrl )
)) })
.filter(|v| *v != 0u8) .filter(|v| *v != 0u8)
.collect(); .collect();
write(&pty, bytes.as_slice()); write(&pty, bytes.as_slice());
@@ -279,23 +286,25 @@ fn main() {
} }
// forks a new pty and returns file descriptor of the master // forks a new pty and returns file descriptor of the master
fn spawn_pty() -> Option<PtyMaster> { fn spawn_pty() -> Option<(PtyMaster, Pid)> {
// SAFETY safe unless os out of PTYs; incredibly unlikely // SAFETY safe unless os out of PTYs; incredibly unlikely
match unsafe { forkpty(None, None) } { match unsafe { forkpty(None, None) } {
Ok(fork_pty_res) => match fork_pty_res { Ok(fork_pty_res) => match fork_pty_res {
ForkptyResult::Parent { child: _, master } => { ForkptyResult::Parent { child, master } => {
// SAFETY `master` is a valid PtyMaster // 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 => { ForkptyResult::Child => {
let _ = execve::<CString, CString>( let _ = execve::<CString, CString>(
&CString::new("/usr/bin/env").unwrap(), &CString::new("/usr/bin/env").unwrap(),
&[ CString::new("/usr/bin/env").unwrap(), &[
CString::new("/usr/bin/env").unwrap(),
CString::new("-i").unwrap(), CString::new("-i").unwrap(),
CString::new("sh").unwrap(), CString::new("sh").unwrap(),
CString::new("--norc").unwrap(), CString::new("--norc").unwrap(),
CString::new("--noprofile").unwrap() ], CString::new("--noprofile").unwrap(),
&[ CString::new("TERM=dumb").unwrap() ], ],
&[CString::new("TERM=dumb").unwrap()],
); );
return None; return None;
} }