From e45b169cba4202c47239b3ca2447e1266d6f09f8 Mon Sep 17 00:00:00 2001 From: pwygab <88221256+merelymyself@users.noreply.github.com> Date: Thu, 25 Aug 2022 03:46:00 +0800 Subject: [PATCH] default to file completion after first command, add `command` option for completions (#6257) * remove unnecessary FlatShape * add test --- .../src/completions/command_completions.rs | 10 ++++-- crates/nu-cli/src/completions/completer.rs | 21 ++++++++++++ crates/nu-cli/tests/completions.rs | 33 +++++++++++++++++++ 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/crates/nu-cli/src/completions/command_completions.rs b/crates/nu-cli/src/completions/command_completions.rs index 37417e3a20..468708ad50 100644 --- a/crates/nu-cli/src/completions/command_completions.rs +++ b/crates/nu-cli/src/completions/command_completions.rs @@ -11,6 +11,7 @@ pub struct CommandCompletion { engine_state: Arc, flattened: Vec<(Span, FlatShape)>, flat_shape: FlatShape, + force_completion_after_space: bool, } impl CommandCompletion { @@ -19,11 +20,13 @@ impl CommandCompletion { _: &StateWorkingSet, flattened: Vec<(Span, FlatShape)>, flat_shape: FlatShape, + force_completion_after_space: bool, ) -> Self { Self { engine_state, flattened, flat_shape, + force_completion_after_space, } } @@ -81,9 +84,6 @@ impl CommandCompletion { match_algorithm: MatchAlgorithm, ) -> Vec { let partial = working_set.get_span_contents(span); - if partial.is_empty() { - return Vec::new(); - } let filter_predicate = |command: &[u8]| match_algorithm.matches_u8(command, partial); @@ -209,6 +209,10 @@ impl Completer for CommandCompletion { || ((span.end - span.start) == 0) { // we're in a gap or at a command + if working_set.get_span_contents(span).is_empty() && !self.force_completion_after_space + { + return vec![]; + } self.complete_commands( working_set, span, diff --git a/crates/nu-cli/src/completions/completer.rs b/crates/nu-cli/src/completions/completer.rs index e78d0ae04d..c1bd49973c 100644 --- a/crates/nu-cli/src/completions/completer.rs +++ b/crates/nu-cli/src/completions/completer.rs @@ -215,6 +215,26 @@ impl NuCompleter { } } + // specially check if it is currently empty - always complete commands + if flat_idx == 0 && working_set.get_span_contents(new_span).is_empty() { + let mut completer = CommandCompletion::new( + self.engine_state.clone(), + &working_set, + flattened.clone(), + // flat_idx, + FlatShape::String, + true, + ); + return self.process_completion( + &mut completer, + &working_set, + prefix, + new_span, + offset, + pos, + ); + } + // Completions that depends on the previous expression (e.g: use, source) if flat_idx > 0 { if let Some(previous_expr) = flattened.get(flat_idx - 1) { @@ -302,6 +322,7 @@ impl NuCompleter { flattened.clone(), // flat_idx, flat_shape.clone(), + false, ); let mut out: Vec<_> = self.process_completion( diff --git a/crates/nu-cli/tests/completions.rs b/crates/nu-cli/tests/completions.rs index c947e43122..c7463bbea9 100644 --- a/crates/nu-cli/tests/completions.rs +++ b/crates/nu-cli/tests/completions.rs @@ -625,3 +625,36 @@ fn run_external_completion(block: &str, input: &str) -> Vec { completer.complete(&input, input.len()) } + +#[test] +fn unknown_command_completion() { + let (_, _, engine, stack) = new_engine(); + + let mut completer = NuCompleter::new(std::sync::Arc::new(engine), stack); + + let target_dir = "thiscommanddoesnotexist "; + let suggestions = completer.complete(target_dir, target_dir.len()); + + #[cfg(windows)] + let expected_paths: Vec = vec![ + "nushell".to_string(), + "test_a\\".to_string(), + "test_b\\".to_string(), + "another\\".to_string(), + "custom_completion.nu".to_string(), + ".hidden_file".to_string(), + ".hidden_folder\\".to_string(), + ]; + #[cfg(not(windows))] + let expected_paths: Vec = vec![ + "nushell".to_string(), + "test_a/".to_string(), + "test_b/".to_string(), + "another/".to_string(), + "custom_completion.nu".to_string(), + ".hidden_file".to_string(), + ".hidden_folder/".to_string(), + ]; + + match_suggestions(expected_paths, suggestions) +}