nonblocking, good stuff w/ vte :)

This commit is contained in:
andromeda
2026-01-17 00:40:22 +01:00
parent eedc84d871
commit 2fee948de1
3 changed files with 40 additions and 18 deletions

10
Cargo.lock generated
View File

@@ -50,11 +50,21 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "nonblock"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51c7a4f22e5f2e2bd805d6ab56f1ae87eb1815673e1b452048896fb687a8a3d4"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "rustty" name = "rustty"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"nix", "nix",
"nonblock",
"vte", "vte",
] ]

View File

@@ -5,4 +5,5 @@ edition = "2024"
[dependencies] [dependencies]
nix = {default-features = false, features=["term","process","fs"], version="0.30.1"} nix = {default-features = false, features=["term","process","fs"], version="0.30.1"}
nonblock = "0.2.0"
vte = "0.15.0" vte = "0.15.0"

View File

@@ -1,14 +1,16 @@
use nix::fcntl::{fcntl, F_GETFL, F_SETFL, OFlag};
use nix::pty::{ForkptyResult, forkpty, PtyMaster}; use nix::pty::{ForkptyResult, forkpty, PtyMaster};
use nix::unistd::read; use nix::unistd::{execv, read, write};
use std::vec::Vec; use nonblock::NonBlockingReader;
use std::io::{self, Read, Write};
use std::process::Command; use std::vec;
use std::thread; use std::ffi::CString;
use std::time::Duration; use std::io;
use vte::{Params, Parser, Perform}; use vte::{Params, Parser, Perform};
// yoinked form vte docs
struct Performer; struct Performer;
impl Perform for Performer { impl Perform for Performer {
fn print(&mut self, c: char) { fn print(&mut self, c: char) {
@@ -54,25 +56,35 @@ impl Perform for Performer {
} }
fn main() { fn main() {
// TODO get rid of hard coded `sh` path // 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); 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 stdin = io::stdin();
let mut handle = input.lock(); let mut nb_stdin = NonBlockingReader::from_fd(stdin).unwrap();
let mut statemachine = Parser::new(); let mut statemachine = Parser::new();
let mut performer = Performer; let mut performer = Performer;
let mut buf = [0u8; 2048]; let mut buf = [0u8; 2048];
let mut vec: Vec<u8> = vec!();
while true { loop {
match read(&pty, &mut buf) { 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) => { 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 // 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 {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)});
} }
ForkptyResult::Child =>{ ForkptyResult::Child =>{
Command::new(shell).spawn(); let _ = execv::<CString>(&CString::new(shell).unwrap(), &[]);
// TODO come up with an elegant solution
thread::sleep(Duration::MAX);
return None; return None;
} }
}, },