Sort inside complete_rec

This commit is contained in:
ysthakur 2024-06-23 20:50:03 -04:00
parent a055e59309
commit 9744ffd375
7 changed files with 55 additions and 84 deletions

View File

@ -9,7 +9,7 @@ use nu_protocol::{
}; };
use reedline::Suggestion; use reedline::Suggestion;
use super::{completion_common::sort_completions, SemanticSuggestion}; use super::{completion_common::sort_suggestions, SemanticSuggestion};
pub struct CommandCompletion { pub struct CommandCompletion {
flattened: Vec<(Span, FlatShape)>, flattened: Vec<(Span, FlatShape)>,
@ -224,7 +224,7 @@ impl Completer for CommandCompletion {
}; };
let all_suggestions = subcommands.into_iter().chain(commands).collect::<Vec<_>>(); let all_suggestions = subcommands.into_iter().chain(commands).collect::<Vec<_>>();
sort_completions( sort_suggestions(
&String::from_utf8_lossy(&prefix), &String::from_utf8_lossy(&prefix),
all_suggestions, all_suggestions,
self.get_sort_by(), self.get_sort_by(),

View File

@ -50,6 +50,7 @@ fn complete_rec(
return completions; return completions;
}; };
let mut entries = Vec::new();
for entry in result.filter_map(|e| e.ok()) { for entry in result.filter_map(|e| e.ok()) {
let entry_name = entry.file_name().to_string_lossy().into_owned(); let entry_name = entry.file_name().to_string_lossy().into_owned();
let entry_isdir = entry.path().is_dir(); let entry_isdir = entry.path().is_dir();
@ -58,20 +59,26 @@ fn complete_rec(
built.isdir = entry_isdir; built.isdir = entry_isdir;
if !dir || entry_isdir { if !dir || entry_isdir {
match partial.split_first() { entries.push((entry_name, built));
Some((base, rest)) => { }
if matches(base, &entry_name, options) { }
if !rest.is_empty() || isdir {
completions let prefix = partial.first().unwrap_or(&"");
.extend(complete_rec(rest, &built, cwd, options, dir, isdir)); let sorted_entries = sort_completions(prefix, entries, SortBy::Ascending, |(entry, _)| entry);
} else {
completions.push(built); for (entry_name, built) in sorted_entries {
} match partial.split_first() {
Some((base, rest)) => {
if matches(base, &entry_name, options) {
if !rest.is_empty() || isdir {
completions.extend(complete_rec(rest, &built, cwd, options, dir, isdir));
} else {
completions.push(built);
} }
} }
None => { }
completions.push(built); None => {
} completions.push(built);
} }
} }
} }
@ -262,24 +269,34 @@ pub fn adjust_if_intermediate(
} }
} }
/// # Arguments /// Convenience function to sort suggestions using [`sort_completions`]
/// * `prefix` - What the user's typed, for sorting by Levenshtein distance pub fn sort_suggestions(
pub fn sort_completions(
prefix: &str, prefix: &str,
mut items: Vec<SemanticSuggestion>, items: Vec<SemanticSuggestion>,
sort_by: SortBy, sort_by: SortBy,
) -> Vec<SemanticSuggestion> { ) -> Vec<SemanticSuggestion> {
sort_completions(prefix, items, sort_by, |it| &it.suggestion.value)
}
/// # Arguments
/// * `prefix` - What the user's typed, for sorting by Levenshtein distance
pub fn sort_completions<T>(
prefix: &str,
mut items: Vec<T>,
sort_by: SortBy,
get_value: fn(&T) -> &str,
) -> Vec<T> {
// Sort items // Sort items
match sort_by { match sort_by {
SortBy::LevenshteinDistance => { SortBy::LevenshteinDistance => {
items.sort_by(|a, b| { items.sort_by(|a, b| {
let a_distance = levenshtein_distance(prefix, &a.suggestion.value); let a_distance = levenshtein_distance(prefix, get_value(a));
let b_distance = levenshtein_distance(prefix, &b.suggestion.value); let b_distance = levenshtein_distance(prefix, get_value(b));
a_distance.cmp(&b_distance) a_distance.cmp(&b_distance)
}); });
} }
SortBy::Ascending => { SortBy::Ascending => {
items.sort_by(|a, b| a.suggestion.value.cmp(&b.suggestion.value)); items.sort_by(|a, b| get_value(a).cmp(get_value(b)));
} }
SortBy::None => {} SortBy::None => {}
}; };

View File

@ -12,7 +12,7 @@ use nu_protocol::{
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
use std::collections::HashMap; use std::collections::HashMap;
use super::completion_common::sort_completions; use super::completion_common::sort_suggestions;
pub struct CustomCompletion { pub struct CustomCompletion {
stack: Stack, stack: Stack,
@ -129,7 +129,7 @@ impl Completer for CustomCompletion {
} else { } else {
filter(&prefix, suggestions, completion_options) filter(&prefix, suggestions, completion_options)
}; };
sort_completions( sort_suggestions(
&String::from_utf8_lossy(&prefix), &String::from_utf8_lossy(&prefix),
suggestions, suggestions,
self.get_sort_by(), self.get_sort_by(),

View File

@ -1,14 +1,14 @@
use crate::completions::{ use crate::completions::{
completion_common::{adjust_if_intermediate, complete_item, AdjustView}, completion_common::{adjust_if_intermediate, complete_item, AdjustView},
Completer, CompletionOptions, SortBy, Completer, CompletionOptions,
}; };
use nu_ansi_term::Style; use nu_ansi_term::Style;
use nu_protocol::{ use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
levenshtein_distance, Span, Span,
}; };
use reedline::Suggestion; use reedline::Suggestion;
use std::path::{Path, MAIN_SEPARATOR as SEP}; use std::path::Path;
use super::SemanticSuggestion; use super::SemanticSuggestion;
@ -62,34 +62,11 @@ impl Completer for DirectoryCompletion {
}) })
.collect(); .collect();
// Sort items
let mut sorted_items = items;
match self.get_sort_by() {
SortBy::Ascending => {
sorted_items.sort_by(|a, b| {
// Ignore trailing slashes in folder names when sorting
a.suggestion
.value
.trim_end_matches(SEP)
.cmp(b.suggestion.value.trim_end_matches(SEP))
});
}
SortBy::LevenshteinDistance => {
sorted_items.sort_by(|a, b| {
let a_distance = levenshtein_distance(&prefix, &a.suggestion.value);
let b_distance = levenshtein_distance(&prefix, &b.suggestion.value);
a_distance.cmp(&b_distance)
});
}
_ => (),
}
// Separate the results between hidden and non hidden // Separate the results between hidden and non hidden
let mut hidden: Vec<SemanticSuggestion> = vec![]; let mut hidden: Vec<SemanticSuggestion> = vec![];
let mut non_hidden: Vec<SemanticSuggestion> = vec![]; let mut non_hidden: Vec<SemanticSuggestion> = vec![];
for item in sorted_items.into_iter() { for item in items.into_iter() {
let item_path = Path::new(&item.suggestion.value); let item_path = Path::new(&item.suggestion.value);
if let Some(value) = item_path.file_name() { if let Some(value) = item_path.file_name() {

View File

@ -1,15 +1,15 @@
use crate::completions::{ use crate::completions::{
completion_common::{adjust_if_intermediate, complete_item, AdjustView}, completion_common::{adjust_if_intermediate, complete_item, AdjustView},
Completer, CompletionOptions, SortBy, Completer, CompletionOptions,
}; };
use nu_ansi_term::Style; use nu_ansi_term::Style;
use nu_protocol::{ use nu_protocol::{
engine::{EngineState, Stack, StateWorkingSet}, engine::{EngineState, Stack, StateWorkingSet},
levenshtein_distance, Span, Span,
}; };
use nu_utils::IgnoreCaseExt; use nu_utils::IgnoreCaseExt;
use reedline::Suggestion; use reedline::Suggestion;
use std::path::{Path, MAIN_SEPARATOR as SEP}; use std::path::Path;
use super::SemanticSuggestion; use super::SemanticSuggestion;
@ -69,34 +69,11 @@ impl Completer for FileCompletion {
// Sort results prioritizing the non hidden folders // Sort results prioritizing the non hidden folders
// Sort items
let mut sorted_items = items;
match self.get_sort_by() {
SortBy::Ascending => {
sorted_items.sort_by(|a, b| {
// Ignore trailing slashes in folder names when sorting
a.suggestion
.value
.trim_end_matches(SEP)
.cmp(b.suggestion.value.trim_end_matches(SEP))
});
}
SortBy::LevenshteinDistance => {
sorted_items.sort_by(|a, b| {
let a_distance = levenshtein_distance(&prefix, &a.suggestion.value);
let b_distance = levenshtein_distance(&prefix, &b.suggestion.value);
a_distance.cmp(&b_distance)
});
}
_ => (),
}
// Separate the results between hidden and non hidden // Separate the results between hidden and non hidden
let mut hidden: Vec<SemanticSuggestion> = vec![]; let mut hidden: Vec<SemanticSuggestion> = vec![];
let mut non_hidden: Vec<SemanticSuggestion> = vec![]; let mut non_hidden: Vec<SemanticSuggestion> = vec![];
for item in sorted_items.into_iter() { for item in items.into_iter() {
let item_path = Path::new(&item.suggestion.value); let item_path = Path::new(&item.suggestion.value);
if let Some(value) = item_path.file_name() { if let Some(value) = item_path.file_name() {

View File

@ -1,4 +1,4 @@
use crate::completions::{completion_common::sort_completions, Completer, CompletionOptions}; use crate::completions::{completion_common::sort_suggestions, Completer, CompletionOptions};
use nu_protocol::{ use nu_protocol::{
ast::{Expr, Expression}, ast::{Expr, Expression},
engine::{Stack, StateWorkingSet}, engine::{Stack, StateWorkingSet},
@ -90,7 +90,7 @@ impl Completer for FlagCompletion {
} }
} }
return sort_completions( return sort_suggestions(
&String::from_utf8_lossy(&prefix), &String::from_utf8_lossy(&prefix),
output, output,
self.get_sort_by(), self.get_sort_by(),

View File

@ -9,7 +9,7 @@ use nu_protocol::{
use reedline::Suggestion; use reedline::Suggestion;
use std::str; use std::str;
use super::completion_common::sort_completions; use super::completion_common::sort_suggestions;
#[derive(Clone)] #[derive(Clone)]
pub struct VariableCompletion { pub struct VariableCompletion {
@ -72,7 +72,7 @@ impl Completer for VariableCompletion {
} }
} }
return sort_completions(&prefix_str, output, self.get_sort_by()); return sort_suggestions(&prefix_str, output, self.get_sort_by());
} }
} else { } else {
// No nesting provided, return all env vars // No nesting provided, return all env vars
@ -96,7 +96,7 @@ impl Completer for VariableCompletion {
} }
} }
return sort_completions(&prefix_str, output, self.get_sort_by()); return sort_suggestions(&prefix_str, output, self.get_sort_by());
} }
} }
@ -120,7 +120,7 @@ impl Completer for VariableCompletion {
} }
} }
return sort_completions(&prefix_str, output, self.get_sort_by()); return sort_suggestions(&prefix_str, output, self.get_sort_by());
} }
} }
@ -142,7 +142,7 @@ impl Completer for VariableCompletion {
} }
} }
return sort_completions(&prefix_str, output, self.get_sort_by()); return sort_suggestions(&prefix_str, output, self.get_sort_by());
} }
} }
} }