Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions cli/usage_md.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
use parallel_disk_usage::usage_md::render_usage_md;
use std::process::ExitCode;

fn main() {
println!("{}", render_usage_md().trim_end());
fn main() -> ExitCode {
match render_usage_md() {
Ok(content) => {
println!("{}", content.trim_end());
ExitCode::SUCCESS
}
Err(error) => {
eprintln!("error: {error}");
ExitCode::FAILURE
}
}
}
51 changes: 49 additions & 2 deletions src/usage_md.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,27 @@
use crate::args::Args;
use clap::builder::PossibleValue;
use clap::{Arg, ArgAction, Command, CommandFactory};
use derive_more::{Display, Error};
use itertools::Itertools;
use pipe_trait::Pipe;
use std::borrow::Cow;

/// Error produced when generating the usage Markdown.
#[derive(Debug, Display, Error)]
#[non_exhaustive]
pub enum RenderUsageMdError {
/// A `visible_alias` duplicates the argument's own long flag name.
#[display("--{_0} has a visible_alias that duplicates its own flag name")]
RedundantVisibleLongAlias(#[error(not(source))] String),
/// A `visible_short_alias` duplicates the argument's own short flag name.
#[display("-{_0} has a visible_short_alias that duplicates its own flag name")]
RedundantVisibleShortAlias(#[error(not(source))] char),
}

/// Renders a Markdown reference page for `pdu`'s CLI.
pub fn render_usage_md() -> String {
pub fn render_usage_md() -> Result<String, RenderUsageMdError> {
let mut command: Command = Args::command();
reject_redundant_aliases(&command)?;
let mut out = String::new();

let usage = command.render_usage().to_string();
Expand Down Expand Up @@ -59,7 +74,7 @@ pub fn render_usage_md() -> String {
}
}

out
Ok(out)
}

fn render_argument(out: &mut String, arg: &Arg) {
Expand Down Expand Up @@ -232,3 +247,35 @@ fn ensure_ends_with_punctuation(line: &str) -> Cow<'_, str> {
Cow::Owned(format!("{line}."))
}
}

/// Rejects any argument whose visible alias duplicates its own primary flag name.
///
/// A visible alias matching the argument's own long name, or a visible short alias
/// matching its own short flag, is a coding mistake that produces redundant output in
/// USAGE.md.
fn reject_redundant_aliases(command: &Command) -> Result<(), RenderUsageMdError> {
for arg in command.get_arguments() {
if let Some(primary_long) = arg.get_long() {
for alias in arg.get_visible_aliases().unwrap_or_default() {
if alias == primary_long {
return primary_long
.to_owned()
.pipe(RenderUsageMdError::RedundantVisibleLongAlias)
.pipe(Err);
}
}
}

if let Some(primary_short) = arg.get_short() {
for alias in arg.get_visible_short_aliases().unwrap_or_default() {
if alias == primary_short {
return primary_short
.pipe(RenderUsageMdError::RedundantVisibleShortAlias)
.pipe(Err);
}
Comment thread
KSXGitHub marked this conversation as resolved.
}
}
}

Ok(())
}
4 changes: 3 additions & 1 deletion tests/sync_usage_md.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ use parallel_disk_usage::usage_md::render_usage_md;

#[test]
fn usage_md() {
let actual = render_usage_md();
let actual = render_usage_md().unwrap_or_else(|error| {
panic!("failed to render usage markdown: {error}");
});
let expected = include_str!("../USAGE.md");
assert!(
actual.trim_end() == expected.trim_end(),
Expand Down