diff --git a/examples/compiler.rs b/examples/compiler.rs index c4ebfd0..cd421b2 100644 --- a/examples/compiler.rs +++ b/examples/compiler.rs @@ -7,7 +7,11 @@ arg!(OLevel: "optimize" -> usize); fn main() { let args = badargs::badargs!(OutFile, Force, OLevel); - 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::(); + + println!("output: {:?}", outfile); + println!("force: {:?}", force); + println!("o-level: {:?}", o_level); } diff --git a/src/lib.rs b/src/lib.rs index 849e839..40121a7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ mod macros; mod parse; +mod reporting; mod schema; use crate::parse::CliArgs; @@ -56,9 +57,11 @@ where { let arg_schema = Schema::create::().expect("Invalid schema!"); - let args = CliArgs::from_args(&arg_schema, std::env::args()).expect("todo"); - - BadArgs { args } + let args = CliArgs::from_args(&arg_schema, std::env::args()); + match args { + Ok(args) => BadArgs { args }, + Err(err) => reporting::report(err), + } } /// @@ -89,6 +92,11 @@ impl BadArgs { let long_name = T::long(); self.args.get::(long_name) } + + /// Get all unnamed additional arguments + pub fn unnamed(&self) -> &[String] { + self.args.unnamed() + } } /// @@ -123,6 +131,8 @@ mod sealed { } mod error { + use crate::schema::SchemaKind; + /// Invalid schema #[derive(Debug, Clone, Eq, PartialEq)] pub enum SchemaError { @@ -133,10 +143,9 @@ mod error { /// Invalid arguments provided #[derive(Debug, Clone, Eq, PartialEq)] pub enum CallError { - SingleMinus, ShortFlagNotFound(char), LongFlagNotFound(String), - ExpectedValue(String), + ExpectedValue(String, SchemaKind), INan(String), UNan(String), CombinedShortWithValue(String), diff --git a/src/parse.rs b/src/parse.rs index 8810233..405373c 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -65,7 +65,8 @@ fn parse_shorts( parse_value(command.kind, results, &command.long, args)?; } else { - return Err(CallError::SingleMinus); + // '-' is a valid argument, like the `cat -` + results.unnamed.push("-".to_string()); } for flag in all_shorts { @@ -106,13 +107,13 @@ fn parse_value( SchemaKind::String => { let string = args .next() - .ok_or_else(|| CallError::ExpectedValue(long.to_string()))?; + .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))?; results.insert(long, Box::new(string)); } SchemaKind::INum => { let integer = args .next() - .ok_or_else(|| CallError::ExpectedValue(long.to_string()))? + .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))? .parse::() .map_err(|_| CallError::INan(long.to_string()))?; results.insert(long, Box::new(integer)) @@ -120,7 +121,7 @@ fn parse_value( SchemaKind::UNum => { let integer = args .next() - .ok_or_else(|| CallError::ExpectedValue(long.to_string()))? + .ok_or_else(|| CallError::ExpectedValue(long.to_string(), kind))? .parse::() .map_err(|_| CallError::UNan(long.to_string()))?; results.insert(long, Box::new(integer)) diff --git a/src/reporting.rs b/src/reporting.rs new file mode 100644 index 0000000..30425f8 --- /dev/null +++ b/src/reporting.rs @@ -0,0 +1,26 @@ +use crate::error::CallError; +use crate::schema::SchemaKind; + +pub fn report(err: CallError) -> ! { + match err { + CallError::ShortFlagNotFound(arg) => println!("error: argument '{}' does not exist.", arg), + CallError::LongFlagNotFound(arg) => println!("error: argument '{}' does not exist.", arg), + CallError::ExpectedValue(arg, kind) => { + println!( + "error: argument '{}' expected {} value, but got nothing.", + arg, + match kind { + SchemaKind::String => "string", + SchemaKind::Bool => unreachable!(), + SchemaKind::INum => "integer", + SchemaKind::UNum => "positive integer", + } + ) + } + CallError::INan(arg) => println!("error: argument '{}' expected a positive integer value, but got an invalid positive integer.", arg), + CallError::UNan(arg) => println!("error: argument '{}' expected an integer value, but got an invalid integer.", arg), + CallError::CombinedShortWithValue(arg) => println!("error: using argument expecting value '{}' in position where only flags are allowed", arg) + } + + std::process::exit(1) +}