1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 04:27:45 +00:00

uudoc: support after_help and read directly from markdown file

This commit is contained in:
Terts Diepraam 2022-11-18 16:00:44 +01:00 committed by Sylvestre Ledru
parent e307f624e8
commit e155a5ea6d
2 changed files with 74 additions and 1 deletions

View file

@ -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<ZipArchive<File>>,
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
markdown: Option<String>,
}
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, "</dl>\n")
}
fn markdown_section(&self, section: &str) -> Option<String> {
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, &section))
.skip(1)
.take_while(|l| !l.starts_with("##"))
.collect::<Vec<_>>()
.join("\n")
.trim()
.to_string();
if result != "" {
Some(result)
} else {
None
}
}
}
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {

View file

@ -1,4 +1,5 @@
// Copyright (C) ~ Roy Ivy III <rivy.dev@gmail.com>; 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(&section, &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`.