Move help text and required flag to with chain, make help text optional

This commit is contained in:
2025-11-02 01:16:17 +11:00
parent 0d9b86c767
commit 912d282d12
4 changed files with 42 additions and 41 deletions

View File

@@ -203,11 +203,11 @@ pub fn main() -> ExitCode {
// Read & parse arguments from the command line, store results into the above structure // Read & parse arguments from the command line, store results into the above structure
enum Arg { Out, Bin, Txt, Whitespace, Help } enum Arg { Out, Bin, Txt, Whitespace, Help }
const OPTIONS: Opts<Arg> = Opts::new(&[ const OPTIONS: Opts<Arg> = Opts::new(&[
Opt::help_flag(Arg::Help, &["--help", "-h"], "Show this help message and exit"), Opt::help_flag(Arg::Help, &["--help", "-h"]).help_text("Show this help message and exit"),
Opt::positional_required(Arg::Out, "out", "Path to generated header file"), Opt::positional(Arg::Out, "out").help_text("Path to generated header file").required(),
Opt::value(Arg::Bin, &["--bin", "-b"], "data.bin", "Add a binary file"), Opt::value(Arg::Bin, &["--bin", "-b"], "data.bin").help_text("Add a binary file"),
Opt::value(Arg::Txt, &["--txt", "-t"], "text.txt", "Add a text file"), Opt::value(Arg::Txt, &["--txt", "-t"], "text.txt").help_text("Add a text file"),
Opt::value(Arg::Whitespace, &["--whitespace"], "\" \"", "Emitted indentation (Default: \"\\t\")"), Opt::value(Arg::Whitespace, &["--whitespace"], "\" \"").help_text("Emitted indentation (Default: \"\\t\")"),
]); ]);
match OPTIONS.parse_easy(|program_name, id, _opt, _name, arg| { match OPTIONS.parse_easy(|program_name, id, _opt, _name, arg| {
match id { match id {

View File

@@ -8,10 +8,10 @@ use std::process::ExitCode;
fn main() -> ExitCode { fn main() -> ExitCode {
const OPTIONS: Opts<&'static str> = Opts::new(&[ const OPTIONS: Opts<&'static str> = Opts::new(&[
Opt::help_flag("help", &["--help"], "Show this help"), Opt::help_flag("help", &["--help"]).help_text("Show this help"),
Opt::positional("positional", "positional", "Positional argument"), Opt::positional("positional", "positional").help_text("Positional argument"),
Opt::value("value", &["-v", "--value"], "string", "Value option"), Opt::value("value", &["-v", "--value"], "string").help_text("Value option"),
Opt::flag("flag", &["-f", "--flag"], "Flag option"), Opt::flag("flag", &["-f", "--flag"]).help_text("Flag option"),
]); ]);
let map = match OPTIONS.parse_map_easy() { let map = match OPTIONS.parse_map_easy() {

View File

@@ -134,10 +134,12 @@ impl<ID> core::fmt::Display for StandardFullHelpWriter<'_, ID> {
} }
// Write positional argument line // Write positional argument line
writeln!(f, " {name} {:.<width$} {help_text}", "", write!(f, " {name}", name = option.first_name())?;
name = option.first_name(), if let Some(help_text) = option.help_string {
help_text = option.help_string, write!(f, " {:.<width$} {help_text}", "",
width = align_width - calculate_left_pad(option))?; width = align_width - calculate_left_pad(option))?;
}
writeln!(f)?;
} }
// Write option parameter argument descriptions // Write option parameter argument descriptions
@@ -167,9 +169,11 @@ impl<ID> core::fmt::Display for StandardFullHelpWriter<'_, ID> {
} }
// Write padding and help text // Write padding and help text
writeln!(f, " {:.<width$} {help_text}", "", if let Some(help_text) = option.help_string {
help_text = option.help_string, write!(f, " {:.<width$} {help_text}", "",
width = align_width - calculate_left_pad(option))?; width = align_width - calculate_left_pad(option))?;
}
writeln!(f)?;
} }
Ok(()) Ok(())

View File

@@ -22,7 +22,7 @@ pub struct Opt<ID> {
id: ID, id: ID,
names: OptIdentifier, names: OptIdentifier,
value_name: Option<&'static str>, value_name: Option<&'static str>,
help_string: &'static str, help_string: Option<&'static str>,
r#type: OptType, r#type: OptType,
flags: OptFlag, flags: OptFlag,
} }
@@ -40,50 +40,47 @@ impl OptFlag {
// TODO: Improve this interface by making the name field take AsOptIdentifier when const traits are stabilised // TODO: Improve this interface by making the name field take AsOptIdentifier when const traits are stabilised
impl<ID> Opt<ID> { impl<ID> Opt<ID> {
#[inline] #[inline]
const fn new(id: ID, names: OptIdentifier, value_name: Option<&'static str>, help_string: &'static str, r#type: OptType) -> Self { const fn new(id: ID, names: OptIdentifier, value_name: Option<&'static str>, r#type: OptType) -> Self {
assert!(match names { assert!(match names {
OptIdentifier::Single(_) => true, OptIdentifier::Single(_) => true,
OptIdentifier::Multi(names) => !names.is_empty(), OptIdentifier::Multi(names) => !names.is_empty(),
}, "Option names cannot be an empty slice"); }, "Option names cannot be an empty slice");
Self { id, names, value_name, help_string, r#type, flags: OptFlag::NONE } Self { id, names, value_name, help_string: None, r#type, flags: OptFlag::NONE }
} }
/// A positional argument that is parsed sequentially without being invoked by an option flag /// A positional argument that is parsed sequentially without being invoked by an option flag
pub const fn positional(id: ID, name: &'static str, help_string: &'static str) -> Self { pub const fn positional(id: ID, name: &'static str) -> Self {
Self::new(id, OptIdentifier::Single(name), None, help_string, OptType::Positional) Self::new(id, OptIdentifier::Single(name), None, OptType::Positional)
}
/// A required positional argument that is parsed sequentially without being invoked by an option flag
pub const fn positional_required(id: ID, name: &'static str, help_string: &'static str) -> Self {
Self::new(id, OptIdentifier::Single(name), None, help_string, OptType::Positional).with_required()
} }
/// A flag-type option that serves as the interface's help flag /// A flag-type option that serves as the interface's help flag
pub const fn help_flag(id: ID, names: &'static[&'static str], help_string: &'static str) -> Self { pub const fn help_flag(id: ID, names: &'static[&'static str]) -> Self {
Self::new(id, OptIdentifier::Multi(names), None, help_string, OptType::Flag).with_help_flag() Self::new(id, OptIdentifier::Multi(names), None, OptType::Flag)
.with_help_flag()
} }
/// A flag-type option that takes no value /// A flag-type option, takes no value
pub const fn flag(id: ID, names: &'static[&'static str], help_string: &'static str) -> Self { pub const fn flag(id: ID, names: &'static[&'static str]) -> Self {
Self::new(id, OptIdentifier::Multi(names), None, help_string, OptType::Flag) Self::new(id, OptIdentifier::Multi(names), None, OptType::Flag)
}
/// A required flag-type option that takes no value
pub const fn flag_required(id: ID, names: &'static[&'static str], help_string: &'static str) -> Self {
Self::new(id, OptIdentifier::Multi(names), None, help_string, OptType::Flag).with_required()
} }
/// An option argument that takes a value /// An option argument that takes a value
pub const fn value(id: ID, names: &'static[&'static str], value_name: &'static str, help_string: &'static str) -> Self { pub const fn value(id: ID, names: &'static[&'static str], value_name: &'static str) -> Self {
Self::new(id, OptIdentifier::Multi(names), Some(value_name), help_string, OptType::Value) Self::new(id, OptIdentifier::Multi(names), Some(value_name), OptType::Value)
}
/// A required option argument that takes a value
pub const fn value_required(id: ID, names: &'static[&'static str], value_name: &'static str, help_string: &'static str) -> Self {
Self::new(id, OptIdentifier::Multi(names), Some(value_name), help_string, OptType::Value).with_required()
} }
/// This option is required, ie; parsing will fail if it is not specified.
#[inline] #[inline]
const fn with_required(mut self) -> Self { pub const fn required(mut self) -> Self {
assert!(!self.is_help(), "Help flag cannot be made required"); assert!(!self.is_help(), "Help flag cannot be made required");
self.flags.0 |= OptFlag::REQUIRED.0; self.flags.0 |= OptFlag::REQUIRED.0;
self self
} }
/// Sets the help string for an option.
#[inline]
pub const fn help_text(mut self, help_string: &'static str) -> Self {
self.help_string = Some(help_string);
self
}
#[inline] #[inline]
const fn with_help_flag(mut self) -> Self { const fn with_help_flag(mut self) -> Self {
assert!(matches!(self.r#type, OptType::Flag), "Only flags are allowed to be help options"); assert!(matches!(self.r#type, OptType::Flag), "Only flags are allowed to be help options");