forc/cli/commands/
completions.rs1use std::fmt::Display;
2
3use clap::{Command as ClapCommand, CommandFactory, Parser};
4use clap_complete::{generate, Generator, Shell};
5use forc_util::ForcResult;
6
7#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum)]
8enum Target {
9 Bash,
11 Elvish,
13 Fish,
15 PowerShell,
17 Zsh,
19 Fig,
21}
22
23impl Display for Target {
24 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25 write!(
26 f,
27 "{}",
28 match self {
29 Target::Bash => "bash".to_string(),
30 Target::Elvish => "elvish".to_string(),
31 Target::Fish => "fish".to_string(),
32 Target::PowerShell => "powershell".to_string(),
33 Target::Zsh => "zsh".to_string(),
34 Target::Fig => "fig".to_string(),
35 }
36 )
37 }
38}
39
40#[derive(Debug, Parser)]
42pub struct Command {
43 #[clap(short = 'T', long, value_enum)]
49 target: Target,
50}
51
52pub(crate) fn exec(command: Command) -> ForcResult<()> {
53 let mut cmd = super::super::Opt::command();
54 match command.target {
55 Target::Fig => print_completions(clap_complete_fig::Fig, &mut cmd),
56 Target::Bash => print_completions(Shell::Bash, &mut cmd),
57 Target::Elvish => print_completions(Shell::Elvish, &mut cmd),
58 Target::PowerShell => print_completions(Shell::PowerShell, &mut cmd),
59 Target::Zsh => print_completions(Shell::Zsh, &mut cmd),
60 Target::Fish => print_completions(Shell::Fish, &mut cmd),
61 }
62 Ok(())
63}
64
65fn print_completions<G: Generator>(gen: G, cmd: &mut ClapCommand) {
66 generate(gen, cmd, cmd.get_name().to_string(), &mut std::io::stdout());
67}
68
69#[cfg(test)]
70mod test {
71 use super::*;
72 use crate::cli::{Forc, Opt};
73
74 #[test]
75 fn bash() {
76 testsuite::<completest_pty::BashRuntimeBuilder>(Shell::Bash);
77 }
78
79 #[test]
80 fn zsh() {
81 testsuite::<completest_pty::ZshRuntimeBuilder>(Shell::Zsh);
82 }
83
84 #[test]
85 fn fish() {
86 testsuite::<completest_pty::FishRuntimeBuilder>(Shell::Fish);
87 }
88
89 fn testsuite<R>(shell: Shell)
90 where
91 R: completest_pty::RuntimeBuilder,
92 {
93 let bin_root = "/tmp/bin".into();
94 let home = "/tmp/home".into();
95 let runtime = R::new(bin_root, home).expect("runtime");
96 build_script_and_test(runtime, shell, "forc", &Forc::possible_values());
97 }
98
99 fn build_script_and_test<R>(
100 mut runtime: R,
101 shell: Shell,
102 command_to_complete: &str,
103 expectations: &[&str],
104 ) where
105 R: completest_pty::Runtime,
106 {
107 let term = completest_pty::Term::new();
108 let mut cmd = Opt::command();
109 let mut completion_script = Vec::<u8>::new();
110
111 generate(shell, &mut cmd, "forc".to_owned(), &mut completion_script);
112
113 runtime
114 .register("forc", &String::from_utf8_lossy(&completion_script))
115 .expect("register completion script");
116
117 let output =
118 if let Ok(output) = runtime.complete(&format!("{command_to_complete} \t\t"), &term) {
119 output
120 } else {
121 println!("Skipping {shell}");
122 return;
123 };
124
125 for expectation in expectations {
126 assert!(
127 output.contains(expectation),
128 "Failed find {expectation} in {output}"
129 );
130 }
131 }
132}