summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/nu-cli/src/completions/completion_common.rs38
1 files changed, 32 insertions, 6 deletions
diff --git a/crates/nu-cli/src/completions/completion_common.rs b/crates/nu-cli/src/completions/completion_common.rs
index 5469ba132..2b85f6091 100644
--- a/crates/nu-cli/src/completions/completion_common.rs
+++ b/crates/nu-cli/src/completions/completion_common.rs
@@ -12,7 +12,7 @@ use nu_protocol::{
use nu_utils::get_ls_colors;
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
-use super::SortBy;
+use super::{MatchAlgorithm, SortBy};
#[derive(Clone, Default)]
pub struct PathBuiltFromString {
@@ -20,12 +20,21 @@ pub struct PathBuiltFromString {
isdir: bool,
}
-fn complete_rec(
+/// Recursively goes through paths that match a given `partial`.
+/// built: State struct for a valid matching path built so far.
+///
+/// `isdir`: whether the current partial path has a trailing slash.
+/// Parsing a path string into a pathbuf loses that bit of information.
+///
+/// want_directory: Whether we want only directories as completion matches.
+/// Some commands like `cd` can only be run on directories whereas others
+/// like `ls` can be run on regular files as well.
+pub fn complete_rec(
partial: &[&str],
built: &PathBuiltFromString,
cwd: &Path,
options: &CompletionOptions,
- dir: bool,
+ want_directory: bool,
isdir: bool,
) -> Vec<PathBuiltFromString> {
let mut completions = vec![];
@@ -35,7 +44,7 @@ fn complete_rec(
let mut built = built.clone();
built.parts.push(base.to_string());
built.isdir = true;
- return complete_rec(rest, &built, cwd, options, dir, isdir);
+ return complete_rec(rest, &built, cwd, options, want_directory, isdir);
}
}
@@ -56,7 +65,7 @@ fn complete_rec(
built.parts.push(entry_name.clone());
built.isdir = entry_isdir;
- if !dir || entry_isdir {
+ if !want_directory || entry_isdir {
entries.push((entry_name, built));
}
}
@@ -68,12 +77,29 @@ fn complete_rec(
match partial.split_first() {
Some((base, rest)) => {
if matches(base, &entry_name, options) {
+ // We use `isdir` to confirm that the current component has
+ // at least one next component or a slash.
+ // Serves as confirmation to ignore longer completions for
+ // components in between.
if !rest.is_empty() || isdir {
- completions.extend(complete_rec(rest, &built, cwd, options, dir, isdir));
+ completions.extend(complete_rec(
+ rest,
+ &built,
+ cwd,
+ options,
+ want_directory,
+ isdir,
+ ));
} else {
completions.push(built);
}
}
+ if entry_name.eq(base)
+ && matches!(options.match_algorithm, MatchAlgorithm::Prefix)
+ && isdir
+ {
+ break;
+ }
}
None => {
completions.push(built);