use rustyline::completion::Completer;
use rustyline::Result;
use cmd::Cmd;
pub struct ClickCompleter<'a> {
commands: &'a Vec<Box<Cmd>>,
env: &'a ::Env,
}
impl<'a> ClickCompleter<'a> {
pub fn new(commands: &'a Vec<Box<Cmd>>, env: *const ::Env) -> ClickCompleter<'a> {
ClickCompleter {
commands: commands,
env: unsafe { &*env },
}
}
}
impl<'a> ClickCompleter<'a> {
fn get_exact_command(&self, line: &str) -> Option<&Box<Cmd>> {
for cmd in self.commands.iter() {
if cmd.is(line) {
return Some(cmd);
}
}
None
}
}
impl<'a> Completer for ClickCompleter<'a> {
fn complete(&self, line: &str, pos: usize) -> Result<(usize, Vec<String>)> {
let mut v = Vec::new();
if pos == 0 {
for cmd in self.commands.iter() {
v.push(cmd.get_name().to_owned());
}
Ok((0, v))
} else {
let mut split = line.split_whitespace();
if let Some(linecmd) = split.next() {
let rest: Vec<&str> = split.filter(|s| !s.starts_with("-")).collect();
if let Some(cmd) = self.get_exact_command(linecmd) {
let (offset, opts) = cmd.try_complete(rest, self.env);
if pos == linecmd.len() && opts.len() > 1 {
let space_opts = opts.iter().map(|o| format!(" {}", o)).collect();
return Ok((line.len(), space_opts));
} else {
return Ok((line.len() - offset, opts));
}
} else {
for cmd in self.commands.iter() {
if cmd.get_name().starts_with(linecmd) {
v.push(cmd.get_name().to_owned());
}
}
}
}
Ok((0, v))
}
}
}