diff options
| author | andromeda <andromeda@lenovo> | 2026-01-17 00:40:22 +0100 |
|---|---|---|
| committer | andromeda <andromeda@lenovo> | 2026-01-17 00:40:22 +0100 |
| commit | 2fee948de10d28a4b09ac4188d6967373bac5cac (patch) | |
| tree | 69cebdb47e10315d55d27c02cadb004aa6d26f20 | |
| parent | eedc84d871c901992a4dae31c5a17f49f8b4a199 (diff) | |
nonblocking, good stuff w/ vte :)
| -rw-r--r-- | Cargo.lock | 10 | ||||
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/main.rs | 47 |
3 files changed, 40 insertions, 18 deletions
@@ -51,10 +51,20 @@ dependencies = [ ] [[package]] +name = "nonblock" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51c7a4f22e5f2e2bd805d6ab56f1ae87eb1815673e1b452048896fb687a8a3d4" +dependencies = [ + "libc", +] + +[[package]] name = "rustty" version = "0.1.0" dependencies = [ "nix", + "nonblock", "vte", ] @@ -5,4 +5,5 @@ edition = "2024" [dependencies] nix = {default-features = false, features=["term","process","fs"], version="0.30.1"} +nonblock = "0.2.0" vte = "0.15.0" diff --git a/src/main.rs b/src/main.rs index 05fb64e..6e680f8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,14 +1,16 @@ +use nix::fcntl::{fcntl, F_GETFL, F_SETFL, OFlag}; use nix::pty::{ForkptyResult, forkpty, PtyMaster}; -use nix::unistd::read; +use nix::unistd::{execv, read, write}; -use std::vec::Vec; -use std::io::{self, Read, Write}; -use std::process::Command; -use std::thread; -use std::time::Duration; +use nonblock::NonBlockingReader; + +use std::vec; +use std::ffi::CString; +use std::io; use vte::{Params, Parser, Perform}; +// yoinked form vte docs struct Performer; impl Perform for Performer { fn print(&mut self, c: char) { @@ -54,25 +56,35 @@ impl Perform for Performer { } fn main() { - // TODO get rid of hard coded `sh` path - let mut pty = spawn_pty("/home/andromeda/.nix-profile/bin/sh").unwrap(); + let pty = spawn_pty("/home/andromeda/.nix-profile/bin/sh").unwrap(); println!("{:?}", &pty); + let pty_flags = fcntl(&pty, F_GETFL).unwrap(); + fcntl(&pty, F_SETFL(OFlag::from_bits_truncate(pty_flags) | OFlag::O_NONBLOCK)).unwrap(); - let input = io::stdin(); - let mut handle = input.lock(); + let stdin = io::stdin(); + let mut nb_stdin = NonBlockingReader::from_fd(stdin).unwrap(); let mut statemachine = Parser::new(); let mut performer = Performer; let mut buf = [0u8; 2048]; + let mut vec: Vec<u8> = vec!(); - while true { + loop { match read(&pty, &mut buf) { - Ok(0) => break, + Ok(0) => (), + Ok(n) => statemachine.advance(&mut performer, &buf[..n]), + Err(_e) => (), + }; + vec.clear(); + match &nb_stdin.read_available(&mut vec) { + Ok(0) => (), Ok(n) => { - statemachine.advance(&mut performer, &buf[..n]); + let un = *n as usize; + buf[..un].copy_from_slice(&vec[..un]); + let _ = write(&pty, &buf[..un]); }, - Err(_e) => break, + Err(e) => println!("error: {:?}", e), }; }; } @@ -82,14 +94,13 @@ fn spawn_pty(shell: &str) -> Option<PtyMaster> { // SAFETY safe unless os out of PTYs; incredibly unlikely match unsafe {forkpty(None, None)} { Ok(fork_pty_res) => match fork_pty_res { - ForkptyResult::Parent {master, ..} => { + ForkptyResult::Parent {child:_, master} => { + // SAFETY `master` is a valid PtyMaster return Some(unsafe{PtyMaster::from_owned_fd(master)}); } ForkptyResult::Child =>{ - Command::new(shell).spawn(); - // TODO come up with an elegant solution - thread::sleep(Duration::MAX); + let _ = execv::<CString>(&CString::new(shell).unwrap(), &[]); return None; } }, |
