From 4f7b423f3679e237d615b91e45cf14119aafe290 Mon Sep 17 00:00:00 2001 From: Tw Date: Sun, 19 Sep 2021 13:23:05 +0800 Subject: [PATCH] Support completion when cursor inside an argument (#4023) * Support completion when cursor inside an argument Bash supports completion even when cursor is in an argument, this is very useful for some fixup after the initial completion. Let add this feature as well. Signed-off-by: Tw * Add test for when cursor inside an argument To support test this case, let's also take the position into account. Signed-off-by: Tw --- crates/nu-completion/src/engine.rs | 57 ++++++++++++++++++++---------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/crates/nu-completion/src/engine.rs b/crates/nu-completion/src/engine.rs index 8f5e648b0..67158548e 100644 --- a/crates/nu-completion/src/engine.rs +++ b/crates/nu-completion/src/engine.rs @@ -238,11 +238,19 @@ pub fn completion_location(line: &str, block: &Block, pos: usize) -> Vec vec![loc.clone()], + _ => vec![{ + let mut partial_loc = loc.clone(); + partial_loc.span = Span::new(loc.span.start(), pos); + partial_loc + }], }; } else if pos < loc.span.start() { break; @@ -339,7 +347,7 @@ mod tests { line: &str, scope: &dyn ParserScope, pos: usize, - ) -> Vec { + ) -> Vec { let (tokens, _) = lex(line, 0, nu_parser::NewlineMode::Normal); let (lite_block, _) = parse_block(tokens); @@ -348,9 +356,6 @@ mod tests { scope.exit_scope(); super::completion_location(line, &block, pos) - .into_iter() - .map(|v| v.item) - .collect() } #[test] @@ -362,7 +367,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 10), - vec![LocationType::Command], + vec![LocationType::Command.spanned(Span::new(9, 10)),], ); } @@ -373,7 +378,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 10), - vec![LocationType::Command], + vec![LocationType::Command.spanned(Span::new(9, 10)),], ); } @@ -384,7 +389,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 4), - vec![LocationType::Command], + vec![LocationType::Command.spanned(Span::new(0, 4)),], ); } @@ -395,7 +400,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 13), - vec![LocationType::Variable], + vec![LocationType::Variable.spanned(Span::new(5, 13)),], ); } @@ -410,7 +415,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 7), - vec![LocationType::Flag("du".to_string())], + vec![LocationType::Flag("du".to_string()).spanned(Span::new(3, 7)),], ); } @@ -421,7 +426,7 @@ mod tests { assert_eq!( completion_location(line, ®istry, 8), - vec![LocationType::Command], + vec![LocationType::Command.spanned(Span::new(6, 8)),], ); } @@ -433,8 +438,8 @@ mod tests { assert_eq!( completion_location(line, ®istry, 3), vec![ - LocationType::Command, - LocationType::Argument(Some("cd".to_string()), None) + LocationType::Command.spanned(Span::new(0, 3)), + LocationType::Argument(Some("cd".to_string()), None).spanned(Span::new(3, 3)), ], ); } @@ -451,8 +456,8 @@ mod tests { assert_eq!( completion_location(line, ®istry, 3), vec![ - LocationType::Argument(Some("du".to_string()), None), - LocationType::Flag("du".to_string()), + LocationType::Argument(Some("du".to_string()), None).spanned(Span::new(3, 4)), + LocationType::Flag("du".to_string()).spanned(Span::new(3, 4)), ], ); } @@ -467,8 +472,24 @@ mod tests { assert_eq!( completion_location(line, ®istry, 6), vec![ - LocationType::Command, - LocationType::Argument(Some("echo".to_string()), None) + LocationType::Command.spanned(Span::new(0, 6)), + LocationType::Argument(Some("echo".to_string()), None).spanned(Span::new(5, 6)), + ], + ); + } + + #[test] + fn completes_argument_when_cursor_inside_argument() { + let registry: VecRegistry = + vec![Signature::build("echo").rest("rest", SyntaxShape::Any, "the values to echo")] + .into(); + let line = "echo 123"; + + assert_eq!( + completion_location(line, ®istry, 6), + vec![ + LocationType::Command.spanned(Span::new(0, 6)), + LocationType::Argument(Some("echo".to_string()), None).spanned(Span::new(5, 6)), ], ); }