extern crate commands;
extern crate rustyline;
use commands::parser::{Command, CommandTree, Node, ParseError, Parser};
use commands::tokenizer::tokenize;
use rustyline::{Editor, Result};
use rustyline::completion::Completer;
use std::rc::Rc;
struct CommandCompleter {
root: Rc<Node>,
}
impl CommandCompleter {
fn new(root: Rc<Node>) -> Self {
CommandCompleter { root: root }
}
}
impl Completer for CommandCompleter {
fn complete(&self, line: &str, _pos: usize) -> Result<(usize, Vec<String>)> {
if let Ok(tokens) = tokenize(line) {
let p = Parser::new(self.root.clone());
let cs = p.complete(Some(tokens[0]));
if !cs.is_empty() {
Ok((0,
cs[0]
.options
.iter()
.map(|co| co.option_string.clone())
.collect()))
} else {
Ok((0, Vec::new()))
}
} else {
Ok((0, Vec::new()))
}
}
}
fn main() {
let mut tree = CommandTree::new();
tree.command(Command::new("show"));
let root = tree.finalize();
let c = CommandCompleter::new(root.clone());
let mut rl = Editor::<CommandCompleter>::new();
rl.set_completer(Some(c));
while let Ok(line) = rl.readline(">> ") {
rl.add_history_entry(&line);
if let Ok(tokens) = tokenize(&line) {
let mut parser = Parser::new(root.clone());
if let Err(err) = parser.parse(tokens) {
match err {
ParseError::NoMatches(_, acceptable) => {
println!("No match for '{}'", line);
println!("\nPossible options:");
for ref option in acceptable {
let n = option.node();
println!(" {} - {}", n.help_symbol, n.help_text);
}
}
ParseError::AmbiguousMatch(_, matches) => {
println!("\nCan be interpreted as:");
for ref option in matches {
let n = option.node();
println!(" {} - {}", n.help_symbol, n.help_text);
}
}
}
} else if let Err(err) = parser.verify() {
println!("{}", err);
} else {
parser.execute();
}
}
println!("");
}
println!("\nExiting.");
}