1use std::io;
21use std::path::{Path, PathBuf};
22
23use clap::Command as Cmd;
24pub use clap_complete::Shell;
26
27use super::family::Family;
28
29fn named_commands(family: &'static Family) -> Vec<(String, u8, Cmd)> {
32 let mut all: Vec<(String, u8, Cmd)> = family
33 .tools
34 .iter()
35 .map(|tool| {
36 (
37 tool.name.to_string(),
38 tool.section,
39 super::tool_command(family, tool),
40 )
41 })
42 .collect();
43 all.push((family.repo.to_string(), 1, super::repo_command(family)));
44 all
45}
46
47pub fn man_pages(family: &'static Family, share: &Path) -> io::Result<Vec<PathBuf>> {
51 let mut written = Vec::new();
52 for (name, section, cmd) in named_commands(family) {
53 let dir = share.join("man").join(format!("man{section}"));
54 std::fs::create_dir_all(&dir)?;
55 let cmd = cmd.version(family.version);
58 let skip: Vec<&str> = if name == family.repo {
62 family.tools.iter().map(|t| t.verb).collect()
63 } else {
64 Vec::new()
65 };
66 write_pages(family, &dir, section, &name, cmd, &skip, &mut written)?;
67 }
68 Ok(written)
69}
70
71fn write_pages(
72 family: &Family,
73 dir: &Path,
74 section: u8,
75 name: &str,
76 cmd: Cmd,
77 skip: &[&str],
78 written: &mut Vec<PathBuf>,
79) -> io::Result<()> {
80 let path = dir.join(format!("{name}.{section}"));
81 let mut page = Vec::new();
82 let leaked: &'static str = Box::leak(name.to_string().into_boxed_str());
84 clap_mangen::Man::new(cmd.clone().name(leaked))
85 .title(name.to_uppercase())
86 .section(section.to_string())
87 .source(format!("{} {}", family.crate_name, family.version))
88 .manual(family.repo)
89 .render(&mut page)?;
90 std::fs::write(&path, page)?;
91 written.push(path);
92 for sub in cmd.get_subcommands() {
93 if sub.is_hide_set() || sub.get_name() == "help" || skip.contains(&sub.get_name()) {
94 continue;
95 }
96 let sub_name = format!("{name}-{}", sub.get_name());
97 write_pages(family, dir, section, &sub_name, sub.clone(), &[], written)?;
98 }
99 Ok(())
100}
101
102pub fn completion_path(share: &Path, shell: Shell, name: &str) -> PathBuf {
104 match shell {
105 Shell::Zsh => share.join("zsh/site-functions").join(format!("_{name}")),
106 Shell::Bash => share.join("bash-completion/completions").join(name),
107 Shell::Fish => share
108 .join("fish/vendor_completions.d")
109 .join(format!("{name}.fish")),
110 other => share.join(other.to_string()).join(name),
111 }
112}
113
114pub const SHELLS: [Shell; 3] = [Shell::Zsh, Shell::Bash, Shell::Fish];
116
117pub fn completions(family: &'static Family, share: &Path) -> io::Result<Vec<PathBuf>> {
120 let mut written = Vec::new();
121 for (name, _, mut cmd) in named_commands(family) {
122 for shell in SHELLS {
123 let path = completion_path(share, shell, &name);
124 std::fs::create_dir_all(path.parent().expect("a completion has a directory"))?;
125 let mut script = Vec::new();
126 clap_complete::generate(shell, &mut cmd, name.clone(), &mut script);
127 std::fs::write(&path, script)?;
128 written.push(path);
129 }
130 }
131 Ok(written)
132}