From 495d2ebd70e20860dc40774069f9ffbc5f869473 Mon Sep 17 00:00:00 2001 From: Coen Fox <9779696+Gymea@users.noreply.github.com> Date: Wed, 13 Jan 2021 15:04:29 +1100 Subject: [PATCH] Improve tab completion behaviour (#2916) * Improve tab completion behaviour * Fix clippy issue * Add test cases --- crates/nu-cli/src/shell/helper.rs | 68 ++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/crates/nu-cli/src/shell/helper.rs b/crates/nu-cli/src/shell/helper.rs index 0c4c5cd30..0e2009c65 100644 --- a/crates/nu-cli/src/shell/helper.rs +++ b/crates/nu-cli/src/shell/helper.rs @@ -51,7 +51,27 @@ impl rustyline::completion::Completer for Helper { } fn update(&self, line: &mut rustyline::line_buffer::LineBuffer, start: usize, elected: &str) { - let end = line.pos(); + let end = start + + match line + .as_str() + .chars() + .into_iter() + .skip(start) + .zip(elected.chars().into_iter()) + .enumerate() + .find(|(_, (line, replace))| line != replace) + { + Some((index, (_, _))) => index, + None => line.pos(), + }; + + let mut end = end.max(line.pos()); + + let remaining = &line.as_str()[end..]; + if remaining.starts_with('"') { + end += 1; + } + line.replace(start..end, elected) } } @@ -144,3 +164,49 @@ fn vec_tag(input: Vec>) -> Option { } impl rustyline::Helper for Helper {} + +#[cfg(test)] +mod tests { + use super::*; + use nu_engine::basic_evaluation_context; + use rustyline::completion::Completer; + use rustyline::line_buffer::LineBuffer; + + #[test] + fn closing_quote_should_replaced() { + let text = "cd \"folder with spaces\\subdirectory\\\""; + let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\""; + + let mut buffer = LineBuffer::with_capacity(256); + buffer.insert_str(0, text); + buffer.set_pos(text.len() - 1); + + let helper = Helper::new(basic_evaluation_context().unwrap(), None); + + helper.update(&mut buffer, "cd ".len(), &replacement); + + assert_eq!( + buffer.as_str(), + "cd \"folder with spaces\\subdirectory\\subsubdirectory\\\"" + ); + } + + #[test] + fn replacement_with_cursor_in_text() { + let text = "cd \"folder with spaces\\subdirectory\\\""; + let replacement = "\"folder with spaces\\subdirectory\\subsubdirectory\\\""; + + let mut buffer = LineBuffer::with_capacity(256); + buffer.insert_str(0, text); + buffer.set_pos(text.len() - 30); + + let helper = Helper::new(basic_evaluation_context().unwrap(), None); + + helper.update(&mut buffer, "cd ".len(), &replacement); + + assert_eq!( + buffer.as_str(), + "cd \"folder with spaces\\subdirectory\\subsubdirectory\\\"" + ); + } +}