-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcmd_completion.rs
155 lines (140 loc) · 5 KB
/
cmd_completion.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use anyhow::Result;
use clap::{Command, CommandFactory, Parser};
use clap_complete::{generate, Shell};
/// Generate shell completion scripts.
///
/// When installing `zoo` CLI through a package manager, it's possible that
/// no additional shell configuration is necessary to gain completion support. For
/// Homebrew, see <https://docs.brew.sh/Shell-Completion>.
///
/// If you need to set up completions manually, follow the instructions below. The exact
/// config file locations might vary based on your system. Make sure to restart your
/// shell before testing whether completions are working.
///
/// ### bash
///
/// First, ensure that you install `bash-completion` using your package manager.
///
/// After, add this to your `~/.bash_profile`:
///
/// eval "$(zoo completion -s bash)"
///
/// ### zsh
/// Generate a `_zoo` completion script and put it somewhere in your `$fpath`:
///
/// zoo completion -s zsh > /usr/local/share/zsh/site-functions/_zoo
///
/// Ensure that the following is present in your `~/.zshrc`:
///
/// autoload -U compinit
/// compinit -i
///
/// Zsh version 5.7 or later is recommended.
///
/// ### fish
///
/// Generate a `zoo.fish` completion script:
///
/// zoo completion -s fish > ~/.config/fish/completions/zoo.fish
///
/// ### PowerShell
///
/// Open your profile script with:
///
/// mkdir -Path (Split-Path -Parent $profile) -ErrorAction SilentlyContinue
/// notepad $profile
///
/// Add the line and save the file:
///
/// Invoke-Expression -Command $(zoo completion -s powershell | Out-String)
#[derive(Parser, Debug, Clone)]
#[clap(verbatim_doc_comment)]
pub struct CmdCompletion {
/// The shell type.
#[clap(short, long, default_value = "bash", value_enum)]
pub shell: Shell,
}
#[async_trait::async_trait(?Send)]
impl crate::cmd::Command for CmdCompletion {
async fn run(&self, ctx: &mut crate::context::Context) -> Result<()> {
// Convert our opts into a clap app.
let mut app: Command = crate::Opts::command();
let name = app.get_name().to_string();
// Generate the completion script.
generate(self.shell, &mut app, name, &mut ctx.io.out);
// Add a new line.
writeln!(ctx.io.out)?;
Ok(())
}
}
#[cfg(test)]
mod test {
use clap::ValueEnum;
use pretty_assertions::assert_eq;
use crate::cmd::Command;
pub struct TestItem {
name: String,
input: String,
want_out: String,
want_err: String,
}
#[tokio::test(flavor = "multi_thread")]
async fn test_cmd_completion_get() {
let tests = vec![
TestItem {
name: "bash completion".to_string(),
input: "bash".to_string(),
want_out: "complete -F _zoo -o nosort -o bashdefault -o default zoo".to_string(),
want_err: "".to_string(),
},
TestItem {
name: "zsh completion".to_string(),
input: "zsh".to_string(),
want_out: "#compdef zoo".to_string(),
want_err: "".to_string(),
},
TestItem {
name: "fish completion".to_string(),
input: "fish".to_string(),
want_out: "complete -c zoo ".to_string(),
want_err: "".to_string(),
},
TestItem {
name: "PowerShell completion".to_string(),
input: "powershell".to_string(),
want_out: "Register-ArgumentCompleter".to_string(),
want_err: "".to_string(),
},
TestItem {
name: "unsupported shell".to_string(),
input: "csh".to_string(),
want_out: "".to_string(),
want_err: "invalid variant: csh".to_string(),
},
];
for t in tests {
if let Err(e) = clap_complete::Shell::from_str(&t.input, true) {
assert_eq!(e.to_string(), t.want_err, "test {}", t.name);
continue;
}
let cmd = crate::cmd_completion::CmdCompletion {
shell: clap_complete::Shell::from_str(&t.input, true).unwrap(),
};
let (io, stdout_path, stderr_path) = crate::iostreams::IoStreams::test();
let mut config = crate::config::new_blank_config().unwrap();
let mut c = crate::config_from_env::EnvConfig::inherit_env(&mut config);
let mut ctx = crate::context::Context {
config: &mut c,
io,
debug: false,
};
cmd.run(&mut ctx).await.unwrap();
let stdout = std::fs::read_to_string(&stdout_path).unwrap();
let stderr = std::fs::read_to_string(&stderr_path).unwrap();
assert_eq!(stdout.is_empty(), t.want_out.is_empty());
assert!(stdout.contains(&t.want_out), "test {}", t.name);
assert_eq!(stderr.is_empty(), t.want_err.is_empty());
assert!(stderr.contains(&t.want_err), "test {}", t.name);
}
}
}