Implement methods for adding command line arguments to the parser.
This commit is contained in:
parent
3d198452c9
commit
db277c7805
112
src/lib.rs
112
src/lib.rs
|
@ -1,6 +1,8 @@
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::env::args_os;
|
use std::env::args_os;
|
||||||
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
|
/// A command line argument parser.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Parser {
|
pub struct Parser {
|
||||||
flags: Vec<Flag>,
|
flags: Vec<Flag>,
|
||||||
|
@ -12,17 +14,107 @@ pub struct Parser {
|
||||||
short_set: HashSet<String>,
|
short_set: HashSet<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Parser {
|
||||||
|
pub fn new() -> Parser {
|
||||||
|
Parser {
|
||||||
|
flags: Vec::new(),
|
||||||
|
args: Vec::new(),
|
||||||
|
pos_args: Vec::new(),
|
||||||
|
long_set: HashSet::new(),
|
||||||
|
short_set: HashSet::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a flag argument.
|
||||||
|
pub fn flag(&mut self, long: &str, short: Option<&str>, doc_string: &str) {
|
||||||
|
self.ensure_not_duplicate(long, short);
|
||||||
|
|
||||||
|
self.flags.push(Flag {
|
||||||
|
long: long.into(),
|
||||||
|
short: short.map(|s| s.into()),
|
||||||
|
doc_string: doc_string.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a standard argument.
|
||||||
|
pub fn argument<R: RangeBounds<usize>>(
|
||||||
|
&mut self,
|
||||||
|
long: &str,
|
||||||
|
short: Option<&str>,
|
||||||
|
doc_string: &str,
|
||||||
|
value_name: &str,
|
||||||
|
acceptable_count: R,
|
||||||
|
) {
|
||||||
|
self.ensure_not_duplicate(long, short);
|
||||||
|
|
||||||
|
use std::ops::Bound;
|
||||||
|
let count_start: Option<usize> = match acceptable_count.start_bound() {
|
||||||
|
Bound::Included(&n) => Some(n),
|
||||||
|
Bound::Excluded(&n) => Some(n + 1),
|
||||||
|
Bound::Unbounded => None,
|
||||||
|
};
|
||||||
|
let count_end: Option<usize> = match acceptable_count.end_bound() {
|
||||||
|
Bound::Included(&n) => Some(n + 1),
|
||||||
|
Bound::Excluded(&n) => Some(n),
|
||||||
|
Bound::Unbounded => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.args.push(Arg {
|
||||||
|
long: long.into(),
|
||||||
|
short: short.map(|s| s.into()),
|
||||||
|
acceptable_count: (count_start, count_end),
|
||||||
|
value_name: value_name.into(),
|
||||||
|
doc_string: doc_string.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add a positional argument.
|
||||||
|
///
|
||||||
|
/// There can only be one positional argument with `count == None`,
|
||||||
|
/// which represents any left over positional arguments after those
|
||||||
|
/// with explicit counts have been parsed.
|
||||||
|
pub fn positional_argument(
|
||||||
|
&mut self,
|
||||||
|
doc_string: &str,
|
||||||
|
value_name: &str,
|
||||||
|
count: Option<usize>,
|
||||||
|
) {
|
||||||
|
self.pos_args.push(PosArg {
|
||||||
|
count: count,
|
||||||
|
value_name: value_name.into(),
|
||||||
|
doc_string: doc_string.into(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------
|
||||||
|
|
||||||
|
fn ensure_not_duplicate(&mut self, long: &str, short: Option<&str>) {
|
||||||
|
if self.long_set.contains(long) {
|
||||||
|
panic!("Attempted to add duplicate long argument \"--{}\".", long);
|
||||||
|
}
|
||||||
|
self.long_set.insert(long.into());
|
||||||
|
|
||||||
|
if let Some(short) = short {
|
||||||
|
if self.short_set.contains(short) {
|
||||||
|
panic!("Attempted to add duplicate short argument \"-{}\".", short);
|
||||||
|
}
|
||||||
|
self.short_set.insert(short.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parsed command line arguments.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Arguments {
|
pub struct Arguments {
|
||||||
// TODO: allow OsString argument values.
|
// TODO: allow OsString argument values.
|
||||||
/// Positional arguments, in the order passed.
|
/// The flags that were passed, indexed by `long`.
|
||||||
pub positional: Vec<String>,
|
|
||||||
|
|
||||||
/// The flags that were passed.
|
|
||||||
pub flags: HashSet<String>,
|
pub flags: HashSet<String>,
|
||||||
|
|
||||||
/// Non-positional arguments that were passed.
|
/// Non-positional arguments that were passed, indexed by `long`.
|
||||||
pub args: HashMap<String, String>,
|
pub args: HashMap<String, Vec<String>>,
|
||||||
|
|
||||||
|
/// Positional arguments, indexed by `value_name`.
|
||||||
|
pub positional: HashMap<String, Vec<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------------------------------
|
//-------------------------------------------------------------
|
||||||
|
@ -30,7 +122,7 @@ pub struct Arguments {
|
||||||
/// Flag spec.
|
/// Flag spec.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Flag {
|
struct Flag {
|
||||||
long: Option<String>,
|
long: String,
|
||||||
short: Option<String>,
|
short: Option<String>,
|
||||||
|
|
||||||
// For documentation.
|
// For documentation.
|
||||||
|
@ -40,9 +132,9 @@ struct Flag {
|
||||||
/// Argument spec.
|
/// Argument spec.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct Arg {
|
struct Arg {
|
||||||
long: Option<String>,
|
long: String,
|
||||||
short: Option<String>,
|
short: Option<String>,
|
||||||
is_required: bool,
|
acceptable_count: (Option<usize>, Option<usize>),
|
||||||
|
|
||||||
// For documentation.
|
// For documentation.
|
||||||
value_name: String,
|
value_name: String,
|
||||||
|
@ -52,7 +144,7 @@ struct Arg {
|
||||||
/// Positional argument spec.
|
/// Positional argument spec.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
struct PosArg {
|
struct PosArg {
|
||||||
is_required: bool,
|
count: Option<usize>,
|
||||||
|
|
||||||
// For documentation.
|
// For documentation.
|
||||||
value_name: String,
|
value_name: String,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user