summaryrefslogtreecommitdiffstats
path: root/default-plugins/strider/src/search/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'default-plugins/strider/src/search/mod.rs')
-rw-r--r--default-plugins/strider/src/search/mod.rs317
1 files changed, 0 insertions, 317 deletions
diff --git a/default-plugins/strider/src/search/mod.rs b/default-plugins/strider/src/search/mod.rs
deleted file mode 100644
index 6ffa60cba..000000000
--- a/default-plugins/strider/src/search/mod.rs
+++ /dev/null
@@ -1,317 +0,0 @@
-pub mod controls_line;
-pub mod search_results;
-pub mod search_state;
-pub mod selection_controls_area;
-pub mod ui;
-
-use crate::state::{CURRENT_SEARCH_TERM, ROOT};
-use crate::MessageToPlugin;
-use search_state::SearchType;
-use std::collections::{BTreeMap, BTreeSet, HashMap};
-use std::path::{Path, PathBuf};
-
-use unicode_width::UnicodeWidthStr;
-use zellij_tile::prelude::*;
-
-use fuzzy_matcher::skim::SkimMatcherV2;
-use fuzzy_matcher::FuzzyMatcher;
-use ignore::Walk;
-use search_results::SearchResult;
-use serde::{Deserialize, Serialize};
-
-use std::io::{self, BufRead};
-
-#[derive(Default, Serialize, Deserialize)]
-pub struct Search {
- search_type: SearchType,
- file_names: BTreeSet<String>,
- file_contents: BTreeMap<(String, usize), String>, // file_name, line_number, line
- cached_file_name_results: HashMap<String, Vec<SearchResult>>,
- cached_file_contents_results: HashMap<String, Vec<SearchResult>>,
-}
-
-impl Search {
- pub fn new(search_type: SearchType) -> Self {
- Search {
- search_type,
- ..Default::default()
- }
- }
- fn on_message(&mut self, message: String, payload: String) {
- match serde_json::from_str::<MessageToSearch>(&message) {
- Ok(MessageToSearch::ScanFolder) => {
- self.scan_hd();
- post_message_to_plugin(PluginMessage {
- worker_name: None,
- name: serde_json::to_string(&MessageToPlugin::DoneScanningFolder).unwrap(),
- payload: "".to_owned(),
- });
- },
- Ok(MessageToSearch::Search) => {
- if let Some(current_search_term) = self.read_search_term_from_hd_cache() {
- self.search(current_search_term);
- }
- },
- Ok(MessageToSearch::FileSystemCreate) => {
- self.rescan_files(payload);
- },
- Ok(MessageToSearch::FileSystemUpdate) => {
- self.rescan_files(payload);
- },
- Ok(MessageToSearch::FileSystemDelete) => {
- self.delete_files(payload);
- },
- Err(e) => eprintln!("Failed to deserialize worker message {:?}", e),
- }
- }
- pub fn scan_hd(&mut self) {
- for result in Walk::new(ROOT) {
- if let Ok(entry) = result {
- self.add_file_entry(entry.path(), entry.metadata().ok());
- }
- }
- }
- pub fn search(&mut self, search_term: String) {
- let search_results_limit = 100; // artificial limit to prevent probably unwanted chaos
- // let mut matcher = SkimMatcherV2::default().use_cache(true).element_limit(search_results_limit);
- let mut file_names_search_results = None;
- let mut file_contents_search_results = None;
- if let SearchType::Names | SearchType::NamesAndContents = self.search_type {
- let file_names_matches = match self.cached_file_name_results.get(&search_term) {
- Some(cached_results) => cached_results.clone(),
- None => {
- let mut matcher = SkimMatcherV2::default().use_cache(true);
- let results = self.search_file_names(&search_term, &mut matcher);
- self.cached_file_name_results
- .insert(search_term.clone(), results.clone());
- results
- },
- };
- file_names_search_results = Some(
- ResultsOfSearch::new(search_term.clone(), file_names_matches)
- .limit_search_results(search_results_limit),
- );
- };
- if let SearchType::Contents | SearchType::NamesAndContents = self.search_type {
- let file_contents_matches = match self.cached_file_contents_results.get(&search_term) {
- Some(cached_results) => cached_results.clone(),
- None => {
- let mut matcher = SkimMatcherV2::default().use_cache(true);
- let results = self.search_file_contents(&search_term, &mut matcher);
- self.cached_file_contents_results
- .insert(search_term.clone(), results.clone());
- results
- },
- };
- file_contents_search_results = Some(
- ResultsOfSearch::new(search_term.clone(), file_contents_matches)
- .limit_search_results(search_results_limit),
- );
- };
-
- // if the search term changed before we finished, let's search again!
- if let Some(current_search_term) = self.read_search_term_from_hd_cache() {
- if current_search_term != search_term {
- return self.search(current_search_term.into());
- }
- }
- if let Some(file_names_search_results) = file_names_search_results {
- post_message_to_plugin(PluginMessage {
- name: serde_json::to_string(&MessageToPlugin::UpdateFileNameSearchResults).unwrap(),
- payload: serde_json::to_string(&file_names_search_results).unwrap(),
- ..Default::default()
- });
- }
- if let Some(file_contents_search_results) = file_contents_search_results {
- post_message_to_plugin(PluginMessage {
- name: serde_json::to_string(&MessageToPlugin::UpdateFileContentsSearchResults)
- .unwrap(),
- payload: serde_json::to_string(&file_contents_search_results).unwrap(),
- ..Default::default()
- });
- }
- }
- pub fn rescan_files(&mut self, paths: String) {
- match serde_json::from_str::<Vec<PathBuf>>(&paths) {
- Ok(paths) => {
- for path in paths {
- self.add_file_entry(&path, path.metadata().ok());
- }
- self.cached_file_name_results.clear();
- self.cached_file_contents_results.clear();
- },
- Err(e) => eprintln!("Failed to deserialize paths: {:?}", e),
- }
- }
- pub fn delete_files(&mut self, paths: String) {
- match serde_json::from_str::<Vec<PathBuf>>(&paths) {
- Ok(paths) => {
- self.remove_existing_entries(&paths);
- self.cached_file_name_results.clear();
- self.cached_file_contents_results.clear();
- },
- Err(e) => eprintln!("Failed to deserialize paths: {:?}", e),
- }
- }
- fn add_file_entry(&mut self, file_name: &Path, file_metadata: Option<std::fs::Metadata>) {
- let file_path = file_name.display().to_string();
- let file_path_stripped_prefix = self.strip_file_prefix(&file_name);
-
- self.file_names.insert(file_path_stripped_prefix.clone());
- if let SearchType::NamesAndContents | SearchType::Contents = self.search_type {
- if file_metadata.map(|f| f.is_file()).unwrap_or(false) {
- if let Ok(file) = std::fs::File::open(&file_path) {
- let lines = io::BufReader::new(file).lines();
- for (index, line) in lines.enumerate() {
- match line {
- Ok(line) => {
- self.file_contents.insert(
- (file_path_stripped_prefix.clone(), index + 1),
- String::from_utf8_lossy(
- &strip_ansi_escapes::strip(line).unwrap(),
- )
- .to_string(),
- );
- },
- Err(_) => {
- break; // probably a binary file, skip it
- },
- }
- }
- }
- }
- }
- }
- fn search_file_names(
- &self,
- search_term: &str,
- matcher: &mut SkimMatcherV2,
- ) -> Vec<SearchResult> {
- let mut matches = vec![];
- for entry in &self.file_names {
- if let Some((score, indices)) = matcher.fuzzy_indices(&entry, &search_term) {
- matches.push(SearchResult::new_file_name(
- score,
- indices,
- entry.to_owned(),
- ));
- }
- }
- matches
- }
- fn search_file_contents(
- &self,
- search_term: &str,
- matcher: &mut SkimMatcherV2,
- ) -> Vec<SearchResult> {
- let mut matches = vec![];
- for ((file_name, line_number), line_entry) in &self.file_contents {
- if let Some((score, indices)) = matcher.fuzzy_indices(&line_entry, &search_term) {
- matches.push(SearchResult::new_file_line(
- score,
- indices,
- file_name.clone(),
- line_entry.clone(),
- *line_number,
- ));
- }
- }
- matches
- }
- fn strip_file_prefix(&self, file_name: &Path) -> String {
- let mut file_path_stripped_prefix = file_name.display().to_string().split_off(ROOT.width());
- if file_path_stripped_prefix.starts_with('/') {
- file_path_stripped_prefix.remove(0);
- }
- file_path_stripped_prefix
- }
- fn read_search_term_from_hd_cache(&self) -> Option<String> {
- match std::fs::read(CURRENT_SEARCH_TERM) {
- Ok(current_search_term) => {
- Some(String::from_utf8_lossy(&current_search_term).to_string())
- },
- _ => None,
- }
- }
- fn remove_existing_entries(&mut self, paths: &Vec<PathBuf>) {
- let file_path_stripped_prefixes: Vec<String> =
- paths.iter().map(|p| self.strip_file_prefix(&p)).collect();
- self.file_names
- .retain(|file_name| !file_path_stripped_prefixes.contains(file_name));
- self.file_contents.retain(|(file_name, _line_in_file), _| {
- !file_path_stripped_prefixes.contains(file_name)
- });
- }
-}
-
-#[derive(Serialize, Deserialize)]
-pub enum MessageToSearch {
- ScanFolder,
- Search,
- FileSystemCreate,
- FileSystemUpdate,
- FileSystemDelete,
-}
-
-#[derive(Serialize, Deserialize)]
-pub struct FileNameWorker {
- search: Search,
-}
-
-impl Default for FileNameWorker {
- fn default() -> Self {
- FileNameWorker {
- search: Search::new(SearchType::Names),
- }
- }
-}
-
-#[derive(Serialize, Deserialize)]
-pub struct FileContentsWorker {
- search: Search,
-}
-
-impl Default for FileContentsWorker {
- fn default() -> Self {
- FileContentsWorker {
- search: Search::new(SearchType::Contents),
- }
- }
-}
-
-impl<'de> ZellijWorker<'de> for FileNameWorker {
- fn on_message(&mut self, message: String, payload: String) {
- self.search.on_message(message, payload);
- }
-}
-
-impl<'de> ZellijWorker<'de> for FileContentsWorker {
- fn on_message(&mut self, message: String, payload: String) {
- self.search.on_message(message, payload);
- }
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-pub struct ResultsOfSearch {
- pub search_term: String,
- pub search_results: Vec<SearchResult>,
-}
-
-impl ResultsOfSearch {
- pub fn new(search_term: String, search_results: Vec<SearchResult>) -> Self {
- ResultsOfSearch {
- search_term,
- search_results,
- }
- }
- pub fn limit_search_results(mut self, max_results: usize) -> Self {
- self.search_results
- .sort_by(|a, b| b.score().cmp(&a.score()));
- self.search_results = if self.search_results.len() > max_results {
- self.search_results.drain(..max_results).collect()
- } else {
- self.search_results.drain(..).collect()
- };
- self
- }
-}