From 374dd9b36dec8d122078cb7ef10dd912fef32460 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Thu, 17 Oct 2024 13:49:52 +0200 Subject: testwise rewrite entry table parsing --- src/frontend/app.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/frontend/app.rs') diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 8d6454d..a035231 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -79,7 +79,7 @@ impl App { let biblio_data = BibiData::new(&main_biblio.bibliography, &main_biblio.citekeys); let tag_list = TagList::new(main_biblio.keyword_list.clone()); let search_struct = BibiSearch::default(); - let entry_table = EntryTable::from_iter(biblio_data.entry_list.bibentries.clone()); + let entry_table = EntryTable::new(&main_biblio.citekeys, &main_biblio.bibliography); let current_area = CurrentArea::EntryArea; Ok(Self { running, @@ -133,7 +133,8 @@ impl App { BibiData::new(&self.main_biblio.bibliography, &self.main_biblio.citekeys); // self.tag_list = TagList::from_iter(self.main_biblio.keyword_list.clone()); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); - self.entry_table = EntryTable::from_iter(self.biblio_data.entry_list.bibentries.clone()); + self.entry_table = + EntryTable::new(&self.main_biblio.citekeys, &self.main_biblio.bibliography); } // Toggle moveable list between entries and tags @@ -157,7 +158,8 @@ impl App { } pub fn reset_current_list(&mut self) { - self.entry_table = EntryTable::from_iter(self.biblio_data.entry_list.bibentries.clone()); + self.entry_table = + EntryTable::new(&self.main_biblio.citekeys, &self.main_biblio.bibliography); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); if let CurrentArea::TagArea = self.current_area { self.tag_list.tag_list_state.select(Some(0)) -- cgit v1.2.3 From 1fb272e563aca3b90a82fcbef68ed1c28cb7b212 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Thu, 17 Oct 2024 23:02:06 +0200 Subject: Implement sorting and remove unneccessary struct - Implement sorting of list (by authors for now) - Remove hole BibiData struct - Create entry table content directly through iterator --- src/backend/bib.rs | 55 --------------------- src/frontend/app.rs | 6 --- src/frontend/entries.rs | 126 ++++++++++++++++++++++-------------------------- src/frontend/handler.rs | 3 ++ src/frontend/ui.rs | 27 +++++++---- 5 files changed, 78 insertions(+), 139 deletions(-) (limited to 'src/frontend/app.rs') diff --git a/src/backend/bib.rs b/src/backend/bib.rs index 8539ab3..aca08b3 100644 --- a/src/backend/bib.rs +++ b/src/backend/bib.rs @@ -113,61 +113,6 @@ impl BibiMain { keyword_list.dedup(); keyword_list } -} - -#[derive(Debug)] -pub struct BibiData { - pub entry_list: BibiDataSets, -} - -impl BibiData { - pub fn new(biblio: &Bibliography, citekeys: &Vec) -> Self { - Self { - entry_list: { - let bibentries = citekeys - .into_iter() - .map(|citekey| BibiEntry::new(&citekey, &biblio)) - .collect(); - BibiDataSets { bibentries } - }, - } - } -} - -// Parent struct which keeps the Vector of all bibentries -// Necessary for implementing FromIterator -#[derive(Debug)] -pub struct BibiDataSets { - pub bibentries: Vec>, -} - -// Struct which has to be created for every entry of bibdatabase -#[derive(Debug)] -pub struct BibiEntry { - pub authors: String, - pub title: String, - pub year: String, - pub pubtype: String, - pub keywords: String, - pub citekey: String, - pub weblink: String, - pub filepath: String, -} - -impl BibiEntry { - pub fn new(citekey: &str, biblio: &Bibliography) -> Vec { - vec![ - Self::get_authors(&citekey, &biblio), - Self::get_title(&citekey, &biblio), - Self::get_year(&citekey, &biblio), - Self::get_pubtype(&citekey, &biblio), - Self::get_keywords(&citekey, &biblio), - citekey.to_string(), - Self::get_abstract(&citekey, &biblio), - Self::get_weblink(&citekey, &biblio), - Self::get_filepath(&citekey, &biblio), - ] - } pub fn get_authors(citekey: &str, biblio: &Bibliography) -> String { if biblio.get(&citekey).unwrap().author().is_ok() { diff --git a/src/frontend/app.rs b/src/frontend/app.rs index a035231..10cfa9b 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -53,8 +53,6 @@ pub struct App { pub main_bibfile: PathBuf, // main bibliography pub main_biblio: BibiMain, - // bibliographic data - pub biblio_data: BibiData, // search struct: pub search_struct: BibiSearch, // tag list @@ -76,7 +74,6 @@ impl App { let running = true; let main_bibfile = args.bibfilearg; let main_biblio = BibiMain::new(main_bibfile.clone()); - let biblio_data = BibiData::new(&main_biblio.bibliography, &main_biblio.citekeys); let tag_list = TagList::new(main_biblio.keyword_list.clone()); let search_struct = BibiSearch::default(); let entry_table = EntryTable::new(&main_biblio.citekeys, &main_biblio.bibliography); @@ -85,7 +82,6 @@ impl App { running, main_bibfile, main_biblio, - biblio_data, tag_list, search_struct, entry_table, @@ -129,8 +125,6 @@ impl App { pub fn update_lists(&mut self) { self.main_biblio = BibiMain::new(self.main_bibfile.clone()); - self.biblio_data = - BibiData::new(&self.main_biblio.bibliography, &self.main_biblio.citekeys); // self.tag_list = TagList::from_iter(self.main_biblio.keyword_list.clone()); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); self.entry_table = diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs index fb80b46..38b1852 100644 --- a/src/frontend/entries.rs +++ b/src/frontend/entries.rs @@ -17,12 +17,11 @@ use super::app::App; use super::tui::Tui; -use crate::backend::{bib::BibiEntry, search::BibiSearch}; +use crate::backend::{bib::BibiMain, search::BibiSearch}; use biblatex::Bibliography; use color_eyre::eyre::{Context, Ok, Result}; use core::panic; use editor_command::EditorBuilder; -use itertools::Itertools; use ratatui::widgets::{ScrollbarState, TableState}; use std::process::{Command, Stdio}; @@ -31,69 +30,82 @@ use std::process::{Command, Stdio}; pub struct EntryTable { pub entry_table_items: Vec, pub entry_table_at_search_start: Vec, + 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 FromIterator> for EntryTable { -// fn from_iter>>(iter: T) -> Self { -// let entry_table_items: Vec = iter -// .into_iter() -// .sorted() -// // 0: authors, 1: title, 2: date, 3: pubtype, 4: keywords, 5: citekey -// // 6: abstract, 7: doi/url, 8: pdf filepath -// // See backend/bib.rs BibiEntry impl -// .map(|i| { -// EntryTableItem::new( -// &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], &i[6], &i[7], &i[8], -// ) -// }) -// .collect(); -// 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_state, -// entry_scroll_state, -// entry_info_scroll: 0, -// entry_info_scroll_state, -// } -// } -// } - impl EntryTable { pub fn new(citekeys: &Vec, biblio: &Bibliography) -> Self { - let entry_table_items: Vec = citekeys - .into_iter() - .sorted() - .map(|key| EntryTableItem { - authors: BibiEntry::get_authors(&key, &biblio), - title: BibiEntry::get_title(&key, &biblio), - year: BibiEntry::get_year(&key, &biblio), - pubtype: BibiEntry::get_pubtype(&key, &biblio), - keywords: BibiEntry::get_keywords(&key, &biblio), - citekey: key.clone(), - abstract_text: BibiEntry::get_abstract(&key, &biblio), - doi_url: BibiEntry::get_weblink(&key, &biblio), - filepath: BibiEntry::get_filepath(&key, &biblio), - }) - .collect(); + let entry_table_items = Self::set_entry_table(&citekeys, &biblio); 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_reversed_sort: false, entry_table_state, entry_scroll_state, entry_info_scroll: 0, entry_info_scroll_state, } } + + pub fn set_entry_table(citekeys: &Vec, biblio: &Bibliography) -> Vec { + let mut entry_table: Vec = citekeys + .into_iter() + .map(|key| EntryTableItem { + authors: BibiMain::get_authors(&key, &biblio), + title: BibiMain::get_title(&key, &biblio), + year: BibiMain::get_year(&key, &biblio), + pubtype: BibiMain::get_pubtype(&key, &biblio), + keywords: BibiMain::get_keywords(&key, &biblio), + citekey: key.to_owned(), + abstract_text: BibiMain::get_abstract(&key, &biblio), + doi_url: BibiMain::get_weblink(&key, &biblio), + filepath: BibiMain::get_filepath(&key, &biblio), + }) + .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, sorting: &str) { + if self.entry_table_reversed_sort { + match sorting { + "author" => self + .entry_table_items + .sort_by(|a, b| a.authors.to_lowercase().cmp(&b.authors.to_lowercase())), + "title" => self + .entry_table_items + .sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase())), + "year" => self + .entry_table_items + .sort_by(|a, b| a.year.to_lowercase().cmp(&b.year.to_lowercase())), + _ => {} + } + } else if !self.entry_table_reversed_sort { + match sorting { + "author" => self + .entry_table_items + .sort_by(|a, b| b.authors.to_lowercase().cmp(&a.authors.to_lowercase())), + "title" => self + .entry_table_items + .sort_by(|a, b| b.title.to_lowercase().cmp(&a.title.to_lowercase())), + "year" => self + .entry_table_items + .sort_by(|a, b| b.year.to_lowercase().cmp(&a.year.to_lowercase())), + _ => {} + } + } + self.entry_table_reversed_sort = !self.entry_table_reversed_sort; + } } // Define contents of each entry table row @@ -111,30 +123,6 @@ pub struct EntryTableItem { } impl EntryTableItem { - // pub fn new( - // authors: String, - // title: String, - // year: String, - // pubtype: String, - // keywords: String, - // citekey: String, - // abstract_text: String, - // doi_url: String, - // filepath: String, - // ) -> Self { - // Self { - // authors, - // title, - // year, - // pubtype, - // keywords, - // citekey, - // abstract_text, - // doi_url, - // filepath, - // } - // } - // 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(&self) -> Vec<&String> { diff --git a/src/frontend/handler.rs b/src/frontend/handler.rs index c2cacf5..70ba5c7 100644 --- a/src/frontend/handler.rs +++ b/src/frontend/handler.rs @@ -121,6 +121,9 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R KeyCode::Char('G') | KeyCode::End => { app.select_last_entry(); } + KeyCode::Char('s') => { + app.entry_table.sort_entry_table("author"); + } KeyCode::Char('y') => { App::yank_text(&app.get_selected_citekey()); } diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index 08cebcb..1767cea 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -47,6 +47,8 @@ const SELECTED_STYLE: Style = Style::new() .add_modifier(Modifier::REVERSED); const TEXT_FG_COLOR: Color = Color::Indexed(252); const TEXT_UNSELECTED_FG_COLOR: Color = Color::Indexed(245); +const SORTED_ENTRIES: &str = "▼"; +const SORTED_ENTRIES_REVERSED: &str = "▲"; const SCROLLBAR_UPPER_CORNER: Option<&str> = Some("┓"); const SCROLLBAR_LOWER_CORNER: Option<&str> = Some("┛"); @@ -259,15 +261,22 @@ impl App { let header_style = Style::default().bold().fg(TEXT_FG_COLOR); - let header = [ - "Authors".underlined(), - "Title".underlined(), - "Year".underlined(), - "Type".underlined(), - ] - .into_iter() - .map(Cell::from) - .collect::() + let header = Row::new(vec![ + Cell::from(Line::from(vec![ + Span::raw("Author").underlined(), + Span::raw(format!( + " {}", + if self.entry_table.entry_table_reversed_sort { + SORTED_ENTRIES_REVERSED + } else { + SORTED_ENTRIES + } + )), + ])), + Cell::from("Title".to_string().underlined()), + Cell::from("Year".to_string().underlined()), + Cell::from("Type".to_string().underlined()), + ]) .style(header_style) .height(1); -- cgit v1.2.3 From 8beb373c4a587cdcea772f725f51c2ff2db7273d Mon Sep 17 00:00:00 2001 From: lukeflo Date: Sat, 19 Oct 2024 21:30:37 +0200 Subject: reinvent BibiData, start integrating yaml --- src/backend/bib.rs | 101 +++++++++++++++++++++++++++++++++++------------- src/frontend/app.rs | 8 ++-- src/frontend/entries.rs | 30 +++++++------- 3 files changed, 93 insertions(+), 46 deletions(-) (limited to 'src/frontend/app.rs') diff --git a/src/backend/bib.rs b/src/backend/bib.rs index 1f5d05d..29ce22e 100644 --- a/src/backend/bib.rs +++ b/src/backend/bib.rs @@ -17,6 +17,7 @@ use biblatex::{self, Bibliography}; use biblatex::{ChunksExt, Type}; +use hayagriva::io::from_yaml_str; use itertools::Itertools; use std::{fs, path::PathBuf}; @@ -36,6 +37,20 @@ pub struct BibiMain { pub bibliography: Bibliography, // parsed bibliography pub citekeys: Vec, // list of all citekeys pub keyword_list: Vec, // list of all available keywords + pub entry_list: Vec, // List of all entries +} + +#[derive(Debug, Clone)] +pub struct BibiData { + pub authors: 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 BibiMain { @@ -47,6 +62,7 @@ impl BibiMain { let bibliography = biblatex::Bibliography::parse(&bibfilestring).unwrap(); let citekeys = Self::get_citekeys(&bibliography); let keyword_list = Self::collect_tag_list(&citekeys, &bibliography); + let entry_list = Self::create_entry_list(&citekeys, &bibliography, &bibfile_format); Self { bibfile, bibfile_format, @@ -54,6 +70,15 @@ impl BibiMain { bibliography, citekeys, keyword_list, + entry_list, + } + } + + fn parse_bibliography(format: &FileFormat, bibfilestring: &str) -> Bibliography { + if let FileFormat::BibLatex = format { + biblatex::Bibliography::parse(bibfilestring).unwrap() + } else if let FileFormat::Hayagriva = format { + from_yaml_str(&bibfilestring).unwrap() } } @@ -70,6 +95,27 @@ impl BibiMain { } } + fn create_entry_list( + citekeys: &[String], + bibliography: &Bibliography, + format: &FileFormat, + ) -> Vec { + citekeys + .into_iter() + .map(|k| BibiData { + authors: Self::get_authors(&k, &bibliography, format), + title: Self::get_title(&k, &bibliography), + year: Self::get_year(&k, &bibliography), + pubtype: Self::get_pubtype(&k, &bibliography), + keywords: Self::get_keywords(&k, &bibliography), + citekey: k.to_owned(), + abstract_text: Self::get_abstract(&k, &bibliography), + doi_url: Self::get_weblink(&k, &bibliography), + filepath: Self::get_filepath(&k, &bibliography), + }) + .collect() + } + // get list of citekeys from the given bibfile // this list is the base for further operations on the bibentries // since it is the entry point of the biblatex crate. @@ -112,38 +158,41 @@ impl BibiMain { keyword_list } - pub fn get_authors(citekey: &str, biblio: &Bibliography) -> String { - if biblio.get(&citekey).unwrap().author().is_ok() { - let authors = biblio.get(&citekey).unwrap().author().unwrap(); - if authors.len() > 1 { - let all_authors = authors.iter().map(|a| &a.name).join(", "); - all_authors - } else if authors.len() == 1 { - let authors = authors[0].name.to_string(); - authors - } else { - let editors_authors = format!("empty"); - editors_authors - } - } else { - if !biblio.get(&citekey).unwrap().editors().unwrap().is_empty() { - let editors = biblio.get(&citekey).unwrap().editors().unwrap(); - if editors[0].0.len() > 1 { - // let editors = format!("{} (ed.) et al.", editors[0].0[0].name); - let mut editors = editors[0].0.iter().map(|e| &e.name).join(", "); - editors.push_str(" (ed.)"); - editors - } else if editors[0].0.len() == 1 { - let editors = format!("{} (ed.)", editors[0].0[0].name); - editors + pub fn get_authors(citekey: &str, biblio: &Bibliography, format: &FileFormat) -> String { + if let FileFormat::BibLatex = format { + if biblio.get(&citekey).unwrap().author().is_ok() { + let authors = biblio.get(&citekey).unwrap().author().unwrap(); + if authors.len() > 1 { + let all_authors = authors.iter().map(|a| &a.name).join(", "); + all_authors + } else if authors.len() == 1 { + let authors = authors[0].name.to_string(); + authors } else { let editors_authors = format!("empty"); editors_authors } } else { - let editors_authors = format!("empty"); - editors_authors + if !biblio.get(&citekey).unwrap().editors().unwrap().is_empty() { + let editors = biblio.get(&citekey).unwrap().editors().unwrap(); + if editors[0].0.len() > 1 { + // let editors = format!("{} (ed.) et al.", editors[0].0[0].name); + let mut editors = editors[0].0.iter().map(|e| &e.name).join(", "); + editors.push_str(" (ed.)"); + editors + } else if editors[0].0.len() == 1 { + let editors = format!("{} (ed.)", editors[0].0[0].name); + editors + } else { + let editors_authors = format!("empty"); + editors_authors + } + } else { + let editors_authors = format!("empty"); + editors_authors + } } + } else if let FileFormat::Hayagriva = format { } } diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 10cfa9b..822c6f0 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -76,7 +76,7 @@ impl App { let main_biblio = BibiMain::new(main_bibfile.clone()); let tag_list = TagList::new(main_biblio.keyword_list.clone()); let search_struct = BibiSearch::default(); - let entry_table = EntryTable::new(&main_biblio.citekeys, &main_biblio.bibliography); + let entry_table = EntryTable::new(main_biblio.entry_list.clone()); let current_area = CurrentArea::EntryArea; Ok(Self { running, @@ -127,8 +127,7 @@ impl App { self.main_biblio = BibiMain::new(self.main_bibfile.clone()); // self.tag_list = TagList::from_iter(self.main_biblio.keyword_list.clone()); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); - self.entry_table = - EntryTable::new(&self.main_biblio.citekeys, &self.main_biblio.bibliography); + self.entry_table = EntryTable::new(self.main_biblio.entry_list.clone()); } // Toggle moveable list between entries and tags @@ -152,8 +151,7 @@ impl App { } pub fn reset_current_list(&mut self) { - self.entry_table = - EntryTable::new(&self.main_biblio.citekeys, &self.main_biblio.bibliography); + self.entry_table = EntryTable::new(self.main_biblio.entry_list.clone()); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); if let CurrentArea::TagArea = self.current_area { self.tag_list.tag_list_state.select(Some(0)) diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs index f64e35e..dea970e 100644 --- a/src/frontend/entries.rs +++ b/src/frontend/entries.rs @@ -18,7 +18,7 @@ use super::app::App; use super::tui::Tui; use crate::backend::{ - bib::{BibiMain, FileFormat}, + bib::{BibiData, BibiMain, FileFormat}, search::BibiSearch, }; use biblatex::Bibliography; @@ -41,8 +41,8 @@ pub struct EntryTable { } impl EntryTable { - pub fn new(citekeys: &Vec, biblio: &Bibliography) -> Self { - let entry_table_items = Self::set_entry_table(&citekeys, &biblio); + pub fn new(entry_list: Vec) -> 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(); @@ -57,20 +57,20 @@ impl EntryTable { } } - pub fn set_entry_table(citekeys: &[String], biblio: &Bibliography) -> Vec { - let mut entry_table: Vec = citekeys + pub fn set_entry_table(entry_list: Vec) -> Vec { + let mut entry_table: Vec = entry_list .into_iter() - .map(|key| EntryTableItem { - authors: BibiMain::get_authors(&key, &biblio), + .map(|e| EntryTableItem { + authors: e.authors, short_author: String::new(), - title: BibiMain::get_title(&key, &biblio), - year: BibiMain::get_year(&key, &biblio), - pubtype: BibiMain::get_pubtype(&key, &biblio), - keywords: BibiMain::get_keywords(&key, &biblio), - citekey: key.to_owned(), - abstract_text: BibiMain::get_abstract(&key, &biblio), - doi_url: BibiMain::get_weblink(&key, &biblio), - filepath: BibiMain::get_filepath(&key, &biblio), + 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(); -- cgit v1.2.3