use super::*;
use std::collections::hash_map::{self, HashMap};
use std::io;
use std::process::exit;
#[derive(Debug)]
pub struct Config<'a, T> {
name: String,
version: Option<String>,
author: Option<String>,
about: Option<String>,
args: Vec<Arg<'a, T>>,
short_map: HashMap<char, usize>,
long_map: HashMap<String, usize>,
positional: Option<Arg<'a, T>>,
}
impl<'a, T> Config<'a, T> {
pub fn new<S: Into<String>>(name: S) -> Self {
Config {
name: name.into(),
version: None,
author: None,
about: None,
args: Vec::new(),
short_map: HashMap::new(),
long_map: HashMap::new(),
positional: None,
}
}
pub fn name<S: Into<String>>(mut self, name: S) -> Self {
self.name = name.into();
self
}
pub fn version<S: Into<String>>(mut self, version: S) -> Self {
self.version = Some(version.into());
self
}
pub fn author<S: Into<String>>(mut self, author: S) -> Self {
self.author = Some(author.into());
self
}
pub fn about<S: Into<String>>(mut self, about: S) -> Self {
self.about = Some(about.into());
self
}
pub fn arg_safe(&mut self, arg: Arg<'a, T>) -> Result<()> {
use self::hash_map::Entry::*;
if arg.is_positional() {
if self.positional.is_none () {
self.positional = Some(arg);
return Ok(());
} else {
return Err(Error::from_string("multiple positional arguments"))
}
}
let index = self.args.len();
if let Some(c) = arg.get_short() {
match self.short_map.entry(c) {
Vacant(entry) => {
entry.insert(index);
}
Occupied(_) => {
return Err(Error::from_string("repeated in config")
.with_option(format!("-{}", c)));
}
}
}
if let Some(s) = arg.get_long() {
match self.long_map.entry(s.to_owned()) {
Vacant(entry) => {
entry.insert(index);
}
Occupied(_) => {
return Err(Error::from_string("repeated in config")
.with_option(format!("--{}", s)));
}
}
}
self.args.push(arg);
Ok(())
}
pub fn arg(mut self, arg: Arg<'a, T>) -> Self {
self.arg_safe(arg).expect("foropts::Arg::arg: repeated arg");
self
}
pub fn args<I: IntoIterator<Item=Arg<'a, T>>>(mut self, args: I) -> Self {
for arg in args {
self.arg_safe(arg).expect("foropts::Arg::args: repeated arg");
}
self
}
pub fn iter<'b, I: IntoIterator<Item=String>>(&'b self, args: I) -> Iter<'b, 'a, I, T> {
Iter::new(self, args)
}
pub fn exit_error(&self, error: &Error) -> ! {
eprintln!("Syntax error: {}", error);
self.write_usage(io::stderr()).unwrap();
exit(1);
}
pub fn exit_usage(&self) -> ! {
let stdout = io::stdout();
self.write_usage(stdout.lock()).unwrap();
exit(0);
}
pub fn exit_version(&self) -> ! {
let stdout = io::stdout();
self.write_version(stdout.lock()).unwrap();
exit(0);
}
pub fn write_version<W: io::Write>(&self, mut out: W) -> io::Result<()> {
write!(out, "{}", self.name)?;
if let Some(ref version) = self.version {
write!(out, " {}", *version)?;
}
writeln!(out)
}
fn write_usage_line<W: io::Write>(&self, mut out: W) -> io::Result<()> {
write!(out, "Usage: {} OPTION...", self.name)?;
if let Some(ref arg) = self.positional {
writeln!(out, " [--] {}...", arg.positional_name())
} else {
writeln!(out)
}
}
pub fn write_usage<W: io::Write>(&self, mut out: W) -> io::Result<()> {
self.write_version(&mut out)?;
if let Some(ref author) = self.author {
writeln!(out, "{}", *author)?;
}
if let Some(ref about) = self.about {
writeln!(out, "{}", *about)?;
}
writeln!(out)?;
self.write_usage_line(&mut out)?;
writeln!(out, "\nOPTIONS:")?;
for arg in &self.args {
arg.write_option_usage(&mut out)?;
}
Ok(())
}
pub (crate) fn get_positional(&self) -> Option<&Arg<'a, T>> {
self.positional.as_ref()
}
pub (crate) fn get_short(&self, c: char) -> Option<&Arg<'a, T>> {
self.short_map.get(&c).map(|i| &self.args[*i])
}
pub (crate) fn get_long(&self, s: &str) -> Option<&Arg<'a, T>> {
self.long_map.get(s).map(|i| &self.args[*i])
}
}