diff --git a/crates/nu-cli/src/completion/command.rs b/crates/nu-cli/src/completion/command.rs index 077baee052..66457ac9f6 100644 --- a/crates/nu-cli/src/completion/command.rs +++ b/crates/nu-cli/src/completion/command.rs @@ -33,7 +33,7 @@ impl Completer { .collect(); if partial != "" { - let path_completer = crate::completion::path::Completer::new(); + let path_completer = crate::completion::path::Completer; let path_results = path_completer.complete(ctx, partial); suggestions.extend(path_results.into_iter().filter(|suggestion| { let path = Path::new(&suggestion.replacement); diff --git a/crates/nu-cli/src/completion/path.rs b/crates/nu-cli/src/completion/path.rs index 88c3fc4d8d..85acc83082 100644 --- a/crates/nu-cli/src/completion/path.rs +++ b/crates/nu-cli/src/completion/path.rs @@ -1,27 +1,47 @@ -use rustyline::completion::FilenameCompleter; +use std::path::Path; use crate::completion::{Context, Suggestion}; -pub struct Completer { - inner: FilenameCompleter, -} +const SEP: char = std::path::MAIN_SEPARATOR; + +pub struct Completer; impl Completer { - pub fn new() -> Completer { - Completer { - inner: FilenameCompleter::new(), - } - } - pub fn complete(&self, _ctx: &Context<'_>, partial: &str) -> Vec { let expanded = nu_parser::expand_ndots(partial); + let expanded = expanded.as_ref(); - if let Ok((_pos, pairs)) = self.inner.complete_path(&expanded, expanded.len()) { - pairs - .into_iter() - .map(|v| Suggestion { - replacement: v.replacement, - display: v.display, + let (base_dir_name, partial) = match expanded.rfind(SEP) { + Some(pos) => expanded.split_at(pos + SEP.len_utf8()), + None => ("", expanded), + }; + + let base_dir = if base_dir_name == "" { + Path::new(".") + } else { + Path::new(base_dir_name) + }; + + if let Ok(result) = base_dir.read_dir() { + result + .filter_map(|entry| { + entry.ok().and_then(|entry| { + let mut file_name = entry.file_name().to_string_lossy().into_owned(); + if file_name.starts_with(partial) { + let mut path = format!("{}{}", base_dir_name, file_name); + if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) { + path.push(std::path::MAIN_SEPARATOR); + file_name.push(std::path::MAIN_SEPARATOR); + } + + Some(Suggestion { + replacement: path, + display: file_name, + }) + } else { + None + } + }) }) .collect() } else { diff --git a/crates/nu-cli/src/shell/completer.rs b/crates/nu-cli/src/shell/completer.rs index 46fda94472..2e107a0f2a 100644 --- a/crates/nu-cli/src/shell/completer.rs +++ b/crates/nu-cli/src/shell/completer.rs @@ -41,12 +41,12 @@ impl NuCompleter { } LocationType::Flag(cmd) => { - let flag_completer = crate::completion::flag::Completer {}; + let flag_completer = crate::completion::flag::Completer; flag_completer.complete(context, cmd, partial) } LocationType::Argument(cmd, _arg_name) => { - let path_completer = crate::completion::path::Completer::new(); + let path_completer = crate::completion::path::Completer; let completed_paths = path_completer.complete(context, partial); match cmd.as_deref().unwrap_or("") { "cd" => select_directory_suggestions(completed_paths),