From e155a5ea6d9cbf118d4a7dec9b8954ae614f7aa6 Mon Sep 17 00:00:00 2001 From: Terts Diepraam Date: Fri, 18 Nov 2022 16:00:44 +0100 Subject: [PATCH] uudoc: support after_help and read directly from markdown file --- src/bin/uudoc.rs | 58 +++++++++++++++++++++++++++++++++++++ src/uucore_procs/src/lib.rs | 17 ++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/bin/uudoc.rs b/src/bin/uudoc.rs index 874bdc201..fe28323f2 100644 --- a/src/bin/uudoc.rs +++ b/src/bin/uudoc.rs @@ -91,6 +91,15 @@ fn main() -> io::Result<()> { continue; } let p = format!("docs/src/utils/{}.md", name); + + let markdown = File::open(format!("src/uu/{name}/{name}.md")) + .and_then(|mut f: File| { + let mut s = String::new(); + f.read_to_string(&mut s)?; + Ok(s) + }) + .ok(); + if let Ok(f) = File::create(&p) { MDWriter { w: Box::new(f), @@ -98,6 +107,7 @@ fn main() -> io::Result<()> { name, tldr_zip: &mut tldr_zip, utils_per_platform: &utils_per_platform, + markdown, } .markdown()?; println!("Wrote to '{}'", p); @@ -115,6 +125,7 @@ struct MDWriter<'a, 'b> { name: &'a str, tldr_zip: &'b mut Option>, utils_per_platform: &'b HashMap<&'b str, Vec>, + markdown: Option, } impl<'a, 'b> MDWriter<'a, 'b> { @@ -124,6 +135,7 @@ impl<'a, 'b> MDWriter<'a, 'b> { self.usage()?; self.description()?; self.options()?; + self.after_help()?; self.examples() } @@ -184,6 +196,10 @@ impl<'a, 'b> MDWriter<'a, 'b> { } fn description(&mut self) -> io::Result<()> { + if let Some(after_help) = self.markdown_section("about") { + return writeln!(self.w, "\n\n{}", after_help); + } + if let Some(about) = self .command .get_long_about() @@ -195,6 +211,22 @@ impl<'a, 'b> MDWriter<'a, 'b> { } } + fn after_help(&mut self) -> io::Result<()> { + if let Some(after_help) = self.markdown_section("after help") { + return writeln!(self.w, "\n\n{}", after_help); + } + + if let Some(after_help) = self + .command + .get_after_long_help() + .or_else(|| self.command.get_after_help()) + { + writeln!(self.w, "\n\n{}", after_help) + } else { + Ok(()) + } + } + fn examples(&mut self) -> io::Result<()> { if let Some(zip) = self.tldr_zip { let content = if let Some(f) = @@ -295,6 +327,32 @@ impl<'a, 'b> MDWriter<'a, 'b> { } writeln!(self.w, "\n") } + + fn markdown_section(&self, section: &str) -> Option { + let md = self.markdown.as_ref()?; + let section = section.to_lowercase(); + + fn is_section_header(line: &str, section: &str) -> bool { + line.strip_prefix("##") + .map_or(false, |l| l.trim().to_lowercase() == section) + } + + let result = md + .lines() + .skip_while(|&l| !is_section_header(l, §ion)) + .skip(1) + .take_while(|l| !l.starts_with("##")) + .collect::>() + .join("\n") + .trim() + .to_string(); + + if result != "" { + Some(result) + } else { + None + } + } } fn get_zip_content(archive: &mut ZipArchive, name: &str) -> Option { diff --git a/src/uucore_procs/src/lib.rs b/src/uucore_procs/src/lib.rs index 32a247309..89ac1a749 100644 --- a/src/uucore_procs/src/lib.rs +++ b/src/uucore_procs/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (C) ~ Roy Ivy III ; MIT license +// spell-checker:ignore backticks extern crate proc_macro; use std::{fs::File, io::Read, path::PathBuf}; @@ -37,6 +38,19 @@ pub fn main(_args: TokenStream, stream: TokenStream) -> TokenStream { TokenStream::from(new) } +// FIXME: This is currently a stub. We could do much more here and could +// even pull in a full markdown parser to get better results. +/// Render markdown into a format that's easier to read in the terminal. +/// +/// For now, all this function does is remove backticks. +/// Some ideas for future improvement: +/// - Render headings as bold +/// - Convert triple backticks to indented +/// - Printing tables in a nice format +fn render_markdown(s: &str) -> String { + s.replace('`', "") +} + /// 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 @@ -81,7 +95,8 @@ pub fn help_section(input: TokenStream) -> TokenStream { let section = get_argument(&input, 0, "section"); let filename = get_argument(&input, 1, "filename"); let text = parse_help(§ion, &filename); - TokenTree::Literal(Literal::string(&text)).into() + let rendered = render_markdown(&text); + TokenTree::Literal(Literal::string(&rendered)).into() } /// Get an argument from the input vector of `TokenTree`.