use Env;
use rustyline::completion::{Completer, Pair};
use rustyline::highlight::Highlighter;
use rustyline::hint::Hinter;
use rustyline::{Context, Helper, Result};
use cmd::Cmd;
pub struct ClickHelper<'a> {
commands: &'a Vec<Box<Cmd>>,
env: &'a ::Env,
}
impl<'a> Helper for ClickHelper<'a> {}
impl<'a> Highlighter for ClickHelper<'a> {}
impl<'a> Hinter for ClickHelper<'a> {
fn hint(&self, _line: &str, _pos: usize, _context: &Context) -> Option<String> {
None
}
}
impl<'a> ClickHelper<'a> {
pub fn new(commands: &'a Vec<Box<Cmd>>, env: *const ::Env) -> ClickHelper<'a> {
ClickHelper {
commands: commands,
env: unsafe { &*env },
}
}
}
impl<'a> ClickHelper<'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
}
}
pub fn long_matches(long: &Option<&str>, prefix: &str) -> bool {
match long {
Some(lstr) => lstr.starts_with(prefix),
None => false
}
}
impl<'a> Completer for ClickHelper<'a> {
type Candidate = Pair;
fn complete(&self, line: &str, pos: usize, _ctx: &Context) -> Result<(usize, Vec<Pair>)> {
let mut v = Vec::new();
if pos == 0 {
for cmd in self.commands.iter() {
v.push(Pair {
display: cmd.get_name().to_owned(),
replacement: cmd.get_name().to_owned(),
});
}
Ok((0, v))
} else {
let mut split = line.split_whitespace();
if let Some(linecmd) = split.next() {
if let Some(cmd) = self.get_exact_command(linecmd) {
let (pos, prefix) = match split.next_back() {
Some(back) => {
if line.ends_with(" ") {
let mut count = split.filter(|s| !s.starts_with("-")).count();
if !back.starts_with("-") {
count += 1;
}
(count, "")
} else if back == "-" {
return Ok((line.len(), vec![Pair {
display: "-".to_owned(),
replacement: "-".to_owned(),
}]));
} else if back.starts_with("--") {
let mut opts = cmd.complete_option(&back[2..]);
if "--help".starts_with(back) {
opts.push(Pair {
display: "--help".to_owned(),
replacement: "help"[(back.len()-2)..].to_owned(),
});
}
return Ok((line.len(), opts));
}
else {
(split.filter(|s| !s.starts_with("-")).count(),
back)
}
}
None => {
(0, "")
}
};
let opts = cmd.try_complete(pos, prefix, self.env);
return Ok((line.len(), opts));
} else {
for cmd in self.commands.iter() {
if cmd.get_name().starts_with(linecmd) {
v.push(Pair{
display: cmd.get_name().to_owned(),
replacement: cmd.get_name().to_owned(),
});
}
}
}
}
Ok((0, v))
}
}
}
pub fn context_complete(prefix: &str, env: &Env) -> Vec<Pair> {
let mut v = Vec::new();
for context in env.config.contexts.keys() {
if context.starts_with(prefix) {
v.push(Pair {
display: context.to_string(),
replacement: context[prefix.len()..].to_string(),
})
}
}
v
}
pub fn namespace_completer(prefix: &str, env: &Env) -> Vec<Pair> {
match env.run_on_kluster(|k| k.namespaces_for_context()) {
Some(v) => v.iter()
.filter(|ns| ns.starts_with(prefix))
.map(|ns| Pair {
display: ns.clone(),
replacement: ns[prefix.len()..].to_string(),
}).collect(),
None => vec![]
}
}
pub fn container_completer(prefix: &str, env: &Env) -> Vec<Pair> {
let mut v = vec![];
match env.current_object {
::KObj::Pod {
name: _,
ref containers,
} => for cont in containers.iter() {
if cont.starts_with(prefix) {
v.push(Pair {
display: cont.clone(),
replacement: cont[prefix.len()..].to_string(),
});
}
},
_ => {}
}
v
}
macro_rules! possible_values_completer {
($name: ident, $values: expr) => {
pub fn $name(prefix: &str, _env: &Env) -> Vec<Pair> {
let mut v = vec![];
for val in $values.iter() {
if val.starts_with(prefix) {
v.push(Pair {
display: val.to_string(),
replacement: val[prefix.len()..].to_string(),
});
}
}
v
}
}
}
possible_values_completer!(
setoptions_values_completer, ["completion_type", "edit_mode", "editor", "terminal"]
);
possible_values_completer!(portforwardaction_values_completer, ["list", "output", "stop"]);