diff --git a/src/uu/base32/base32.md b/src/uu/base32/base32.md index 442f300bf..0889292ce 100644 --- a/src/uu/base32/base32.md +++ b/src/uu/base32/base32.md @@ -1,8 +1,9 @@ # base32 ## Usage - -{} [OPTION]... [FILE] +``` +base32 [OPTION]... [FILE] +``` ## About diff --git a/src/uu/base32/src/base32.rs b/src/uu/base32/src/base32.rs index 281a9084d..25faf101d 100644 --- a/src/uu/base32/src/base32.rs +++ b/src/uu/base32/src/base32.rs @@ -8,12 +8,12 @@ use std::io::{stdin, Read}; use clap::Command; -use uucore::{encoding::Format, error::UResult, help_section}; +use uucore::{encoding::Format, error::UResult, help_section, help_usage}; pub mod base_common; const ABOUT: &str = help_section!("about"); -const USAGE: &str = help_section!("usage"); +const USAGE: &str = help_usage!(); #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { diff --git a/src/uu/base64/base64.md b/src/uu/base64/base64.md index 864948985..89b9cb618 100644 --- a/src/uu/base64/base64.md +++ b/src/uu/base64/base64.md @@ -1,7 +1,9 @@ # base64 ## Usage -{} [OPTION]... [FILE] +``` +base64 [OPTION]... [FILE] +``` ## About diff --git a/src/uu/base64/src/base64.rs b/src/uu/base64/src/base64.rs index d0120e4a8..0b5dcb5b5 100644 --- a/src/uu/base64/src/base64.rs +++ b/src/uu/base64/src/base64.rs @@ -9,12 +9,12 @@ use uu_base32::base_common; pub use uu_base32::uu_app; -use uucore::{encoding::Format, error::UResult, help_section}; +use uucore::{encoding::Format, error::UResult, help_section, help_usage}; use std::io::{stdin, Read}; const ABOUT: &str = help_section!("about"); -const USAGE: &str = help_section!("usage"); +const USAGE: &str = help_usage!(); #[uucore::main] pub fn uumain(args: impl uucore::Args) -> UResult<()> { diff --git a/src/uu/numfmt/numfmt.md b/src/uu/numfmt/numfmt.md index 51ce1de15..52bd743d8 100644 --- a/src/uu/numfmt/numfmt.md +++ b/src/uu/numfmt/numfmt.md @@ -1,6 +1,11 @@ # numfmt +## Usage +``` +numfmt [OPTION]... [NUMBER]... +``` + ## About Convert numbers from/to human-readable strings diff --git a/src/uu/numfmt/src/numfmt.rs b/src/uu/numfmt/src/numfmt.rs index dbe769ed5..b026bec2d 100644 --- a/src/uu/numfmt/src/numfmt.rs +++ b/src/uu/numfmt/src/numfmt.rs @@ -15,7 +15,7 @@ use units::{IEC_BASES, SI_BASES}; use uucore::display::Quotable; use uucore::error::UResult; use uucore::ranges::Range; -use uucore::{format_usage, help_section, InvalidEncodingHandling}; +use uucore::{format_usage, help_section, help_usage, InvalidEncodingHandling}; pub mod errors; pub mod format; @@ -24,7 +24,7 @@ mod units; const ABOUT: &str = help_section!("about"); const LONG_HELP: &str = help_section!("long help"); -const USAGE: &str = "{} [OPTION]... [NUMBER]..."; +const USAGE: &str = help_usage!(); fn handle_args<'a>(args: impl Iterator, options: &NumfmtOptions) -> UResult<()> { for l in args { diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 3b40d1460..26667d9d7 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -37,6 +37,69 @@ pub fn main(_args: TokenStream, stream: TokenStream) -> TokenStream { TokenStream::from(new) } +fn parse_help(section: &str) -> String { + let section = section.to_lowercase(); + let section = section.trim_matches('"'); + let mut content = String::new(); + let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); + + // The package name will be something like uu_numfmt, hence we split once + // on '_' and take the second element. The help section should then be in a + // file called numfmt.md + path.push(format!( + "{}.md", + std::env::var("CARGO_PKG_NAME") + .unwrap() + .split_once('_') + .unwrap() + .1, + )); + + File::open(path) + .unwrap() + .read_to_string(&mut content) + .unwrap(); + + content + .lines() + .skip_while(|&l| { + l.strip_prefix("##") + .map_or(true, |l| l.trim().to_lowercase() != section) + }) + .skip(1) + .take_while(|l| !l.starts_with("##")) + .collect::>() + .join("\n") + .trim() + .to_string() +} + +/// Get the usage from the "Usage" section in the help file. +/// +/// The usage is assumed to be surrounded by markdown code fences. It may span +/// multiple lines. The first word of each line is assumed to be the name of +/// the util and is replaced by "{}" so that the output of this function can be +/// used with `uucore::format_usage`. +#[proc_macro] +pub fn help_usage(_input: TokenStream) -> TokenStream { + let text: String = parse_help("usage") + .strip_suffix("```") + .unwrap() + .lines() + .skip(1) // Skip the "```" of markdown syntax + .map(|l| { + // Replace the util name (assumed to be the first word) with "{}" + // to be replaced with the runtime value later. + if let Some((_util, args)) = l.split_once(' ') { + format!("{{}} {}", args) + } else { + "{}".to_string() + } + }) + .collect(); + TokenTree::Literal(Literal::string(&text)).into() +} + /// Reads a section from the help file of the util as a `str` literal. /// /// It is read verbatim, without parsing or escaping. The name of the help file @@ -61,41 +124,6 @@ pub fn help_section(input: TokenStream) -> TokenStream { _ => panic!("Input to help_section should be a string literal!"), }; let input_str: String = value.parse().unwrap(); - let input_str = input_str.to_lowercase().trim_matches('"').to_string(); - - let mut content = String::new(); - let mut path = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR").unwrap()); - - // The package name will be something like uu_numfmt, hence we split once - // on '_' and take the second element. The help section should then be in a - // file called numfmt.md - path.push(format!( - "{}.md", - std::env::var("CARGO_PKG_NAME") - .unwrap() - .split_once('_') - .unwrap() - .1, - )); - - File::open(path) - .unwrap() - .read_to_string(&mut content) - .unwrap(); - - let text = content - .lines() - .skip_while(|&l| { - l.strip_prefix("##") - .map_or(true, |l| l.trim().to_lowercase() != input_str) - }) - .skip(1) - .take_while(|l| !l.starts_with("##")) - .collect::>() - .join("\n") - .trim() - .to_string(); - - let str = TokenTree::Literal(Literal::string(&text)); - str.into() + let text = parse_help(&input_str); + TokenTree::Literal(Literal::string(&text)).into() }