diff options
| author | lukeflo | 2024-10-12 21:34:12 +0200 |
|---|---|---|
| committer | lukeflo | 2024-10-12 22:41:38 +0200 |
| commit | 12b67d9d67d0e3256f6ddc8bc47572f6a178df4c (patch) | |
| tree | 65479de8c69bf7ce7eff1d65881c2d79f914322d | |
| parent | 84e80b4074a174163a4c57c59ff616356e0a4350 (diff) | |
| download | bibiman-12b67d9d67d0e3256f6ddc8bc47572f6a178df4c.tar.gz bibiman-12b67d9d67d0e3256f6ddc8bc47572f6a178df4c.zip | |
reworked search mechanism
| -rw-r--r-- | src/backend/search.rs | 64 | ||||
| -rw-r--r-- | src/frontend/app.rs | 11 | ||||
| -rw-r--r-- | src/frontend/entries.rs | 20 | ||||
| -rw-r--r-- | src/frontend/keywords.rs | 60 |
4 files changed, 75 insertions, 80 deletions
diff --git a/src/backend/search.rs b/src/backend/search.rs index 6757790..bb87416 100644 --- a/src/backend/search.rs +++ b/src/backend/search.rs @@ -4,10 +4,13 @@ use nucleo_matcher::{ }; use std::collections::HashMap; +use crate::frontend::entries::EntryTableItem; + #[derive(Debug)] pub struct BibiSearch { pub search_string: String, // Search string show in footer, used for search pub inner_search: bool, // True, if we trigger a search for already filtered list + // pub entry_list_at_search_start: Vec<EntryTableItem>, pub filtered_entry_list_by_search: Vec<Vec<String>>, // Temporary holds entry list filtered by search pattern to refilter it pub filtered_entry_list_by_tags: Vec<Vec<String>>, // Holds entry list filtered by tag to filter it further by search pub filtered_tag_list: Vec<String>, @@ -18,6 +21,7 @@ impl Default for BibiSearch { Self { search_string: String::new(), inner_search: false, + // entry_list_at_search_start: Vec::new(), filtered_entry_list_by_search: Vec::new(), filtered_entry_list_by_tags: Vec::new(), filtered_tag_list: Vec::new(), @@ -26,18 +30,29 @@ impl Default for BibiSearch { } impl BibiSearch { - // Stringify inner Vec<String> by joining/concat - fn convert_to_string(inner_vec: &Vec<String>) -> String { - inner_vec[0..6].join(" ") + // Stringify EntryTableItem by joining/concat + fn convert_to_string(inner_vec: &EntryTableItem) -> String { + let entry_table_item_str = { + format!( + "{} {} {} {} {} {}", + &inner_vec.authors, + &inner_vec.title, + &inner_vec.year, + &inner_vec.pubtype, + &inner_vec.keywords, + &inner_vec.citekey + ) + }; + entry_table_item_str } // Return a filtered entry list pub fn search_entry_list( search_pattern: &str, - orig_list: Vec<Vec<String>>, - ) -> Vec<Vec<String>> { + orig_list: Vec<EntryTableItem>, + ) -> Vec<EntryTableItem> { // Create a hashmap to connect stingified entry with entry vec - let mut entry_string_hm: HashMap<String, Vec<String>> = HashMap::new(); + let mut entry_string_hm: HashMap<String, EntryTableItem> = HashMap::new(); // Convert all entries to string and insert them into the hashmap // next to the original inner Vec<String> of the entry list @@ -58,10 +73,11 @@ impl BibiSearch { // Create filtered entry list and push the inner entry vec's to it // Use the filtered stringified hm-key as index - let mut filtered_list: Vec<Vec<String>> = Vec::new(); + let mut filtered_list: Vec<EntryTableItem> = Vec::new(); for m in filtered_matches { filtered_list.push(entry_string_hm[&m].to_owned()); } + filtered_list.sort(); filtered_list } @@ -79,11 +95,17 @@ impl BibiSearch { filtered_matches } - pub fn filter_entries_by_tag(keyword: &str, orig_list: &Vec<Vec<String>>) -> Vec<Vec<String>> { - let mut filtered_list: Vec<Vec<String>> = Vec::new(); + pub fn filter_entries_by_tag( + keyword: &str, + orig_list: &Vec<EntryTableItem>, + ) -> Vec<EntryTableItem> { + let mut filtered_list: Vec<EntryTableItem> = Vec::new(); + // Loop over the whole given entry table + // Check if the selected keyword is present in the current entry + // If present, push the entry to the filtered list for e in orig_list { - if e[4].contains(keyword) { + if e.keywords.contains(keyword) { filtered_list.push(e.to_owned()); } } @@ -98,17 +120,17 @@ mod tests { #[test] fn test_vector_join() { - let bibvec = vec![ - "Author".to_string(), - "Title".to_string(), - "1999".to_string(), - "article".to_string(), - "hello, bye".to_string(), - "author_1999".to_string(), - "An abstract with multiple sentences. Sometimes thats necessary".to_string(), - "www.bibiman.org".to_string(), - "/home/file/path.pdf".to_string(), - ]; + let bibvec: EntryTableItem = EntryTableItem::new( + "Author", + "Title", + "1999", + "article", + "hello, bye", + "author_1999", + "An abstract with multiple sentences. Here is the second", + "https://www.bibiman.org", + "/home/file/path.pdf", + ); let joined_vec = BibiSearch::convert_to_string(&bibvec); diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 2f88ff2..3f679bf 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -163,6 +163,7 @@ impl App { } self.search_struct.filtered_entry_list_by_search.clear(); self.search_struct.filtered_entry_list_by_tags.clear(); + self.entry_table.entry_table_at_search_start.clear(); self.search_struct.filtered_tag_list.clear(); self.search_struct.inner_search = false; self.former_area = None @@ -176,7 +177,6 @@ impl App { } pub fn scroll_info_down(&mut self) { - // self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll + 1; self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll.saturating_add(1); self.entry_table.entry_info_scroll_state = self .entry_table @@ -185,11 +185,6 @@ impl App { } pub fn scroll_info_up(&mut self) { - // if self.entry_table.entry_info_scroll == 0 { - // {} - // } else { - // self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll - 1; - // } self.entry_table.entry_info_scroll = self.entry_table.entry_info_scroll.saturating_sub(1); self.entry_table.entry_info_scroll_state = self .entry_table @@ -205,6 +200,8 @@ impl App { if let Some(FormerArea::TagArea) = self.former_area { self.search_struct.inner_search = true } + self.entry_table.entry_table_at_search_start = + self.entry_table.entry_table_items.clone(); self.former_area = Some(FormerArea::EntryArea) } else if let CurrentArea::TagArea = self.current_area { self.former_area = Some(FormerArea::TagArea) @@ -222,6 +219,7 @@ impl App { } self.former_area = Some(FormerArea::SearchArea); self.search_struct.search_string.clear(); + self.entry_table.entry_table_at_search_start.clear(); } // Break search: leave search area without filtering list @@ -239,6 +237,7 @@ impl App { self.former_area = None; // If search is canceled, reset default status of struct self.search_struct.search_string.clear(); + self.entry_table.entry_table_at_search_start.clear(); } // Remove last char from search pattern and filter list immidiately diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs index ac6d1b0..98604f9 100644 --- a/src/frontend/entries.rs +++ b/src/frontend/entries.rs @@ -29,6 +29,7 @@ use std::process::{Command, Stdio}; #[derive(Debug)] pub struct EntryTable { pub entry_table_items: Vec<EntryTableItem>, + pub entry_table_at_search_start: Vec<EntryTableItem>, pub entry_table_state: TableState, pub entry_scroll_state: ScrollbarState, pub entry_info_scroll: u16, @@ -54,6 +55,7 @@ impl FromIterator<Vec<String>> for EntryTable { let entry_info_scroll_state = ScrollbarState::default(); Self { entry_table_items, + entry_table_at_search_start: Vec::new(), entry_table_state, entry_scroll_state, entry_info_scroll: 0, @@ -63,7 +65,7 @@ impl FromIterator<Vec<String>> for EntryTable { } // Define contents of each entry table row -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct EntryTableItem { pub authors: String, pub title: String, @@ -248,20 +250,12 @@ impl App { // Search entry list pub fn search_entries(&mut self) { - let orig_list = { - if self.search_struct.inner_search { - let orig_list = &self.search_struct.filtered_entry_list_by_tags; - orig_list - } else { - let orig_list = &self.biblio_data.entry_list.bibentries; - orig_list - } - }; + // Use snapshot of entry list saved when starting the search + // so deleting a char, will show former entries too + let orig_list = self.entry_table.entry_table_at_search_start.clone(); let filtered_list = BibiSearch::search_entry_list(&mut self.search_struct.search_string, orig_list.clone()); - //search::search_entry_list(&self.search_string, orig_list.clone()); - self.search_struct.filtered_entry_list_by_search = filtered_list.clone(); - self.entry_table = EntryTable::from_iter(filtered_list); + self.entry_table.entry_table_items = filtered_list; } // Open file connected with entry through 'file' or 'pdf' field diff --git a/src/frontend/keywords.rs b/src/frontend/keywords.rs index b4cc7e9..0363609 100644 --- a/src/frontend/keywords.rs +++ b/src/frontend/keywords.rs @@ -16,7 +16,6 @@ ///// use super::app::{App, FormerArea}; -use super::entries::EntryTable; use crate::backend::search::BibiSearch; use ratatui::widgets::{ListState, ScrollbarState}; @@ -105,56 +104,37 @@ impl App { } pub fn filter_tags_by_entries(&mut self) { - if !self.search_struct.filtered_entry_list_by_search.is_empty() - || !self.search_struct.filtered_entry_list_by_tags.is_empty() - { - self.search_struct.filtered_tag_list.clear(); - - let orig_list = if !self.search_struct.filtered_entry_list_by_search.is_empty() { - self.search_struct.filtered_entry_list_by_search.clone() - } else { - self.search_struct.filtered_entry_list_by_tags.clone() - }; - - let mut filtered_keywords: Vec<String> = Vec::new(); - - for e in orig_list { - if !e[4].is_empty() { - let mut key_vec: Vec<String> = e[4] - .split(',') - .map(|s| s.trim().to_string()) - .filter(|s| !s.is_empty()) - .collect(); - filtered_keywords.append(&mut key_vec); - } + let mut filtered_keywords: Vec<String> = Vec::new(); + + let orig_list = &self.entry_table.entry_table_items; + + for e in orig_list { + if !e.keywords.is_empty() { + let mut key_vec: Vec<String> = e + .keywords + .split(',') + .map(|s| s.trim().to_string()) + .filter(|s| !s.is_empty()) + .collect(); + filtered_keywords.append(&mut key_vec); } + } - filtered_keywords.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); - filtered_keywords.dedup(); + filtered_keywords.sort_by(|a, b| a.to_lowercase().cmp(&b.to_lowercase())); + filtered_keywords.dedup(); - self.search_struct.filtered_tag_list = filtered_keywords.clone(); - self.tag_list = TagList::from_iter(filtered_keywords); - } + self.search_struct.filtered_tag_list = filtered_keywords.clone(); + self.tag_list = TagList::from_iter(filtered_keywords); } // Filter the entry list by tags when hitting enter // If already inside a filtered tag or entry list, apply the filtering // to the already filtered list only pub fn filter_for_tags(&mut self) { - let orig_list = { - if self.search_struct.inner_search { - let orig_list = &self.search_struct.filtered_entry_list_by_search; - orig_list - } else { - let orig_list = &self.biblio_data.entry_list.bibentries; - orig_list - } - }; + let orig_list = &self.entry_table.entry_table_items; let keyword = self.get_selected_tag(); let filtered_list = BibiSearch::filter_entries_by_tag(&keyword, &orig_list); - self.search_struct.filtered_entry_list_by_tags = filtered_list; - self.entry_table = - EntryTable::from_iter(self.search_struct.filtered_entry_list_by_tags.clone()); + self.entry_table.entry_table_items = filtered_list; self.filter_tags_by_entries(); self.toggle_area(); self.former_area = Some(FormerArea::TagArea); |
