diff options
| author | Jonas Maier <> | 2026-03-05 07:26:59 +0100 |
|---|---|---|
| committer | Jonas Maier <> | 2026-03-05 07:26:59 +0100 |
| commit | 4b83b63ddb81817ea7cc418f1b61f687ba813085 (patch) | |
| tree | 02dfad0d4235d44545a930a1bd2304b2c6d36031 | |
| parent | d4050c3a8cfabd4ae77d001d665573729d28a096 (diff) | |
| download | pish-4b83b63ddb81817ea7cc418f1b61f687ba813085.tar.gz | |
begin of a parser
| -rw-r--r-- | src/main.rs | 42 | ||||
| -rw-r--r-- | src/parse.rs | 84 | ||||
| -rw-r--r-- | src/raw.rs | 30 |
3 files changed, 128 insertions, 28 deletions
diff --git a/src/main.rs b/src/main.rs index 3017995..2836b2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,35 +4,10 @@ use std::process::Command; use std::ffi::OsStr; use std::os::unix::ffi::OsStrExt; use std::path::Path; -use termios::*; -struct ScopedRawMode { - fd: i32, - settings: Termios, -} - -impl Drop for ScopedRawMode { - fn drop(&mut self) { - self.disable(); - } -} - -impl ScopedRawMode { - fn on_fd(fd: i32) -> Self { - 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(); - } -} +mod raw; +mod parse; +use raw::*; macro_rules! print { ($($x:tt)*) => {{ @@ -41,6 +16,17 @@ macro_rules! print { }} } +macro_rules! println { + () => {{ + println!("") + }}; + ($($x:tt)*) => {{ + write!(io::stdout(), $($x)*).unwrap(); + write!(io::stdout(), "\r\n").unwrap(); + io::stdout().flush().unwrap(); + }}; +} + struct LineBuffer { pre: Vec<u8>, post: Vec<u8>, diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..cc495b1 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,84 @@ +pub enum Ast { + AssignVar(AssignVar), + Pipes(Pipes), +} + +pub struct AssignVar { + pub to: String, + // TODO: body +} + +pub struct Pipes { + pub cmds: Vec<Command>, +} + +pub struct Command { + pub path: String, + pub args: Vec<String>, +} + +enum ParseError { + Incomplete, + UnexpectedPipe, + UnknownChar(char), +} + +type Result<T> = std::result::Result<T, ParseError>; + +pub fn parse(x: &str) -> Result<Ast> { + let chars: Vec<char> = x.chars().collect(); + Ast::parse(&mut &chars[..]) +} + +trait Parse: Sized { + fn parse(b: &mut &[char]) -> Result<Self>; +} + +fn spaces(b: &mut &[char]) { + while let Some(' ' | '\t') = b.get(0) { + *b = &b[1..]; + } +} + +fn parse_quoted_string(b: &mut &[char], delim: char) -> Result<String> { + // TODO: escape sequence stuff + + *b = &b[1..]; + let mut s = String::new(); + while b.len() > 0 { + if b[0] == delim { + *b = &b[1..]; + return Ok(s); + } + + s.push(b[0]); + *b = &b[1..]; + } + Err(ParseError::Incomplete) +} + +impl Parse for String { + fn parse(b: &mut &[char]) -> Result<Self> { + spaces(b); + if b.is_empty() { + return Err(ParseError::Incomplete); + } + let c = b[0]; + if c == '|' { + Err(ParseError::UnexpectedPipe) + } else if c == '\'' || c == '"' { + *b = &b[1..]; + parse_quoted_string(b, c) + } else if c.is_ascii_graphic() { + parse_quoted_string(b, ' ') + } else { + Err(ParseError::UnknownChar(c)) + } + } +} + +impl Parse for Ast { + fn parse(b: &mut &[char]) -> Result<Self> { + todo!() + } +} diff --git a/src/raw.rs b/src/raw.rs new file mode 100644 index 0000000..e116620 --- /dev/null +++ b/src/raw.rs @@ -0,0 +1,30 @@ +use termios::*; + +/// can toggle raw mode on a fd, at the latest disables it when it gets dropped +pub struct ScopedRawMode { + fd: i32, + settings: Termios, +} + +impl Drop for ScopedRawMode { + fn drop(&mut self) { + self.disable(); + } +} + +impl ScopedRawMode { + pub fn on_fd(fd: i32) -> Self { + let settings = Termios::from_fd(fd).unwrap(); + Self { fd, settings } + } + + pub fn enable(&self) { + let mut settings = self.settings.clone(); + cfmakeraw(&mut settings); + tcsetattr(self.fd, TCSANOW, &settings).unwrap(); + } + + pub fn disable(&self) { + tcsetattr(self.fd, TCSANOW, &self.settings).unwrap(); + } +} |
