mirror of
https://github.com/nushell/nushell.git
synced 2025-08-09 19:57:44 +02:00
Add completions.sort option (#13311)
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
completions::{Completer, CompletionOptions, MatchAlgorithm, SortBy},
|
||||
completions::{Completer, CompletionOptions, MatchAlgorithm},
|
||||
SuggestionKind,
|
||||
};
|
||||
use nu_parser::FlatShape;
|
||||
@ -193,11 +193,7 @@ impl Completer for CommandCompletion {
|
||||
};
|
||||
|
||||
if !subcommands.is_empty() {
|
||||
return sort_suggestions(
|
||||
&String::from_utf8_lossy(&prefix),
|
||||
subcommands,
|
||||
SortBy::LevenshteinDistance,
|
||||
);
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), subcommands, options);
|
||||
}
|
||||
|
||||
let config = working_set.get_config();
|
||||
@ -222,11 +218,7 @@ impl Completer for CommandCompletion {
|
||||
vec![]
|
||||
};
|
||||
|
||||
sort_suggestions(
|
||||
&String::from_utf8_lossy(&prefix),
|
||||
commands,
|
||||
SortBy::LevenshteinDistance,
|
||||
)
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), commands, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -48,6 +48,7 @@ impl NuCompleter {
|
||||
let options = CompletionOptions {
|
||||
case_sensitive: config.case_sensitive_completions,
|
||||
match_algorithm: config.completion_algorithm.into(),
|
||||
sort: config.completion_sort,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
@ -2,17 +2,18 @@ use crate::{
|
||||
completions::{matches, CompletionOptions},
|
||||
SemanticSuggestion,
|
||||
};
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use nu_ansi_term::Style;
|
||||
use nu_engine::env_to_string;
|
||||
use nu_path::{expand_to_real_path, home_dir};
|
||||
use nu_protocol::{
|
||||
engine::{EngineState, Stack, StateWorkingSet},
|
||||
levenshtein_distance, Span,
|
||||
CompletionSort, Span,
|
||||
};
|
||||
use nu_utils::get_ls_colors;
|
||||
use std::path::{is_separator, Component, Path, PathBuf, MAIN_SEPARATOR as SEP};
|
||||
|
||||
use super::{MatchAlgorithm, SortBy};
|
||||
use super::MatchAlgorithm;
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct PathBuiltFromString {
|
||||
@ -71,7 +72,7 @@ pub fn complete_rec(
|
||||
}
|
||||
|
||||
let prefix = partial.first().unwrap_or(&"");
|
||||
let sorted_entries = sort_completions(prefix, entries, SortBy::Ascending, |(entry, _)| entry);
|
||||
let sorted_entries = sort_completions(prefix, entries, options, |(entry, _)| entry);
|
||||
|
||||
for (entry_name, built) in sorted_entries {
|
||||
match partial.split_first() {
|
||||
@ -305,33 +306,37 @@ pub fn adjust_if_intermediate(
|
||||
pub fn sort_suggestions(
|
||||
prefix: &str,
|
||||
items: Vec<SemanticSuggestion>,
|
||||
sort_by: SortBy,
|
||||
options: &CompletionOptions,
|
||||
) -> Vec<SemanticSuggestion> {
|
||||
sort_completions(prefix, items, sort_by, |it| &it.suggestion.value)
|
||||
sort_completions(prefix, items, options, |it| &it.suggestion.value)
|
||||
}
|
||||
|
||||
/// # Arguments
|
||||
/// * `prefix` - What the user's typed, for sorting by Levenshtein distance
|
||||
/// * `prefix` - What the user's typed, for sorting by fuzzy matcher score
|
||||
pub fn sort_completions<T>(
|
||||
prefix: &str,
|
||||
mut items: Vec<T>,
|
||||
sort_by: SortBy,
|
||||
options: &CompletionOptions,
|
||||
get_value: fn(&T) -> &str,
|
||||
) -> Vec<T> {
|
||||
// Sort items
|
||||
match sort_by {
|
||||
SortBy::LevenshteinDistance => {
|
||||
items.sort_by(|a, b| {
|
||||
let a_distance = levenshtein_distance(prefix, get_value(a));
|
||||
let b_distance = levenshtein_distance(prefix, get_value(b));
|
||||
a_distance.cmp(&b_distance)
|
||||
});
|
||||
}
|
||||
SortBy::Ascending => {
|
||||
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
|
||||
}
|
||||
SortBy::None => {}
|
||||
};
|
||||
if options.sort == CompletionSort::Smart && options.match_algorithm == MatchAlgorithm::Fuzzy {
|
||||
let mut matcher = SkimMatcherV2::default();
|
||||
if options.case_sensitive {
|
||||
matcher = matcher.respect_case();
|
||||
} else {
|
||||
matcher = matcher.ignore_case();
|
||||
};
|
||||
items.sort_by(|a, b| {
|
||||
let a_str = get_value(a);
|
||||
let b_str = get_value(b);
|
||||
let a_score = matcher.fuzzy_match(a_str, prefix).unwrap_or_default();
|
||||
let b_score = matcher.fuzzy_match(b_str, prefix).unwrap_or_default();
|
||||
b_score.cmp(&a_score).then(a_str.cmp(b_str))
|
||||
});
|
||||
} else {
|
||||
items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
|
||||
}
|
||||
|
||||
items
|
||||
}
|
||||
|
@ -1,17 +1,10 @@
|
||||
use fuzzy_matcher::{skim::SkimMatcherV2, FuzzyMatcher};
|
||||
use nu_parser::trim_quotes_str;
|
||||
use nu_protocol::CompletionAlgorithm;
|
||||
use nu_protocol::{CompletionAlgorithm, CompletionSort};
|
||||
use std::fmt::Display;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum SortBy {
|
||||
LevenshteinDistance,
|
||||
Ascending,
|
||||
None,
|
||||
}
|
||||
|
||||
/// Describes how suggestions should be matched.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum MatchAlgorithm {
|
||||
/// Only show suggestions which begin with the given input
|
||||
///
|
||||
@ -96,6 +89,7 @@ pub struct CompletionOptions {
|
||||
pub case_sensitive: bool,
|
||||
pub positional: bool,
|
||||
pub match_algorithm: MatchAlgorithm,
|
||||
pub sort: CompletionSort,
|
||||
}
|
||||
|
||||
impl Default for CompletionOptions {
|
||||
@ -104,6 +98,7 @@ impl Default for CompletionOptions {
|
||||
case_sensitive: true,
|
||||
positional: true,
|
||||
match_algorithm: MatchAlgorithm::Prefix,
|
||||
sort: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
use crate::completions::{
|
||||
completer::map_value_completions, Completer, CompletionOptions, MatchAlgorithm,
|
||||
SemanticSuggestion, SortBy,
|
||||
SemanticSuggestion,
|
||||
};
|
||||
use nu_engine::eval_call;
|
||||
use nu_protocol::{
|
||||
ast::{Argument, Call, Expr, Expression},
|
||||
debugger::WithoutDebug,
|
||||
engine::{Stack, StateWorkingSet},
|
||||
PipelineData, Span, Type, Value,
|
||||
CompletionSort, PipelineData, Span, Type, Value,
|
||||
};
|
||||
use nu_utils::IgnoreCaseExt;
|
||||
use std::collections::HashMap;
|
||||
@ -18,7 +18,6 @@ pub struct CustomCompletion {
|
||||
stack: Stack,
|
||||
decl_id: usize,
|
||||
line: String,
|
||||
sort_by: SortBy,
|
||||
}
|
||||
|
||||
impl CustomCompletion {
|
||||
@ -27,7 +26,6 @@ impl CustomCompletion {
|
||||
stack,
|
||||
decl_id,
|
||||
line,
|
||||
sort_by: SortBy::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -93,10 +91,6 @@ impl Completer for CustomCompletion {
|
||||
.and_then(|val| val.as_bool().ok())
|
||||
.unwrap_or(false);
|
||||
|
||||
if should_sort {
|
||||
self.sort_by = SortBy::Ascending;
|
||||
}
|
||||
|
||||
custom_completion_options = Some(CompletionOptions {
|
||||
case_sensitive: options
|
||||
.get("case_sensitive")
|
||||
@ -114,6 +108,11 @@ impl Completer for CustomCompletion {
|
||||
.unwrap_or(MatchAlgorithm::Prefix),
|
||||
None => completion_options.match_algorithm,
|
||||
},
|
||||
sort: if should_sort {
|
||||
CompletionSort::Alphabetical
|
||||
} else {
|
||||
CompletionSort::Smart
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -124,12 +123,11 @@ impl Completer for CustomCompletion {
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let suggestions = if let Some(custom_completion_options) = custom_completion_options {
|
||||
filter(&prefix, suggestions, &custom_completion_options)
|
||||
} else {
|
||||
filter(&prefix, suggestions, completion_options)
|
||||
};
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, self.sort_by)
|
||||
let options = custom_completion_options
|
||||
.as_ref()
|
||||
.unwrap_or(completion_options);
|
||||
let suggestions = filter(&prefix, suggestions, completion_options);
|
||||
sort_suggestions(&String::from_utf8_lossy(&prefix), suggestions, options)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use nu_protocol::{
|
||||
use reedline::Suggestion;
|
||||
use std::path::{is_separator, Path, MAIN_SEPARATOR as SEP, MAIN_SEPARATOR_STR};
|
||||
|
||||
use super::{completion_common::sort_suggestions, SemanticSuggestion, SortBy};
|
||||
use super::{completion_common::sort_suggestions, SemanticSuggestion};
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub struct DotNuCompletion {}
|
||||
@ -130,6 +130,6 @@ impl Completer for DotNuCompletion {
|
||||
})
|
||||
.collect();
|
||||
|
||||
sort_suggestions(&prefix_str, output, SortBy::Ascending)
|
||||
sort_suggestions(&prefix_str, output, options)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
use crate::completions::{
|
||||
completion_common::sort_suggestions, Completer, CompletionOptions, SortBy,
|
||||
};
|
||||
use crate::completions::{completion_common::sort_suggestions, Completer, CompletionOptions};
|
||||
use nu_protocol::{
|
||||
ast::{Expr, Expression},
|
||||
engine::{Stack, StateWorkingSet},
|
||||
@ -90,7 +88,7 @@ impl Completer for FlagCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, SortBy::Ascending);
|
||||
return sort_suggestions(&String::from_utf8_lossy(&prefix), output, options);
|
||||
}
|
||||
|
||||
vec![]
|
||||
|
@ -13,7 +13,7 @@ mod variable_completions;
|
||||
pub use base::{Completer, SemanticSuggestion, SuggestionKind};
|
||||
pub use command_completions::CommandCompletion;
|
||||
pub use completer::NuCompleter;
|
||||
pub use completion_options::{CompletionOptions, MatchAlgorithm, SortBy};
|
||||
pub use completion_options::{CompletionOptions, MatchAlgorithm};
|
||||
pub use custom_completions::CustomCompletion;
|
||||
pub use directory_completions::DirectoryCompletion;
|
||||
pub use dotnu_completions::DotNuCompletion;
|
||||
|
@ -9,7 +9,7 @@ use nu_protocol::{
|
||||
use reedline::Suggestion;
|
||||
use std::str;
|
||||
|
||||
use super::{completion_common::sort_suggestions, SortBy};
|
||||
use super::completion_common::sort_suggestions;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct VariableCompletion {
|
||||
@ -72,7 +72,7 @@ impl Completer for VariableCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
}
|
||||
} else {
|
||||
// No nesting provided, return all env vars
|
||||
@ -93,7 +93,7 @@ impl Completer for VariableCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,7 +117,7 @@ impl Completer for VariableCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ impl Completer for VariableCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
return sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
return sort_suggestions(&prefix_str, output, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -217,7 +217,7 @@ impl Completer for VariableCompletion {
|
||||
}
|
||||
}
|
||||
|
||||
output = sort_suggestions(&prefix_str, output, SortBy::Ascending);
|
||||
output = sort_suggestions(&prefix_str, output, options);
|
||||
|
||||
output.dedup(); // TODO: Removes only consecutive duplicates, is it intended?
|
||||
|
||||
|
Reference in New Issue
Block a user