From d064d187ab443d3291492d99889d9538e40b7d3e Mon Sep 17 00:00:00 2001 From: Himadri Bhattacharjee Date: Fri, 6 Oct 2023 16:45:30 +0000 Subject: [PATCH] fix: complete paths surrounded by quotes or backticks (#10600) Fixes #10586 # Description Any partial path that begins with or is surrounded by a quote or backtick will be tab completed. The completed result would be surrounded by backticks unconditionally. ![output](https://github.com/nushell/nushell/assets/107522312/13e01104-18a1-4483-b010-79985294748b) # User-Facing Changes See above. # Tests + Formatting Formatted and added test cases. # After Submitting --- .../src/completions/completion_common.rs | 19 ++++++++++++++++++- crates/nu-cli/tests/completions.rs | 14 ++++++++++++++ .../quoted_completions/test dir/double quote | 0 .../quoted_completions/test dir/single quote | 0 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/quoted_completions/test dir/double quote create mode 100644 tests/fixtures/quoted_completions/test dir/single quote diff --git a/crates/nu-cli/src/completions/completion_common.rs b/crates/nu-cli/src/completions/completion_common.rs index 6b57fd7097..bcb46c47c7 100644 --- a/crates/nu-cli/src/completions/completion_common.rs +++ b/crates/nu-cli/src/completions/completion_common.rs @@ -62,6 +62,22 @@ impl OriginalCwd { } } +fn surround_remove(partial: &str) -> String { + for c in ['`', '"', '\''] { + if partial.starts_with(c) { + let ret = partial.strip_prefix(c).unwrap_or(partial); + return match ret.split(c).collect::>()[..] { + [inside] => inside.to_string(), + [inside, outside] if inside.ends_with(is_separator) => { + format!("{inside}{outside}") + } + _ => ret.to_string(), + }; + } + } + partial.to_string() +} + pub fn complete_item( want_directory: bool, span: nu_protocol::Span, @@ -69,10 +85,11 @@ pub fn complete_item( cwd: &str, options: &CompletionOptions, ) -> Vec<(nu_protocol::Span, String)> { + let partial = surround_remove(partial); let isdir = partial.ends_with(is_separator); let cwd_pathbuf = Path::new(cwd).to_path_buf(); let mut original_cwd = OriginalCwd::None; - let mut components = Path::new(partial).components().peekable(); + let mut components = Path::new(&partial).components().peekable(); let mut cwd = match components.peek().cloned() { Some(c @ Component::Prefix(..)) => { // windows only by definition diff --git a/crates/nu-cli/tests/completions.rs b/crates/nu-cli/tests/completions.rs index f73720e962..c70c10b16b 100644 --- a/crates/nu-cli/tests/completions.rs +++ b/crates/nu-cli/tests/completions.rs @@ -1,5 +1,7 @@ pub mod support; +use std::path::PathBuf; + use nu_cli::NuCompleter; use nu_parser::parse; use nu_protocol::engine::StateWorkingSet; @@ -529,6 +531,18 @@ fn file_completion_quoted() { "`te#st.txt`".to_string(), "`te'st.txt`".to_string(), "`te(st).txt`".to_string(), + format!("`{}`", folder("test dir".into())), + ]; + + match_suggestions(expected_paths, suggestions); + + let dir: PathBuf = "test dir".into(); + let target_dir = format!("open '{}'", folder(dir.clone())); + let suggestions = completer.complete(&target_dir, target_dir.len()); + + let expected_paths: Vec = vec![ + format!("`{}`", file(dir.join("double quote"))), + format!("`{}`", file(dir.join("single quote"))), ]; match_suggestions(expected_paths, suggestions) diff --git a/tests/fixtures/quoted_completions/test dir/double quote b/tests/fixtures/quoted_completions/test dir/double quote new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/fixtures/quoted_completions/test dir/single quote b/tests/fixtures/quoted_completions/test dir/single quote new file mode 100644 index 0000000000..e69de29bb2