mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
feat(generate): Add fig autocomplete generator
This commit is contained in:
parent
5512c90380
commit
f3611ad6b9
10 changed files with 923 additions and 6 deletions
|
@ -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
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//! ./target/debug/examples/value_hints_derive --<TAB>
|
||||
//! ```
|
||||
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::<Bash>(&mut app),
|
||||
GeneratorChoice::Elvish => print_completions::<Elvish>(&mut app),
|
||||
GeneratorChoice::Fig => print_completions::<Fig>(&mut app),
|
||||
GeneratorChoice::Fish => print_completions::<Fish>(&mut app),
|
||||
GeneratorChoice::PowerShell => print_completions::<PowerShell>(&mut app),
|
||||
GeneratorChoice::Zsh => print_completions::<Zsh>(&mut app),
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//! ./target/debug/examples/value_hints --<TAB>
|
||||
//! ```
|
||||
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::<Bash>(&mut app),
|
||||
"elvish" => print_completions::<Elvish>(&mut app),
|
||||
"fig" => print_completions::<Fig>(&mut app),
|
||||
"fish" => print_completions::<Fish>(&mut app),
|
||||
"powershell" => print_completions::<PowerShell>(&mut app),
|
||||
"zsh" => print_completions::<Zsh>(&mut app),
|
||||
|
|
305
clap_generate/src/generators/shells/fig.rs
Normal file
305
clap_generate/src/generators/shells/fig.rs
Normal file
|
@ -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::<Vec<_>>();
|
||||
|
||||
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::<Vec<_>>()
|
||||
.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::<Vec<_>>()
|
||||
.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
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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]",
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
466
clap_generate/tests/completions/fig.rs
Normal file
466
clap_generate/tests/completions/fig.rs
Normal file
|
@ -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::<Fig>(&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::<Fig>(&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::<Fig>(&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::<Fig>(&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::<Fig>(&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;
|
||||
"#;
|
|
@ -4,6 +4,7 @@ use std::fmt;
|
|||
|
||||
mod bash;
|
||||
mod elvish;
|
||||
mod fig;
|
||||
mod fish;
|
||||
mod powershell;
|
||||
mod zsh;
|
||||
|
|
|
@ -19,6 +19,7 @@ fn generate_completions() {
|
|||
);
|
||||
|
||||
generate::<Bash, _>(&mut app, "test_app", &mut io::sink());
|
||||
generate::<Fig, _>(&mut app, "test_app", &mut io::sink());
|
||||
generate::<Fish, _>(&mut app, "test_app", &mut io::sink());
|
||||
generate::<PowerShell, _>(&mut app, "test_app", &mut io::sink());
|
||||
generate::<Elvish, _>(&mut app, "test_app", &mut io::sink());
|
||||
|
|
|
@ -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::<Fish>(&mut app, "my_app", FISH_VALUE_HINTS);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fig_with_value_hints() {
|
||||
let mut app = build_app_with_value_hints();
|
||||
common::<Fig>(&mut app, "my_app", FIG_VALUE_HINTS);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue