Pull help querying and getting an iterator over options into a public methods

This commit is contained in:
2025-11-05 05:06:59 +11:00
parent b11c55a1ee
commit b0072855bc
4 changed files with 31 additions and 11 deletions

View File

@@ -140,7 +140,7 @@ impl<ID: 'static> Opts<ID> {
// Ensure that all required arguments have been provided // Ensure that all required arguments have been provided
let mut required_flag_idx = 0; let mut required_flag_idx = 0;
for (i, option) in self.options.iter().enumerate() { for (i, option) in self.iter().enumerate() {
match option.r#type { match option.r#type {
OptType::Positional => if i >= state.positional_index && option.is_required() { OptType::Positional => if i >= state.positional_index && option.is_required() {
error(program_name, ParseError::RequiredPositional(option.first_name())); error(program_name, ParseError::RequiredPositional(option.first_name()));
@@ -192,7 +192,7 @@ impl<ID: 'static> Opts<ID> {
let mut required_idx = 0; let mut required_idx = 0;
// Match a suitable option by name (ignoring the first flag character & skipping positional arguments) // Match a suitable option by name (ignoring the first flag character & skipping positional arguments)
let (name, option) = self.options.iter() let (name, option) = self.iter()
.filter(|opt| matches!(opt.r#type, OptType::Flag | OptType::Value)).find_map(|opt| { .filter(|opt| matches!(opt.r#type, OptType::Flag | OptType::Value)).find_map(|opt| {
if let Some(name) = opt.match_name(option_str, 1) { if let Some(name) = opt.match_name(option_str, 1) {
Some((name, opt)) Some((name, opt))

View File

@@ -23,7 +23,7 @@ impl<ID: 'static> core::fmt::Display for StandardShortUsageWriter<'_, ID> {
write!(f, "Usage: {}", self.0.program_name)?; write!(f, "Usage: {}", self.0.program_name)?;
// Write option parameter arguments // Write option parameter arguments
for option in self.0.options.options.iter() for option in self.0.options.iter()
.filter(|o| matches!(o.r#type, OptType::Value | OptType::Flag)) { .filter(|o| matches!(o.r#type, OptType::Value | OptType::Flag)) {
write!(f, " {}", if option.is_required() { '<' } else { '[' })?; write!(f, " {}", if option.is_required() { '<' } else { '[' })?;
match (option.first_short_name(), option.first_long_name()) { match (option.first_short_name(), option.first_long_name()) {
@@ -39,7 +39,7 @@ impl<ID: 'static> core::fmt::Display for StandardShortUsageWriter<'_, ID> {
} }
// Write positional arguments // Write positional arguments
for option in self.0.options.options.iter() for option in self.0.options.iter()
.filter(|o| matches!(o.r#type, OptType::Positional)) { .filter(|o| matches!(o.r#type, OptType::Positional)) {
let name = option.first_name(); let name = option.first_name();
match option.is_required() { match option.is_required() {
@@ -100,7 +100,7 @@ impl<ID> core::fmt::Display for StandardFullHelpWriter<'_, ID> {
} }
// Write positional arguments // Write positional arguments
for option in self.0.options.options.iter() for option in self.0.options.iter()
.filter(|o| matches!(o.r#type, OptType::Positional)) { .filter(|o| matches!(o.r#type, OptType::Positional)) {
let name = option.first_name(); let name = option.first_name();
match option.is_required() { match option.is_required() {
@@ -124,12 +124,12 @@ impl<ID> core::fmt::Display for StandardFullHelpWriter<'_, ID> {
} }
// Determine the alignment width from the longest option parameter // Determine the alignment width from the longest option parameter
let align_width = 2 + self.0.options.options.iter() let align_width = 2 + self.0.options.iter()
.map(|o| calculate_left_pad(o)).max().unwrap_or(0); .map(|o| calculate_left_pad(o)).max().unwrap_or(0);
// Write positional argument descriptions // Write positional argument descriptions
first = true; first = true;
for option in self.0.options.options.iter() for option in self.0.options.iter()
.filter(|o| matches!(o.r#type, OptType::Positional)) { .filter(|o| matches!(o.r#type, OptType::Positional)) {
if first { if first {
// Write separator and positional section header // Write separator and positional section header
@@ -149,7 +149,7 @@ impl<ID> core::fmt::Display for StandardFullHelpWriter<'_, ID> {
// Write option parameter argument descriptions // Write option parameter argument descriptions
first = true; first = true;
for option in self.0.options.options.iter() for option in self.0.options.iter()
.filter(|o| matches!(o.r#type, OptType::Flag | OptType::Value)) { .filter(|o| matches!(o.r#type, OptType::Flag | OptType::Value)) {
if first { if first {
// Write separator and options section header // Write separator and options section header

View File

@@ -40,15 +40,35 @@ impl<ID: 'static> Opts<ID> {
} }
} }
/// Set the recognised flag/option characters. /// Sets the recognised flag/option characters.
#[inline]
pub const fn with_flag_chars(mut self, flag_chars: &'static str) -> Self { pub const fn with_flag_chars(mut self, flag_chars: &'static str) -> Self {
self.flag_chars = flag_chars; self.flag_chars = flag_chars;
self self
} }
/// Set the description of the program, available to help writers. /// Sets the description of the program, available to help writers.
#[inline]
pub const fn with_description(mut self, description: &'static str) -> Self { pub const fn with_description(mut self, description: &'static str) -> Self {
self.description = Some(description); self.description = Some(description);
self self
} }
/// Gets the first available help option if one exists.
pub const fn help_option(&self) -> Option<&'static Opt<ID>> {
let mut i = 0;
while i < self.options.len() {
if self.options[i].is_help() {
return Some(&self.options[i]);
}
i += 1;
}
None
}
/// Gets an iterator over the parser's options.
#[inline]
pub fn iter(&self) -> core::slice::Iter<'static, Opt<ID>> {
self.options.iter()
}
} }

View File

@@ -56,7 +56,7 @@ impl<ID: 'static> Opts<ID> {
fn easy_error(&self, program_name: &str, err: ParseError) { fn easy_error(&self, program_name: &str, err: ParseError) {
eprintln!("{program_name}: {err}"); eprintln!("{program_name}: {err}");
self.eprint_help::<StandardShortUsageWriter<'_, ID>>(program_name); self.eprint_help::<StandardShortUsageWriter<'_, ID>>(program_name);
if let Some(help_option) = self.options.iter().find(|o| o.is_help()) { if let Some(help_option) = self.help_option() {
eprintln!("Run '{program_name} {help}' to view all available options.", eprintln!("Run '{program_name} {help}' to view all available options.",
help = help_option.first_long_name().unwrap_or(help_option.first_name())); help = help_option.first_long_name().unwrap_or(help_option.first_name()));
} }