diff --git a/README.md b/README.md index 44135ce5..0c120c45 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ Below are a few of the features which `clap` supports, full descriptions and usa * Generate a CLI simply by defining a struct! * **Auto-generated Help, Version, and Usage information** - Can optionally be fully, or partially overridden if you want a custom help, version, or usage statements -* **Auto-generated completion scripts (Bash, Zsh, Fish, Elvish and PowerShell)** +* **Auto-generated completion scripts (Bash, Zsh, Fish, Fig, Elvish and PowerShell)** - Using [`clap_generate`](https://github.com/clap-rs/clap/tree/master/clap_generate) - Even works through many multiple levels of subcommands - Works with options which only accept certain values diff --git a/clap_derive/examples/value_hints_derive.rs b/clap_derive/examples/value_hints_derive.rs index d0be2c00..88d7ed6e 100644 --- a/clap_derive/examples/value_hints_derive.rs +++ b/clap_derive/examples/value_hints_derive.rs @@ -13,7 +13,7 @@ //! ./target/debug/examples/value_hints_derive -- //! ``` use clap::{App, AppSettings, ArgEnum, Clap, IntoApp, ValueHint}; -use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh}; +use clap_generate::generators::{Bash, Elvish, Fig, Fish, PowerShell, Zsh}; use clap_generate::{generate, Generator}; use std::ffi::OsString; use std::io; @@ -23,6 +23,7 @@ use std::path::PathBuf; enum GeneratorChoice { Bash, Elvish, + Fig, Fish, #[clap(name = "powershell")] PowerShell, @@ -82,6 +83,7 @@ fn main() { match generator { GeneratorChoice::Bash => print_completions::(&mut app), GeneratorChoice::Elvish => print_completions::(&mut app), + GeneratorChoice::Fig => print_completions::(&mut app), GeneratorChoice::Fish => print_completions::(&mut app), GeneratorChoice::PowerShell => print_completions::(&mut app), GeneratorChoice::Zsh => print_completions::(&mut app), diff --git a/clap_generate/examples/value_hints.rs b/clap_generate/examples/value_hints.rs index 43113883..b97ee422 100644 --- a/clap_generate/examples/value_hints.rs +++ b/clap_generate/examples/value_hints.rs @@ -13,7 +13,7 @@ //! ./target/debug/examples/value_hints -- //! ``` use clap::{App, AppSettings, Arg, ValueHint}; -use clap_generate::generators::{Bash, Elvish, Fish, PowerShell, Zsh}; +use clap_generate::generators::{Bash, Elvish, Fig, Fish, PowerShell, Zsh}; use clap_generate::{generate, Generator}; use std::io; @@ -25,6 +25,7 @@ fn build_cli() -> App<'static> { .arg(Arg::new("generator").long("generate").possible_values([ "bash", "elvish", + "fig", "fish", "powershell", "zsh", @@ -109,6 +110,7 @@ fn main() { match generator { "bash" => print_completions::(&mut app), "elvish" => print_completions::(&mut app), + "fig" => print_completions::(&mut app), "fish" => print_completions::(&mut app), "powershell" => print_completions::(&mut app), "zsh" => print_completions::(&mut app), diff --git a/clap_generate/src/generators/shells/fig.rs b/clap_generate/src/generators/shells/fig.rs new file mode 100644 index 00000000..72b75925 --- /dev/null +++ b/clap_generate/src/generators/shells/fig.rs @@ -0,0 +1,305 @@ +// Std +use std::io::Write; + +// Internal +use crate::Generator; +use clap::*; + +/// Generate fig completion file +pub struct Fig; + +impl Generator for Fig { + fn file_name(name: &str) -> String { + format!("{}.ts", name) + } + + fn generate(app: &App, buf: &mut dyn Write) { + let command = app.get_bin_name().unwrap(); + let mut buffer = String::new(); + + buffer.push_str(&format!( + "const completion: Fig.Spec = {{\n name: \"{}\",\n", + command + )); + + buffer.push_str(&format!( + " description: \"{}\",\n", + app.get_about().unwrap_or_default() + )); + + gen_fig_inner(command, &[], 2, app, &mut buffer); + + buffer.push_str("};\n\nexport default completion;\n"); + + w!(buf, buffer.as_bytes()); + } +} + +// Escape string inside double quotes +fn escape_string(string: &str) -> String { + string.replace("\\", "\\\\").replace("\"", "\\\"") +} + +fn gen_fig_inner( + root_command: &str, + parent_commands: &[&str], + indent: usize, + app: &App, + buffer: &mut String, +) { + debug!("gen_fig_inner: parent_commands={:?}", parent_commands); + + if app.has_subcommands() { + buffer.push_str(&format!("{:indent$}subcommands: [\n", "", indent = indent)); + // generate subcommands + for subcommand in app.get_subcommands() { + buffer.push_str(&format!( + "{:indent$}{{\n{:indent$} name: \"{}\",\n", + "", + "", + subcommand.get_name(), + indent = indent + 2 + )); + + if let Some(data) = subcommand.get_about() { + buffer.push_str(&format!( + "{:indent$}description: \"{}\",\n", + "", + escape_string(data), + indent = indent + 4 + )); + } + + let mut parent_commands: Vec<_> = parent_commands.into(); + parent_commands.push(subcommand.get_name()); + gen_fig_inner( + root_command, + &parent_commands, + indent + 4, + subcommand, + buffer, + ); + + buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2)); + } + buffer.push_str(&format!("{:indent$}],\n", "", indent = indent)); + } + + buffer.push_str(&gen_options(app, indent)); + + let args = app.get_positionals().collect::>(); + + match args.len() { + 0 => {} + 1 => { + buffer.push_str(&format!("{:indent$}args: ", "", indent = indent)); + + buffer.push_str(&gen_args(args[0], indent)); + } + _ => { + buffer.push_str(&format!("{:indent$}args: [\n", "", indent = indent)); + for arg in args { + buffer.push_str(&gen_args(arg, indent)); + } + buffer.push_str(&format!("{:indent$}]\n", "", indent = indent)); + } + }; +} + +fn gen_options(app: &App, indent: usize) -> String { + let mut buffer = String::new(); + + buffer.push_str(&format!("{:indent$}options: [\n", "", indent = indent)); + + for option in app.get_opts() { + buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2)); + + let mut names = vec![]; + + if let Some(shorts) = option.get_short_and_visible_aliases() { + names.extend(shorts.iter().map(|short| format!("-{}", short))); + } + + if let Some(longs) = option.get_long_and_visible_aliases() { + names.extend(longs.iter().map(|long| format!("--{}", long))); + } + + if names.len() > 1 { + buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4)); + + buffer.push_str( + &names + .iter() + .map(|name| format!("\"{}\"", name)) + .collect::>() + .join(", "), + ); + + buffer.push_str("],\n"); + } else { + buffer.push_str(&format!( + "{:indent$}name: \"{}\",\n", + "", + names[0], + indent = indent + 4 + )); + } + + if let Some(data) = option.get_about() { + buffer.push_str(&format!( + "{:indent$}description: \"{}\",\n", + "", + escape_string(data), + indent = indent + 4 + )); + } + + buffer.push_str(&format!("{:indent$}args: ", "", indent = indent + 4)); + + buffer.push_str(&gen_args(option, indent + 4)); + + buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2)); + } + + for flag in Fig::flags(app) { + buffer.push_str(&format!("{:indent$}{{\n", "", indent = indent + 2)); + + let mut flags = vec![]; + + if let Some(shorts) = flag.get_short_and_visible_aliases() { + flags.extend(shorts.iter().map(|s| format!("-{}", s))); + } + + if let Some(longs) = flag.get_long_and_visible_aliases() { + flags.extend(longs.iter().map(|s| format!("--{}", s))); + } + + if flags.len() > 1 { + buffer.push_str(&format!("{:indent$}name: [", "", indent = indent + 4)); + + buffer.push_str( + &flags + .iter() + .map(|name| format!("\"{}\"", name)) + .collect::>() + .join(", "), + ); + + buffer.push_str("],\n"); + } else { + buffer.push_str(&format!( + "{:indent$}name: \"{}\",\n", + "", + flags[0], + indent = indent + 4 + )); + } + + if let Some(data) = flag.get_about() { + buffer.push_str(&format!( + "{:indent$}description: \"{}\",\n", + "", + escape_string(data).as_str(), + indent = indent + 4 + )); + } + + buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 2)); + } + + buffer.push_str(&format!("{:indent$}],\n", "", indent = indent)); + + buffer +} + +fn gen_args(arg: &Arg, indent: usize) -> String { + if !arg.is_set(ArgSettings::TakesValue) { + return "".to_string(); + } + + let mut buffer = String::new(); + + buffer.push_str(&format!( + "{{\n{:indent$} name: \"{}\",\n", + "", + arg.get_name(), + indent = indent + )); + + if arg.is_set(ArgSettings::MultipleValues) { + buffer.push_str(&format!( + "{:indent$}isVariadic: true,\n", + "", + indent = indent + 2 + )); + } + + if !arg.is_set(ArgSettings::Required) { + buffer.push_str(&format!( + "{:indent$}isOptional: true,\n", + "", + indent = indent + 2 + )); + } + + if let Some(data) = arg.get_possible_values() { + buffer.push_str(&format!( + "{:indent$}suggestions: [\n", + "", + indent = indent + 2 + )); + + for value in data { + buffer.push_str(&format!( + "{:indent$}{{\n{:indent$} name: \"{}\",\n", + "", + "", + value.get_name(), + indent = indent + 4, + )); + + if let Some(about) = value.get_about() { + buffer.push_str(&format!( + "{:indent$}description: \"{}\",\n", + "", + escape_string(about), + indent = indent + 4 + )); + } + + buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent + 4)); + } + + buffer.push_str(&format!("{:indent$}]\n", "", indent = indent + 2)); + } else { + match arg.get_value_hint() { + ValueHint::AnyPath | ValueHint::FilePath | ValueHint::ExecutablePath => { + buffer.push_str(&format!( + "{:indent$}template: \"filepaths\",\n", + "", + indent = indent + 2 + )); + } + ValueHint::DirPath => { + buffer.push_str(&format!( + "{:indent$}template: \"folders\",\n", + "", + indent = indent + 2 + )); + } + ValueHint::CommandString | ValueHint::CommandName | ValueHint::CommandWithArguments => { + buffer.push_str(&format!( + "{:indent$}isCommand: true,\n", + "", + indent = indent + 2 + )); + } + // Disable completion for others + _ => (), + }; + }; + + buffer.push_str(&format!("{:indent$}}},\n", "", indent = indent)); + + buffer +} diff --git a/clap_generate/src/generators/shells/mod.rs b/clap_generate/src/generators/shells/mod.rs index ef3f4e52..6cece693 100644 --- a/clap_generate/src/generators/shells/mod.rs +++ b/clap_generate/src/generators/shells/mod.rs @@ -1,11 +1,13 @@ mod bash; mod elvish; +mod fig; mod fish; mod powershell; mod zsh; pub use bash::Bash; pub use elvish::Elvish; +pub use fig::Fig; pub use fish::Fish; pub use powershell::PowerShell; pub use zsh::Zsh; diff --git a/clap_generate/src/shell.rs b/clap_generate/src/shell.rs index 229c45ef..0aa5ce9d 100644 --- a/clap_generate/src/shell.rs +++ b/clap_generate/src/shell.rs @@ -9,6 +9,8 @@ pub enum Shell { Bash, /// Elvish shell Elvish, + /// Fig autocomplete + Fig, /// Friendly Interactive SHell (fish) Fish, /// PowerShell @@ -19,8 +21,8 @@ pub enum Shell { impl Shell { /// A list of supported shells in `[&'static str]` form. - pub fn variants() -> [&'static str; 5] { - ["bash", "elvish", "fish", "powershell", "zsh"] + pub fn variants() -> [&'static str; 6] { + ["bash", "elvish", "fig", "fish", "powershell", "zsh"] } } @@ -29,6 +31,7 @@ impl Display for Shell { match *self { Shell::Bash => write!(f, "bash"), Shell::Elvish => write!(f, "elvish"), + Shell::Fig => write!(f, "fig"), Shell::Fish => write!(f, "fish"), Shell::PowerShell => write!(f, "powershell"), Shell::Zsh => write!(f, "zsh"), @@ -43,11 +46,12 @@ impl FromStr for Shell { match s.to_ascii_lowercase().as_str() { "bash" => Ok(Shell::Bash), "elvish" => Ok(Shell::Elvish), + "fig" => Ok(Shell::Fig), "fish" => Ok(Shell::Fish), "powershell" => Ok(Shell::PowerShell), "zsh" => Ok(Shell::Zsh), _ => Err(String::from( - "[valid values: bash, elvish, fish, powershell, zsh]", + "[valid values: bash, elvish, fig, fish, powershell, zsh]", )), } } diff --git a/clap_generate/tests/completions/fig.rs b/clap_generate/tests/completions/fig.rs new file mode 100644 index 00000000..060cc76a --- /dev/null +++ b/clap_generate/tests/completions/fig.rs @@ -0,0 +1,466 @@ +use super::*; + +fn build_app() -> App<'static> { + build_app_with_name("myapp") +} + +fn build_app_with_name(s: &'static str) -> App<'static> { + App::new(s) + .about("Tests completions") + .arg( + Arg::new("file") + .value_hint(ValueHint::FilePath) + .about("some input file"), + ) + .subcommand( + App::new("test").about("tests things").arg( + Arg::new("case") + .long("case") + .takes_value(true) + .about("the case to test"), + ), + ) +} + +#[test] +fn fig() { + let mut app = build_app(); + common::(&mut app, "myapp", FIG); +} + +static FIG: &str = r#"const completion: Fig.Spec = { + name: "myapp", + description: "Tests completions", + subcommands: [ + { + name: "test", + description: "tests things", + options: [ + { + name: "--case", + description: "the case to test", + args: { + name: "case", + isOptional: true, + }, + }, + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "help", + description: "Print this message or the help of the given subcommand(s)", + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + ], + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + args: { + name: "file", + isOptional: true, + template: "filepaths", + }, +}; + +export default completion; +"#; + +#[test] +fn fig_with_special_commands() { + let mut app = build_app_special_commands(); + common::(&mut app, "my_app", FIG_SPECIAL_CMDS); +} + +fn build_app_special_commands() -> App<'static> { + build_app_with_name("my_app") + .subcommand( + App::new("some_cmd").about("tests other things").arg( + Arg::new("config") + .long("--config") + .takes_value(true) + .about("the other case to test"), + ), + ) + .subcommand(App::new("some-cmd-with-hypens").alias("hyphen")) +} + +static FIG_SPECIAL_CMDS: &str = r#"const completion: Fig.Spec = { + name: "my_app", + description: "Tests completions", + subcommands: [ + { + name: "test", + description: "tests things", + options: [ + { + name: "--case", + description: "the case to test", + args: { + name: "case", + isOptional: true, + }, + }, + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "some_cmd", + description: "tests other things", + options: [ + { + name: "--config", + description: "the other case to test", + args: { + name: "config", + isOptional: true, + }, + }, + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "some-cmd-with-hypens", + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "help", + description: "Print this message or the help of the given subcommand(s)", + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + ], + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + args: { + name: "file", + isOptional: true, + template: "filepaths", + }, +}; + +export default completion; +"#; + +#[test] +fn fig_with_special_help() { + let mut app = build_app_special_help(); + common::(&mut app, "my_app", FIG_SPECIAL_HELP); +} + +fn build_app_special_help() -> App<'static> { + App::new("my_app") + .arg( + Arg::new("single-quotes") + .long("single-quotes") + .about("Can be 'always', 'auto', or 'never'"), + ) + .arg( + Arg::new("double-quotes") + .long("double-quotes") + .about("Can be \"always\", \"auto\", or \"never\""), + ) + .arg( + Arg::new("backticks") + .long("backticks") + .about("For more information see `echo test`"), + ) + .arg(Arg::new("backslash").long("backslash").about("Avoid '\\n'")) + .arg( + Arg::new("brackets") + .long("brackets") + .about("List packages [filter]"), + ) + .arg( + Arg::new("expansions") + .long("expansions") + .about("Execute the shell command with $SHELL"), + ) +} + +static FIG_SPECIAL_HELP: &str = r#"const completion: Fig.Spec = { + name: "my_app", + description: "", + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + { + name: "--single-quotes", + description: "Can be 'always', 'auto', or 'never'", + }, + { + name: "--double-quotes", + description: "Can be \"always\", \"auto\", or \"never\"", + }, + { + name: "--backticks", + description: "For more information see `echo test`", + }, + { + name: "--backslash", + description: "Avoid '\\n'", + }, + { + name: "--brackets", + description: "List packages [filter]", + }, + { + name: "--expansions", + description: "Execute the shell command with $SHELL", + }, + ], +}; + +export default completion; +"#; + +#[test] +fn fig_with_aliases() { + let mut app = build_app_with_aliases(); + common::(&mut app, "cmd", FIG_ALIASES); +} + +fn build_app_with_aliases() -> App<'static> { + App::new("cmd") + .about("testing bash completions") + .arg( + Arg::new("flag") + .short('f') + .visible_short_alias('F') + .long("flag") + .visible_alias("flg") + .about("cmd flag"), + ) + .arg( + Arg::new("option") + .short('o') + .visible_short_alias('O') + .long("option") + .visible_alias("opt") + .about("cmd option") + .takes_value(true), + ) + .arg(Arg::new("positional")) +} + +static FIG_ALIASES: &str = r#"const completion: Fig.Spec = { + name: "cmd", + description: "testing bash completions", + options: [ + { + name: ["-o", "-O", "--option", "--opt"], + description: "cmd option", + args: { + name: "option", + isOptional: true, + }, + }, + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + { + name: ["-f", "-F", "--flag", "--flg"], + description: "cmd flag", + }, + ], + args: { + name: "positional", + isOptional: true, + }, +}; + +export default completion; +"#; + +#[test] +fn fig_with_sub_subcommands() { + let mut app = build_app_sub_subcommands(); + common::(&mut app, "my_app", FIG_SUB_SUBCMDS); +} + +fn build_app_sub_subcommands() -> App<'static> { + build_app_with_name("my_app").subcommand( + App::new("some_cmd") + .about("top level subcommand") + .subcommand( + App::new("sub_cmd").about("sub-subcommand").arg( + Arg::new("config") + .long("--config") + .takes_value(true) + .about("the other case to test"), + ), + ), + ) +} + +static FIG_SUB_SUBCMDS: &str = r#"const completion: Fig.Spec = { + name: "my_app", + description: "Tests completions", + subcommands: [ + { + name: "test", + description: "tests things", + options: [ + { + name: "--case", + description: "the case to test", + args: { + name: "case", + isOptional: true, + }, + }, + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "some_cmd", + description: "top level subcommand", + subcommands: [ + { + name: "sub_cmd", + description: "sub-subcommand", + options: [ + { + name: "--config", + description: "the other case to test", + args: { + name: "config", + isOptional: true, + }, + }, + { + name: "--help", + description: "Print help information", + }, + { + name: "--version", + description: "Print version information", + }, + ], + }, + ], + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + { + name: "help", + description: "Print this message or the help of the given subcommand(s)", + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + }, + ], + options: [ + { + name: ["-h", "--help"], + description: "Print help information", + }, + { + name: ["-V", "--version"], + description: "Print version information", + }, + ], + args: { + name: "file", + isOptional: true, + template: "filepaths", + }, +}; + +export default completion; +"#; diff --git a/clap_generate/tests/completions/mod.rs b/clap_generate/tests/completions/mod.rs index b48a656f..262cbf87 100644 --- a/clap_generate/tests/completions/mod.rs +++ b/clap_generate/tests/completions/mod.rs @@ -4,6 +4,7 @@ use std::fmt; mod bash; mod elvish; +mod fig; mod fish; mod powershell; mod zsh; diff --git a/clap_generate/tests/generate_completions.rs b/clap_generate/tests/generate_completions.rs index 32b2c47c..b57428a4 100644 --- a/clap_generate/tests/generate_completions.rs +++ b/clap_generate/tests/generate_completions.rs @@ -19,6 +19,7 @@ fn generate_completions() { ); generate::(&mut app, "test_app", &mut io::sink()); + generate::(&mut app, "test_app", &mut io::sink()); generate::(&mut app, "test_app", &mut io::sink()); generate::(&mut app, "test_app", &mut io::sink()); generate::(&mut app, "test_app", &mut io::sink()); diff --git a/clap_generate/tests/value_hints.rs b/clap_generate/tests/value_hints.rs index 12b6f949..7345a432 100644 --- a/clap_generate/tests/value_hints.rs +++ b/clap_generate/tests/value_hints.rs @@ -147,6 +147,134 @@ complete -c my_app -l email -r -f complete -c my_app -l help -d 'Print help information' "#; +static FIG_VALUE_HINTS: &str = r#"const completion: Fig.Spec = { + name: "my_app", + description: "", + options: [ + { + name: "--choice", + args: { + name: "choice", + isOptional: true, + suggestions: [ + { + name: "bash", + }, + { + name: "fish", + }, + { + name: "zsh", + }, + ] + }, + }, + { + name: "--unknown", + args: { + name: "unknown", + isOptional: true, + }, + }, + { + name: "--other", + args: { + name: "other", + isOptional: true, + }, + }, + { + name: ["-p", "--path"], + args: { + name: "path", + isOptional: true, + template: "filepaths", + }, + }, + { + name: ["-f", "--file"], + args: { + name: "file", + isOptional: true, + template: "filepaths", + }, + }, + { + name: ["-d", "--dir"], + args: { + name: "dir", + isOptional: true, + template: "folders", + }, + }, + { + name: ["-e", "--exe"], + args: { + name: "exe", + isOptional: true, + template: "filepaths", + }, + }, + { + name: "--cmd-name", + args: { + name: "cmd_name", + isOptional: true, + isCommand: true, + }, + }, + { + name: ["-c", "--cmd"], + args: { + name: "cmd", + isOptional: true, + isCommand: true, + }, + }, + { + name: ["-u", "--user"], + args: { + name: "user", + isOptional: true, + }, + }, + { + name: ["-h", "--host"], + args: { + name: "host", + isOptional: true, + }, + }, + { + name: "--url", + args: { + name: "url", + isOptional: true, + }, + }, + { + name: "--email", + args: { + name: "email", + isOptional: true, + }, + }, + { + name: "--help", + description: "Print help information", + }, + ], + args: { + name: "command_with_args", + isVariadic: true, + isOptional: true, + isCommand: true, + }, +}; + +export default completion; +"#; + #[test] fn zsh_with_value_hints() { let mut app = build_app_with_value_hints(); @@ -158,3 +286,9 @@ fn fish_with_value_hints() { let mut app = build_app_with_value_hints(); common::(&mut app, "my_app", FISH_VALUE_HINTS); } + +#[test] +fn fig_with_value_hints() { + let mut app = build_app_with_value_hints(); + common::(&mut app, "my_app", FIG_VALUE_HINTS); +}