diff --git a/schala-repl/src/repl/command_tree.rs b/schala-repl/src/repl/command_tree.rs index 2a13d39..99aa0b6 100644 --- a/schala-repl/src/repl/command_tree.rs +++ b/schala-repl/src/repl/command_tree.rs @@ -1,5 +1,7 @@ use super::Repl; +use colored::*; + pub type BoxedCommandFunction = Box<(fn(&mut Repl, &[&str]) -> Option)>; /// A CommandTree is either a `Terminal` or a `NonTerminal`. When command parsing reaches the first @@ -32,6 +34,12 @@ pub enum ReplAction { QuitProgram } +impl ReplAction { + fn get_function(&self) -> impl Fn(&mut Repl, &[&str]) -> Option { + |_: &mut Repl, _: &[&str]| { None } + } +} + impl CommandTree { pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> CommandTree { CommandTree::NonTerminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children: vec![], action: ReplAction::Null } @@ -41,6 +49,10 @@ impl CommandTree { CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function, children, action: ReplAction::Null } } + pub fn terminal_act(s: &str, help: Option<&str>, children: Vec, action: ReplAction) -> CommandTree { + CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function: Box::new(|_,_| { None }), children, action} + } + pub fn nonterm(s: &str, help: Option<&str>, children: Vec) -> CommandTree { CommandTree::NonTerminal { name: s.to_string(), @@ -50,17 +62,6 @@ impl CommandTree { } } - /* - pub fn nonterm_with_function(s: &str, help: Option<&str>, children: Vec, func: BoxedCommandFunction) -> CommandTree { - CommandTree::NonTerminal { - name: s.to_string(), - help_msg: help.map(|x| x.to_string()), - children, - function: Some(func), - } - } - */ - pub fn get_cmd(&self) -> &str { match self { CommandTree::Terminal { name, .. } => name.as_str(), @@ -83,4 +84,38 @@ impl CommandTree { Top(children) => children.iter().map(|x| x.get_cmd()).collect() } } + + pub fn execute(&self, repl: &mut Repl, arguments: &Vec<&str>) -> Option { + let mut dir_pointer: &CommandTree = self; + let mut idx = 0; + + let res: Result<(ReplAction, usize), String> = loop { + match dir_pointer { + CommandTree::Top(subcommands) | CommandTree::NonTerminal { children: subcommands, .. } => { + let next_command = match arguments.get(idx) { + Some(cmd) => cmd, + None => break Err(format!("Command requires arguments")) + }; + idx += 1; + match subcommands.iter().find(|sc| sc.get_cmd() == *next_command) { + Some(command_tree) => { + dir_pointer = command_tree; + }, + None => break Err(format!("Command {} not found", next_command)) + }; + }, + CommandTree::Terminal { action, .. } => { + break Ok((action.clone(), idx)); + }, + } + }; + + match res { + Ok((action, idx)) => { + let f = action.get_function(); + f(repl, &arguments[idx..]) + }, + Err(err) => Some(err.red().to_string()) + } + } } diff --git a/schala-repl/src/repl/mod.rs b/schala-repl/src/repl/mod.rs index f3a1bc8..08c13a0 100644 --- a/schala-repl/src/repl/mod.rs +++ b/schala-repl/src/repl/mod.rs @@ -130,21 +130,25 @@ impl Repl { fn handle_interpreter_directive(&mut self, input: &str) -> Option { let mut iter = input.chars(); iter.next(); - let commands: Vec<&str> = iter + let arguments: Vec<&str> = iter .as_str() .split_whitespace() .collect(); - if commands.len() < 1 { + if arguments.len() < 1 { return None; } let directives = self.get_directives(); + directives.execute(self, &arguments) + + /* let result: Result<(&BoxedCommandFunction, _), String> = Repl::get_function_from_directives(&directives, &commands); match result { Ok((f, idx)) => f(self, &commands[idx..]), Err(err) => Some(err.red().to_string()) } + */ } fn print_help_message(&mut self, commands_passed_to_help: &[&str] ) -> String {