diff options
Diffstat (limited to 'src/bib/entries.rs')
| -rw-r--r-- | src/bib/entries.rs | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/src/bib/entries.rs b/src/bib/entries.rs new file mode 100644 index 0000000..41edba8 --- /dev/null +++ b/src/bib/entries.rs @@ -0,0 +1,258 @@ +// bibiman - a TUI for managing BibLaTeX databases +// Copyright (C) 2024 lukeflo +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <https://www.gnu.org/licenses/>. +///// + +use crate::bib::bibmain::BibiData; +use ratatui::widgets::{ScrollbarState, TableState}; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum EntryTableColumn { + Authors, + Title, + Year, + Pubtype, +} + +// Define list containing entries as table +#[derive(Debug, PartialEq, Eq)] +pub struct EntryTable { + pub entry_table_items: Vec<EntryTableItem>, + pub entry_table_at_search_start: Vec<EntryTableItem>, + pub entry_table_selected_column: EntryTableColumn, + pub entry_table_sorted_by_col: EntryTableColumn, + pub entry_table_reversed_sort: bool, + pub entry_table_state: TableState, + pub entry_scroll_state: ScrollbarState, + pub entry_info_scroll: u16, + pub entry_info_scroll_state: ScrollbarState, +} + +impl EntryTable { + pub fn new(entry_list: Vec<BibiData>) -> Self { + let entry_table_items = Self::set_entry_table(entry_list); + let entry_table_state = TableState::default().with_selected(0); + let entry_scroll_state = ScrollbarState::new(entry_table_items.len()); + let entry_info_scroll_state = ScrollbarState::default(); + Self { + entry_table_items, + entry_table_at_search_start: Vec::new(), + entry_table_selected_column: EntryTableColumn::Authors, + entry_table_sorted_by_col: EntryTableColumn::Authors, + entry_table_reversed_sort: false, + entry_table_state, + entry_scroll_state, + entry_info_scroll: 0, + entry_info_scroll_state, + } + } + + pub fn set_entry_table(entry_list: Vec<BibiData>) -> Vec<EntryTableItem> { + let mut entry_table: Vec<EntryTableItem> = entry_list + .into_iter() + .map(|e| EntryTableItem { + authors: e.authors, + short_author: String::new(), + title: e.title, + year: e.year, + pubtype: e.pubtype, + keywords: e.keywords, + citekey: e.citekey, + abstract_text: e.abstract_text, + doi_url: e.doi_url, + filepath: e.filepath, + }) + .collect(); + + entry_table.sort_by(|a, b| a.authors.to_lowercase().cmp(&b.authors.to_lowercase())); + entry_table + } + + // Sort entry table by specific column. + // Toggle sorting by hitting same key again + pub fn sort_entry_table(&mut self, toggle: bool) { + if toggle { + self.entry_table_reversed_sort = !self.entry_table_reversed_sort; + } + if self.entry_table_selected_column != self.entry_table_sorted_by_col { + self.entry_table_reversed_sort = false + } + self.entry_table_sorted_by_col = self.entry_table_selected_column.clone(); + if self.entry_table_reversed_sort { + match self.entry_table_selected_column { + EntryTableColumn::Authors => self + .entry_table_items + .sort_by(|a, b| b.authors.to_lowercase().cmp(&a.authors.to_lowercase())), + EntryTableColumn::Title => self + .entry_table_items + .sort_by(|a, b| b.title.to_lowercase().cmp(&a.title.to_lowercase())), + EntryTableColumn::Year => self + .entry_table_items + .sort_by(|a, b| b.year.to_lowercase().cmp(&a.year.to_lowercase())), + EntryTableColumn::Pubtype => self + .entry_table_items + .sort_by(|a, b| b.pubtype.to_lowercase().cmp(&a.pubtype.to_lowercase())), + } + } else if !self.entry_table_reversed_sort { + match self.entry_table_selected_column { + EntryTableColumn::Authors => self + .entry_table_items + .sort_by(|a, b| a.authors.to_lowercase().cmp(&b.authors.to_lowercase())), + EntryTableColumn::Title => self + .entry_table_items + .sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase())), + EntryTableColumn::Year => self + .entry_table_items + .sort_by(|a, b| a.year.to_lowercase().cmp(&b.year.to_lowercase())), + EntryTableColumn::Pubtype => self + .entry_table_items + .sort_by(|a, b| a.pubtype.to_lowercase().cmp(&b.pubtype.to_lowercase())), + } + } + } +} + +// Define contents of each entry table row +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct EntryTableItem { + pub authors: String, + pub short_author: String, + pub title: String, + pub year: String, + pub pubtype: String, + pub keywords: String, + pub citekey: String, + pub abstract_text: String, + pub doi_url: String, + pub filepath: String, +} + +impl EntryTableItem { + // This functions decides which fields are rendered in the entry table + // Fields which should be usable but not visible can be left out + pub fn ref_vec(&mut self) -> Vec<&str> { + self.short_author = match self.authors.split_once(",") { + Some((first, _rest)) => { + if self.authors.contains("(ed.)") { + let first_author = format!("{} et al. (ed.)", first); + first_author + } else { + let first_author = format!("{} et al.", first); + first_author + } + } + None => String::from(""), + }; + + vec![ + { + if self.short_author.is_empty() { + &self.authors + } else { + &self.short_author + } + }, + &self.title, + &self.year, + &self.pubtype, + ] + } + + pub fn authors(&self) -> &str { + &self.authors + } + + pub fn title(&self) -> &str { + &self.title + } + + pub fn year(&self) -> &str { + &self.year + } + + pub fn pubtype(&self) -> &str { + &self.pubtype + } + + pub fn citekey(&self) -> &str { + &self.citekey + } + + pub fn doi_url(&self) -> &str { + &self.doi_url + } + + pub fn filepath(&self) -> &str { + &self.filepath + } +} + +#[cfg(test)] +mod tests { + use super::EntryTableItem; + + #[test] + fn check_os() { + let os = std::env::consts::OS; + assert_eq!( + os, + "linux", + "You're not coding on linux, but on {}... Switch to linux, now!", + std::env::consts::OS + ) + } + + #[test] + fn shorten_authors() { + let mut entry: EntryTableItem = EntryTableItem { + authors: "Miller, Schmitz, Bernard".to_string(), + short_author: "".to_string(), + title: "A title".to_string(), + year: "2000".to_string(), + pubtype: "article".to_string(), + keywords: "key1, key2".to_string(), + citekey: "miller_2000".to_string(), + abstract_text: "An abstract".to_string(), + doi_url: "www.text.org".to_string(), + filepath: "/home/test".to_string(), + }; + + let entry_vec = EntryTableItem::ref_vec(&mut entry); + + let mut entry_editors: EntryTableItem = EntryTableItem { + authors: "Miller, Schmitz, Bernard (ed.)".to_string(), + short_author: "".to_string(), + title: "A title".to_string(), + year: "2000".to_string(), + pubtype: "article".to_string(), + keywords: "key1, key2".to_string(), + citekey: "miller_2000".to_string(), + abstract_text: "An abstract".to_string(), + doi_url: "www.text.org".to_string(), + filepath: "/home/test".to_string(), + }; + + let entry_vec_editors = EntryTableItem::ref_vec(&mut entry_editors); + + assert_eq!( + entry_vec, + vec!["Miller et al.", "A title", "2000", "article"] + ); + assert_eq!( + entry_vec_editors, + vec!["Miller et al. (ed.)", "A title", "2000", "article"] + ) + } +} |
