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