bnb-shell 0.1.0

A fast, polished, cross-platform terminal shell built in Rust with Powerlevel10k aesthetics.
pub mod ast;
pub mod lexer;

use ast::{Command, Pipeline, Redirection};
use lexer::{tokenize, Token};

pub fn parse(input: &str) -> Result<Pipeline, String> {
    let tokens = tokenize(input);
    if tokens.is_empty() {
        return Err("Empty command".into());
    }

    let mut commands = Vec::new();
    let mut current_args = Vec::new();
    let mut current_redirs = Vec::new();
    let mut background = false;

    let mut iter = tokens.into_iter().peekable();

    while let Some(token) = iter.next() {
        match token {
            Token::Pipe => {
                if current_args.is_empty() {
                    return Err("bnb: syntax error near unexpected token '|'".into());
                }
                commands.push(Command {
                    args: current_args,
                    redirections: current_redirs,
                });
                current_args = Vec::new();
                current_redirs = Vec::new();
            }
            Token::RedirectOut => {
                if let Some(Token::Word(filename)) = iter.next() {
                    current_redirs.push(Redirection::OutputTruncate(filename));
                } else {
                    return Err("bnb: syntax error near unexpected token '>'".into());
                }
            }
            Token::RedirectAppend => {
                if let Some(Token::Word(filename)) = iter.next() {
                    current_redirs.push(Redirection::OutputAppend(filename));
                } else {
                    return Err("bnb: syntax error near unexpected token '>>'".into());
                }
            }
            Token::RedirectIn => {
                if let Some(Token::Word(filename)) = iter.next() {
                    current_redirs.push(Redirection::Input(filename));
                } else {
                    return Err("bnb: syntax error near unexpected token '<'".into());
                }
            }
            Token::Background => {
                background = true;
            }
            Token::Word(word) => {
                current_args.push(word);
            }
        }
    }

    if !current_args.is_empty() {
        commands.push(Command {
            args: current_args,
            redirections: current_redirs,
        });
    } else if !commands.is_empty() {
        return Err("bnb: syntax error near unexpected token '|'".into());
    }

    Ok(Pipeline {
        commands,
        run_in_background: background,
    })
}