diff --git a/Cargo.lock b/Cargo.lock index fa1e1895..2fd621e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -570,12 +570,7 @@ version = "4.3.1" dependencies = [ "clap 4.3.19", "clap_complete", - "nu-cli", - "nu-command", - "nu-parser", - "nu-protocol", - "nu-test-support", - "reedline", + "completest", "snapbox", ] @@ -646,11 +641,18 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "completest" -version = "0.0.14" +version = "0.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa515ddcd88ba6e25ed72581b38284255c9126ff2ca4fd81525f72a59187a985" +checksum = "426bfb709a07e01f5ee02dfccf42a73ef64a03ca6295a82e5c1c211a302a770e" dependencies = [ + "dunce", + "nu-cli", + "nu-command", + "nu-parser", + "nu-protocol", + "nu-test-support", "ptyprocess", + "reedline", "vt100", ] diff --git a/clap_complete/Cargo.toml b/clap_complete/Cargo.toml index 9e4c2790..63e2d979 100644 --- a/clap_complete/Cargo.toml +++ b/clap_complete/Cargo.toml @@ -43,7 +43,7 @@ unicode-xid = { version = "0.2.2", optional = true } snapbox = { version = "0.4.11", features = ["diff", "path", "examples"] } # Cutting out `filesystem` feature trycmd = { version = "0.14.16", default-features = false, features = ["color-auto", "diff", "examples"] } -completest = "0.0.14" +completest = "0.0.16" clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "derive", "help"] } [[example]] diff --git a/clap_complete/tests/testsuite/common.rs b/clap_complete/tests/testsuite/common.rs index 481dbd2d..c0cfad12 100644 --- a/clap_complete/tests/testsuite/common.rs +++ b/clap_complete/tests/testsuite/common.rs @@ -296,6 +296,96 @@ pub fn assert_matches_path( .matches_path(expected_path, buf); } +pub fn register_example(name: &str, shell: completest::Shell) { + let scratch = snapbox::path::PathFixture::mutable_temp().unwrap(); + let scratch_path = scratch.path().unwrap(); + + let shell_name = shell.name(); + let home = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests/snapshots/home") + .join(name) + .join(shell_name); + println!("Compiling"); + let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml"); + let bin_path = + snapbox::cmd::compile_example(name, ["--manifest-path", manifest_path.to_str().unwrap()]) + .unwrap(); + println!("Compiled"); + let bin_root = bin_path.parent().unwrap().to_owned(); + + let registration = std::process::Command::new(&bin_path) + .arg(format!("--generate={shell_name}")) + .output() + .unwrap(); + assert!( + registration.status.success(), + "{}", + String::from_utf8_lossy(®istration.stderr) + ); + let registration = std::str::from_utf8(®istration.stdout).unwrap(); + assert!(!registration.is_empty()); + + let mut runtime = shell.init(bin_root, scratch_path.to_owned()).unwrap(); + + runtime.register(name, registration).unwrap(); + + snapbox::assert_subset_eq(home, scratch_path); + + scratch.close().unwrap(); +} + +pub fn load_runtime(name: &str, shell: completest::Shell) -> Box { + let shell_name = shell.name(); + let home = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests/snapshots/home") + .join(name) + .join(shell_name); + let scratch = snapbox::path::PathFixture::mutable_temp() + .unwrap() + .with_template(&home) + .unwrap(); + let home = scratch.path().unwrap().to_owned(); + println!("Compiling"); + let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml"); + let bin_path = + snapbox::cmd::compile_example(name, ["--manifest-path", manifest_path.to_str().unwrap()]) + .unwrap(); + println!("Compiled"); + let bin_root = bin_path.parent().unwrap().to_owned(); + + let runtime = shell.with_home(bin_root, home).unwrap(); + + Box::new(ScratchRuntime { + _scratch: scratch, + runtime, + }) +} + +#[derive(Debug)] +struct ScratchRuntime { + _scratch: snapbox::path::PathFixture, + runtime: Box, +} + +impl completest::Runtime for ScratchRuntime { + fn home(&self) -> &std::path::Path { + self.runtime.home() + } + + fn register(&mut self, name: &str, content: &str) -> std::io::Result<()> { + self.runtime.register(name, content) + } + + fn complete(&mut self, input: &str, term: &completest::Term) -> std::io::Result { + let output = self.runtime.complete(input, term)?; + // HACK: elvish prints and clears this message when a completer takes too long which is + // dependent on a lot of factors, making this show up or no sometimes (especially if we + // aren't clearing the screen properly for fish) + let output = output.replace("\nCOMPLETING argument\n", "\n"); + Ok(output) + } +} + pub fn has_command(command: &str) -> bool { let output = match std::process::Command::new(command) .arg("--version") @@ -341,87 +431,6 @@ pub fn has_command(command: &str) -> bool { true } -#[cfg(unix)] -pub fn register_example(name: &str, shell: completest::Shell) { - let scratch = snapbox::path::PathFixture::mutable_temp().unwrap(); - let scratch_path = scratch.path().unwrap(); - - let shell_name = shell.name(); - let home = std::path::Path::new("tests/snapshots/home") - .join(name) - .join(shell_name); - let bin_path = snapbox::cmd::compile_example(name, []).unwrap(); - let bin_root = bin_path.parent().unwrap().to_owned(); - - let registration = std::process::Command::new(&bin_path) - .arg(format!("--generate={shell_name}")) - .output() - .unwrap(); - assert!( - registration.status.success(), - "{}", - String::from_utf8_lossy(®istration.stderr) - ); - let registration = std::str::from_utf8(®istration.stdout).unwrap(); - assert!(!registration.is_empty()); - - let mut runtime = shell.init(bin_root, scratch_path.to_owned()).unwrap(); - - runtime.register(name, registration).unwrap(); - - snapbox::assert_subset_eq(home, scratch_path); - - scratch.close().unwrap(); -} - -#[cfg(unix)] -pub fn load_runtime(name: &str, shell: completest::Shell) -> Box { - let shell_name = shell.name(); - let home = std::path::Path::new("tests/snapshots/home") - .join(name) - .join(shell_name); - let scratch = snapbox::path::PathFixture::mutable_temp() - .unwrap() - .with_template(&home) - .unwrap(); - let home = scratch.path().unwrap().to_owned(); - let bin_path = snapbox::cmd::compile_example(name, []).unwrap(); - let bin_root = bin_path.parent().unwrap().to_owned(); - - let runtime = shell.with_home(bin_root, home); - - Box::new(ScratchRuntime { - _scratch: scratch, - runtime, - }) -} - -#[cfg(unix)] -struct ScratchRuntime { - _scratch: snapbox::path::PathFixture, - runtime: Box, -} - -#[cfg(unix)] -impl completest::Runtime for ScratchRuntime { - fn home(&self) -> &std::path::Path { - self.runtime.home() - } - - fn register(&mut self, name: &str, content: &str) -> std::io::Result<()> { - self.runtime.register(name, content) - } - - fn complete(&mut self, input: &str, term: &completest::Term) -> std::io::Result { - let output = self.runtime.complete(input, term)?; - // HACK: elvish prints and clears this message when a completer takes too long which is - // dependent on a lot of factors, making this show up or no sometimes (especially if we - // aren't clearing the screen properly for fish) - let output = output.replace("\nCOMPLETING argument\n", "\n"); - Ok(output) - } -} - /// Whether or not this running in a Continuous Integration environment. fn is_ci() -> bool { // Consider using `tracked_env` instead of option_env! when it is stabilized. diff --git a/clap_complete_nushell/Cargo.toml b/clap_complete_nushell/Cargo.toml index c232fac1..e1d9d35f 100644 --- a/clap_complete_nushell/Cargo.toml +++ b/clap_complete_nushell/Cargo.toml @@ -35,11 +35,6 @@ clap = { path = "../", version = "4.0.0", default-features = false, features = [ clap_complete = { path = "../clap_complete", version = "4.0.0" } [dev-dependencies] -snapbox = { version = "0.4.11", features = ["diff"] } +snapbox = { version = "0.4.11", features = ["diff", "examples", "path"] } clap = { path = "../", version = "4.0.0", default-features = false, features = ["std", "help"] } -nu-cli = "0.78.0" -nu-command = "0.78.0" -nu-parser = "0.78.0" -nu-protocol = "0.78.0" -nu-test-support = "0.78.0" -reedline = "0.18.0" +completest = { version = "0.0.16", features = ["nu"] } diff --git a/clap_complete_nushell/examples/test.rs b/clap_complete_nushell/examples/test.rs new file mode 100644 index 00000000..6cfd416b --- /dev/null +++ b/clap_complete_nushell/examples/test.rs @@ -0,0 +1,170 @@ +use clap_complete::generate; +use clap_complete_nushell::Nushell; + +fn main() { + let matches = cli().get_matches(); + if matches.contains_id("generate") { + let mut cmd = cli(); + generate(Nushell, &mut cmd, "test", &mut std::io::stdout()); + } else { + println!("{:?}", matches); + } +} + +fn cli() -> clap::Command { + clap::Command::new("test") + .version("3.0") + .propagate_version(true) + .args([ + clap::Arg::new("global") + .long("global") + .global(true) + .action(clap::ArgAction::SetTrue) + .help("everywhere"), + clap::Arg::new("generate").long("generate").help("generate"), + ]) + .subcommands([ + clap::Command::new("action").args([ + clap::Arg::new("set-true") + .long("set-true") + .action(clap::ArgAction::SetTrue) + .help("bool"), + clap::Arg::new("set") + .long("set") + .action(clap::ArgAction::Set) + .help("value"), + clap::Arg::new("count") + .long("count") + .action(clap::ArgAction::Count) + .help("number"), + clap::Arg::new("choice") + .long("choice") + .value_parser(["first", "second"]) + .help("enum"), + ]), + clap::Command::new("quote") + .args([ + clap::Arg::new("single-quotes") + .long("single-quotes") + .action(clap::ArgAction::SetTrue) + .help("Can be 'always', 'auto', or 'never'"), + clap::Arg::new("double-quotes") + .long("double-quotes") + .action(clap::ArgAction::SetTrue) + .help("Can be \"always\", \"auto\", or \"never\""), + clap::Arg::new("backticks") + .long("backticks") + .action(clap::ArgAction::SetTrue) + .help("For more information see `echo test`"), + clap::Arg::new("backslash") + .long("backslash") + .action(clap::ArgAction::SetTrue) + .help("Avoid '\\n'"), + clap::Arg::new("brackets") + .long("brackets") + .action(clap::ArgAction::SetTrue) + .help("List packages [filter]"), + clap::Arg::new("expansions") + .long("expansions") + .action(clap::ArgAction::SetTrue) + .help("Execute the shell command with $SHELL"), + ]) + .subcommands([ + clap::Command::new("cmd-single-quotes") + .about("Can be 'always', 'auto', or 'never'"), + clap::Command::new("cmd-double-quotes") + .about("Can be \"always\", \"auto\", or \"never\""), + clap::Command::new("cmd-backticks") + .about("For more information see `echo test`"), + clap::Command::new("cmd-backslash").about("Avoid '\\n'"), + clap::Command::new("cmd-brackets").about("List packages [filter]"), + clap::Command::new("cmd-expansions") + .about("Execute the shell command with $SHELL"), + ]), + clap::Command::new("value").args([ + clap::Arg::new("delim").long("delim").value_delimiter(','), + clap::Arg::new("tuple").long("tuple").num_args(2), + clap::Arg::new("require-eq") + .long("require-eq") + .require_equals(true), + clap::Arg::new("term").num_args(1..).value_terminator(";"), + ]), + clap::Command::new("pacman").subcommands([ + clap::Command::new("one").long_flag("one").short_flag('o'), + clap::Command::new("two").long_flag("two").short_flag('t'), + ]), + clap::Command::new("last") + .args([clap::Arg::new("first"), clap::Arg::new("free").last(true)]), + clap::Command::new("alias").args([ + clap::Arg::new("flag") + .short('f') + .visible_short_alias('F') + .long("flag") + .action(clap::ArgAction::SetTrue) + .visible_alias("flg") + .help("cmd flag"), + clap::Arg::new("option") + .short('o') + .visible_short_alias('O') + .long("option") + .visible_alias("opt") + .help("cmd option") + .action(clap::ArgAction::Set), + clap::Arg::new("positional"), + ]), + clap::Command::new("hint").args([ + clap::Arg::new("choice") + .long("choice") + .action(clap::ArgAction::Set) + .value_parser(["bash", "fish", "zsh"]), + clap::Arg::new("unknown") + .long("unknown") + .value_hint(clap::ValueHint::Unknown), + clap::Arg::new("other") + .long("other") + .value_hint(clap::ValueHint::Other), + clap::Arg::new("path") + .long("path") + .short('p') + .value_hint(clap::ValueHint::AnyPath), + clap::Arg::new("file") + .long("file") + .short('f') + .value_hint(clap::ValueHint::FilePath), + clap::Arg::new("dir") + .long("dir") + .short('d') + .value_hint(clap::ValueHint::DirPath), + clap::Arg::new("exe") + .long("exe") + .short('e') + .value_hint(clap::ValueHint::ExecutablePath), + clap::Arg::new("cmd_name") + .long("cmd-name") + .value_hint(clap::ValueHint::CommandName), + clap::Arg::new("cmd") + .long("cmd") + .short('c') + .value_hint(clap::ValueHint::CommandString), + clap::Arg::new("command_with_args") + .action(clap::ArgAction::Set) + .num_args(1..) + .trailing_var_arg(true) + .value_hint(clap::ValueHint::CommandWithArguments), + clap::Arg::new("user") + .short('u') + .long("user") + .value_hint(clap::ValueHint::Username), + clap::Arg::new("host") + .short('H') + .long("host") + .value_hint(clap::ValueHint::Hostname), + clap::Arg::new("url") + .long("url") + .value_hint(clap::ValueHint::Url), + clap::Arg::new("email") + .long("email") + .value_hint(clap::ValueHint::EmailAddress), + ]), + ]) +} diff --git a/clap_complete_nushell/tests/common.rs b/clap_complete_nushell/tests/common.rs index e96323e6..bbf562a0 100644 --- a/clap_complete_nushell/tests/common.rs +++ b/clap_complete_nushell/tests/common.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] // shared with other test modules + use clap::{builder::PossibleValue, Arg, ArgAction, Command, ValueHint}; pub fn basic_command(name: &'static str) -> Command { @@ -244,7 +246,7 @@ pub fn value_hint_command(name: &'static str) -> Command { pub fn assert_matches_path( expected_path: impl AsRef, gen: impl clap_complete::Generator, - mut cmd: Command, + mut cmd: clap::Command, name: &'static str, ) { let mut buf = vec![]; @@ -255,3 +257,91 @@ pub fn assert_matches_path( .normalize_paths(false) .matches_path(expected_path, buf); } + +pub fn register_example(name: &str, shell: completest::Shell) { + let scratch = snapbox::path::PathFixture::mutable_temp().unwrap(); + let scratch_path = scratch.path().unwrap(); + + let shell_name = shell.name(); + let home = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests/snapshots/home") + .join(name) + .join(shell_name); + println!("Compiling"); + let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml"); + let bin_path = + snapbox::cmd::compile_example(name, ["--manifest-path", manifest_path.to_str().unwrap()]) + .unwrap(); + println!("Compiled"); + let bin_root = bin_path.parent().unwrap().to_owned(); + + let registration = std::process::Command::new(&bin_path) + .arg(format!("--generate={shell_name}")) + .output() + .unwrap(); + assert!( + registration.status.success(), + "{}", + String::from_utf8_lossy(®istration.stderr) + ); + let registration = std::str::from_utf8(®istration.stdout).unwrap(); + assert!(!registration.is_empty()); + + let mut runtime = shell.init(bin_root, scratch_path.to_owned()).unwrap(); + + runtime.register(name, registration).unwrap(); + + snapbox::assert_subset_eq(home, scratch_path); + + scratch.close().unwrap(); +} + +pub fn load_runtime(name: &str, shell: completest::Shell) -> Box { + let shell_name = shell.name(); + let home = std::path::Path::new(env!("CARGO_MANIFEST_DIR")) + .join("tests/snapshots/home") + .join(name) + .join(shell_name); + std::fs::create_dir_all(&home).unwrap(); + let scratch = snapbox::path::PathFixture::immutable(&home); + let home = scratch.path().unwrap().to_owned(); + println!("Compiling"); + let manifest_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml"); + let bin_path = + snapbox::cmd::compile_example(name, ["--manifest-path", manifest_path.to_str().unwrap()]) + .unwrap(); + println!("Compiled"); + let bin_root = bin_path.parent().unwrap().to_owned(); + + let runtime = shell.with_home(bin_root, home).unwrap(); + + Box::new(ScratchRuntime { + _scratch: scratch, + runtime, + }) +} + +#[derive(Debug)] +struct ScratchRuntime { + _scratch: snapbox::path::PathFixture, + runtime: Box, +} + +impl completest::Runtime for ScratchRuntime { + fn home(&self) -> &std::path::Path { + self.runtime.home() + } + + fn register(&mut self, name: &str, content: &str) -> std::io::Result<()> { + self.runtime.register(name, content) + } + + fn complete(&mut self, input: &str, term: &completest::Term) -> std::io::Result { + let output = self.runtime.complete(input, term)?; + // HACK: elvish prints and clears this message when a completer takes too long which is + // dependent on a lot of factors, making this show up or no sometimes (especially if we + // aren't clearing the screen properly for fish) + let output = output.replace("\nCOMPLETING argument\n", "\n"); + Ok(output) + } +} diff --git a/clap_complete_nushell/tests/completion.rs b/clap_complete_nushell/tests/completion.rs index d377180d..562cf5e9 100644 --- a/clap_complete_nushell/tests/completion.rs +++ b/clap_complete_nushell/tests/completion.rs @@ -1,326 +1,85 @@ -use std::fs::File; -use std::io::Read; -use std::path::Path; -use std::path::PathBuf; -use std::sync::Arc; +mod common; -use nu_cli::NuCompleter; -use nu_command::create_default_context; -use nu_parser::parse; -use nu_protocol::{ - engine::{EngineState, Stack, StateWorkingSet}, - Value, -}; - -use reedline::{Completer as _, Suggestion}; - -// creates a new engine with the current path into the completions fixtures folder -fn new_engine() -> (PathBuf, EngineState, Stack) { - // Target folder inside assets - let mut dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("tests"); - dir.push("snapshots"); - - let mut dir_str = dir - .clone() - .into_os_string() - .into_string() - .unwrap_or_default(); - dir_str.push(std::path::MAIN_SEPARATOR); - - // Create a new engine with default context - let mut engine_state = create_default_context(); - - // New stack - let mut stack = Stack::new(); - - // Add pwd as env var - stack.add_env_var( - "PWD".to_string(), - Value::String { - val: dir_str.clone(), - span: nu_protocol::Span::new(0, dir_str.len()), - }, - ); - - #[cfg(windows)] - stack.add_env_var( - "Path".to_string(), - Value::String { - val: "c:\\some\\path;c:\\some\\other\\path".to_string(), - span: nu_protocol::Span::new(0, dir_str.len()), - }, - ); - - #[cfg(not(windows))] - stack.add_env_var( - "PATH".to_string(), - Value::String { - val: "/some/path:/some/other/path".to_string(), - span: nu_protocol::Span::new(0, dir_str.len()), - }, - ); - - // Merge environment into the permanent state - let merge_result = engine_state.merge_env(&mut stack, &dir); - assert!(merge_result.is_ok(), "{}", merge_result.unwrap_err()); - - (dir, engine_state, stack) -} - -fn external_completion(file_name: &str) -> NuCompleter { - // Create a new engine - let (dir, mut engine_state, mut stack) = new_engine(); - - let path = dir.join(file_name); - let mut buf = Vec::new(); - let mut file = - File::open(&path).unwrap_or_else(|_| panic!("Failed to open {}", path.display())); - file.read_to_end(&mut buf) - .unwrap_or_else(|_| panic!("Failed to open {}", path.display())); - - let (_, delta) = { - let mut working_set = StateWorkingSet::new(&engine_state); - let (block, err) = parse(&mut working_set, None, &buf, false, &[]); - assert!(err.is_none(), "{:?}", err.unwrap()); - - (block, working_set.render()) - }; - - assert!(engine_state.merge_delta(delta).is_ok()); - - // Merge environment into the permanent state - assert!(engine_state.merge_env(&mut stack, &dir).is_ok()); - - let latest_block_id = engine_state.num_blocks() - 1; - - // Change config adding the external completer - let mut config = engine_state.get_config().clone(); - config.external_completer = Some(latest_block_id); - engine_state.set_config(&config); - - // Instantiate a new completer - NuCompleter::new(Arc::new(engine_state), stack) -} - -// match a list of suggestions with the expected values -#[track_caller] -fn assert_suggestions(expected: &[&str], suggestions: Vec) { - let expected = expected - .iter() - .map(|s| (*s).to_owned()) - .collect::>(); - let suggestions = suggestions - .into_iter() - .map(|s| s.value) - .collect::>(); - assert_eq!(expected, suggestions); +#[test] +fn register_completion() { + common::register_example("test", completest::Shell::Nu); } #[test] -fn completion_basic() { - let mut completer = external_completion("basic.nu"); +fn completion() { + let term = completest::Term::new(); + let mut runtime = common::load_runtime("test", completest::Shell::Nu); - let input = "my-app -"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--help", "-c", "-h", "-v"]; - assert_suggestions(expected, suggestions); + let input = "test -\t"; + let expected = r#"% test - +--generate generate +--global everywhere +--help Print help +--version Print version +-V Print version +-h Print help +"#; + let actual = runtime.complete(input, &term).unwrap(); + snapbox::assert_eq(expected, actual); - let input = "my-app test -"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--help", "-c", "-d", "-h"]; - assert_suggestions(expected, suggestions); -} - -#[test] -fn completion_feature_sample() { - let mut completer = external_completion("feature_sample.nu"); - - let input = "my-app test --"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--case", "--help", "--version"]; - assert_suggestions(expected, suggestions); - - let input = "my-app choice "; - let suggestions = completer.complete(input, input.len()); - let expected = &["first", "second"]; - assert_suggestions(expected, suggestions); - - let input = "my-app -"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "--conf", - "--config", - "--help", - "--version", - "-C", - "-V", - "-c", - "-h", - ]; - assert_suggestions(expected, suggestions); - - let input = "my-app --"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--conf", "--config", "--help", "--version"]; - assert_suggestions(expected, suggestions); -} - -#[test] -fn completion_special_commands() { - let mut completer = external_completion("special_commands.nu"); - - let input = "my-app some"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "my-app some_cmd", - "my-app some-hidden-cmd", - "my-app some-cmd-with-hyphens", - ]; - assert_suggestions(expected, suggestions); - - let input = "my-app choice "; - let suggestions = completer.complete(input, input.len()); - let expected = &["first", "second"]; - assert_suggestions(expected, suggestions); - - let input = "my-app -"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "--conf", - "--config", - "--help", - "--version", - "-C", - "-V", - "-c", - "-h", - ]; - assert_suggestions(expected, suggestions); - - let input = "my-app --"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--conf", "--config", "--help", "--version"]; - assert_suggestions(expected, suggestions); -} - -#[test] -fn completion_quoting() { - let mut completer = external_completion("quoting.nu"); - - let input = "my-app cmd-s"; - let suggestions = completer.complete(input, input.len()); - let expected = &["my-app cmd-single-quotes"]; - assert_suggestions(expected, suggestions); - - let input = "my-app --"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "--backslash", - "--backticks", - "--brackets", - "--double-quotes", - "--expansions", - "--help", - "--single-quotes", - "--version", - ]; - assert_suggestions(expected, suggestions); -} - -#[test] -fn completion_aliases() { - let mut completer = external_completion("aliases.nu"); - - let input = "my-app -"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "--flag", - "--flg", - "--help", - "--opt", - "--option", - "--version", - "-F", - "-O", - "-V", - "-f", - "-h", - "-o", - ]; - assert_suggestions(expected, suggestions); -} - -#[test] -fn completion_sub_subcommands() { - let mut completer = external_completion("sub_subcommands.nu"); - - let input = "my-app"; - let mut suggestions = completer.complete(input, input.len()); - suggestions.sort_by_key(|s| s.value.clone()); - let expected = &[ - "my-app", - "my-app help", - "my-app help help", - "my-app help some_cmd", - "my-app help some_cmd sub_cmd", - "my-app help test", - "my-app some_cmd", - "my-app some_cmd help", - "my-app some_cmd help help", - "my-app some_cmd help sub_cmd", - "my-app some_cmd sub_cmd", - "my-app test", - ]; - assert_suggestions(expected, suggestions); - - let input = "my-app some_cmd sub_cmd -"; - let suggestions = completer.complete(input, input.len()); - let expected = &["--config", "--help", "--version", "-V", "-h"]; - assert_suggestions(expected, suggestions); - - let input = "my-app some_cmd sub_cmd --config "; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "\"Lest quotes, aren't escaped.\"", - "\"Second to trigger display of options\"", - ]; - assert_suggestions(expected, suggestions); + let input = "test action -\t"; + let expected = r#"% test action - +--choice enum +--count number +--global everywhere +--help Print help +--set value +--set-true bool +--version Print version +-V Print version +-h Print help +"#; + let actual = runtime.complete(input, &term).unwrap(); + snapbox::assert_eq(expected, actual); } #[test] fn completion_value_hint() { - let mut completer = external_completion("value_hint.nu"); + let term = completest::Term::new(); + let mut runtime = common::load_runtime("test", completest::Shell::Nu); - let input = "my-app -"; - let suggestions = completer.complete(input, input.len()); - let expected = &[ - "--choice", - "--cmd", - "--cmd-name", - "--dir", - "--email", - "--exe", - "--file", - "--help", - "--host", - "--other", - "--path", - "--unknown", - "--url", - "--user", - "-H", - "-c", - "-d", - "-e", - "-f", - "-h", - "-p", - "-u", - ]; - assert_suggestions(expected, suggestions); + let input = "test hint -\t"; + let expected = r#"% test hint - +--choice +--cmd +--cmd-name +--dir +--email +--exe +--file +--global everywhere +--help Print help +--host +--other +--path +--unknown +--url +--user +--version Print version +-H +-V Print version +-c +-d +-e +-f +-h Print help +-p +-u +"#; + let actual = runtime.complete(input, &term).unwrap(); + snapbox::assert_eq(expected, actual); - let input = "my-app --choice "; - let suggestions = completer.complete(input, input.len()); - let expected = &["bash", "fish", "zsh"]; - assert_suggestions(expected, suggestions); + let input = "test hint --choice \t"; + let expected = r#"% test hint --choice +bash +fish +zsh +"#; + let actual = runtime.complete(input, &term).unwrap(); + snapbox::assert_eq(expected, actual); } diff --git a/clap_complete_nushell/tests/snapshots/home/test/nu/.config/nushell/completions/test.nu b/clap_complete_nushell/tests/snapshots/home/test/nu/.config/nushell/completions/test.nu new file mode 100644 index 00000000..b8e0d6d4 --- /dev/null +++ b/clap_complete_nushell/tests/snapshots/home/test/nu/.config/nushell/completions/test.nu @@ -0,0 +1,258 @@ +module completions { + + export extern test [ + --global # everywhere + --generate: string # generate + --help(-h) # Print help + --version(-V) # Print version + ] + + def "nu-complete test action choice" [] { + [ "first" "second" ] + } + + export extern "test action" [ + --set-true # bool + --set: string # value + --count # number + --choice: string@"nu-complete test action choice" # enum + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "test quote" [ + --single-quotes # Can be 'always', 'auto', or 'never' + --double-quotes # Can be "always", "auto", or "never" + --backticks # For more information see `echo test` + --backslash # Avoid '\n' + --brackets # List packages [filter] + --expansions # Execute the shell command with $SHELL + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Can be 'always', 'auto', or 'never' + export extern "test quote cmd-single-quotes" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Can be "always", "auto", or "never" + export extern "test quote cmd-double-quotes" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # For more information see `echo test` + export extern "test quote cmd-backticks" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Avoid '\n' + export extern "test quote cmd-backslash" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # List packages [filter] + export extern "test quote cmd-brackets" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Execute the shell command with $SHELL + export extern "test quote cmd-expansions" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Print this message or the help of the given subcommand(s) + export extern "test quote help" [ + ] + + # Can be 'always', 'auto', or 'never' + export extern "test quote help cmd-single-quotes" [ + ] + + # Can be "always", "auto", or "never" + export extern "test quote help cmd-double-quotes" [ + ] + + # For more information see `echo test` + export extern "test quote help cmd-backticks" [ + ] + + # Avoid '\n' + export extern "test quote help cmd-backslash" [ + ] + + # List packages [filter] + export extern "test quote help cmd-brackets" [ + ] + + # Execute the shell command with $SHELL + export extern "test quote help cmd-expansions" [ + ] + + # Print this message or the help of the given subcommand(s) + export extern "test quote help help" [ + ] + + export extern "test value" [ + --delim: string + --tuple: string + --require-eq: string + ...term: string + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "test pacman" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "test pacman one" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "test pacman two" [ + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Print this message or the help of the given subcommand(s) + export extern "test pacman help" [ + ] + + export extern "test pacman help one" [ + ] + + export extern "test pacman help two" [ + ] + + # Print this message or the help of the given subcommand(s) + export extern "test pacman help help" [ + ] + + export extern "test last" [ + first?: string + free?: string + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + export extern "test alias" [ + --flag(-f) # cmd flag + --flg # cmd flag + -F # cmd flag + --option(-o): string # cmd option + --opt: string # cmd option + -O: string # cmd option + positional?: string + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + def "nu-complete test hint choice" [] { + [ "bash" "fish" "zsh" ] + } + + export extern "test hint" [ + --choice: string@"nu-complete test hint choice" + --unknown: string + --other: string + --path(-p): string + --file(-f): string + --dir(-d): string + --exe(-e): string + --cmd-name: string + --cmd(-c): string + command_with_args?: string + --user(-u): string + --host(-H): string + --url: string + --email: string + --global # everywhere + --help(-h) # Print help + --version(-V) # Print version + ] + + # Print this message or the help of the given subcommand(s) + export extern "test help" [ + ] + + export extern "test help action" [ + ] + + export extern "test help quote" [ + ] + + # Can be 'always', 'auto', or 'never' + export extern "test help quote cmd-single-quotes" [ + ] + + # Can be "always", "auto", or "never" + export extern "test help quote cmd-double-quotes" [ + ] + + # For more information see `echo test` + export extern "test help quote cmd-backticks" [ + ] + + # Avoid '\n' + export extern "test help quote cmd-backslash" [ + ] + + # List packages [filter] + export extern "test help quote cmd-brackets" [ + ] + + # Execute the shell command with $SHELL + export extern "test help quote cmd-expansions" [ + ] + + export extern "test help value" [ + ] + + export extern "test help pacman" [ + ] + + export extern "test help pacman one" [ + ] + + export extern "test help pacman two" [ + ] + + export extern "test help last" [ + ] + + export extern "test help alias" [ + ] + + export extern "test help hint" [ + ] + + # Print this message or the help of the given subcommand(s) + export extern "test help help" [ + ] + +} + +use completions * diff --git a/clap_complete_nushell/tests/snapshots/home/test/nu/.config/nushell/config.nu b/clap_complete_nushell/tests/snapshots/home/test/nu/.config/nushell/config.nu new file mode 100644 index 00000000..e69de29b