Skip to content

Commit 4401473

Browse files
committed
feat: add generate-shell-completion subcommand
1 parent 57edf25 commit 4401473

File tree

4 files changed

+66
-2
lines changed

4 files changed

+66
-2
lines changed

src/command.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
use std::path::PathBuf;
22

3-
use clap::Subcommand;
3+
use clap::{Subcommand, ValueHint};
4+
use clap_complete::Shell;
45
use globset::Glob;
56

67
use crate::output::Format;
78

89
pub mod check;
10+
pub mod generate_shell_completion;
911

1012
#[derive(Subcommand)]
1113
#[allow(clippy::exhaustive_enums)]
1214
pub enum Command {
1315
/// Check markdown on the given files or directories
1416
Check {
1517
/// List of files or directories to check
16-
#[arg(default_value = ".")]
18+
#[arg(default_value = ".", value_hint = ValueHint::AnyPath)]
1719
files: Vec<PathBuf>,
1820

1921
/// Output format for violations. The default format is "concise"
@@ -28,4 +30,9 @@ pub enum Command {
2830
#[arg(long, value_delimiter = ',')]
2931
exclude: Option<Vec<Glob>>,
3032
},
33+
/// Generate shell completion
34+
GenerateShellCompletion {
35+
/// Shell to generate a completion script
36+
shell: Shell,
37+
},
3138
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use std::io;
2+
3+
use clap::Command;
4+
use clap_complete::{generate, Generator};
5+
6+
#[derive(Debug, Clone)]
7+
pub struct ShellCompletionGenerator {
8+
cmd: Command,
9+
}
10+
11+
impl ShellCompletionGenerator {
12+
#[inline]
13+
#[must_use]
14+
pub const fn new(cmd: Command) -> Self {
15+
Self { cmd }
16+
}
17+
18+
#[inline]
19+
pub fn generate<G: Generator>(&mut self, gen: G) {
20+
let name = self.cmd.get_name().to_owned();
21+
generate(gen, &mut self.cmd, name, &mut io::stdout());
22+
}
23+
}

src/main.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
1717

1818
use std::process::ExitCode;
1919

20+
use clap::CommandFactory as _;
2021
use clap::Parser as _;
2122
use mado::command::check::Options;
2223
use miette::Result;
2324

2425
use mado::command::check::Checker;
26+
use mado::command::generate_shell_completion::ShellCompletionGenerator;
2527
use mado::Cli;
2628
use mado::Command;
2729

@@ -45,5 +47,11 @@ fn main() -> Result<ExitCode> {
4547
let checker = Checker::new(files, config)?;
4648
checker.check()
4749
}
50+
Command::GenerateShellCompletion { shell } => {
51+
let cmd = Cli::command();
52+
let mut generator = ShellCompletionGenerator::new(cmd);
53+
generator.generate(*shell);
54+
Ok(ExitCode::SUCCESS)
55+
}
4856
}
4957
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use assert_cmd::Command;
2+
use indoc::indoc;
3+
use miette::{IntoDiagnostic as _, Result};
4+
5+
#[test]
6+
fn generate_shell_completion_zsh() -> Result<()> {
7+
let mut cmd = Command::cargo_bin("mado").into_diagnostic()?;
8+
let assert = cmd.args(["generate-shell-completion", "zsh"]).assert();
9+
assert.success();
10+
Ok(())
11+
}
12+
13+
#[test]
14+
fn generate_shell_completion_invalid() -> Result<()> {
15+
let mut cmd = Command::cargo_bin("mado").into_diagnostic()?;
16+
let assert = cmd.args(["generate-shell-completion", "foo"]).assert();
17+
assert
18+
.failure()
19+
.stderr(indoc! {"
20+
\u{1b}[1m\u{1b}[31merror:\u{1b}[0m invalid value \'\u{1b}[33mfoo\u{1b}[0m\' for \'\u{1b}[1m<SHELL>\u{1b}[0m\'
21+
[possible values: \u{1b}[32mbash\u{1b}[0m, \u{1b}[32melvish\u{1b}[0m, \u{1b}[32mfish\u{1b}[0m, \u{1b}[32mpowershell\u{1b}[0m, \u{1b}[32mzsh\u{1b}[0m]
22+
23+
For more information, try \'\u{1b}[1m--help\u{1b}[0m\'.
24+
"});
25+
Ok(())
26+
}

0 commit comments

Comments
 (0)