aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Maier <>2026-03-04 17:46:36 +0100
committerJonas Maier <>2026-03-04 17:46:36 +0100
commit7c46116456ebddba482d9f5c25d0e5d9c38e5c37 (patch)
tree3064239328e81c6f405b598ccd5bd42fcd7e1e71
parent3c880475148d770ed39918fb0344faaed43299d0 (diff)
downloadpish-7c46116456ebddba482d9f5c25d0e5d9c38e5c37.tar.gz
lets you run commands
-rw-r--r--src/main.rs58
1 files changed, 48 insertions, 10 deletions
diff --git a/src/main.rs b/src/main.rs
index bb74b2d..8747d85 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,8 @@
use std::io::{self, Read, Write, IsTerminal};
use std::os::unix::io::AsRawFd;
+use std::process::Command;
+use std::ffi::OsStr;
+use std::os::unix::ffi::OsStrExt;
use termios::*;
struct ScopedRawMode {
@@ -15,13 +18,16 @@ impl Drop for ScopedRawMode {
impl ScopedRawMode {
fn on_fd(fd: i32) -> Self {
- let mut termios = Termios::from_fd(fd).unwrap();
- let settings = termios.clone();
- cfmakeraw(&mut termios);
- tcsetattr(fd, TCSANOW, &termios).unwrap();
+ let settings = Termios::from_fd(fd).unwrap();
Self { fd, settings }
}
+ fn enable(&self) {
+ let mut settings = self.settings.clone();
+ cfmakeraw(&mut settings);
+ tcsetattr(self.fd, TCSANOW, &settings).unwrap();
+ }
+
fn disable(&self) {
tcsetattr(self.fd, TCSANOW, &self.settings).unwrap();
}
@@ -113,6 +119,13 @@ pub fn move_cursor(direction: Direction, n: usize) {
print!("\x1b[{n}{code}");
}
+/// Represents a cursor position
+#[derive(Debug, Clone, Copy)]
+pub struct CursorPos {
+ pub row: usize,
+ pub col: usize,
+}
+
fn main() {
let stdin = io::stdin();
let stdout = io::stdout();
@@ -123,14 +136,17 @@ fn main() {
}
let fd = stdin.as_raw_fd();
- let _scoped_raw = ScopedRawMode::on_fd(fd); // needs to be a var, gets dropped on scope exit,
- // even if something panics
+ let raw = ScopedRawMode::on_fd(fd);
+ raw.enable();
let mut stdin = stdin.lock();
let mut stdout = stdout.lock();
let mut buffer = [0u8; 1];
let mut line = LineBuffer::new();
+ let prompt = "> ";
+
+ print!("{prompt}");
loop {
let Ok(_) = stdin.read_exact(&mut buffer) else {
@@ -146,14 +162,36 @@ fn main() {
// Enter
b'\r' => {
print!("\r\n");
- stdout.write_all(&line.dump()).unwrap();
- print!("\r\n");
+ let line = line.dump();
+ let words: Vec<&[u8]> = line.split(|x| *x == b' ').collect();
+ if words.is_empty() {
+ print!("{prompt}");
+ continue;
+ }
+
+ let mut cmd = Command::new(OsStr::from_bytes(words[0]));
+ for arg in words[1..].iter() {
+ cmd.arg(OsStr::from_bytes(arg));
+ }
+
+ raw.disable();
+ let status = cmd.status();
+ raw.enable();
+
+ let status_string = match status {
+ Ok(ec) if ec.success() => String::new(),
+ Ok(ec) => format!("{ec} "),
+ Err(_) => String::from("IO ERROR "),
+ };
+ //ensure_newline();
+ print!("{status_string}{prompt}");
}
// Backspace (127 on most systems)
127 => {
- line.del_left();
- print!("\x08 \x08");
+ if line.del_left().is_some() {
+ print!("\x08 \x08");
+ }
}
// Escape sequence