use prelude::v1::*;
use property::*;
use terminal::*;
use autocomplete::*;
use cli_property::*;
use cli_command::*;
use super::i18n::Strings;
pub trait CliContext<'a> {
fn with_prefix<'b>(&'b mut self, prefix: &str) -> Option<PrefixedExecutor<'a, 'b>>;
fn command<'b>(&'b mut self, cmd: &str) -> Option<CommandContext<'b>>;
fn property<'b, V, P, Id: Into<Cow<'b, str>>>(&'b mut self, property_id: Id, input_parser: P) -> Option<PropertyContext<'b, V>> where P: ValueInput<V>, V: Display;
}
pub struct CliExecutor<'a> {
matcher: CliLineMatcher<'a>,
strings: &'a Strings,
terminal: &'a mut CharacterTerminalWriter
}
impl<'a> CliContext<'a> for CliExecutor<'a> {
fn with_prefix<'b>(&'b mut self, prefix: &str) -> Option<PrefixedExecutor<'a, 'b>> {
if self.matcher.starts_with(&prefix) {
let p = PrefixedExecutor {
prefix: prefix.to_string().into(),
executor: self
};
return Some(p);
} else {
self.matcher.add_unmatched_prefix(&prefix);
}
None
}
fn command<'b>(&'b mut self, cmd: &str) -> Option<CommandContext<'b>> {
if self.matcher.match_cmd_str(cmd, None) == LineMatcherProgress::MatchFound {
let args = if let &LineBufferResult::Match { ref args, .. } = self.matcher.get_state() {
Some(args.clone())
} else {
None
};
if let Some(args) = args {
let ctx = CommandContext {
args: args.into(),
terminal: self.terminal,
current_path: ""
};
return Some(ctx);
}
}
None
}
fn property<'b, V, P, Id: Into<Cow<'b, str>>>(&'b mut self, property_id: Id, input_parser: P) -> Option<PropertyContext<'b, V>> where P: ValueInput<V>, V: Display {
let property_id: Cow<str> = property_id.into();
if self.matcher.match_cmd_str(&format!("{}/get", property_id), None) == LineMatcherProgress::MatchFound {
let args = if let &LineBufferResult::Match { ref args, .. } = self.matcher.get_state() {
args.clone()
} else {
"".into()
};
return Some(PropertyContext::Get(PropertyContextGet {
common: PropertyContextCommon {
args: args.into(),
terminal: self.terminal,
current_path: "",
id: property_id,
style: PropertyCommandStyle::DelimitedGetSet,
strings: &*self.strings
}
}));
}
if self.matcher.match_cmd_str(&format!("{}/set", property_id), None) == LineMatcherProgress::MatchFound {
let args = if let &LineBufferResult::Match { ref args, .. } = self.matcher.get_state() {
args.trim()
} else {
"".into()
};
match input_parser.input(&args) {
Ok(val) => {
return Some(PropertyContext::Set(PropertyContextSet {
common: PropertyContextCommon {
args: args.into(),
terminal: self.terminal,
current_path: "",
id: property_id,
style: PropertyCommandStyle::DelimitedGetSet,
strings: &*self.strings
},
value: val
}));
},
Err(e) => {
match e {
PropertyValidationError::InvalidInput => {
self.strings.property_invalid_value(self.terminal, &property_id, &args);
},
PropertyValidationError::ValueTooSmall { min, val } => {
self.strings.property_value_too_small(self.terminal, &property_id, &val, &min);
},
PropertyValidationError::ValueTooBig { max, val } => {
self.strings.property_value_too_big(self.terminal, &property_id, &val, &max);
}
}
self.terminal.newline();
}
}
}
None
}
}
impl<'a> CliExecutor<'a> {
pub fn new<T: CharacterTerminalWriter>(matcher: CliLineMatcher<'a>, strings: &'a Strings, terminal: &'a mut T) -> Self {
CliExecutor {
matcher: matcher,
strings: strings,
terminal: terminal
}
}
pub fn close(self) -> CliLineMatcher<'a> {
self.matcher
}
pub fn get_terminal(&mut self) -> &mut CharacterTerminalWriter {
self.terminal
}
}
impl<'a> Deref for CliExecutor<'a> {
type Target = &'a mut CharacterTerminalWriter;
fn deref<'b>(&'b self) -> &'b &'a mut CharacterTerminalWriter {
&self.terminal
}
}
pub struct PrefixedExecutor<'a: 'p, 'p> {
prefix: Cow<'p, str>,
executor: &'p mut CliExecutor<'a>
}
impl<'a, 'p> PrefixedExecutor<'a, 'p> {
fn add_prefix(&self, cmd: &str) -> String {
format!("{}{}", self.prefix, cmd)
}
}
impl<'a, 'p> CliContext<'a> for PrefixedExecutor<'a, 'p> {
fn with_prefix<'b>(&'b mut self, prefix: &str) -> Option<PrefixedExecutor<'a, 'b>> {
let prefix = self.add_prefix(prefix);
self.executor.with_prefix(&prefix)
}
fn command<'b>(&'b mut self, cmd: &str) -> Option<CommandContext<'b>> {
let cmd = self.add_prefix(cmd);
self.executor.command(&cmd)
}
fn property<'b, V, P, Id: Into<Cow<'b, str>>>(&'b mut self, property_id: Id, input_parser: P) -> Option<PropertyContext<'b, V>> where P: ValueInput<V>, V: Display {
let property_id: Cow<str> = property_id.into();
let property_id = self.add_prefix(&property_id);
self.executor.property(property_id, input_parser)
}
}