clap_utilities/
completion_generator.rs1use clap::{CommandFactory, Parser};
2use clap_complete::{generate, Shell};
3use derive_more::{Display, Error};
4use std::{
5 fs::File,
6 io,
7 path::{Path, PathBuf},
8 process::ExitCode,
9};
10
11#[derive(Debug, Parser)]
13pub struct CompletionGenerator {
14 #[clap(long, short)]
16 name: String,
17 #[clap(long, short, value_enum)]
19 shell: Shell,
20 #[clap(long, short)]
22 output: PathBuf,
23}
24
25#[derive(Debug, Display, Error)]
27#[display("Failed to create file {}: {error}", path.to_string_lossy())]
28pub struct CreateFileError {
29 #[error(not(source))]
31 path: PathBuf,
32 #[error(source)]
34 error: io::Error,
35}
36
37impl CreateFileError {
38 fn new(path: PathBuf, error: io::Error) -> Self {
40 Self { path, error }
41 }
42
43 pub fn path(&self) -> &Path {
45 &self.path
46 }
47
48 pub fn source(&self) -> &io::Error {
50 &self.error
51 }
52}
53
54#[derive(Debug, Display, Error)]
56#[non_exhaustive]
57pub enum Error {
58 CreateFile(CreateFileError),
60}
61
62impl CompletionGenerator {
63 pub fn run<App: CommandFactory>(self) -> Result<(), Error> {
65 let CompletionGenerator {
66 name,
67 shell,
68 output,
69 } = self;
70 let mut cmd = App::command();
71 let mut output_file = match File::create(&output) {
72 Ok(output_file) => output_file,
73 Err(error) => return Err(Error::CreateFile(CreateFileError::new(output, error))),
74 };
75 generate(shell, &mut cmd, name, &mut output_file);
76 Ok(())
77 }
78
79 pub fn main<App: CommandFactory>() -> ExitCode {
81 match CompletionGenerator::parse().run::<App>() {
82 Ok(()) => ExitCode::SUCCESS,
83 Err(error) => {
84 eprintln!("{error}");
85 ExitCode::FAILURE
86 }
87 }
88 }
89}