249 feature request better search results (#282)
Some checks failed
Linux / build (push) Has been cancelled
MacOS / build (push) Has been cancelled
Windows / build (push) Has been cancelled

* feat: issue 249 - fuzzy search replaced the old find explorer

* fix: forgot to upload file

* fix: removed debug
This commit is contained in:
Christian Visintin
2024-10-02 17:45:48 +02:00
committed by GitHub
parent c507d54700
commit b2a8a3041c
13 changed files with 625 additions and 226 deletions

View File

@@ -4,12 +4,15 @@
use std::path::Path;
use nucleo::Utf32String;
use remotefs::File;
use crate::explorer::builder::FileExplorerBuilder;
use crate::explorer::{FileExplorer, FileSorting, GroupDirs};
use crate::explorer::{FileExplorer, FileSorting};
use crate::system::config_client::ConfigClient;
const FUZZY_SEARCH_THRESHOLD: u16 = 50;
/// File explorer tab
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum FileExplorerTab {
@@ -28,10 +31,10 @@ pub enum FoundExplorerTab {
/// Browser contains the browser options
pub struct Browser {
local: FileExplorer, // Local File explorer state
remote: FileExplorer, // Remote File explorer state
found: Option<(FoundExplorerTab, FileExplorer)>, // File explorer for find result
tab: FileExplorerTab, // Current selected tab
local: FileExplorer, // Local File explorer state
remote: FileExplorer, // Remote File explorer state
found: Option<Found>, // File explorer for find result
tab: FileExplorerTab, // Current selected tab
pub sync_browsing: bool,
}
@@ -64,17 +67,35 @@ impl Browser {
}
pub fn found(&self) -> Option<&FileExplorer> {
self.found.as_ref().map(|x| &x.1)
self.found.as_ref().map(|x| &x.explorer)
}
pub fn found_mut(&mut self) -> Option<&mut FileExplorer> {
self.found.as_mut().map(|x| &mut x.1)
self.found.as_mut().map(|x| &mut x.explorer)
}
/// Perform fuzzy search on found tab
pub fn fuzzy_search(&mut self, needle: &str) {
if let Some(x) = self.found.as_mut() {
x.fuzzy_search(needle)
}
}
/// Initialize fuzzy search
pub fn init_fuzzy_search(&mut self) {
if let Some(explorer) = self.found_mut() {
explorer.set_files(vec![]);
}
}
pub fn set_found(&mut self, tab: FoundExplorerTab, files: Vec<File>, wrkdir: &Path) {
let mut explorer = Self::build_found_explorer(wrkdir);
explorer.set_files(files);
self.found = Some((tab, explorer));
explorer.set_files(files.clone());
self.found = Some(Found {
tab,
explorer,
search_results: files,
});
}
pub fn del_found(&mut self) {
@@ -83,7 +104,7 @@ impl Browser {
/// Returns found tab if any
pub fn found_tab(&self) -> Option<FoundExplorerTab> {
self.found.as_ref().map(|x| x.0)
self.found.as_ref().map(|x| x.tab)
}
pub fn tab(&self) -> FileExplorerTab {
@@ -129,8 +150,8 @@ impl Browser {
/// Build explorer reading from `ConfigClient`, for found result (has some differences)
fn build_found_explorer(wrkdir: &Path) -> FileExplorer {
FileExplorerBuilder::new()
.with_file_sorting(FileSorting::Name)
.with_group_dirs(Some(GroupDirs::First))
.with_file_sorting(FileSorting::None)
.with_group_dirs(None)
.with_hidden_files(true)
.with_stack_size(0)
.with_formatter(Some(
@@ -139,3 +160,48 @@ impl Browser {
.build()
}
}
/// Found state
struct Found {
explorer: FileExplorer,
/// Search results; original copy of files
search_results: Vec<File>,
tab: FoundExplorerTab,
}
impl Found {
/// Fuzzy search from `search_results` and update `explorer.files` with the results.
pub fn fuzzy_search(&mut self, needle: &str) {
let search = Utf32String::from(needle);
let mut nucleo = nucleo::Matcher::new(nucleo::Config::DEFAULT.match_paths());
// get scores
let mut fuzzy_results_with_score = self
.search_results
.iter()
.map(|f| {
(
Utf32String::from(f.path().to_string_lossy().into_owned()),
f,
)
})
.filter_map(|(path, file)| {
nucleo
.fuzzy_match(path.slice(..), search.slice(..))
.map(|score| (path, file, score))
})
.filter(|(_, _, score)| *score >= FUZZY_SEARCH_THRESHOLD)
.collect::<Vec<_>>();
// sort by score; highest first
fuzzy_results_with_score.sort_by(|(_, _, a), (_, _, b)| b.cmp(a));
// update files
self.explorer.set_files(
fuzzy_results_with_score
.into_iter()
.map(|(_, file, _)| file.clone())
.collect(),
);
}
}