aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/main.rs42
-rw-r--r--src/parse.rs84
-rw-r--r--src/raw.rs30
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();
+ }
+}