nushell/crates/nu-cli/tests/completions.rs
Ryan Devenney d34a2c353f
files and directory completions now use ascending ordering rather than Levenshtein. #8023 (#8085)
# Description

This change sorts completions for files and directories by the ascending
ordering method, related to issue:
[#8023](https://github.com/nushell/nushell/issues/8023)

Currently the Suggestions are being sorted twice, so it's now following
the convention from `completion/base.rs` to match on the
`self.get_sort_by()` result.

# User-Facing Changes

Previously the suggestions were being sorted by the Levenshtein method:
```
/home/rdevenney/projects/open_source/nushell| cd
src/                wix/                docs/               tests/
assets/             crates/             docker/             images/
target/             benches/            pkg_mgrs/           .git/
.cargo/             .github/
```

Now when you tab for autocompletions, they show up in ascending
alphabetical order as shown below (with hidden files/folders at the
end).
```
/home/rdevenney/projects/open_source/nushell| cd
assets/             benches/            crates/             docker/
docs/               images/             pkg_mgrs/           src/
target/             tests/              wix/                .cargo/
.git/               .github/
```

And when you've already typed a bit of the path:
```
/home/rdevenney/projects/open_source/nushell| cd crates/nu
crates/nu-cli/                   crates/nu-color-config/          crates/nu-command/
crates/nu-engine/                crates/nu-explore/               crates/nu-glob/
crates/nu-json/                  crates/nu-parser/                crates/nu-path/
crates/nu-plugin/                crates/nu-pretty-hex/            crates/nu-protocol/
crates/nu-system/                crates/nu-table/                 crates/nu-term-grid/
crates/nu-test-support/          crates/nu-utils/                 crates/nu_plugin_custom_values/
crates/nu_plugin_example/        crates/nu_plugin_formats/        crates/nu_plugin_gstat/
crates/nu_plugin_inc/            crates/nu_plugin_python/         crates/nu_plugin_query/
```

And another for when there are files and directories present:
```
/home/rdevenney/projects/open_source/nushell/crates/nu-cli/src| nvim                              02/16/2023 08:22:16 AM
commands.rs          completions/         config_files.rs      eval_file.rs
lib.rs               menus/               nu_highlight.rs      print.rs
prompt.rs            prompt_update.rs     reedline_config.rs   repl.rs
syntax_highlight.rs  util.rs              validation.rs
```

# 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` to check that you're using the standard code
style
[*] `cargo test --workspace` to check that all tests pass

# 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.
2023-02-22 13:03:48 +00:00

868 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 = "let external_completer = {|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 = "let external_completer = {|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!(9, suggestions.len());
let expected: Vec<String> = vec![
"config-path".into(),
"env-path".into(),
"history-path".into(),
"home-path".into(),
"loginshell-path".into(),
"os-info".into(),
"pid".into(),
"scope".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 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, err) = parse(&mut working_set, None, block.as_bytes(), false, &[]);
assert!(err.is_none());
(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());
}