|
1 | 1 | use crate::args::Args; |
2 | 2 | use clap::builder::PossibleValue; |
3 | 3 | use clap::{Arg, ArgAction, Command, CommandFactory}; |
| 4 | +use derive_more::{Display, Error}; |
4 | 5 | use itertools::Itertools; |
5 | 6 | use std::borrow::Cow; |
6 | 7 |
|
| 8 | +/// Error produced when generating the usage Markdown. |
| 9 | +#[derive(Debug, Display, Error)] |
| 10 | +#[non_exhaustive] |
| 11 | +pub enum RenderUsageMdError { |
| 12 | + /// A `visible_alias` or `visible_short_alias` duplicates the argument's own flag name. |
| 13 | + #[display("redundant visible alias: {_0}")] |
| 14 | + RedundantVisibleAlias(#[error(not(source))] String), |
| 15 | +} |
| 16 | + |
7 | 17 | /// Renders a Markdown reference page for `pdu`'s CLI. |
8 | | -pub fn render_usage_md() -> String { |
| 18 | +pub fn render_usage_md() -> Result<String, RenderUsageMdError> { |
9 | 19 | let mut command: Command = Args::command(); |
10 | | - validate_no_redundant_visible_aliases(&command); |
| 20 | + validate_no_redundant_visible_aliases(&command)?; |
11 | 21 | let mut out = String::new(); |
12 | 22 |
|
13 | 23 | let usage = command.render_usage().to_string(); |
@@ -60,7 +70,7 @@ pub fn render_usage_md() -> String { |
60 | 70 | } |
61 | 71 | } |
62 | 72 |
|
63 | | - out |
| 73 | + Ok(out) |
64 | 74 | } |
65 | 75 |
|
66 | 76 | fn render_argument(out: &mut String, arg: &Arg) { |
@@ -239,35 +249,28 @@ fn ensure_ends_with_punctuation(line: &str) -> Cow<'_, str> { |
239 | 249 | /// A `visible_alias` matching the argument's own `--long` name, or a `visible_short_alias` |
240 | 250 | /// matching its own `-short` flag, is a coding mistake that produces redundant output in |
241 | 251 | /// USAGE.md. This function detects such mistakes and terminates the process. |
242 | | -fn validate_no_redundant_visible_aliases(command: &Command) { |
243 | | - let mut errors = Vec::<String>::new(); |
244 | | - |
| 252 | +fn validate_no_redundant_visible_aliases(command: &Command) -> Result<(), RenderUsageMdError> { |
245 | 253 | for arg in command.get_arguments() { |
246 | 254 | if let Some(primary_long) = arg.get_long() { |
247 | 255 | for alias in arg.get_visible_aliases().unwrap_or_default() { |
248 | 256 | if alias == primary_long { |
249 | | - errors.push(format!( |
| 257 | + return Err(RenderUsageMdError::RedundantVisibleAlias(format!( |
250 | 258 | "--{primary_long} has visible_alias \"{alias}\" that duplicates its own flag name", |
251 | | - )); |
| 259 | + ))); |
252 | 260 | } |
253 | 261 | } |
254 | 262 | } |
255 | 263 |
|
256 | 264 | if let Some(primary_short) = arg.get_short() { |
257 | 265 | for alias in arg.get_visible_short_aliases().unwrap_or_default() { |
258 | 266 | if alias == primary_short { |
259 | | - errors.push(format!( |
| 267 | + return Err(RenderUsageMdError::RedundantVisibleAlias(format!( |
260 | 268 | "-{primary_short} has visible_short_alias '{alias}' that duplicates its own flag name", |
261 | | - )); |
| 269 | + ))); |
262 | 270 | } |
263 | 271 | } |
264 | 272 | } |
265 | 273 | } |
266 | 274 |
|
267 | | - if !errors.is_empty() { |
268 | | - for error in &errors { |
269 | | - eprintln!("error: {error}"); |
270 | | - } |
271 | | - std::process::exit(1); |
272 | | - } |
| 275 | + Ok(()) |
273 | 276 | } |
0 commit comments