pimalaya_cli/clap/commands/
completion.rs1use std::{fmt, fs, path::PathBuf};
2
3use anyhow::Result;
4use clap::{Command, Parser, value_parser};
5use clap_complete::Shell;
6use log::debug;
7use serde::{Serialize, Serializer};
8
9use crate::{clap::parsers::path_parser, printer::Printer};
10
11#[derive(Debug, Parser)]
18pub struct CompletionCommand {
19 #[arg(value_parser = value_parser!(Shell))]
21 pub shells: Vec<Shell>,
22
23 #[arg(short, long, value_name = "PATH", value_parser = path_parser, default_value = "./")]
25 pub dir: PathBuf,
26}
27
28impl CompletionCommand {
29 pub fn execute(self, printer: &mut impl Printer, mut command: Command) -> Result<()> {
31 let dir = self.dir.canonicalize().unwrap_or(self.dir);
32 fs::create_dir_all(&dir)?;
33
34 let cmd_name = command.get_name().to_string();
35 let mut scripts = Vec::with_capacity(5);
36
37 for shell in self.shells {
38 let path = clap_complete::generate_to(shell, &mut command, &cmd_name, &dir)?;
39 let path = path.canonicalize().unwrap_or(path);
40 debug!("generated {shell} completion script at {}", path.display());
41 scripts.push(Script { shell, path })
42 }
43
44 printer.out(Completions { dir, scripts })
45 }
46}
47
48#[derive(Serialize)]
50struct Completions {
51 dir: PathBuf,
52 scripts: Vec<Script>,
53}
54
55impl fmt::Display for Completions {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 let n = self.scripts.len();
58 let p = self.dir.display();
59 writeln!(f, "{n} completion script(s) successfully generated in {p}:")?;
60
61 for Script { shell, path } in &self.scripts {
62 let p = path.display();
63 writeln!(f, " - {shell} completion script at {p}")?;
64 }
65
66 Ok(())
67 }
68}
69
70#[derive(Serialize)]
72struct Script {
73 #[serde(serialize_with = "serialize_shell")]
74 pub shell: Shell,
75 pub path: PathBuf,
76}
77
78pub fn serialize_shell<S: Serializer>(shell: &Shell, s: S) -> Result<S::Ok, S::Error> {
79 s.serialize_str(&shell.to_string())
80}