use crate::line_reader::LineReader;
use crate::scope::Scope;
use crate::Line;
use crate::{line_writer::LineWriter, result::Action, CommandResult};
use std::fmt::Debug;
#[derive(Debug)]
pub struct Runner<R: LineReader, W: LineWriter> {
reader: R,
writer: W,
}
impl<R: LineReader, W: LineWriter> Runner<R, W> {
pub fn new(reader: R, writer: W) -> Self {
Runner { reader, writer }
}
pub fn run<S: Scope>(&mut self, scope: &mut S) -> CommandResult {
let mut result = self.run_scope(scope);
while let Ok(Action::NewScope(mut sub_scope)) = result {
result = self.run_scope(sub_scope.as_mut());
}
result
}
fn run_scope(&mut self, scope: &mut dyn Scope) -> CommandResult {
scope.before_loop();
let mut last_result = Ok(Action::Done);
let commands = scope.commands();
while let Ok(Action::Done) = last_result {
last_result = match self.reader.read_line(scope.prompt().as_ref()) {
Err(error) => Err(error),
Ok(line_string) => {
let line = Line::try_parse(line_string.as_ref());
match line {
Err(error) => Err(error),
Ok(line) => {
let line = scope.before_command(line);
let result = match commands.command_for_line(&line) {
Some(command) => {
scope.run_command(&command, &line.args, &mut self.writer)
}
None => scope.default(&line),
};
let result = if let Ok(Action::SubScope(mut sub_scope)) = result {
self.run_scope(sub_scope.as_mut())
} else {
result
};
scope.after_command(&line, result)
}
}
}
};
if let Err(error) = last_result {
last_result = scope.handle_error_internal(error)
}
}
scope.after_loop();
match last_result {
Ok(Action::Exit) => Ok(Action::Done),
_ => last_result,
}
}
}