From 3e8114dbf8c9bcdef8e6f685156f7d6aced66d8a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 9 Mar 2026 23:47:20 +0100 Subject: [PATCH 1/3] uudoc: render tldr examples as proper roff EXAMPLES section in man pages --- src/bin/uudoc.rs | 84 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 27 deletions(-) diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 76f04774ec7..85785c8f8cb 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -3,7 +3,7 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore mangen tldr +// spell-checker:ignore mangen tldr roff use std::{ collections::HashMap, @@ -79,25 +79,45 @@ fn gen_manpage( .get_matches_from(std::iter::once(OsString::from("manpage")).chain(args)); let utility = matches.get_one::("utility").unwrap(); - let command = if utility == "coreutils" { - gen_coreutils_app(util_map) + let (command, raw_examples) = if utility == "coreutils" { + (gen_coreutils_app(util_map), None) } else { validation::setup_localization_or_exit(utility); let mut cmd = util_map.get(utility).unwrap().1(); cmd.set_bin_name(utility.clone()); - let mut cmd = cmd.display_name(utility); - if let Some(zip) = tldr { - if let Ok(examples) = write_zip_examples(zip, utility, false) { - cmd = cmd.after_help(examples); - } - } - cmd + let cmd = cmd.display_name(utility); + let raw = tldr.as_mut().and_then(|zip| { + get_zip_content(zip, &format!("pages/common/{utility}.md")) + .or_else(|| get_zip_content(zip, &format!("pages/linux/{utility}.md"))) + }); + (cmd, raw) }; - let man = Man::new(command); - man.render(&mut io::stdout()) + let stdout = &mut io::stdout(); + Man::new(command) + .render(stdout) .expect("Man page generation failed"); - io::stdout().flush().unwrap(); + if let Some(content) = raw_examples { + use clap_mangen::roff::{Roff, bold, roman}; + let mut roff = Roff::default(); + roff.control("SH", ["EXAMPLES"]); + for line in content.lines().skip_while(|l| !l.starts_with('-')) { + if let Some(desc) = line.strip_prefix("- ") { + roff.text([roman(desc)]); + } else if line.starts_with('`') { + let cmd = strip_placeholders(line.trim_matches('`')); + roff.text([bold(cmd)]); + } else if line.is_empty() { + roff.control("PP", []); + } + } + roff.control("PP", []); + roff.text([roman( + "The examples are provided by the tldr-pages project under the CC BY 4.0 License. Please note that, as uutils is a work in progress, some examples might fail.", + )]); + roff.to_writer(stdout).expect("Man page generation failed"); + } + stdout.flush().unwrap(); process::exit(0); } @@ -596,21 +616,29 @@ fn write_zip_examples( } } +/// Strip tldr placeholder markers `{{` and `}}` from a command line. +fn strip_placeholders(s: &str) -> String { + s.replace("{{", "").replace("}}", "") +} + /// Format examples using std::fmt::Write fn format_examples(content: String, output_markdown: bool) -> Result { use std::fmt::Write; let mut s = String::new(); - writeln!(s)?; - writeln!(s, "## Examples")?; - writeln!(s)?; + if output_markdown { + writeln!(s)?; + writeln!(s, "## Examples")?; + writeln!(s)?; + } for line in content.lines().skip_while(|l| !l.starts_with('-')) { if let Some(l) = line.strip_prefix("- ") { writeln!(s, "{l}")?; } else if line.starts_with('`') { + let cmd = strip_placeholders(line.trim_matches('`')); if output_markdown { - writeln!(s, "```shell\n{}\n```", line.trim_matches('`'))?; + writeln!(s, "```shell\n{cmd}\n```")?; } else { - writeln!(s, "{}", line.trim_matches('`'))?; + writeln!(s, "{cmd}")?; } } else if line.is_empty() { writeln!(s)?; @@ -620,14 +648,16 @@ fn format_examples(content: String, output_markdown: bool) -> Result The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md)." - )?; - writeln!(s, ">")?; - writeln!( - s, - "> Please note that, as uutils is a work in progress, some examples might fail." - )?; + if output_markdown { + writeln!( + s, + "> The examples are provided by the [tldr-pages project](https://tldr.sh) under the [CC BY 4.0 License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md). Please note that, as uutils is a work in progress, some examples might fail." + )?; + } else { + writeln!( + s, + "The examples are provided by the tldr-pages project under the CC BY 4.0 License. Please note that, as uutils is a work in progress, some examples might fail." + )?; + } Ok(s) } From 05fe3cf1b39973b683650747ecf06c701bad516a Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 9 Mar 2026 23:50:45 +0100 Subject: [PATCH 2/3] ci: verify tldr EXAMPLES section in man page output --- .github/workflows/documentation.yml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 53f830a7911..90bdec8ff59 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -122,15 +122,10 @@ jobs: - name: Verify tldr examples integration run: | - if [ ! -f "docs/src/utils/cp.md" ]; then - echo "docs/src/utils/cp.md does not exist" - exit 1 - fi + grep -q "The examples are provided by" docs/src/utils/cp.md - if ! grep -q "The examples are provided by" docs/src/utils/cp.md; then - echo "tldr examples integration missing from cp.md" - echo "Expected to find 'The examples are provided by' text" - echo "Content of cp.md:" - tail -20 docs/src/utils/cp.md - exit 1 - fi + - name: Verify tldr examples appear in man page output + run: | + cargo run --bin uudoc --all-features -- manpage cp > /tmp/cp.1 + grep -q "\.SH EXAMPLES" /tmp/cp.1 + grep -q "tldr-pages" /tmp/cp.1 From 7cb80e298ab27abe2a63fb1a7d1ca455580941b7 Mon Sep 17 00:00:00 2001 From: Sylvestre Ledru Date: Mon, 9 Mar 2026 23:51:52 +0100 Subject: [PATCH 3/3] ci: verify no {{ }} placeholders in man page examples --- .github/workflows/documentation.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 90bdec8ff59..605985164bd 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -128,4 +128,5 @@ jobs: run: | cargo run --bin uudoc --all-features -- manpage cp > /tmp/cp.1 grep -q "\.SH EXAMPLES" /tmp/cp.1 - grep -q "tldr-pages" /tmp/cp.1 + grep -q "tldr.sh" /tmp/cp.1 + ! grep -q "{{" /tmp/cp.1