xtask/completions/
mod.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use clap::Parser;
5use std::io::IsTerminal;
6use std::io::Write;
7
8#[derive(Clone, clap::ValueEnum)]
9enum Shell {
10    Zsh,
11}
12
13/// Emit shell-completion script
14#[derive(Parser)]
15pub struct Completions {
16    /// Supported shells
17    shell: Shell,
18}
19
20impl Completions {
21    pub fn run(self) -> anyhow::Result<()> {
22        match self.shell {
23            Shell::Zsh => {
24                std::io::stdout().write_all(include_bytes!("./complete.zsh"))?;
25                if std::io::stdout().is_terminal() {
26                    eprintln!(
27                        "{}",
28                        ZSH_HELP.replace(
29                            "<<CMD_PATH>>",
30                            &std::env::current_exe()?.display().to_string()
31                        )
32                    );
33                }
34            }
35        }
36
37        Ok(())
38    }
39}
40
41const ZSH_HELP: &str = r#"
42# To enable `cargo xtask` completions, there are two steps:
43#
44# 1. Use `rustup completions cargo` to set up `cargo` completions.
45# 2. Copy this script into your `.zshrc`
46#
47# NOTE: This is _not_ your typical `zsh` completion!
48#
49# No need to `compdef` anything. Just make sure that the `_cargo-xtask` function
50# is in-scope, and that `rustup completions cargo` infrastructure redirect
51# `cargo xtask` completions to that function.
52"#;
53
54pub(crate) struct XtaskCompleteFactory {
55    pub ctx: crate::XtaskCtx,
56}
57
58impl clap_dyn_complete::CustomCompleterFactory for XtaskCompleteFactory {
59    type CustomCompleter = XtaskComplete;
60    async fn build(&self, _ctx: &clap_dyn_complete::RootCtx<'_>) -> Self::CustomCompleter {
61        XtaskComplete {
62            ctx: self.ctx.clone(),
63        }
64    }
65}
66
67pub(crate) struct XtaskComplete {
68    ctx: crate::XtaskCtx,
69}
70
71impl clap_dyn_complete::CustomCompleter for XtaskComplete {
72    async fn complete(
73        &self,
74        _ctx: &clap_dyn_complete::RootCtx<'_>,
75        command_path: &[&str],
76        arg_id: &str,
77    ) -> Vec<String> {
78        match (command_path, arg_id) {
79            (["xtask", "fuzz", cmd], "target")
80                if matches!(
81                    *cmd,
82                    "run"
83                        | "build"
84                        | "clean"
85                        | "fmt"
86                        | "cmin"
87                        | "tmin"
88                        | "coverage"
89                        | "onefuzz-allowlist"
90                ) =>
91            {
92                crate::tasks::cli_completions::fuzz::complete_fuzzer_targets(&self.ctx)
93            }
94            _ => Vec::new(),
95        }
96    }
97}