mirror of
https://github.com/clap-rs/clap
synced 2024-12-14 14:52:33 +00:00
136 lines
4.4 KiB
Rust
136 lines
4.4 KiB
Rust
use std::str::Chars;
|
|
|
|
pub enum UsageToken<'u> {
|
|
Name(&'u str, Option<bool>),
|
|
Short(char),
|
|
Long(&'u str),
|
|
Help(&'u str),
|
|
Multiple,
|
|
}
|
|
|
|
pub struct UsageParser<'u> {
|
|
usage: &'u str,
|
|
chars: Chars<'u>,
|
|
s: usize,
|
|
e: usize,
|
|
}
|
|
|
|
impl<'u> UsageParser<'u> {
|
|
pub fn with_usage(u: &'u str) -> UsageParser<'u> {
|
|
UsageParser {
|
|
usage: u,
|
|
chars: u.chars(),
|
|
s: 0,
|
|
e: 0,
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
impl<'u> Iterator for UsageParser<'u> {
|
|
type Item = UsageToken<'u>;
|
|
|
|
fn next(&mut self) -> Option<UsageToken<'u>> {
|
|
loop {
|
|
match self.chars.next() {
|
|
Some(c) if c == '[' || c == '<' => {
|
|
// self.s = self.e + 1;
|
|
if self.e != 0 {
|
|
self.e += 1;
|
|
}
|
|
self.s = self.e + 1;
|
|
let closing = match c {
|
|
'[' => ']',
|
|
'<' => '>',
|
|
_ => unreachable!()
|
|
};
|
|
while let Some(c) = self.chars.next() {
|
|
self.e += 1;
|
|
if c == closing { break }
|
|
}
|
|
if self.e > self.usage.len() { return None }
|
|
|
|
// self.e += 1;
|
|
|
|
let name = &self.usage[self.s..self.e];
|
|
|
|
|
|
return Some(UsageToken::Name(name, if c == '<' { Some(true) } else { None }));
|
|
},
|
|
Some('\'') => {
|
|
self.s = self.e + 2;
|
|
self.e = self.usage.len() - 1;
|
|
|
|
while let Some(_) = self.chars.next() { continue }
|
|
|
|
return Some(UsageToken::Help(&self.usage[self.s..self.e]));
|
|
},
|
|
Some('-') => {
|
|
self.e += 1;
|
|
match self.chars.next() {
|
|
Some('-') => {
|
|
if self.e != 1 {
|
|
self.e += 1;
|
|
}
|
|
|
|
self.s = self.e + 1;
|
|
|
|
while let Some(c) = self.chars.next() {
|
|
self.e += 1;
|
|
if c == ' ' || c == '=' || c == '.' { break }
|
|
}
|
|
if self.e > self.usage.len() { return None }
|
|
|
|
if self.e == self.usage.len() - 1 {
|
|
return Some(UsageToken::Long(&self.usage[self.s..]))
|
|
}
|
|
return Some(UsageToken::Long(&self.usage[self.s..self.e]))
|
|
},
|
|
Some(c) => {
|
|
// When short is first don't increment e
|
|
if self.e != 1 {
|
|
self.e += 1;
|
|
}
|
|
// Short
|
|
if !c.is_alphanumeric() {
|
|
return None
|
|
}
|
|
return Some(UsageToken::Short(c))
|
|
},
|
|
_ => {
|
|
return None
|
|
}
|
|
}
|
|
},
|
|
Some('.') => {
|
|
self.e += 1;
|
|
let mut mult = false;
|
|
for _ in 0..2 {
|
|
self.e += 1;
|
|
match self.chars.next() {
|
|
// longs consume one '.' so they match '.. ' whereas shorts can
|
|
// match '...'
|
|
Some('.') | Some(' ') => { mult = true; },
|
|
_ => {
|
|
// if there is no help or following space all we can match is '..'
|
|
if self.e == self.usage.len() - 1 {
|
|
mult = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if mult { return Some(UsageToken::Multiple) }
|
|
},
|
|
Some(' ') | Some('=') | Some(']') | Some('>') | Some('\t') => {
|
|
self.e += 1;
|
|
continue
|
|
},
|
|
_ => {
|
|
return None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|