Skip to main content

hugo_server/
args.rs

1use std::{env, io};
2
3use anyhow::Result;
4use clap::builder::Styles;
5use clap::builder::styling::{AnsiColor, Style};
6use clap::{CommandFactory, Parser, ValueEnum};
7use clap_complete::Generator;
8use clap_verbosity_flag::Verbosity;
9use supports_color::Stream;
10
11#[derive(Parser)]
12#[command(about, version = version_msg(), styles = get_styles())]
13pub struct Args {
14    /// Generate shell completion to standard output
15    #[arg(long, value_enum)]
16    pub completion: Option<Shell>,
17
18    #[command(flatten)]
19    pub verbose: Verbosity,
20}
21
22#[must_use]
23fn version_msg() -> String {
24    let version = clap::crate_version!();
25    let author = clap::crate_authors!();
26    let home_page = env!("CARGO_PKG_HOMEPAGE");
27
28    format!(
29        "\
30{version}
31
32Author: {author}
33Author's Telegram: https://t.me/TerakomariGandesblood
34Project home page: {home_page}"
35    )
36}
37
38const HEADER: Style = AnsiColor::Green.on_default().bold();
39const USAGE: Style = AnsiColor::Green.on_default().bold();
40const LITERAL: Style = AnsiColor::Cyan.on_default().bold();
41const PLACEHOLDER: Style = AnsiColor::Cyan.on_default();
42const ERROR: Style = AnsiColor::Red.on_default().bold();
43const VALID: Style = AnsiColor::Cyan.on_default().bold();
44const INVALID: Style = AnsiColor::Yellow.on_default().bold();
45const HELP_STYLES: Styles = Styles::styled()
46    .header(HEADER)
47    .usage(USAGE)
48    .literal(LITERAL)
49    .placeholder(PLACEHOLDER)
50    .error(ERROR)
51    .valid(VALID)
52    .invalid(INVALID);
53
54fn get_styles() -> Styles {
55    if supports_color::on(Stream::Stdout).is_some() {
56        HELP_STYLES
57    } else {
58        Styles::plain()
59    }
60}
61
62#[must_use]
63#[derive(Clone, ValueEnum)]
64pub enum Shell {
65    Bash,
66    Elvish,
67    Fish,
68    PowerShell,
69    Zsh,
70    Nushell,
71}
72
73impl Shell {
74    fn to_clap_type(&self) -> Box<dyn Generator> {
75        match self {
76            Self::Bash => Box::new(clap_complete::Shell::Bash),
77            Self::Elvish => Box::new(clap_complete::Shell::Elvish),
78            Self::Fish => Box::new(clap_complete::Shell::Fish),
79            Self::PowerShell => Box::new(clap_complete::Shell::PowerShell),
80            Self::Zsh => Box::new(clap_complete::Shell::Zsh),
81            Self::Nushell => Box::new(clap_complete_nushell::Nushell),
82        }
83    }
84}
85
86impl Generator for Shell {
87    fn file_name(&self, name: &str) -> String {
88        self.to_clap_type().file_name(name)
89    }
90
91    fn generate(&self, cmd: &clap::Command, buf: &mut dyn io::Write) {
92        self.to_clap_type().generate(cmd, buf);
93    }
94}
95
96pub fn generate_completion(shell: Shell) -> Result<()> {
97    let mut cmd = Args::command();
98    let bin_name = cmd.get_name().to_string();
99
100    clap_complete::generate(shell, &mut cmd, bin_name, &mut io::stdout());
101
102    Ok(())
103}
104
105#[cfg(test)]
106mod tests {
107    use clap::CommandFactory;
108
109    use super::*;
110
111    #[test]
112    fn verify_cli() {
113        Args::command().debug_assert();
114    }
115}