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