Rearchitect CommandTree

- CommandTree::Term is now terminal only with respect to searching for
the debug-handling function to execute, it can have children that only
the tab-completion code cares about

- CommandTree::NonTerminal never has a function associated with it, if the
processing of a list of repl debug commands gets to a NonTerminal leaf,
there's just nothing to do
This commit is contained in:
greg 2019-03-26 19:43:11 -07:00
parent 8e9b410e02
commit 004b056232
2 changed files with 17 additions and 19 deletions

View File

@ -6,25 +6,25 @@ pub type BoxedCommandFunction = Box<(fn(&mut Repl, &[&str]) -> Option<String>)>;
pub enum CommandTree { pub enum CommandTree {
Terminal { Terminal {
name: String, name: String,
children: Vec<CommandTree>,
help_msg: Option<String>, help_msg: Option<String>,
function: Option<BoxedCommandFunction>, function: BoxedCommandFunction,
}, },
NonTerminal { NonTerminal {
name: String, name: String,
children: Vec<CommandTree>, children: Vec<CommandTree>,
help_msg: Option<String>, help_msg: Option<String>,
function: Option<BoxedCommandFunction>,
}, },
Top(Vec<CommandTree>), Top(Vec<CommandTree>),
} }
impl CommandTree { impl CommandTree {
pub fn term(s: &str, help: Option<&str>) -> CommandTree { pub fn nonterm_no_further_tab_completions(s: &str, help: Option<&str>) -> CommandTree {
CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function: None } CommandTree::NonTerminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), children: vec![] }
} }
pub fn term_with_function(s: &str, help: Option<&str>, func: BoxedCommandFunction) -> CommandTree { pub fn term_with_function(s: &str, help: Option<&str>, function: BoxedCommandFunction) -> CommandTree {
CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function: Some(func) } CommandTree::Terminal {name: s.to_string(), help_msg: help.map(|x| x.to_string()), function, children: vec![] }
} }
pub fn nonterm(s: &str, help: Option<&str>, children: Vec<CommandTree>) -> CommandTree { pub fn nonterm(s: &str, help: Option<&str>, children: Vec<CommandTree>) -> CommandTree {
@ -32,10 +32,10 @@ impl CommandTree {
name: s.to_string(), name: s.to_string(),
help_msg: help.map(|x| x.to_string()), help_msg: help.map(|x| x.to_string()),
children, children,
function: None,
} }
} }
/*
pub fn nonterm_with_function(s: &str, help: Option<&str>, children: Vec<CommandTree>, func: BoxedCommandFunction) -> CommandTree { pub fn nonterm_with_function(s: &str, help: Option<&str>, children: Vec<CommandTree>, func: BoxedCommandFunction) -> CommandTree {
CommandTree::NonTerminal { CommandTree::NonTerminal {
name: s.to_string(), name: s.to_string(),
@ -44,6 +44,7 @@ impl CommandTree {
function: Some(func), function: Some(func),
} }
} }
*/
pub fn get_cmd(&self) -> &str { pub fn get_cmd(&self) -> &str {
match self { match self {

View File

@ -112,11 +112,8 @@ impl Repl {
}; };
}, },
CommandTree::Terminal { name, function, .. } => { CommandTree::Terminal { name, function, .. } => {
break match function.as_ref() { break Ok((function, idx));
Some(f) => Ok((f, idx)), },
None => Err(format!("No action specified for: {:?}", commands)),
};
}
} }
} }
} }
@ -200,7 +197,7 @@ impl Repl {
}; };
let passes_directives: Vec<CommandTree> = pass_names.iter() let passes_directives: Vec<CommandTree> = pass_names.iter()
.map(|pass_name| { CommandTree::term(pass_name, None) }) .map(|pass_name| { CommandTree::nonterm_no_further_tab_completions(pass_name, None) })
.collect(); .collect();
CommandTree::Top(vec![ CommandTree::Top(vec![
@ -237,20 +234,20 @@ impl Repl {
CommandTree::nonterm("show", None, passes_directives.clone()), CommandTree::nonterm("show", None, passes_directives.clone()),
CommandTree::nonterm("hide", None, passes_directives.clone()), CommandTree::nonterm("hide", None, passes_directives.clone()),
CommandTree::nonterm("timing", None, vec![ CommandTree::nonterm("timing", None, vec![
CommandTree::term("on", None), CommandTree::nonterm_no_further_tab_completions("on", None),
CommandTree::term("off", None), CommandTree::nonterm_no_further_tab_completions("off", None),
]) ])
] ]
), ),
CommandTree::nonterm("lang", CommandTree::nonterm("lang",
Some("switch between languages, or go directly to a langauge by name"), Some("switch between languages, or go directly to a langauge by name"),
vec![ vec![
CommandTree::term("next", None), CommandTree::nonterm_no_further_tab_completions("next", None),
CommandTree::term("prev", None), CommandTree::nonterm_no_further_tab_completions("prev", None),
CommandTree::nonterm("go", None, vec![]), CommandTree::nonterm("go", None, vec![]),
] ]
), ),
CommandTree::term("doc", Some("Get language-specific help for an item")), CommandTree::nonterm_no_further_tab_completions("doc", Some("Get language-specific help for an item")),
]) ])
} }
} }
@ -339,7 +336,7 @@ impl<T: Terminal> Completer<T> for TabCompleteHandler {
let new_ptr: Option<&CommandTree> = command_tree.and_then(|cm| match cm { let new_ptr: Option<&CommandTree> = command_tree.and_then(|cm| match cm {
CommandTree::Top(children) => children.iter().find(|c| c.get_cmd() == s), CommandTree::Top(children) => children.iter().find(|c| c.get_cmd() == s),
CommandTree::NonTerminal { children, .. } => children.iter().find(|c| c.get_cmd() == s), CommandTree::NonTerminal { children, .. } => children.iter().find(|c| c.get_cmd() == s),
CommandTree::Terminal { .. } => None, CommandTree::Terminal { children, .. } => children.iter().find(|c| c.get_cmd() == s),
}); });
command_tree = new_ptr; command_tree = new_ptr;
} }