From 217be249637f45049141a22325a5ade9980a1340 Mon Sep 17 00:00:00 2001 From: RobbingDaHood <16130319+RobbingDaHood@users.noreply.github.com> Date: Wed, 4 Dec 2024 03:39:11 +0100 Subject: [PATCH] #14238 Now the file completion is triggered on a custom command after the first parameter. (#14481) - this PR should close #14238 # Description Solved as described here (First suggestion): https://github.com/nushell/nushell/issues/14238#issuecomment-2506387012 Below I make the example from the issue, it shows that the completion now works past the first parameter. ``` ~/Projects/nushell> def list [...args] { 11/30/2024 03:21:24 PM ::: $args ::: | each { ::: open $args ::: } ::: } ~/Projects/nushell> cd tests/fixtures/completions/ 11/30/2024 03:25:24 PM ~/Projects/nushell/tests/fixtures/completions| list custom_completion.nu 11/30/2024 03:25:35 PM another/ custom_completion.nu directory_completion/ nushell test_a/ test_b/ .hidden_file .hidden_folder/ ``` # User-Facing Changes The changes introduced to completions in `baadaee0163a5066ae73509ff6052962b3422673` now does not return if it did not find "Operator completions". This could have impact on more than just custom commands, but it could be seemed as making everything a bit more robust. # Tests + Formatting I ran all of: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the tests for the standard library # After Submitting I do not think there is any need to update [the documentation](https://github.com/nushell/nushell.github.io), right? --------- Co-authored-by: Daniel Winther Petersen --- crates/nu-cli/src/completions/completer.rs | 5 +- crates/nu-cli/tests/completions/mod.rs | 102 +++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index 555d14ff27..16b1673a4f 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -297,7 +297,7 @@ impl NuCompleter { let mut completer = OperatorCompletion::new(pipeline_element.expr.clone()); - return self.process_completion( + let operator_suggestion = self.process_completion( &mut completer, &working_set, prefix, @@ -305,6 +305,9 @@ impl NuCompleter { fake_offset, pos, ); + if !operator_suggestion.is_empty() { + return operator_suggestion; + } } } } diff --git a/crates/nu-cli/tests/completions/mod.rs b/crates/nu-cli/tests/completions/mod.rs index 7f6fe30430..78c36cad7e 100644 --- a/crates/nu-cli/tests/completions/mod.rs +++ b/crates/nu-cli/tests/completions/mod.rs @@ -357,6 +357,39 @@ fn file_completions() { // Match the results match_suggestions(&expected_paths, &suggestions); + // Test completions for the current folder even with parts before the autocomplet + let target_dir = format!("cp somefile.txt {dir_str}{MAIN_SEPARATOR}"); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + // Create the expected values + let expected_paths: Vec = vec![ + folder(dir.join("another")), + file(dir.join("custom_completion.nu")), + folder(dir.join("directory_completion")), + file(dir.join("nushell")), + folder(dir.join("test_a")), + folder(dir.join("test_b")), + file(dir.join(".hidden_file")), + folder(dir.join(".hidden_folder")), + ]; + + #[cfg(windows)] + { + let separator = '/'; + let target_dir = format!("cp somefile.txt {dir_str}{separator}"); + let slash_suggestions = completer.complete(&target_dir, target_dir.len()); + + let expected_slash_paths: Vec = expected_paths + .iter() + .map(|s| s.replace('\\', "/")) + .collect(); + + match_suggestions(&expected_slash_paths, &slash_suggestions); + } + + // 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()); @@ -391,6 +424,75 @@ fn file_completions() { match_suggestions(&expected_paths, &suggestions); } +#[test] +fn custom_command_rest_any_args_file_completions() { + // Create a new engine + let (dir, dir_str, mut engine, mut stack) = new_engine(); + let command = r#"def list [ ...args: any ] {}"#; + assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok()); + + // Instantiate a new completer + let mut completer = NuCompleter::new(Arc::new(engine), Arc::new(stack)); + + // Test completions for the current folder + let target_dir = format!("list {dir_str}{MAIN_SEPARATOR}"); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + // Create the expected values + let expected_paths: Vec = vec![ + folder(dir.join("another")), + file(dir.join("custom_completion.nu")), + folder(dir.join("directory_completion")), + 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 the current folder even with parts before the autocomplet + let target_dir = format!("list somefile.txt {dir_str}{MAIN_SEPARATOR}"); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + // Create the expected values + let expected_paths: Vec = vec![ + folder(dir.join("another")), + file(dir.join("custom_completion.nu")), + folder(dir.join("directory_completion")), + 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!("list {}", folder(dir.join("another"))); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + // Create the expected values + let expected_paths: Vec = vec![file(dir.join("another").join("newfile"))]; + + // Match the results + match_suggestions(&expected_paths, &suggestions); + + // Test completions for hidden files + let target_dir = format!("list {}", file(dir.join(".hidden_folder").join("."))); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + let expected_paths: Vec = + vec![file(dir.join(".hidden_folder").join(".hidden_subfile"))]; + + // Match the results + match_suggestions(&expected_paths, &suggestions); +} + #[cfg(windows)] #[test] fn file_completions_with_mixed_separators() {