1use crate::error::UsageErr;
2use crate::Spec;
3
4mod bash;
5mod fish;
6mod nu;
7mod powershell;
8mod zsh;
9
10pub struct CompleteOptions {
12 pub usage_bin: String,
14 pub shell: String,
16 pub bin: String,
18 pub cache_key: Option<String>,
20 pub spec: Option<Spec>,
22 pub usage_cmd: Option<String>,
24 pub source_file: Option<String>,
26}
27
28pub fn complete(options: &CompleteOptions) -> Result<String, UsageErr> {
42 let viewed;
43 let effective;
44 let options = if let Some((spec, view)) = options
45 .spec
46 .as_ref()
47 .and_then(|spec| spec.view_for_program(&options.bin).map(|view| (spec, view)))
48 {
49 viewed = spec.for_view(view)?;
50 effective = CompleteOptions {
51 usage_bin: options.usage_bin.clone(),
52 shell: options.shell.clone(),
53 bin: options.bin.clone(),
54 cache_key: options.cache_key.clone(),
55 spec: Some(viewed),
56 usage_cmd: options.usage_cmd.clone(),
57 source_file: options.source_file.clone(),
58 };
59 &effective
60 } else {
61 options
62 };
63 match options.shell.as_str() {
64 "bash" => Ok(bash::complete_bash(options)),
65 "fish" => Ok(fish::complete_fish(options)),
66 "nu" => Ok(nu::complete_nu(options)),
67 "powershell" => Ok(powershell::complete_powershell(options)),
68 "zsh" => Ok(zsh::complete_zsh(options)),
69 _ => Err(UsageErr::UnsupportedShell(options.shell.clone())),
70 }
71}
72
73pub fn complete_init(shell: &str, usage_bin: &str) -> Result<String, UsageErr> {
83 match shell {
84 "bash" => Ok(bash::complete_bash_init(usage_bin)),
85 "fish" => Ok(fish::complete_fish_init(usage_bin)),
86 "zsh" => Ok(zsh::complete_zsh_init(usage_bin)),
87 _ => Err(UsageErr::UnsupportedShell(shell.to_string())),
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
96 fn complete_init_supported_shells() {
97 for shell in ["bash", "zsh", "fish"] {
98 let out = complete_init(shell, "usage").expect("supported shell");
99 assert!(!out.is_empty(), "{shell} init should not be empty");
100 }
101 }
102
103 #[test]
104 fn complete_init_rejects_unsupported_shell() {
105 let err = complete_init("nu", "usage").expect_err("nu has no init script");
106 assert!(matches!(err, UsageErr::UnsupportedShell(ref s) if s == "nu"));
107 }
108}