aboutsummaryrefslogtreecommitdiff
path: root/src/parser.rs
blob: 0c771f90cefe8ce3d8face1a748e589216dd9625 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use std::io::Error;
use std::path::PathBuf;
use std::process::ExitStatus;

// ;   on prev cmd any
// &&  on prev cmd okay
// ||  on prev cmd fail

mod command;
use command::{CommandInfo, RunOn, RunResult};

pub struct CommandLine(Vec<CommandInfo>);

impl CommandLine {
    pub fn new(line: &str) -> Self {
        CommandLine(split(line))
    }

    pub fn run(
        &self,
        home: &PathBuf,
        mut status: Option<ExitStatus>,
    ) -> Result<Option<ExitStatus>, Error> {
        for cmd in &self.0 {
            if cmd.when.can_run(&status) {
                match cmd.run(&home, &status)? {
                    RunResult::Command(s) => status = Some(s),
                    RunResult::Builtin => {}
                }
            }
        }
        Ok(status)
    }
}

fn split(line: &str) -> Vec<CommandInfo> {
    let mut r: Vec<CommandInfo> = Vec::new();

    let mut next = line.chars().peekable();
    let mut iter = line.chars().enumerate();

    let mut start_idx = 0;
    let mut state = RunOn::Always;

    while let Some((i, v)) = {
        next.next();
        iter.next()
    } {
        let n = next.peek();

        if v == ';' {
            r.push(CommandInfo::new(&line[start_idx..i], state));
            state = RunOn::Always;
            start_idx = i + 1;
        } else if v == '|' && n == Some(&'|') {
            r.push(CommandInfo::new(&line[start_idx..i], state));
            state = RunOn::ExitFailure;
            start_idx = i + 2;
            next.next();
            iter.next();
        } else if v == '&' && n == Some(&'&') {
            r.push(CommandInfo::new(&line[start_idx..i], state));
            state = RunOn::ExitSuccess;
            start_idx = i + 2;
            next.next();
            iter.next();
        } else if n == None {
            r.push(CommandInfo::new(&line[start_idx..], state));
        }
    }

    r
}