From c6043eb5002312a40425db8fbc85109a988f6180 Mon Sep 17 00:00:00 2001 From: Antoine Stevan <44101798+amtoine@users.noreply.github.com> Date: Tue, 19 Dec 2023 10:14:34 +0100 Subject: [PATCH] improve completions of `use` and `overlay use` (#11330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Description this PR is two-fold - make `use` and `overlay use` use the same completion algorithm in 48f29b633 - list directory modules in completions of both with 402acde5c # User-Facing Changes i currently have the following in my `NU_LIB_DIRS`
click to see the script ```nushell for dir in $env.NU_LIB_DIRS { print $dir print (ls $dir --short-names | select name type) } ```
``` /home/amtoine/.local/share/nupm/modules #┬────────name────────┬type 0│nu-git-manager │dir 1│nu-git-manager-sugar│dir 2│nu-hooks │dir 3│nu-scripts │dir 4│nu-themes │dir 5│nupm │dir ─┴────────────────────┴──── /home/amtoine/.config/nushell/overlays #┬──name──┬type 0│ocaml.nu│file ─┴────────┴──── ``` > **Note** > all the samples below are run from the Nushell repo, i.e. a directory with a `toolkit.nu` module ## before the changes - `use` would give me `["ocaml.nu", "toolkit.nu"]` - `overlay use` would give me `[]` ## after the changes both commands give me ```nushell [ "nupm/", "ocaml.nu", "toolkit.nu", "nu-scripts/", "nu-git-manager/", "nu-git-manager-sugar/", ] ``` # Tests + Formatting - adds a new `directory_completion/mod.nu` to the completion fixtures - make sure `source-env`, `use` and `overlay-use` are all tested in the _dotnu_ test - fix all the other tests that use completions in the fixtures directory for completions # After Submitting --- crates/nu-cli/src/completions/completer.rs | 4 +- .../src/completions/dotnu_completions.rs | 17 ++++--- crates/nu-cli/tests/completions.rs | 45 +++++++++++++++++-- .../completions/directory_completion/mod.nu | 0 4 files changed, 56 insertions(+), 10 deletions(-) create mode 100644 tests/fixtures/completions/directory_completion/mod.nu diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index b6a15ff0a2..ed81782768 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -250,7 +250,9 @@ impl NuCompleter { working_set.get_span_contents(previous_expr.0).to_vec(); // Completion for .nu files - if prev_expr_str == b"use" || prev_expr_str == b"source-env" + if prev_expr_str == b"use" + || prev_expr_str == b"overlay use" + || prev_expr_str == b"source-env" { let mut completer = DotNuCompletion::new(self.engine_state.clone()); diff --git a/crates/nu-cli/src/completions/dotnu_completions.rs b/crates/nu-cli/src/completions/dotnu_completions.rs index fd5c346d95..d82d5a8913 100644 --- a/crates/nu-cli/src/completions/dotnu_completions.rs +++ b/crates/nu-cli/src/completions/dotnu_completions.rs @@ -5,7 +5,7 @@ use nu_protocol::{ }; use reedline::Suggestion; use std::{ - path::{is_separator, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR}, + path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR}, sync::Arc, }; @@ -91,16 +91,21 @@ impl Completer for DotNuCompletion { // and transform them into suggestions let output: Vec = search_dirs .into_iter() - .flat_map(|it| { - file_path_completion(span, &partial, &it, options) + .flat_map(|search_dir| { + let completions = file_path_completion(span, &partial, &search_dir, options); + completions .into_iter() - .filter(|it| { + .filter(move |it| { // Different base dir, so we list the .nu files or folders if !is_current_folder { it.1.ends_with(".nu") || it.1.ends_with(SEP) } else { - // Lib dirs, so we filter only the .nu files - it.1.ends_with(".nu") + // Lib dirs, so we filter only the .nu files or directory modules + if it.1.ends_with(SEP) { + Path::new(&search_dir).join(&it.1).join("mod.nu").exists() + } else { + it.1.ends_with(".nu") + } } }) .map(move |x| Suggestion { diff --git a/crates/nu-cli/tests/completions.rs b/crates/nu-cli/tests/completions.rs index e5db82e4ea..e48c1e9ee4 100644 --- a/crates/nu-cli/tests/completions.rs +++ b/crates/nu-cli/tests/completions.rs @@ -91,7 +91,7 @@ fn variables_dollar_sign_with_varialblecompletion() { let target_dir = "$ "; let suggestions = completer.complete(target_dir, target_dir.len()); - assert_eq!(7, suggestions.len()); + assert_eq!(8, suggestions.len()); } #[rstest] @@ -144,15 +144,34 @@ fn dotnu_completions() { let completion_str = "source-env ".to_string(); let suggestions = completer.complete(&completion_str, completion_str.len()); - assert_eq!(1, suggestions.len()); + assert_eq!(2, suggestions.len()); assert_eq!("custom_completion.nu", suggestions.first().unwrap().value); + #[cfg(windows)] + assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value); + #[cfg(not(windows))] + assert_eq!("directory_completion/", suggestions.get(1).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!(2, suggestions.len()); assert_eq!("custom_completion.nu", suggestions.first().unwrap().value); + #[cfg(windows)] + assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value); + #[cfg(not(windows))] + assert_eq!("directory_completion/", suggestions.get(1).unwrap().value); + + // Test overlay use completion + let completion_str = "overlay use ".to_string(); + let suggestions = completer.complete(&completion_str, completion_str.len()); + + assert_eq!(2, suggestions.len()); + assert_eq!("custom_completion.nu", suggestions.first().unwrap().value); + #[cfg(windows)] + assert_eq!("directory_completion\\", suggestions.get(1).unwrap().value); + #[cfg(not(windows))] + assert_eq!("directory_completion/", suggestions.get(1).unwrap().value); } #[test] @@ -208,6 +227,7 @@ fn file_completions() { 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")), @@ -323,6 +343,7 @@ fn command_ls_with_filecompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -333,6 +354,7 @@ fn command_ls_with_filecompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -355,6 +377,7 @@ fn command_open_with_filecompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -365,6 +388,7 @@ fn command_open_with_filecompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -388,6 +412,7 @@ fn command_rm_with_globcompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -398,6 +423,7 @@ fn command_rm_with_globcompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -421,6 +447,7 @@ fn command_cp_with_globcompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -431,6 +458,7 @@ fn command_cp_with_globcompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -454,6 +482,7 @@ fn command_save_with_filecompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -464,6 +493,7 @@ fn command_save_with_filecompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -487,6 +517,7 @@ fn command_touch_with_filecompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -497,6 +528,7 @@ fn command_touch_with_filecompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -520,6 +552,7 @@ fn command_watch_with_filecompletion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -530,6 +563,7 @@ fn command_watch_with_filecompletion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -625,6 +659,7 @@ fn folder_with_directorycompletions() { // Create the expected values let expected_paths: Vec = vec![ folder(dir.join("another")), + folder(dir.join("directory_completion")), folder(dir.join("test_a")), folder(dir.join("test_b")), folder(dir.join(".hidden_folder")), @@ -839,6 +874,7 @@ fn unknown_command_completion() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -849,6 +885,7 @@ fn unknown_command_completion() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), @@ -899,6 +936,7 @@ fn filecompletions_triggers_after_cursor() { let expected_paths: Vec = vec![ "another\\".to_string(), "custom_completion.nu".to_string(), + "directory_completion\\".to_string(), "nushell".to_string(), "test_a\\".to_string(), "test_b\\".to_string(), @@ -909,6 +947,7 @@ fn filecompletions_triggers_after_cursor() { let expected_paths: Vec = vec![ "another/".to_string(), "custom_completion.nu".to_string(), + "directory_completion/".to_string(), "nushell".to_string(), "test_a/".to_string(), "test_b/".to_string(), diff --git a/tests/fixtures/completions/directory_completion/mod.nu b/tests/fixtures/completions/directory_completion/mod.nu new file mode 100644 index 0000000000..e69de29bb2