diff --git a/examples/btreemap.rs b/examples/btreemap.rs new file mode 100644 index 0000000..5fc442b --- /dev/null +++ b/examples/btreemap.rs @@ -0,0 +1,29 @@ +/* btreemap - jaarg example program using BTreeMap + * SPDX-FileCopyrightText: (C) 2025 Gay Pizza Specifications + * SPDX-License-Identifier: MIT + */ + +use jaarg::{std::ParseMapResult, Opt, Opts}; +use std::process::ExitCode; + +fn main() -> ExitCode { + const OPTIONS: Opts<&'static str> = Opts::new(&[ + Opt::flag("help", &["--help"], "Show this help"), + Opt::positional("positional", "positional", "Positional argument"), + Opt::value("value", &["-v", "--value"], "path", "Value option"), + Opt::flag("flag", &["-f", "--flag"], "Flag option"), + ]); + + let map = match OPTIONS.parse_map_easy() { + // TODO: There should probably be a more efficient way to make jaarg handle help for us + ParseMapResult::Map(map) if map.contains_key("help") => { + OPTIONS.print_full_help("btreemap"); + return ExitCode::SUCCESS; + } + ParseMapResult::Map(map) => map, + ParseMapResult::Exit(code) => { return code; } + }; + + println!("{:?}", map); + ExitCode::SUCCESS +} diff --git a/src/options.rs b/src/options.rs index 1cfba3c..34ab655 100644 --- a/src/options.rs +++ b/src/options.rs @@ -16,6 +16,7 @@ impl Opts { pub const fn new(options: &'static[Opt]) -> Self { Self { flag_chars: "-", options } } + // TODO: Replace with a parser options construct pub const fn new_flag(flag_chars: &'static str, options: &'static[Opt]) -> Self { Self { flag_chars, options } } diff --git a/src/std.rs b/src/std.rs index 728dfb5..27915ef 100644 --- a/src/std.rs +++ b/src/std.rs @@ -5,9 +5,12 @@ extern crate std; -use std::{env, eprintln, println}; +use crate::{HandlerResult, HelpWriter, HelpWriterContext, Opt, Opts, ParseControl, ParseError, ParseResult, StandardFullHelpWriter, StandardShortUsageWriter}; +use std::collections::BTreeMap; use std::path::Path; -use crate::{HandlerResult, Opt, Opts, ParseControl, ParseResult, StandardShortUsageWriter, HelpWriterContext, StandardFullHelpWriter, HelpWriter}; +use std::rc::Rc; +use std::string::String; +use std::{env, eprintln, println}; impl Opts { /// Wrapper around `jaarg::parse` that gathers arguments from the command line and prints errors to stderr. @@ -16,14 +19,8 @@ impl Opts { /// Requires features = [std] pub fn parse_easy<'a>(&self, handler: impl FnMut(&str, &ID, &Opt, &str, &str) -> HandlerResult<'a, ParseControl> ) -> ParseResult { - let mut argv = env::args(); - let argv0 = argv.next().unwrap(); - let program_name = Path::new(&argv0).file_name().unwrap().to_string_lossy(); - self.parse(&program_name, argv, handler, |program_name, e| { - eprintln!("{program_name}: {e}"); - self.eprint_help::>(program_name); - eprintln!("Run '{program_name} --help' to view all available options."); - }) + let (program_name, argv) = Self::easy_args(); + self.parse(&program_name, argv, handler, |name, e| self.easy_error(name, e)) } /// Prints full help text for the options using the standard full @@ -48,4 +45,50 @@ impl Opts { let ctx = HelpWriterContext { options: self, program_name }; eprintln!("{}", W::new(ctx)); } + + fn easy_args<'a>() -> (Rc, env::Args) { + let mut argv = env::args(); + let argv0 = argv.next().unwrap(); + let program_name = Path::new(&argv0).file_name().unwrap().to_string_lossy(); + (program_name.into(), argv) + } + + fn easy_error(&self, program_name: &str, err: ParseError) { + eprintln!("{program_name}: {err}"); + self.eprint_help::>(program_name); + // TODO: only show when an option is marked help + eprintln!("Run '{program_name} --help' to view all available options."); + } +} + +/// The result of parsing commands using `jaarg::Opts::parse_map`. +pub enum ParseMapResult { + Map(BTreeMap<&'static str, String>), + Exit(std::process::ExitCode), +} + +impl Opts<&'static str> { + /// Parse an iterator of strings as arguments and return the results in a BTreeMap. + /// + /// Requires features = [std] + pub fn parse_map<'a, S: AsRef + 'a, I: Iterator>(&self, program_name: &str, args: I, + error: impl FnOnce(&str, ParseError)) -> ParseMapResult { + let mut out: BTreeMap<&'static str, String> = BTreeMap::new(); + match self.parse(&program_name, args, |program_name, id, _opt, _name, arg| { + out.insert(id, arg.into()); + Ok(ParseControl::Continue) + }, error) { + ParseResult::ContinueSuccess => ParseMapResult::Map(out), + ParseResult::ExitSuccess => ParseMapResult::Exit(std::process::ExitCode::SUCCESS), + ParseResult::ExitError => ParseMapResult::Exit(std::process::ExitCode::FAILURE), + } + } + + /// Parse arguments from the command line and return the results in a BTreeMap. + /// + /// Requires features = [std] + pub fn parse_map_easy(&self) -> ParseMapResult { + let (program_name, argv) = Self::easy_args(); + self.parse_map(&program_name, argv, |name, e| self.easy_error(name, e)) + } }