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

docs: show platforms for each util

This commit is contained in:
Terts Diepraam 2022-04-07 15:12:21 +02:00
parent 5a3434161d
commit 3c09c747dd
2 changed files with 221 additions and 132 deletions

11
docs/theme/head.hbs vendored
View file

@ -5,10 +5,17 @@
main {
position: relative;
}
.version {
.additional {
position: absolute;
top: 1em;
top: 0em;
right: 0;
display: flex;
gap: 5px;
align-items: center;
font-size: 1.3em;
}
.platforms {
font-size: 1.5em;
}
dd > p {
margin-top: 0.2em;

View file

@ -5,6 +5,7 @@
// spell-checker:ignore tldr
use clap::Command;
use std::collections::HashMap;
use std::ffi::OsString;
use std::fs::File;
use std::io::Cursor;
@ -29,6 +30,7 @@ fn main() -> io::Result<()> {
x => x,
}?;
println!("Writing initial info to SUMMARY.md");
let mut summary = File::create("docs/src/SUMMARY.md")?;
let _ = write!(
@ -44,6 +46,40 @@ fn main() -> io::Result<()> {
* [Multi-call binary](multicall.md)\n",
);
println!("Gathering utils per platform");
let utils_per_platform = {
let mut map = HashMap::new();
for platform in ["unix", "macos", "windows"] {
let platform_utils: Vec<String> = String::from_utf8(
std::process::Command::new("./util/show-utils.sh")
.arg(format!("--features=feat_os_{}", platform))
.output()?
.stdout,
)
.unwrap()
.split(' ')
.map(ToString::to_string)
.collect();
map.insert(platform, platform_utils);
}
// Linux is a special case because it can support selinux
let platform_utils: Vec<String> = String::from_utf8(
std::process::Command::new("./util/show-utils.sh")
.arg("--features=feat_os_unix feat_selinux")
.output()?
.stdout,
)
.unwrap()
.split(' ')
.map(ToString::to_string)
.collect();
map.insert("linux", platform_utils);
map
};
println!("Writing to utils");
let mut utils = utils.entries().collect::<Vec<_>>();
utils.sort();
for (&name, (_, command)) in utils {
@ -52,7 +88,14 @@ fn main() -> io::Result<()> {
}
let p = format!("docs/src/utils/{}.md", name);
if let Ok(f) = File::create(&p) {
write_markdown(f, &mut command(), name, &mut tldr_zip)?;
MDWriter {
w: Box::new(f),
command: command(),
name,
tldr_zip: &mut tldr_zip,
utils_per_platform: &utils_per_platform,
}
.markdown()?;
println!("Wrote to '{}'", p);
} else {
println!("Error writing to {}", p);
@ -62,31 +105,65 @@ fn main() -> io::Result<()> {
Ok(())
}
fn write_markdown(
mut w: impl Write,
command: &mut Command,
name: &str,
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
) -> io::Result<()> {
write!(w, "# {}\n\n", name)?;
write_version(&mut w, command)?;
write_usage(&mut w, command, name)?;
write_description(&mut w, command)?;
write_options(&mut w, command)?;
write_examples(&mut w, name, tldr_zip)
struct MDWriter<'a, 'b> {
w: Box<dyn Write>,
command: Command<'a>,
name: &'a str,
tldr_zip: &'b mut ZipArchive<Cursor<Vec<u8>>>,
utils_per_platform: &'b HashMap<&'b str, Vec<String>>,
}
fn write_version(w: &mut impl Write, command: &Command) -> io::Result<()> {
impl<'a, 'b> MDWriter<'a, 'b> {
fn markdown(&mut self) -> io::Result<()> {
write!(self.w, "# {}\n\n", self.name)?;
self.additional()?;
self.usage()?;
self.description()?;
self.options()?;
self.examples()
}
fn additional(&mut self) -> io::Result<()> {
writeln!(self.w, "<div class=\"additional\">")?;
self.platforms()?;
self.version()?;
writeln!(self.w, "</div>")
}
fn platforms(&mut self) -> io::Result<()> {
writeln!(self.w, "<div class=\"platforms\">")?;
for (feature, icon) in [
("linux", "linux"),
// freebsd is disabled for now because mdbook does not use font-awesome 5 yet.
// ("unix", "freebsd"),
("macos", "apple"),
("windows", "windows"),
] {
if self.name.contains("sum")
|| self.utils_per_platform[feature]
.iter()
.any(|u| u == self.name)
{
writeln!(self.w, "<i class=\"fa-brands fa-{}\"></i>", icon)?;
}
}
writeln!(self.w, "</div>")?;
Ok(())
}
fn version(&mut self) -> io::Result<()> {
writeln!(
w,
"<div class=\"version\">version: {}</div>",
command.render_version().split_once(' ').unwrap().1
self.w,
"<div class=\"version\">v{}</div>",
self.command.render_version().split_once(' ').unwrap().1
)
}
}
fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Result<()> {
writeln!(w, "\n```")?;
let mut usage: String = command
fn usage(&mut self) -> io::Result<()> {
writeln!(self.w, "\n```")?;
let mut usage: String = self
.command
.render_usage()
.lines()
.skip(1)
@ -94,81 +171,79 @@ fn write_usage(w: &mut impl Write, command: &mut Command, name: &str) -> io::Res
.filter(|l| !l.is_empty())
.collect::<Vec<_>>()
.join("\n");
usage = usage.replace(uucore::execution_phrase(), name);
writeln!(w, "{}", usage)?;
writeln!(w, "```")
}
usage = usage.replace(uucore::execution_phrase(), self.name);
writeln!(self.w, "{}", usage)?;
writeln!(self.w, "```")
}
fn write_description(w: &mut impl Write, command: &Command) -> io::Result<()> {
if let Some(about) = command.get_long_about().or_else(|| command.get_about()) {
writeln!(w, "{}", about)
fn description(&mut self) -> io::Result<()> {
if let Some(about) = self
.command
.get_long_about()
.or_else(|| self.command.get_about())
{
writeln!(self.w, "{}", about)
} else {
Ok(())
}
}
}
fn write_examples(
w: &mut impl Write,
name: &str,
tldr_zip: &mut zip::ZipArchive<impl Read + Seek>,
) -> io::Result<()> {
let content = if let Some(f) = get_zip_content(tldr_zip, &format!("pages/common/{}.md", name)) {
fn examples(&mut self) -> io::Result<()> {
let content = if let Some(f) =
get_zip_content(self.tldr_zip, &format!("pages/common/{}.md", self.name))
{
f
} else if let Some(f) = get_zip_content(tldr_zip, &format!("pages/linux/{}.md", name)) {
} else if let Some(f) =
get_zip_content(self.tldr_zip, &format!("pages/linux/{}.md", self.name))
{
f
} else {
return Ok(());
};
writeln!(w, "## Examples")?;
writeln!(w)?;
writeln!(self.w, "## Examples")?;
writeln!(self.w)?;
for line in content.lines().skip_while(|l| !l.starts_with('-')) {
if let Some(l) = line.strip_prefix("- ") {
writeln!(w, "{}", l)?;
writeln!(self.w, "{}", l)?;
} else if line.starts_with('`') {
writeln!(w, "```shell\n{}\n```", line.trim_matches('`'))?;
writeln!(self.w, "```shell\n{}\n```", line.trim_matches('`'))?;
} else if line.is_empty() {
writeln!(w)?;
writeln!(self.w)?;
} else {
println!("Not sure what to do with this line:");
println!("{}", line);
}
}
writeln!(w)?;
writeln!(self.w)?;
writeln!(
w,
self.w,
"> 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!(w, ">")?;
writeln!(self.w, ">")?;
writeln!(
w,
self.w,
"> Please note that, as uutils is a work in progress, some examples might fail."
)
}
}
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {
let mut s = String::new();
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
Some(s)
}
fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> {
writeln!(w, "<h2>Options</h2>")?;
write!(w, "<dl>")?;
for arg in command.get_arguments() {
write!(w, "<dt>")?;
fn options(&mut self) -> io::Result<()> {
writeln!(self.w, "<h2>Options</h2>")?;
write!(self.w, "<dl>")?;
for arg in self.command.get_arguments() {
write!(self.w, "<dt>")?;
let mut first = true;
for l in arg.get_long_and_visible_aliases().unwrap_or_default() {
if !first {
write!(w, ", ")?;
write!(self.w, ", ")?;
} else {
first = false;
}
write!(w, "<code>")?;
write!(w, "--{}", l)?;
write!(self.w, "<code>")?;
write!(self.w, "--{}", l)?;
if let Some(names) = arg.get_value_names() {
write!(
w,
self.w,
"={}",
names
.iter()
@ -177,19 +252,19 @@ fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> {
.join(" ")
)?;
}
write!(w, "</code>")?;
write!(self.w, "</code>")?;
}
for s in arg.get_short_and_visible_aliases().unwrap_or_default() {
if !first {
write!(w, ", ")?;
write!(self.w, ", ")?;
} else {
first = false;
}
write!(w, "<code>")?;
write!(w, "-{}", s)?;
write!(self.w, "<code>")?;
write!(self.w, "-{}", s)?;
if let Some(names) = arg.get_value_names() {
write!(
w,
self.w,
" {}",
names
.iter()
@ -198,14 +273,21 @@ fn write_options(w: &mut impl Write, command: &Command) -> io::Result<()> {
.join(" ")
)?;
}
write!(w, "</code>")?;
write!(self.w, "</code>")?;
}
writeln!(w, "</dt>")?;
writeln!(self.w, "</dt>")?;
writeln!(
w,
self.w,
"<dd>\n\n{}\n\n</dd>",
arg.get_help().unwrap_or_default().replace('\n', "<br />")
)?;
}
writeln!(w, "</dl>\n")
writeln!(self.w, "</dl>\n")
}
}
fn get_zip_content(archive: &mut ZipArchive<impl Read + Seek>, name: &str) -> Option<String> {
let mut s = String::new();
archive.by_name(name).ok()?.read_to_string(&mut s).unwrap();
Some(s)
}