use crate::cli::Cli;
use crate::config::Config;
use crate::fs_wrappers;
use crate::mkdev_error::Context;
use crate::mkdev_error::Error;
use std::io::{BufWriter, ErrorKind};
use std::path::{Path, PathBuf};
use clap::CommandFactory;
use clap::{crate_name, crate_version};
use clap_mangen::Man;
use clap_mangen::roff::{Roff, bold, roman};
use confique::meta::Meta;
use rust_i18n::t;
pub fn hook(args: &Cli) -> Result<(), Error> {
if args.man_page {
let command = Cli::command();
let out_dir = Path::new("mkdev-man");
fs_wrappers::create_dir_all(out_dir, Context::Man)?;
let to_render: Vec<(clap::Command, Option<&str>)> = vec![(command.clone(), None)]
.into_iter()
.chain(
command
.get_subcommands()
.map(|sc| (sc.to_owned(), Some("mk"))),
)
.collect();
to_render
.into_iter()
.try_for_each(|(command, name)| -> Result<(), Error> {
let man = Man::new(command.clone());
let base_filename = man.get_filename();
let filename = match name {
Some(n) => format!("{n}-{base_filename}"),
None => base_filename,
};
let path = out_dir.join(&filename);
let file = fs_wrappers::file_create(&path, Context::Man)?;
let mut writer = BufWriter::new(file);
man.render(&mut writer).map_err(|e| match e.kind() {
ErrorKind::PermissionDenied => Error::FsDenied {
which: path.clone(),
context: Context::Man,
},
ErrorKind::StorageFull => {
let what: PathBuf = path.clone();
crate::die!(
"{}",
t!("warnings.storage_full", what => what.to_string_lossy())
)
}
_ => crate::borked!(e),
})?;
Ok(())
})?;
man5()?;
std::process::exit(0);
}
Ok(())
}
fn man5() -> Result<(), Error> {
let mut roff = Roff::new();
roff
.control(
"TH",
[
"mkdev-config",
"5",
" ",
concat!(crate_name!(), " ", crate_version!()),
"File Formats and Configuration",
],
)
.control("SH", ["NAME"])
.text([roman("mkdev-config - Configuration file for mkdev")])
.control("SH", ["DESCRIPTION"])
.text([
bold("mkdev"),
roman(concat!(
" stores its configuration file at ~/.config/mkdev/config.toml by default.",
" This can be overridden with the --config flag or CONFIG environment variable;",
" see "
)),
bold("mk(1)"),
])
.control("SH", ["CONFIGURATION OPTIONS"])
.control("SS", ["global options"]);
insert_opts(&mut roff, &<Config as confique::Config>::META);
roff.control("SH", ["SEE ALSO"]).text([
bold("mk(1)"),
roman(", "),
bold("mk-evoke(1)"),
roman(", "),
bold("mk-list(1)"),
]);
let path = "mkdev-man/mkdev-config.5";
let man5_file = fs_wrappers::file_create(path, Context::Man)?;
let mut w = BufWriter::new(man5_file);
roff.to_writer(&mut w).map_err(|e| match e.kind() {
ErrorKind::PermissionDenied => Error::FsDenied {
which: path.into(),
context: Context::Man,
},
ErrorKind::StorageFull => {
let what: PathBuf = path.into();
crate::die!(
"{}",
t!("warnings.storage_full", what => what.to_string_lossy())
)
}
_ => crate::borked!(e),
})?;
Ok(())
}
fn insert_opts(roff: &mut Roff, meta_root: &Meta) {
use confique::meta::FieldKind;
meta_root.fields.iter().for_each(|field| match field.kind {
FieldKind::Leaf { .. } => {
let description = field
.doc
.iter()
.map(|s| s.trim())
.take_while(|s| !s.is_empty())
.collect::<Vec<_>>()
.join(" ");
let defaults = field
.doc
.iter()
.map(|s| s.trim())
.skip_while(|s| !s.starts_with("Default:"))
.skip(1)
.collect::<Vec<_>>();
roff.control("TP", [])
.text([bold(field.name)])
.text([roman(description)])
.control("sp", [])
.text([bold("Default:")])
.control("br", []);
for default in defaults.into_iter() {
roff.control("br", []).text([roman(default)]);
}
}
FieldKind::Nested { meta, .. } => {
roff.control("SS", [field.name])
.text([roman(field.doc.first().map_or("", |s| (*s).trim()))]);
insert_opts(roff, meta);
}
});
}