cmdr/
runner.rs

1use crate::line_reader::LineReader;
2use crate::scope::Scope;
3use crate::Line;
4use crate::{line_writer::LineWriter, result::Action, CommandResult};
5use std::fmt::Debug;
6
7/// Wraps a LineReader and a Scope and allows using the scope to interpret commands from the
8/// LineReader
9#[derive(Debug)]
10pub struct Runner<R: LineReader, W: LineWriter> {
11    reader: R,
12    writer: W,
13}
14
15impl<R: LineReader, W: LineWriter> Runner<R, W> {
16    /// Create a new runner that takes lines from the `reader` and executes them using the `scope`
17    pub fn new(reader: R, writer: W) -> Self {
18        Runner { reader, writer }
19    }
20
21    /// Start reading lines and executing them
22    pub fn run<S: Scope>(&mut self, scope: &mut S) -> CommandResult {
23        let mut result = self.run_scope(scope);
24
25        while let Ok(Action::NewScope(mut sub_scope)) = result {
26            result = self.run_scope(sub_scope.as_mut());
27        }
28
29        result
30    }
31
32    /// Execute commands in this scope. Uses a LineReader to get commands and executes them one by
33    /// one until a command returns CommandResult::Quit
34    fn run_scope(&mut self, scope: &mut dyn Scope) -> CommandResult {
35        scope.before_loop();
36
37        let mut last_result = Ok(Action::Done);
38        let commands = scope.commands();
39
40        while let Ok(Action::Done) = last_result {
41            last_result = match self.reader.read_line(scope.prompt().as_ref()) {
42                Err(error) => Err(error),
43                Ok(line_string) => {
44                    let line = Line::try_parse(line_string.as_ref());
45                    match line {
46                        Err(error) => Err(error),
47                        Ok(line) => {
48                            let line = scope.before_command(line);
49
50                            let result = match commands.command_for_line(&line) {
51                                Some(command) => {
52                                    scope.run_command(&command, &line.args, &mut self.writer)
53                                }
54                                None => scope.default(&line),
55                            };
56
57                            let result = if let Ok(Action::SubScope(mut sub_scope)) = result {
58                                self.run_scope(sub_scope.as_mut())
59                            } else {
60                                result
61                            };
62
63                            scope.after_command(&line, result)
64                        }
65                    }
66                }
67            };
68
69            if let Err(error) = last_result {
70                last_result = scope.handle_error_internal(error)
71            }
72        }
73
74        scope.after_loop();
75
76        match last_result {
77            Ok(Action::Exit) => Ok(Action::Done),
78            _ => last_result,
79        }
80    }
81}