mdsf/
cli.rs

1use std::io::Read;
2
3use clap::{Args, Parser, Subcommand};
4
5const HELP_TEMPLATE: &str = "\
6{before-help}{name} {version}
7{about-with-newline}{author-with-newline}
8{usage-heading} {usage}
9
10{all-args}{after-help}
11";
12
13#[derive(Parser, Debug)]
14#[command(author, version, about, long_about = None, propagate_version = true, help_template = HELP_TEMPLATE)]
15pub struct Cli {
16    #[command(subcommand)]
17    pub command: Commands,
18}
19
20#[derive(Subcommand, Debug)]
21pub enum Commands {
22    /// Run formatters on input files.
23    Format(FormatCommandArguments),
24
25    /// Verify files are formatted.
26    Verify(VerifyCommandArguments),
27
28    /// Create a new mdsf config.
29    Init,
30
31    /// Generate shell completion.
32    Completions(CompletionsCommandArguments),
33
34    /// Remove caches.
35    CachePrune,
36}
37
38#[derive(Args, Debug)]
39pub struct FormatCommandArguments {
40    /// Path to files and/or directories.
41    #[arg()]
42    pub input: Vec<std::path::PathBuf>,
43
44    /// Read input from stdin and write output to stdout
45    #[arg(long, default_value_t = false)]
46    pub stdin: bool,
47
48    /// Path to config
49    #[arg(long)]
50    pub config: Option<std::path::PathBuf>,
51
52    /// Log stdout and stderr of formatters
53    #[arg(long, default_value_t = false)]
54    pub debug: bool,
55
56    #[arg(long, value_enum)]
57    pub log_level: Option<LogLevel>,
58
59    /// Amount of threads to use.
60    ///
61    /// Defaults to 0 (auto).
62    #[arg(long)]
63    pub threads: Option<usize>,
64
65    /// Cache results
66    #[arg(long, default_value_t = false)]
67    pub cache: bool,
68
69    /// Tool timeout in seconds
70    ///
71    /// Defaults to no timeout
72    #[arg(long)]
73    pub timeout: Option<u64>,
74}
75
76#[derive(Args, Debug)]
77pub struct VerifyCommandArguments {
78    /// Path to files and/or directories.
79    #[arg()]
80    pub input: Vec<std::path::PathBuf>,
81
82    /// Read input from stdin and write output to stdout
83    #[arg(long, default_value_t = false)]
84    pub stdin: bool,
85
86    /// Path to config
87    #[arg(long)]
88    pub config: Option<std::path::PathBuf>,
89
90    /// Log stdout and stderr of formatters
91    #[arg(long, default_value_t = false)]
92    pub debug: bool,
93
94    #[arg(long, value_enum)]
95    pub log_level: Option<LogLevel>,
96
97    /// Amount of threads to use.
98    ///
99    /// Defaults to 0 (auto).
100    #[arg(long)]
101    pub threads: Option<usize>,
102
103    /// Tool timeout in seconds
104    ///
105    /// Defaults to no timeout
106    #[arg(long)]
107    pub timeout: Option<u64>,
108}
109
110impl From<VerifyCommandArguments> for FormatCommandArguments {
111    #[inline]
112    fn from(value: VerifyCommandArguments) -> Self {
113        Self {
114            input: value.input,
115            stdin: value.stdin,
116            config: value.config,
117            debug: value.debug,
118            log_level: value.log_level,
119            threads: value.threads,
120            timeout: value.timeout,
121            cache: false,
122        }
123    }
124}
125
126#[derive(clap::ValueEnum, Clone, Copy, PartialEq, Eq, Debug, Default)]
127pub enum LogLevel {
128    Trace,
129    #[default]
130    Debug,
131    Info,
132    Warn,
133    Error,
134    Off,
135}
136
137#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
138pub enum Shell {
139    /// Bourne Again `SHell` (bash)
140    Bash,
141
142    /// Elvish shell (elvish)
143    Elvish,
144
145    /// Friendly Interactive `SHell` (fish)
146    Fish,
147
148    /// `Nushell` (nushell)
149    Nushell,
150
151    /// `PowerShell` (powershell)
152    PowerShell,
153
154    /// Z `SHell` (zsh)
155    Zsh,
156}
157
158impl clap::ValueEnum for Shell {
159    fn value_variants<'a>() -> &'a [Self] {
160        &[
161            Self::Bash,
162            Self::Elvish,
163            Self::Fish,
164            Self::Nushell,
165            Self::PowerShell,
166            Self::Zsh,
167        ]
168    }
169
170    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
171        Some(match self {
172            Self::Bash => clap::builder::PossibleValue::new("bash"),
173            Self::Elvish => clap::builder::PossibleValue::new("elvish"),
174            Self::Fish => clap::builder::PossibleValue::new("fish"),
175            Self::Nushell => clap::builder::PossibleValue::new("nushell"),
176            Self::PowerShell => clap::builder::PossibleValue::new("powershell"),
177            Self::Zsh => clap::builder::PossibleValue::new("zsh"),
178        })
179    }
180}
181
182#[derive(Args, Debug)]
183pub struct CompletionsCommandArguments {
184    pub shell: Shell,
185}
186
187#[derive(Args, Debug)]
188pub struct CachePruneArguments {}
189
190#[inline]
191pub fn read_stdin() -> std::io::Result<String> {
192    let stdin = std::io::stdin();
193
194    let mut input = String::new();
195
196    stdin.lock().read_to_string(&mut input)?;
197
198    Ok(input)
199}