forked from extern/nushell
5d9e2455f7
# Description This changes the default behaviour of `let` to be able to take a pipeline as its initial value. For example: ``` > let x = "hello world" | str length ``` This is a change from the existing behaviour, where the right hand side is assumed to be an expression. Pipelines are more general, and can be more powerful. My google foo is failing me, but this also fixes this issue: ``` let x = foo ``` Currently, this reads `foo` as a bareword that gets converted to a string rather than running the `foo` command. In practice, this is really annoying and is a really hard to spot bug in a script. # User-Facing Changes BREAKING CHANGE BREAKING CHANGE `let` gains the power to be assigned via a pipeline. However, this changes the behaviour of `let x = foo` from assigning the string "foo" to `$x` to being "run the command `foo` and give the result to `$x`" # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect -A clippy::result_large_err` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. -->
885 lines
27 KiB
Rust
885 lines
27 KiB
Rust
pub mod support;
|
|
|
|
use nu_cli::NuCompleter;
|
|
use nu_parser::parse;
|
|
use nu_protocol::engine::StateWorkingSet;
|
|
use reedline::{Completer, Suggestion};
|
|
use rstest::{fixture, rstest};
|
|
use support::{completions_helpers::new_quote_engine, file, folder, match_suggestions, new_engine};
|
|
|
|
#[fixture]
|
|
fn completer() -> NuCompleter {
|
|
// Create a new engine
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Add record value as example
|
|
let record = "def tst [--mod -s] {}";
|
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
// Instantiate a new completer
|
|
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
|
}
|
|
|
|
#[fixture]
|
|
fn completer_strings() -> NuCompleter {
|
|
// Create a new engine
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Add record value as example
|
|
let record = r#"def animals [] { ["cat", "dog", "eel" ] }
|
|
def my-command [animal: string@animals] { print $animal }"#;
|
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
// Instantiate a new completer
|
|
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
|
}
|
|
|
|
#[fixture]
|
|
fn extern_completer() -> NuCompleter {
|
|
// Create a new engine
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Add record value as example
|
|
let record = r#"
|
|
def animals [] { [ "cat", "dog", "eel" ] }
|
|
extern spam [
|
|
animal: string@animals
|
|
--foo (-f): string@animals
|
|
-b: string@animals
|
|
]
|
|
"#;
|
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
// Instantiate a new completer
|
|
NuCompleter::new(std::sync::Arc::new(engine), stack)
|
|
}
|
|
|
|
#[test]
|
|
fn variables_dollar_sign_with_varialblecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "$ ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
assert_eq!(7, suggestions.len());
|
|
}
|
|
|
|
#[rstest]
|
|
fn variables_double_dash_argument_with_flagcompletion(mut completer: NuCompleter) {
|
|
let suggestions = completer.complete("tst --", 6);
|
|
let expected: Vec<String> = vec!["--help".into(), "--mod".into()];
|
|
// dbg!(&expected, &suggestions);
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn variables_single_dash_argument_with_flagcompletion(mut completer: NuCompleter) {
|
|
let suggestions = completer.complete("tst -", 5);
|
|
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn variables_command_with_commandcompletion(mut completer_strings: NuCompleter) {
|
|
let suggestions = completer_strings.complete("my-c ", 4);
|
|
let expected: Vec<String> = vec!["my-command".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn variables_subcommands_with_customcompletion(mut completer_strings: NuCompleter) {
|
|
let suggestions = completer_strings.complete("my-command ", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn variables_customcompletion_subcommands_with_customcompletion_2(
|
|
mut completer_strings: NuCompleter,
|
|
) {
|
|
let suggestions = completer_strings.complete("my-command ", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn dotnu_completions() {
|
|
// Create a new engine
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
// Instantiate a new completer
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Test source completion
|
|
let completion_str = "source-env ".to_string();
|
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
|
|
|
assert_eq!(1, suggestions.len());
|
|
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
|
|
|
// Test use completion
|
|
let completion_str = "use ".to_string();
|
|
let suggestions = completer.complete(&completion_str, completion_str.len());
|
|
|
|
assert_eq!(1, suggestions.len());
|
|
assert_eq!("custom_completion.nu", suggestions.get(0).unwrap().value);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn external_completer_trailing_space() {
|
|
// https://github.com/nushell/nushell/issues/6378
|
|
let block = "let external_completer = {|spans| $spans}";
|
|
let input = "gh alias ".to_string();
|
|
|
|
let suggestions = run_external_completion(block, &input);
|
|
assert_eq!(3, suggestions.len());
|
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
|
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
|
assert_eq!("", suggestions.get(2).unwrap().value);
|
|
}
|
|
|
|
#[test]
|
|
fn external_completer_no_trailing_space() {
|
|
let block = "{|spans| $spans}";
|
|
let input = "gh alias".to_string();
|
|
|
|
let suggestions = run_external_completion(block, &input);
|
|
assert_eq!(2, suggestions.len());
|
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
|
assert_eq!("alias", suggestions.get(1).unwrap().value);
|
|
}
|
|
|
|
#[test]
|
|
fn external_completer_pass_flags() {
|
|
let block = "{|spans| $spans}";
|
|
let input = "gh api --".to_string();
|
|
|
|
let suggestions = run_external_completion(block, &input);
|
|
assert_eq!(3, suggestions.len());
|
|
assert_eq!("gh", suggestions.get(0).unwrap().value);
|
|
assert_eq!("api", suggestions.get(1).unwrap().value);
|
|
assert_eq!("--", suggestions.get(2).unwrap().value);
|
|
}
|
|
|
|
#[test]
|
|
fn file_completions() {
|
|
// Create a new engine
|
|
let (dir, dir_str, engine, stack) = new_engine();
|
|
|
|
// Instantiate a new completer
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Test completions for the current folder
|
|
let target_dir = format!("cp {dir_str}");
|
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
|
|
// Create the expected values
|
|
let expected_paths: Vec<String> = vec![
|
|
folder(dir.join("another")),
|
|
file(dir.join("custom_completion.nu")),
|
|
file(dir.join("nushell")),
|
|
folder(dir.join("test_a")),
|
|
folder(dir.join("test_b")),
|
|
file(dir.join(".hidden_file")),
|
|
folder(dir.join(".hidden_folder")),
|
|
];
|
|
|
|
// Match the results
|
|
match_suggestions(expected_paths, suggestions);
|
|
|
|
// Test completions for a file
|
|
let target_dir = format!("cp {}", folder(dir.join("another")));
|
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
|
|
// Create the expected values
|
|
let expected_paths: Vec<String> = vec![file(dir.join("another").join("newfile"))];
|
|
|
|
// Match the results
|
|
match_suggestions(expected_paths, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn command_ls_with_filecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "ls ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
#[test]
|
|
fn command_open_with_filecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "open ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn command_rm_with_globcompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "rm ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn command_cp_with_globcompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "cp ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn command_save_with_filecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "save ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn command_touch_with_filecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "touch ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn command_watch_with_filecompletion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "watch ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn file_completion_quoted() {
|
|
let (_, _, engine, stack) = new_quote_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "open ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
let expected_paths: Vec<String> = vec![
|
|
"`te st.txt`".to_string(),
|
|
"`te#st.txt`".to_string(),
|
|
"`te'st.txt`".to_string(),
|
|
"`te(st).txt`".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn flag_completions() {
|
|
// Create a new engine
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
// Instantiate a new completer
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
// Test completions for the 'ls' flags
|
|
let suggestions = completer.complete("ls -", 4);
|
|
|
|
assert_eq!(16, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec![
|
|
"--all".into(),
|
|
"--directory".into(),
|
|
"--du".into(),
|
|
"--full-paths".into(),
|
|
"--help".into(),
|
|
"--long".into(),
|
|
"--mime-type".into(),
|
|
"--short-names".into(),
|
|
"-D".into(),
|
|
"-a".into(),
|
|
"-d".into(),
|
|
"-f".into(),
|
|
"-h".into(),
|
|
"-l".into(),
|
|
"-m".into(),
|
|
"-s".into(),
|
|
];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn folder_with_directorycompletions() {
|
|
// Create a new engine
|
|
let (dir, dir_str, engine, stack) = new_engine();
|
|
|
|
// Instantiate a new completer
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Test completions for the current folder
|
|
let target_dir = format!("cd {dir_str}");
|
|
let suggestions = completer.complete(&target_dir, target_dir.len());
|
|
|
|
// Create the expected values
|
|
let expected_paths: Vec<String> = vec![
|
|
folder(dir.join("another")),
|
|
folder(dir.join("test_a")),
|
|
folder(dir.join("test_b")),
|
|
folder(dir.join(".hidden_folder")),
|
|
];
|
|
|
|
// Match the results
|
|
match_suggestions(expected_paths, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn variables_completions() {
|
|
// Create a new engine
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Add record value as example
|
|
let record = "let actor = { name: 'Tom Hardy', age: 44 }";
|
|
assert!(support::merge_input(record.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
// Instantiate a new completer
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Test completions for $nu
|
|
let suggestions = completer.complete("$nu.", 4);
|
|
|
|
assert_eq!(14, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec![
|
|
"config-path".into(),
|
|
"current-exe".into(),
|
|
"default-config-dir".into(),
|
|
"env-path".into(),
|
|
"history-path".into(),
|
|
"home-path".into(),
|
|
"is-interactive".into(),
|
|
"is-login".into(),
|
|
"loginshell-path".into(),
|
|
"os-info".into(),
|
|
"pid".into(),
|
|
"plugin-path".into(),
|
|
"startup-time".into(),
|
|
"temp-path".into(),
|
|
];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for $nu.h (filter)
|
|
let suggestions = completer.complete("$nu.h", 5);
|
|
|
|
assert_eq!(2, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec!["history-path".into(), "home-path".into()];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for $nu.os-info
|
|
let suggestions = completer.complete("$nu.os-info.", 12);
|
|
assert_eq!(4, suggestions.len());
|
|
let expected: Vec<String> = vec![
|
|
"arch".into(),
|
|
"family".into(),
|
|
"kernel_version".into(),
|
|
"name".into(),
|
|
];
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for custom var
|
|
let suggestions = completer.complete("$actor.", 7);
|
|
|
|
assert_eq!(2, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec!["age".into(), "name".into()];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for custom var (filtering)
|
|
let suggestions = completer.complete("$actor.n", 8);
|
|
|
|
assert_eq!(1, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec!["name".into()];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for $env
|
|
let suggestions = completer.complete("$env.", 5);
|
|
|
|
assert_eq!(3, suggestions.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected: Vec<String> = vec!["PWD".into(), "Path".into(), "TEST".into()];
|
|
#[cfg(not(windows))]
|
|
let expected: Vec<String> = vec!["PATH".into(), "PWD".into(), "TEST".into()];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
|
|
// Test completions for $env
|
|
let suggestions = completer.complete("$env.T", 6);
|
|
|
|
assert_eq!(1, suggestions.len());
|
|
|
|
let expected: Vec<String> = vec!["TEST".into()];
|
|
|
|
// Match results
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn alias_of_command_and_flags() {
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Create an alias
|
|
let alias = r#"alias ll = ls -l"#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let suggestions = completer.complete("ll t", 4);
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn alias_of_basic_command() {
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Create an alias
|
|
let alias = r#"alias ll = ls "#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let suggestions = completer.complete("ll t", 4);
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[test]
|
|
fn alias_of_another_alias() {
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Create an alias
|
|
let alias = r#"alias ll = ls -la"#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir.clone()).is_ok());
|
|
// Create the second alias
|
|
let alias = r#"alias lf = ll -f"#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let suggestions = completer.complete("lf t", 4);
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec!["test_a\\".to_string(), "test_b\\".to_string()];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec!["test_a/".to_string(), "test_b/".to_string()];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
fn run_external_completion(block: &str, input: &str) -> Vec<Suggestion> {
|
|
// Create a new engine
|
|
let (dir, _, mut engine_state, mut stack) = new_engine();
|
|
let (_, delta) = {
|
|
let mut working_set = StateWorkingSet::new(&engine_state);
|
|
let block = parse(&mut working_set, None, block.as_bytes(), false);
|
|
assert!(working_set.parse_errors.is_empty());
|
|
|
|
(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
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine_state), stack);
|
|
|
|
completer.complete(input, input.len())
|
|
}
|
|
|
|
#[test]
|
|
fn unknown_command_completion() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let target_dir = "thiscommanddoesnotexist ";
|
|
let suggestions = completer.complete(target_dir, target_dir.len());
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions)
|
|
}
|
|
|
|
#[rstest]
|
|
fn flagcompletion_triggers_after_cursor(mut completer: NuCompleter) {
|
|
let suggestions = completer.complete("tst -h", 5);
|
|
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn customcompletion_triggers_after_cursor(mut completer_strings: NuCompleter) {
|
|
let suggestions = completer_strings.complete("my-command c", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn customcompletion_triggers_after_cursor_piped(mut completer_strings: NuCompleter) {
|
|
let suggestions = completer_strings.complete("my-command c | ls", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn flagcompletion_triggers_after_cursor_piped(mut completer: NuCompleter) {
|
|
let suggestions = completer.complete("tst -h | ls", 5);
|
|
let expected: Vec<String> = vec!["--help".into(), "--mod".into(), "-h".into(), "-s".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[test]
|
|
fn filecompletions_triggers_after_cursor() {
|
|
let (_, _, engine, stack) = new_engine();
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
let suggestions = completer.complete("cp test_c", 3);
|
|
|
|
#[cfg(windows)]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another\\".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a\\".to_string(),
|
|
"test_b\\".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder\\".to_string(),
|
|
];
|
|
#[cfg(not(windows))]
|
|
let expected_paths: Vec<String> = vec![
|
|
"another/".to_string(),
|
|
"custom_completion.nu".to_string(),
|
|
"nushell".to_string(),
|
|
"test_a/".to_string(),
|
|
"test_b/".to_string(),
|
|
".hidden_file".to_string(),
|
|
".hidden_folder/".to_string(),
|
|
];
|
|
|
|
match_suggestions(expected_paths, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_custom_completion_positional(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam ", 5);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_custom_completion_long_flag_1(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam --foo=", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_custom_completion_long_flag_2(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam --foo ", 11);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_custom_completion_long_flag_short(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam -f ", 8);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_custom_completion_short_flag(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam -b ", 8);
|
|
let expected: Vec<String> = vec!["cat".into(), "dog".into(), "eel".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[rstest]
|
|
fn extern_complete_flags(mut extern_completer: NuCompleter) {
|
|
let suggestions = extern_completer.complete("spam -", 6);
|
|
let expected: Vec<String> = vec!["--foo".into(), "-b".into(), "-f".into()];
|
|
match_suggestions(expected, suggestions);
|
|
}
|
|
|
|
#[ignore = "was reverted, still needs fixing"]
|
|
#[rstest]
|
|
fn alias_offset_bug_7648() {
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Create an alias
|
|
let alias = r#"alias ea = ^$env.EDITOR /tmp/test.s"#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Issue #7648
|
|
// Nushell crashes when an alias name is shorter than the alias command
|
|
// and the alias command is a external command
|
|
// This happens because of offset is not correct.
|
|
// This crashes before PR #7779
|
|
let _suggestions = completer.complete("e", 1);
|
|
}
|
|
|
|
#[ignore = "was reverted, still needs fixing"]
|
|
#[rstest]
|
|
fn alias_offset_bug_7754() {
|
|
let (dir, _, mut engine, mut stack) = new_engine();
|
|
|
|
// Create an alias
|
|
let alias = r#"alias ll = ls -l"#;
|
|
assert!(support::merge_input(alias.as_bytes(), &mut engine, &mut stack, dir).is_ok());
|
|
|
|
let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack);
|
|
|
|
// Issue #7754
|
|
// Nushell crashes when an alias name is shorter than the alias command
|
|
// and the alias command contains pipes.
|
|
// This crashes before PR #7756
|
|
let _suggestions = completer.complete("ll -a | c", 9);
|
|
}
|
|
|
|
#[test]
|
|
fn get_path_env_var_8003() {
|
|
// Create a new engine
|
|
let (_, _, engine, _) = new_engine();
|
|
// Get the path env var in a platform agnostic way
|
|
let the_path = engine.get_path_env_var();
|
|
// Make sure it's not empty
|
|
assert!(the_path.is_some());
|
|
}
|