wash_cli/
completions.rs

1//! Generate shell completion files
2
3use std::collections::HashMap;
4use std::path::PathBuf;
5
6use anyhow::{bail, Context, Result};
7use clap::{Args, Subcommand};
8use clap_complete::{generator::generate_to, shells::Shell};
9use wash_lib::cli::CommandOutput;
10use wash_lib::config::cfg_dir;
11
12const TOKEN_FILE: &str = ".completion_suggested";
13const COMPLETION_DOC_URL: &str =
14    "https://github.com/wasmCloud/wasmCloud/blob/main/crates/wash-cli/Completions.md";
15const SLACK_URL: &str = "https://slack.wasmcloud.com";
16
17fn instructions() -> String {
18    format!(
19        "🐚 Autocomplete available! To configure autocomplete with your shell, follow the instructions at\n   {}",
20        COMPLETION_DOC_URL
21    )
22}
23
24fn feedback() -> String {
25    format!(
26        "📝 Feedback wanted! If you want to suggest an improvement or would like assistance, join the community at\n   {}",
27        SLACK_URL
28    )
29}
30
31#[derive(Debug, Clone, Args)]
32pub struct CompletionOpts {
33    /// Output directory (default '.')
34    #[clap(short = 'd', long = "dir")]
35    dir: Option<PathBuf>,
36
37    /// Shell
38    #[clap(name = "shell", subcommand)]
39    shell: ShellSelection,
40}
41
42#[derive(Subcommand, Debug, Clone)]
43pub enum ShellSelection {
44    /// generate completions for Zsh
45    Zsh,
46    /// generate completions for Bash
47    Bash,
48    /// generate completions for Fish
49    Fish,
50    /// generate completions for PowerShell
51    PowerShell,
52}
53
54/// Displays a message one time after wash install
55pub fn first_run_suggestion() -> Result<Option<String>> {
56    let cfg_dir = cfg_dir()?;
57    let token = cfg_dir.join(TOKEN_FILE);
58    if token.is_file() {
59        return Ok(None);
60    }
61    let _ = std::fs::File::create(token).with_context(|| {
62        format!(
63            "can't create completion first-run token in {}",
64            cfg_dir.display()
65        )
66    })?;
67    Ok(Some(format!(
68        "Congratulations on installing wash!\n\n{}\n\n{}",
69        instructions(),
70        feedback(),
71    )))
72}
73
74pub fn handle_command(
75    opts: CompletionOpts,
76    mut command: clap::builder::Command,
77) -> Result<CommandOutput> {
78    let output_dir = opts.dir.unwrap_or_else(|| PathBuf::from("."));
79
80    let shell = match opts.shell {
81        ShellSelection::Zsh => Shell::Zsh,
82        ShellSelection::Bash => Shell::Bash,
83        ShellSelection::Fish => Shell::Fish,
84        ShellSelection::PowerShell => Shell::PowerShell,
85    };
86
87    match generate_to(shell, &mut command, "wash", &output_dir) {
88        Ok(path) => {
89            let mut map = HashMap::new();
90            map.insert(
91                "path".to_string(),
92                path.to_string_lossy().to_string().into(),
93            );
94            Ok(CommandOutput::new(
95                format!(
96                    "Generated completion file: {}. {}",
97                    path.display(),
98                    instructions()
99                ),
100                map,
101            ))
102        }
103        Err(e) => bail!(
104            "generating shell completion file in folder '{}': {}",
105            output_dir.display(),
106            e
107        ),
108    }
109}