diff --git a/crates/nu-cli/src/completions/custom_completions.rs b/crates/nu-cli/src/completions/custom_completions.rs index 63e65053b4..4f19cd0eb0 100644 --- a/crates/nu-cli/src/completions/custom_completions.rs +++ b/crates/nu-cli/src/completions/custom_completions.rs @@ -1,13 +1,12 @@ use crate::completions::{ - completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm, - SemanticSuggestion, + completer::map_value_completions, Completer, CompletionOptions, SemanticSuggestion, }; use nu_engine::eval_call; use nu_protocol::{ ast::{Argument, Call, Expr, Expression}, debugger::WithoutDebug, engine::{Stack, StateWorkingSet}, - CompletionSort, DeclId, PipelineData, Span, Type, Value, + DeclId, PipelineData, Span, Type, Value, }; use std::collections::HashMap; @@ -68,6 +67,7 @@ impl Completer for CustomCompletion { ); let mut custom_completion_options = None; + let mut should_sort = true; // Parse result let suggestions = result @@ -85,10 +85,9 @@ impl Completer for CustomCompletion { let options = val.get("options"); if let Some(Value::Record { val: options, .. }) = &options { - let should_sort = options - .get("sort") - .and_then(|val| val.as_bool().ok()) - .unwrap_or(false); + if let Some(sort) = options.get("sort").and_then(|val| val.as_bool().ok()) { + should_sort = sort; + } custom_completion_options = Some(CompletionOptions { case_sensitive: options @@ -98,20 +97,16 @@ impl Completer for CustomCompletion { positional: options .get("positional") .and_then(|val| val.as_bool().ok()) - .unwrap_or(true), + .unwrap_or(completion_options.positional), match_algorithm: match options.get("completion_algorithm") { Some(option) => option .coerce_string() .ok() .and_then(|option| option.try_into().ok()) - .unwrap_or(MatchAlgorithm::Prefix), + .unwrap_or(completion_options.match_algorithm), None => completion_options.match_algorithm, }, - sort: if should_sort { - CompletionSort::Alphabetical - } else { - CompletionSort::Smart - }, + sort: completion_options.sort, }); } @@ -124,9 +119,17 @@ impl Completer for CustomCompletion { let options = custom_completion_options.unwrap_or(completion_options.clone()); let mut matcher = NuMatcher::new(String::from_utf8_lossy(prefix), options); - for sugg in suggestions { - matcher.add_semantic_suggestion(sugg); + + if should_sort { + for sugg in suggestions { + matcher.add_semantic_suggestion(sugg); + } + matcher.results() + } else { + suggestions + .into_iter() + .filter(|sugg| matcher.matches(&sugg.suggestion.value)) + .collect() } - matcher.results() } } diff --git a/crates/nu-cli/tests/completions/mod.rs b/crates/nu-cli/tests/completions/mod.rs index 4bcf8b55c0..7f6fe30430 100644 --- a/crates/nu-cli/tests/completions/mod.rs +++ b/crates/nu-cli/tests/completions/mod.rs @@ -88,6 +88,27 @@ fn completer_strings_with_options() -> NuCompleter { NuCompleter::new(Arc::new(engine), Arc::new(stack)) } +#[fixture] +fn completer_strings_no_sort() -> NuCompleter { + // Create a new engine + let (_, _, mut engine, mut stack) = new_engine(); + let command = r#" + def animals [] { + { + completions: ["zzzfoo", "foo", "not matched", "abcfoo" ], + options: { + completion_algorithm: "fuzzy", + sort: false, + } + } + } + def my-command [animal: string@animals] { print $animal }"#; + assert!(support::merge_input(command.as_bytes(), &mut engine, &mut stack).is_ok()); + + // Instantiate a new completer + NuCompleter::new(Arc::new(engine), Arc::new(stack)) +} + #[fixture] fn custom_completer() -> NuCompleter { // Create a new engine @@ -210,6 +231,13 @@ fn customcompletions_case_insensitive(mut completer_strings_with_options: NuComp match_suggestions(&expected, &suggestions); } +#[rstest] +fn customcompletions_no_sort(mut completer_strings_no_sort: NuCompleter) { + let suggestions = completer_strings_no_sort.complete("my-command foo", 14); + let expected: Vec = vec!["zzzfoo".into(), "foo".into(), "abcfoo".into()]; + match_suggestions(&expected, &suggestions); +} + #[test] fn dotnu_completions() { // Create a new engine