diff options
| -rw-r--r-- | src/backend/bib.rs | 5 | ||||
| -rw-r--r-- | src/backend/cliargs.rs | 46 | ||||
| -rw-r--r-- | src/frontend.rs | 2 | ||||
| -rw-r--r-- | src/frontend/app.rs | 324 | ||||
| -rw-r--r-- | src/frontend/entries.rs | 182 | ||||
| -rw-r--r-- | src/frontend/keywords.rs | 111 | ||||
| -rw-r--r-- | src/frontend/ui.rs | 38 | ||||
| -rw-r--r-- | src/main.rs | 4 | ||||
| -rw-r--r-- | test.bib | 6 |
9 files changed, 372 insertions, 346 deletions
diff --git a/src/backend/bib.rs b/src/backend/bib.rs index c897099..ba752a7 100644 --- a/src/backend/bib.rs +++ b/src/backend/bib.rs @@ -15,7 +15,6 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. ///// -use super::cliargs::PosArgs; use std::{fs, path::PathBuf}; use biblatex::{self, Bibliography}; @@ -33,9 +32,9 @@ pub struct BibiMain { } impl BibiMain { - pub fn new() -> Self { + pub fn new(main_bibfile: PathBuf) -> Self { // TODO: Needs check for config file path as soon as config file is impl - let bibfile = PosArgs::parse_pos_args().bibfilearg; + let bibfile = main_bibfile; let bibfilestring = fs::read_to_string(&bibfile).unwrap(); let bibliography = biblatex::Bibliography::parse(&bibfilestring).unwrap(); let citekeys = Self::get_citekeys(&bibliography); diff --git a/src/backend/cliargs.rs b/src/backend/cliargs.rs index 516de66..31d37f0 100644 --- a/src/backend/cliargs.rs +++ b/src/backend/cliargs.rs @@ -27,7 +27,7 @@ sarge! { // Show help and exit. 'h' help: bool, - // Show version and exit. TODO: Write version... + // Show version and exit. 'v' version: bool, } @@ -35,37 +35,45 @@ sarge! { pub struct CLIArgs { pub helparg: bool, pub versionarg: bool, + pub bibfilearg: PathBuf, } impl CLIArgs { - pub fn parse_cli_args() -> Self { - let (cli_args, _) = ArgumentsCLI::parse().expect("Could not parse CLI arguments"); + pub fn new() -> Self { + let (cli_args, pos_args) = ArgumentsCLI::parse().expect("Could not parse CLI arguments"); + let bibfilearg = if pos_args.len() > 1 { + PathBuf::from(&pos_args[1]) + // pos_args[1].to_string() + } else { + panic!("No path to bibfile provided as argument") + }; Self { helparg: cli_args.help, versionarg: cli_args.version, + bibfilearg, } } } // Struct for positional arguments // TODO: Can surely be improved!! -pub struct PosArgs { - pub bibfilearg: PathBuf, -} +// pub struct PosArgs { +// pub bibfilearg: PathBuf, +// } -impl PosArgs { - pub fn parse_pos_args() -> Self { - let (_, pos_args) = ArgumentsCLI::parse().expect("Could not parse positional arguments"); - Self { - bibfilearg: if pos_args.len() > 1 { - PathBuf::from(&pos_args[1]) - // pos_args[1].to_string() - } else { - panic!("No path to bibfile provided as argument") - }, // bibfilearg: pos_args[1].to_string(), - } - } -} +// impl PosArgs { +// pub fn parse_pos_args() -> Self { +// let (_, pos_args) = ArgumentsCLI::parse().expect("Could not parse positional arguments"); +// Self { +// bibfilearg: if pos_args.len() > 1 { +// PathBuf::from(&pos_args[1]) +// // pos_args[1].to_string() +// } else { +// panic!("No path to bibfile provided as argument") +// }, // bibfilearg: pos_args[1].to_string(), +// } +// } +// } pub fn help_func() -> String { let help = format!( diff --git a/src/frontend.rs b/src/frontend.rs index a03c096..dc16cb5 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -16,6 +16,8 @@ ///// pub mod app; +pub mod entries; pub mod handler; +pub mod keywords; pub mod tui; pub mod ui; diff --git a/src/frontend/app.rs b/src/frontend/app.rs index 8950202..4bd46be 100644 --- a/src/frontend/app.rs +++ b/src/frontend/app.rs @@ -15,22 +15,16 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. ///// -use std::process::Command; - -use editor_command::EditorBuilder; - +use super::tui; +use crate::backend::cliargs::CLIArgs; use crate::backend::{bib::*, search::BibiSearch}; use crate::{ - frontend::handler::handle_key_events, - frontend::tui::{Event, Tui}, + frontend::entries::EntryTable, frontend::handler::handle_key_events, + frontend::keywords::TagList, frontend::tui::Event, }; - use arboard::Clipboard; use color_eyre::eyre::{Ok, Result}; -use itertools::Itertools; -use ratatui::widgets::{ListState, TableState}; - -use super::tui; +use std::path::PathBuf; // Areas in which actions are possible #[derive(Debug)] @@ -54,6 +48,8 @@ pub enum FormerArea { pub struct App { // Is the application running? pub running: bool, + // main bib file + pub main_bibfile: PathBuf, // main bibliography pub main_biblio: BibiMain, // bibliographic data @@ -72,152 +68,13 @@ pub struct App { pub former_area: Option<FormerArea>, } -// Define the fundamental List -#[derive(Debug)] -pub struct TagList { - pub tag_list_items: Vec<TagListItem>, - pub tag_list_state: ListState, -} - -// Structure of the list items. -#[derive(Debug)] -pub struct TagListItem { - pub keyword: String, -} - -// Function to process inputed characters and convert them (to string, or more complex function) -impl TagListItem { - pub fn new(info: &str) -> Self { - Self { - keyword: info.to_string(), - } - } -} - -impl FromIterator<String> for TagList { - fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self { - let tag_list_items = iter - .into_iter() - .map(|info| TagListItem::new(&info)) - .collect(); - let tag_list_state = ListState::default(); // for preselection: .with_selected(Some(0)); - Self { - tag_list_items, - tag_list_state, - } - } -} - -// // Also possible with vector. -impl FromIterator<Vec<String>> for EntryTable { - fn from_iter<T: IntoIterator<Item = Vec<String>>>(iter: T) -> Self { - let entry_table_items = iter - .into_iter() - .sorted() - .map(|i| EntryTableItem::new(&i[0], &i[1], &i[2], &i[3], &i[4], &i[5])) - .collect(); - let entry_table_state = TableState::default().with_selected(0); - Self { - entry_table_items, - entry_table_state, - } - } -} - -// Define list containing entries as table -#[derive(Debug)] -pub struct EntryTable { - pub entry_table_items: Vec<EntryTableItem>, - pub entry_table_state: TableState, -} - -// Define contents of each entry table row -#[derive(Debug)] -pub struct EntryTableItem { - pub authors: String, - pub title: String, - pub year: String, - pub pubtype: String, - pub keywords: String, - pub citekey: String, -} - -impl EntryTableItem { - pub fn new( - authors: &str, - title: &str, - year: &str, - pubtype: &str, - keywords: &str, - citekey: &str, - ) -> Self { - Self { - authors: authors.to_string(), - title: title.to_string(), - year: year.to_string(), - pubtype: pubtype.to_string(), - keywords: keywords.to_string(), - citekey: citekey.to_string(), - } - } - - // 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> { - vec![&self.authors, &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 - } -} - -// impl Default for App { -// fn default() -> Self { -// let running = true; -// let main_biblio = BibiMain::new(); -// let biblio_data = BibiData::new(&main_biblio.bibliography, &main_biblio.citekeys); -// let tag_list = TagList::from_iter(main_biblio.keyword_list.clone()); -// let search_struct = BibiSearch::default(); -// let entry_table = EntryTable::from_iter(biblio_data.entry_list.bibentries.clone()); -// let current_area = CurrentArea::EntryArea; -// Self { -// running, -// main_biblio, -// biblio_data, -// tag_list, -// search_struct, -// entry_table, -// scroll_info: 0, -// current_area, -// former_area: None, -// // search_string: String::new(), -// } -// } -// } - impl App { // Constructs a new instance of [`App`]. - pub fn new() -> Result<Self> { + pub fn new(args: CLIArgs) -> Result<Self> { // Self::default() let running = true; - let main_biblio = BibiMain::new(); + 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::from_iter(main_biblio.keyword_list.clone()); let search_struct = BibiSearch::default(); @@ -225,6 +82,7 @@ impl App { let current_area = CurrentArea::EntryArea; Ok(Self { running, + main_bibfile, main_biblio, biblio_data, tag_list, @@ -269,7 +127,7 @@ impl App { } pub fn update_lists(&mut self) { - self.main_biblio = BibiMain::new(); + 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()); @@ -285,34 +143,6 @@ impl App { self.current_area = CurrentArea::EntryArea; self.tag_list.tag_list_state.select(None) } - // match self.current_area { - // CurrentArea::EntryArea => { - // self.current_area = CurrentArea::TagArea; - // self.tag_list.tag_list_state.select(Some(0)) - // } - // CurrentArea::TagArea => { - // self.current_area = CurrentArea::EntryArea; - // self.tag_list.tag_list_state.select(None) - // } - // CurrentArea::SearchArea => { - // if let Some(former_area) = &self.former_area { - // match former_area { - // FormerArea::EntryArea => self.current_area = CurrentArea::EntryArea, - // FormerArea::TagArea => self.current_area = CurrentArea::TagArea, - // _ => {} - // } - // } - // } - // CurrentArea::HelpArea => { - // if let Some(former_area) = &self.former_area { - // match former_area { - // FormerArea::EntryArea => self.current_area = CurrentArea::EntryArea, - // FormerArea::TagArea => self.current_area = CurrentArea::TagArea, - // FormerArea::SearchArea => self.current_area = CurrentArea::SearchArea, - // } - // } - // } - // } } pub fn reset_current_list(&mut self) { @@ -425,134 +255,4 @@ impl App { self.search_tags(); } } - - // Tag List commands - - // Movement - pub fn select_next_tag(&mut self) { - self.tag_list.tag_list_state.select_next(); - } - - pub fn select_previous_tag(&mut self) { - self.tag_list.tag_list_state.select_previous(); - } - - pub fn select_first_tag(&mut self) { - self.tag_list.tag_list_state.select_first(); - } - - pub fn select_last_tag(&mut self) { - self.tag_list.tag_list_state.select_last(); - } - - pub fn get_selected_tag(&self) -> &str { - let idx = self.tag_list.tag_list_state.selected().unwrap(); - let keyword = &self.tag_list.tag_list_items[idx].keyword; - keyword - } - - pub fn search_tags(&mut self) { - let orig_list = &self.main_biblio.keyword_list; - let filtered_list = - BibiSearch::search_tag_list(&self.search_struct.search_string, orig_list.clone()); - self.tag_list = TagList::from_iter(filtered_list) - } - - // Filter the entry list by tags - // 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; - orig_list - } else { - let orig_list = &self.biblio_data.entry_list.bibentries; - orig_list - } - }; - let keyword = self.get_selected_tag(); - let filtered_list = BibiSearch::filter_entries_by_tag(&keyword, &orig_list); - self.search_struct.filtered_entry_list = filtered_list; - self.entry_table = EntryTable::from_iter(self.search_struct.filtered_entry_list.clone()); - self.toggle_area(); - self.former_area = Some(FormerArea::TagArea); - } - - // Entry Table commands - - // Movement - pub fn select_next_entry(&mut self) { - self.scroll_info = 0; - self.entry_table.entry_table_state.select_next(); - } - - pub fn select_previous_entry(&mut self) { - self.scroll_info = 0; - self.entry_table.entry_table_state.select_previous(); - } - - pub fn select_first_entry(&mut self) { - self.scroll_info = 0; - self.entry_table.entry_table_state.select_first(); - } - - pub fn select_last_entry(&mut self) { - self.scroll_info = 0; - self.entry_table.entry_table_state.select_last(); - } - - // Get the citekey of the selected entry - pub fn get_selected_citekey(&self) -> &str { - let idx = self.entry_table.entry_table_state.selected().unwrap(); - let citekey = &self.entry_table.entry_table_items[idx].citekey; - citekey - } - - pub fn run_editor(&mut self, tui: &mut Tui) -> Result<()> { - // get filecontent and citekey for calculating line number - let citekey = self.get_selected_citekey(); - let filepath = self.main_biblio.bibfile.display().to_string(); - let filecontent = self.main_biblio.bibfilestring.clone(); - let mut line_count = 0; - - for line in filecontent.lines() { - line_count = line_count + 1; - // if reaching the citekey break the loop - // if reaching end of lines without match, reset to 0 - if line.contains(&citekey) { - break; - } else if line_count == filecontent.len() { - eprintln!( - "Citekey {} not found, opening file {} at line 1", - &citekey, &filepath - ); - line_count = 0; - break; - } - } - - // Exit TUI to enter editor - tui.exit()?; - // Use VISUAL or EDITOR. Set "vi" as last fallback - let mut cmd: Command = EditorBuilder::new() - .environment() - .source(Some("vi")) - .build() - .unwrap(); - // Prepare arguments to open file at specific line - let args: Vec<String> = vec![format!("+{}", line_count), filepath]; - let status = cmd.args(&args).status()?; - if !status.success() { - eprintln!("Spawning editor failed with status {}", status); - } - - // Enter TUI again - tui.enter()?; - tui.terminal.clear()?; - - // Update the database and the lists to show changes - self.update_lists(); - Ok(()) - } } diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs new file mode 100644 index 0000000..b0a9c46 --- /dev/null +++ b/src/frontend/entries.rs @@ -0,0 +1,182 @@ +// 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 super::app::App; +use super::tui::Tui; +use color_eyre::eyre::Result; +use editor_command::EditorBuilder; +use itertools::Itertools; +use ratatui::widgets::TableState; +use std::process::Command; + +impl FromIterator<Vec<String>> for EntryTable { + fn from_iter<T: IntoIterator<Item = Vec<String>>>(iter: T) -> Self { + let entry_table_items = iter + .into_iter() + .sorted() + .map(|i| EntryTableItem::new(&i[0], &i[1], &i[2], &i[3], &i[4], &i[5])) + .collect(); + let entry_table_state = TableState::default().with_selected(0); + Self { + entry_table_items, + entry_table_state, + } + } +} + +// Define list containing entries as table +#[derive(Debug)] +pub struct EntryTable { + pub entry_table_items: Vec<EntryTableItem>, + pub entry_table_state: TableState, +} + +// Define contents of each entry table row +#[derive(Debug)] +pub struct EntryTableItem { + pub authors: String, + pub title: String, + pub year: String, + pub pubtype: String, + pub keywords: String, + pub citekey: String, +} + +impl EntryTableItem { + pub fn new( + authors: &str, + title: &str, + year: &str, + pubtype: &str, + keywords: &str, + citekey: &str, + ) -> Self { + Self { + authors: authors.to_string(), + title: title.to_string(), + year: year.to_string(), + pubtype: pubtype.to_string(), + keywords: keywords.to_string(), + citekey: citekey.to_string(), + } + } + + // 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> { + vec![&self.authors, &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 + } +} + +impl App { + // Entry Table commands + + // Movement + pub fn select_next_entry(&mut self) { + self.scroll_info = 0; + self.entry_table.entry_table_state.select_next(); + } + + pub fn select_previous_entry(&mut self) { + self.scroll_info = 0; + self.entry_table.entry_table_state.select_previous(); + } + + pub fn select_first_entry(&mut self) { + self.scroll_info = 0; + self.entry_table.entry_table_state.select_first(); + } + + pub fn select_last_entry(&mut self) { + self.scroll_info = 0; + self.entry_table.entry_table_state.select_last(); + } + + // Get the citekey of the selected entry + pub fn get_selected_citekey(&self) -> &str { + let idx = self.entry_table.entry_table_state.selected().unwrap(); + let citekey = &self.entry_table.entry_table_items[idx].citekey; + citekey + } + + pub fn run_editor(&mut self, tui: &mut Tui) -> Result<()> { + // get filecontent and citekey for calculating line number + let citekey = self.get_selected_citekey(); + let filepath = self.main_biblio.bibfile.display().to_string(); + let filecontent = self.main_biblio.bibfilestring.clone(); + let mut line_count = 0; + + for line in filecontent.lines() { + line_count = line_count + 1; + // if reaching the citekey break the loop + // if reaching end of lines without match, reset to 0 + if line.contains(&citekey) { + break; + } else if line_count == filecontent.len() { + eprintln!( + "Citekey {} not found, opening file {} at line 1", + &citekey, &filepath + ); + line_count = 0; + break; + } + } + + // Exit TUI to enter editor + tui.exit()?; + // Use VISUAL or EDITOR. Set "vi" as last fallback + let mut cmd: Command = EditorBuilder::new() + .environment() + .source(Some("vi")) + .build() + .unwrap(); + // Prepare arguments to open file at specific line + let args: Vec<String> = vec![format!("+{}", line_count), filepath]; + let status = cmd.args(&args).status()?; + if !status.success() { + eprintln!("Spawning editor failed with status {}", status); + } + + // Enter TUI again + tui.enter()?; + tui.terminal.clear()?; + + // Update the database and the lists to show changes + self.update_lists(); + Ok(()) + } +} diff --git a/src/frontend/keywords.rs b/src/frontend/keywords.rs new file mode 100644 index 0000000..cb0c28f --- /dev/null +++ b/src/frontend/keywords.rs @@ -0,0 +1,111 @@ +// 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 super::app::{App, FormerArea}; +use super::entries::EntryTable; +use crate::backend::search::BibiSearch; +use ratatui::widgets::ListState; + +#[derive(Debug)] +pub struct TagList { + pub tag_list_items: Vec<TagListItem>, + pub tag_list_state: ListState, +} + +// Structure of the list items. +#[derive(Debug)] +pub struct TagListItem { + pub keyword: String, +} + +// Function to process inputed characters and convert them (to string, or more complex function) +impl TagListItem { + pub fn new(info: &str) -> Self { + Self { + keyword: info.to_string(), + } + } +} + +impl FromIterator<String> for TagList { + fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self { + let tag_list_items = iter + .into_iter() + .map(|info| TagListItem::new(&info)) + .collect(); + let tag_list_state = ListState::default(); // for preselection: .with_selected(Some(0)); + Self { + tag_list_items, + tag_list_state, + } + } +} + +impl App { + // Tag List commands + + // Movement + pub fn select_next_tag(&mut self) { + self.tag_list.tag_list_state.select_next(); + } + + pub fn select_previous_tag(&mut self) { + self.tag_list.tag_list_state.select_previous(); + } + + pub fn select_first_tag(&mut self) { + self.tag_list.tag_list_state.select_first(); + } + + pub fn select_last_tag(&mut self) { + self.tag_list.tag_list_state.select_last(); + } + + pub fn get_selected_tag(&self) -> &str { + let idx = self.tag_list.tag_list_state.selected().unwrap(); + let keyword = &self.tag_list.tag_list_items[idx].keyword; + keyword + } + + pub fn search_tags(&mut self) { + let orig_list = &self.main_biblio.keyword_list; + let filtered_list = + BibiSearch::search_tag_list(&self.search_struct.search_string, orig_list.clone()); + self.tag_list = TagList::from_iter(filtered_list) + } + + // Filter the entry list by tags + // 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; + orig_list + } else { + let orig_list = &self.biblio_data.entry_list.bibentries; + orig_list + } + }; + let keyword = self.get_selected_tag(); + let filtered_list = BibiSearch::filter_entries_by_tag(&keyword, &orig_list); + self.search_struct.filtered_entry_list = filtered_list; + self.entry_table = EntryTable::from_iter(self.search_struct.filtered_entry_list.clone()); + self.toggle_area(); + self.former_area = Some(FormerArea::TagArea); + } +} diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs index 8b41974..8974a86 100644 --- a/src/frontend/ui.rs +++ b/src/frontend/ui.rs @@ -27,23 +27,25 @@ use ratatui::{ }, }; -use crate::{ - backend::bib::BibiEntry, - frontend::app::{App, TagListItem}, -}; +use crate::{backend::bib::BibiEntry, frontend::app::App, frontend::keywords::TagListItem}; use super::app::{CurrentArea, FormerArea}; const MAIN_BLUE_COLOR: Color = Color::Indexed(39); // const MAIN_PURPLE_COLOR: Color = Color::Indexed(129); const BOX_SELECTED_BOX_STYLE: Style = Style::new().fg(TEXT_FG_COLOR); -const BOX_UNSELECTED_BORDER_STYLE: Style = Style::new().fg(Color::DarkGray); +const BOX_SELECTED_TITLE_STYLE: Style = Style::new().fg(TEXT_FG_COLOR).add_modifier(Modifier::BOLD); +const BOX_UNSELECTED_BORDER_STYLE: Style = Style::new().fg(TEXT_UNSELECTED_FG_COLOR); +const BOX_UNSELECTED_TITLE_STYLE: Style = Style::new() + .fg(TEXT_UNSELECTED_FG_COLOR) + .add_modifier(Modifier::BOLD); const NORMAL_ROW_BG: Color = Color::Black; const ALT_ROW_BG_COLOR: Color = Color::Indexed(234); const SELECTED_STYLE: Style = Style::new() .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED); const TEXT_FG_COLOR: Color = Color::Indexed(252); +const TEXT_UNSELECTED_FG_COLOR: Color = Color::Indexed(250); pub const fn alternate_colors(i: usize) -> Color { if i % 2 == 0 { @@ -117,7 +119,7 @@ impl App { }; let block = Block::bordered() - .title(search_title) + .title(Line::styled(search_title, BOX_SELECTED_TITLE_STYLE)) .border_style(BOX_SELECTED_BOX_STYLE) .border_set(symbols::border::THICK); Paragraph::new(self.search_struct.search_string.clone()) @@ -151,7 +153,17 @@ impl App { pub fn render_entrytable(&mut self, area: Rect, buf: &mut Buffer) { let block = Block::bordered() // can also be Block::new - .title(Line::raw(" Bibliographic Entries ").centered().bold()) + .title( + Line::styled( + " Bibliographic Entries ", + if let CurrentArea::EntryArea = self.current_area { + BOX_SELECTED_TITLE_STYLE + } else { + BOX_UNSELECTED_TITLE_STYLE + }, + ) + .centered(), + ) .border_set(if let CurrentArea::EntryArea = self.current_area { symbols::border::THICK } else { @@ -313,7 +325,17 @@ impl App { pub fn render_taglist(&mut self, area: Rect, buf: &mut Buffer) { let block = Block::bordered() - .title(Line::raw(" Keywords ").centered().bold()) + .title( + Line::styled( + " Keywords ", + if let CurrentArea::TagArea = self.current_area { + BOX_SELECTED_TITLE_STYLE + } else { + BOX_UNSELECTED_TITLE_STYLE + }, + ) + .centered(), + ) .border_set(if let CurrentArea::TagArea = self.current_area { symbols::border::THICK } else { diff --git a/src/main.rs b/src/main.rs index 5a7c538..9ff24c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ pub mod frontend; #[tokio::main] async fn main() -> Result<()> { // Parse CLI arguments - let parsed_args = CLIArgs::parse_cli_args(); + let parsed_args = CLIArgs::new(); // Print help if -h/--help flag is passed and exit if parsed_args.helparg { @@ -40,7 +40,7 @@ async fn main() -> Result<()> { } // Create an application. - let mut app = App::new()?; + let mut app = App::new(parsed_args)?; app.run().await?; Ok(()) @@ -16,6 +16,7 @@ volume = {61}, pages = {204--208}, editor = {Matuz, Roger}, + keywords = {narration}, langid = {english}, langidopts = {variant=american}, annotation = {A \texttt{collection} entry providing the excerpt information for the \texttt{doody} entry. Note the format of the \texttt{pages} field}, @@ -52,7 +53,7 @@ publisher = cup, date = {1907}, editor = {Hicks, Robert Drew}, - keywords = {primary}, + keywords = {primary, ancient, philosophy}, langid = {english}, langidopts = {variant=british}, annotation = {A \texttt{book} entry with an \texttt{author} and an \texttt{editor}}, @@ -66,7 +67,7 @@ publisher = {G. P. Putnam}, date = {1929}, translator = {Wicksteed, P. H. and Cornford, F. M.}, - keywords = {primary}, + keywords = {primary, ancient, philosophy}, langid = {english}, langidopts = {variant=american}, annotation = {A \texttt{book} entry with a \texttt{translator} field}, @@ -145,6 +146,7 @@ eprint = {math/0307200v3}, eprinttype = {arxiv}, langid = {english}, + keywords = {math}, langidopts = {variant=american}, annotation = {An \texttt{article} with \texttt{eprint} and \texttt{eprinttype} fields. Note that the arXiv reference is transformed into a clickable link if \texttt{hyperref} support has been enabled. Compare \texttt{baez\slash online}, which is the same item given as an \texttt{online} entry}, } |
