Skip to main content

smux/
docs.rs

1use std::fs;
2use std::io;
3use std::path::{Path, PathBuf};
4
5use anyhow::{Context, Result};
6use clap_complete::Shell;
7use clap_complete::aot::{generate, generate_to};
8
9use crate::cli::Cli;
10
11pub fn generate_completions(shell: Shell, dir: Option<&Path>) -> Result<Option<PathBuf>> {
12    let mut command = Cli::command();
13
14    match dir {
15        Some(dir) => {
16            fs::create_dir_all(dir).with_context(|| {
17                format!("failed to create completion directory {}", dir.display())
18            })?;
19            let path = generate_to(shell, &mut command, "smux", dir)
20                .with_context(|| format!("failed to write completions to {}", dir.display()))?;
21            Ok(Some(path))
22        }
23        None => {
24            let mut stdout = io::stdout();
25            generate(shell, &mut command, "smux", &mut stdout);
26            Ok(None)
27        }
28    }
29}
30
31pub fn generate_man_pages(dir: Option<&Path>) -> Result<Option<Vec<PathBuf>>> {
32    let command = Cli::command();
33
34    match dir {
35        Some(dir) => {
36            fs::create_dir_all(dir).with_context(|| {
37                format!("failed to create man page directory {}", dir.display())
38            })?;
39            let mut paths = Vec::new();
40            write_man_tree(command, dir, &["smux".to_owned()], &mut paths)?;
41            copy_static_man_page(dir, "smux-config.5", &mut paths)?;
42            Ok(Some(paths))
43        }
44        None => {
45            let mut buffer = Vec::new();
46            clap_mangen::Man::new(command).render(&mut buffer)?;
47            print!(
48                "{}",
49                String::from_utf8(buffer).context("generated man page was not valid utf-8")?
50            );
51            Ok(None)
52        }
53    }
54}
55
56fn write_man_tree(
57    command: clap::Command,
58    dir: &Path,
59    lineage: &[String],
60    paths: &mut Vec<PathBuf>,
61) -> Result<()> {
62    let name = lineage.join("-");
63    let static_name: &'static str = Box::leak(name.clone().into_boxed_str());
64    let command_for_page = command.clone().name(static_name).bin_name(static_name);
65    let mut buffer = Vec::new();
66    clap_mangen::Man::new(command_for_page.clone()).render(&mut buffer)?;
67
68    let path = dir.join(format!("{name}.1"));
69    fs::write(&path, &buffer)
70        .with_context(|| format!("failed to write man page {}", path.display()))?;
71    paths.push(path);
72
73    for subcommand in command_for_page
74        .get_subcommands()
75        .cloned()
76        .collect::<Vec<_>>()
77    {
78        let mut next_lineage = lineage.to_vec();
79        next_lineage.push(subcommand.get_name().to_owned());
80        write_man_tree(subcommand, dir, &next_lineage, paths)?;
81    }
82
83    Ok(())
84}
85
86fn copy_static_man_page(dir: &Path, filename: &str, paths: &mut Vec<PathBuf>) -> Result<()> {
87    let source = Path::new("docs").join(filename);
88    let destination = dir.join(filename);
89    fs::copy(&source, &destination).with_context(|| {
90        format!(
91            "failed to copy static man page {} to {}",
92            source.display(),
93            destination.display()
94        )
95    })?;
96    paths.push(destination);
97    Ok(())
98}