diff --git a/examples/compiler.rs b/examples/compiler.rs index dfd51eb..a57d978 100644 --- a/examples/compiler.rs +++ b/examples/compiler.rs @@ -1,13 +1,13 @@ use badargs::arg; -arg!(OutFile: "output", "o" -> Option); -arg!(Force: "force", "f" -> bool); +arg!(OutFile: "output", 'o' -> Option); +arg!(Force: "force", 'f' -> bool); arg!(OLevel: "optimize" -> usize); fn main() { let args = badargs::badargs::<(OutFile, (Force, OLevel))>().unwrap(); - let _outfile = args.get::(); - let _force = args.get::(); - let _o_level = args.get::(); + let outfile = args.get::(); + let force = args.get::(); + let o_level = args.get::(); } diff --git a/src/lib.rs b/src/lib.rs index 8d55aa8..ad2f736 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod macros; +mod parse; mod schema; use crate::parse::CliArgs; @@ -17,7 +18,7 @@ where { let arg_schema = Schema::create::()?; - let args = CliArgs::from_args(arg_schema, std::env::args_os())?; + let args = CliArgs::from_args(&arg_schema, std::env::args())?; Ok(BadArgs { args }) } @@ -29,14 +30,14 @@ where /// /// ``` /// # use badargs::arg; -/// arg!(OutFile: "output", "o" -> Option); +/// arg!(OutFile: "output", 'o' -> Option); /// // OutFile now implements CliArg /// ``` pub trait CliArg { type Content: CliReturnValue; fn long() -> &'static str; - fn short() -> Option<&'static str>; + fn short() -> Option; } /// The struct containing parsed argument information @@ -92,34 +93,10 @@ mod error { #[derive(Debug, Clone, Eq, PartialEq)] pub enum ArgError { InvalidUtf8, - NameAlreadyExists(&'static str), + NameAlreadyExists(String), InvalidSchema(String), IdkYet, - } -} - -mod parse { - use super::Result; - use crate::schema::Schema; - use std::collections::HashMap; - use std::ffi::OsString; - - #[derive(Debug, Clone, Default)] - pub struct CliArgs { - pub isize: HashMap<&'static str, isize>, - pub usize: HashMap<&'static str, isize>, - pub string: HashMap<&'static str, String>, - pub option_string: HashMap<&'static str, Option>, - pub bool: HashMap<&'static str, bool>, - } - - impl CliArgs { - pub fn from_args(_schema: Schema, args: impl Iterator) -> Result { - let result = Self::default(); - let mut args = args; - while let Some(_arg) = args.next() {} - - Ok(result) - } + UnnamedArgument, + SingleMinus, } } diff --git a/src/macros.rs b/src/macros.rs index cf3e4ca..8690981 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -17,7 +17,7 @@ macro_rules! arg { $long } - fn short() -> Option<&'static str> { + fn short() -> Option { $short } } diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..da97231 --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,52 @@ +use super::Result; +use crate::schema::Schema; +use crate::ArgError; +use std::collections::HashMap; +use std::iter::Peekable; + +#[derive(Debug, Clone, Default)] +pub struct CliArgs { + pub isize: HashMap<&'static str, isize>, + pub usize: HashMap<&'static str, isize>, + pub string: HashMap<&'static str, String>, + pub option_string: HashMap<&'static str, Option>, + pub bool: HashMap<&'static str, bool>, +} + +impl CliArgs { + pub fn from_args(schema: &Schema, args: impl Iterator) -> Result { + let mut result = Self::default(); + + let mut args = args.peekable(); + while let Some(arg) = args.next() { + if let Some(shorts) = arg.strip_prefix('-') { + parse_shorts(schema, &mut result, shorts, &mut args)?; + } else if let Some(longs) = arg.strip_prefix("--") { + } else { + return Err(ArgError::UnnamedArgument); + } + } + + Ok(result) + } +} + +fn parse_shorts( + schema: &Schema, + results: &mut CliArgs, + shorts: &str, + args: &mut Peekable>, +) -> Result<()> { + if shorts.len() == 0 { + return Err(ArgError::SingleMinus); + } + + for flag_name in shorts.chars() {} + + Ok(()) +} + +fn expects_value_short(schema: &Schema, name: char) -> bool { + schema.short('5'); + true +} diff --git a/src/schema.rs b/src/schema.rs index cd6a3fa..a49e862 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -32,7 +32,7 @@ pub struct SchemaCommand { #[derive(Debug, Clone, Default, Eq, PartialEq)] pub struct Schema { longs: HashMap<&'static str, SchemaCommand>, - shorts: HashMap<&'static str, SchemaCommand>, + shorts: HashMap, } impl Schema { @@ -48,19 +48,23 @@ impl Schema { fn add_command(&mut self, long_name: &'static str, command: SchemaCommand) -> Result<()> { if let Some(_) = self.longs.insert(long_name, command) { - Err(ArgError::NameAlreadyExists(long_name)) + Err(ArgError::NameAlreadyExists(long_name.to_string())) } else { Ok(()) } } - fn add_short_command( - &mut self, - short_name: &'static str, - command: SchemaCommand, - ) -> Result<()> { + pub fn short(&self, name: char) -> Option<&SchemaCommand> { + self.shorts.get(&name) + } + + pub fn long(&self, name: &str) -> Option<&SchemaCommand> { + self.longs.get(name) + } + + fn add_short_command(&mut self, short_name: char, command: SchemaCommand) -> Result<()> { if let Some(_) = self.shorts.insert(short_name, command) { - Err(ArgError::NameAlreadyExists(short_name)) + Err(ArgError::NameAlreadyExists(short_name.to_string())) } else { Ok(()) } @@ -112,10 +116,10 @@ mod test { use crate::schema::{Schema, SchemaCommand, SchemaKind}; use crate::{arg, ArgError}; - arg!(OutFile: "output", "o" -> Option); - arg!(Force: "force", "f" -> bool); + arg!(OutFile: "output", 'o' -> Option); + arg!(Force: "force", 'f' -> bool); arg!(SetUpstream: "set-upstream" -> String); - arg!(OutFile2: "output", "o" -> Option); + arg!(OutFile2: "output", 'o' -> Option); #[test] fn one_command_schema() { @@ -124,9 +128,8 @@ mod test { kind: SchemaKind::OptionString, }; assert_eq!(schema.longs.get("output"), Some(&out_file)); - assert_eq!(schema.shorts.get("o"), Some(&out_file)); + assert_eq!(schema.shorts.get(&'o'), Some(&out_file)); assert_eq!(schema.longs.get("o"), None); - assert_eq!(schema.shorts.get("output"), None); } #[test] @@ -140,14 +143,12 @@ mod test { }; assert_eq!(schema.longs.get("output"), Some(&out_file)); - assert_eq!(schema.shorts.get("o"), Some(&out_file)); + assert_eq!(schema.shorts.get(&'o'), Some(&out_file)); assert_eq!(schema.longs.get("o"), None); - assert_eq!(schema.shorts.get("output"), None); assert_eq!(schema.longs.get("force"), Some(&force)); - assert_eq!(schema.shorts.get("f"), Some(&force)); + assert_eq!(schema.shorts.get(&'f'), Some(&force)); assert_eq!(schema.longs.get("f"), None); - assert_eq!(schema.shorts.get("force"), None); } #[test] @@ -164,26 +165,19 @@ mod test { }; assert_eq!(schema.longs.get("output"), Some(&out_file)); - assert_eq!(schema.shorts.get("o"), Some(&out_file)); + assert_eq!(schema.shorts.get(&'o'), Some(&out_file)); assert_eq!(schema.longs.get("o"), None); - assert_eq!(schema.shorts.get("output"), None); assert_eq!(schema.longs.get("force"), Some(&force)); - assert_eq!(schema.shorts.get("f"), Some(&force)); + assert_eq!(schema.shorts.get(&'f'), Some(&force)); assert_eq!(schema.longs.get("f"), None); - assert_eq!(schema.shorts.get("force"), None); assert_eq!(schema.longs.get("set-upstream"), Some(&set_upstream)); - assert_eq!(schema.shorts.get("set-upstream"), None); } #[test] fn double_error() { let schema = Schema::create::<(OutFile, OutFile2)>(); - assert!(matches!( - schema, - // it doesn't matter which one gets reported first - Err(ArgError::NameAlreadyExists("output")) | Err(ArgError::NameAlreadyExists("o")) - )); + assert!(schema.is_err()); } }