From d443843d352d740b895c4d622eb9af9567aa7423 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Mon, 17 Feb 2025 20:55:46 +0100 Subject: improve file handling + If config file **and** CLI args have different files/dirs, concat them and open all + Adapt UI to show which files are choosen + TODO: Flag for ignoring config file --- src/bibiman.rs | 56 +++++++++++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 23 deletions(-) (limited to 'src/bibiman.rs') diff --git a/src/bibiman.rs b/src/bibiman.rs index 71288ce..6aa138d 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -15,12 +15,13 @@ // along with this program. If not, see . ///// -use crate::app; use crate::bibiman::entries::EntryTableColumn; use crate::bibiman::{bibisetup::*, search::BibiSearch}; use crate::cliargs::CLIArgs; +use crate::config::BibiConfig; use crate::tui::popup::{PopupArea, PopupKind}; use crate::tui::Tui; +use crate::{app, cliargs}; use crate::{bibiman::entries::EntryTable, bibiman::keywords::TagList}; use arboard::Clipboard; use color_eyre::eyre::Result; @@ -61,7 +62,7 @@ pub enum FormerArea { #[derive(Debug)] pub struct Bibiman { // main bib file - // pub main_bibfiles: Vec, + pub main_bibfiles: Vec, // main bibliography pub main_biblio: BibiSetup, // search struct: @@ -82,15 +83,17 @@ pub struct Bibiman { impl Bibiman { // Constructs a new instance of [`App`]. - pub fn new(args: &CLIArgs) -> Result { - // let main_bibfiles = args.fileargs.clone(); - let main_biblio = BibiSetup::new(&args.files); + pub fn new(args: &mut CLIArgs, cfg: &mut BibiConfig) -> Result { + let mut main_bibfiles: Vec = args.pos_args.clone(); + main_bibfiles.append(&mut cfg.general.bibfiles); + let main_bibfiles = cliargs::parse_files(main_bibfiles); + let main_biblio = BibiSetup::new(&main_bibfiles); let tag_list = TagList::new(main_biblio.keyword_list.clone()); let search_struct = BibiSearch::default(); let entry_table = EntryTable::new(main_biblio.entry_list.clone()); let current_area = CurrentArea::EntryArea; Ok(Self { - // main_bibfiles, + main_bibfiles, main_biblio, tag_list, search_struct, @@ -128,8 +131,8 @@ impl Bibiman { self.former_area = None; } - pub fn update_lists(&mut self, args: &CLIArgs) { - self.main_biblio = BibiSetup::new(&args.files); + pub fn update_lists(&mut self) { + self.main_biblio = BibiSetup::new(&self.main_bibfiles); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); self.entry_table = EntryTable::new(self.main_biblio.entry_list.clone()); } @@ -338,17 +341,17 @@ impl Bibiman { // Check if multiple files were passed to bibiman and // return the correct file path - let filepath = if args.files.len() == 1 { - args.files.first().unwrap().as_os_str() + let filepath = if self.main_bibfiles.len() == 1 { + self.main_bibfiles.first().unwrap().as_os_str() } else { let mut idx = 0; - for f in &args.files { + for f in &self.main_bibfiles { if search::search_pattern_in_file(&citekey_pattern, &f).is_some() { break; } idx += 1; } - args.files[idx].as_os_str() + self.main_bibfiles[idx].as_os_str() }; let filecontent = fs::read_to_string(&filepath).unwrap(); @@ -391,7 +394,7 @@ impl Bibiman { tui.terminal.clear()?; // Update the database and the lists to show changes - Self::update_lists(self, args); + Self::update_lists(self); // Select entry which was selected before entering editor self.select_entry_by_citekey(citekey); @@ -431,7 +434,7 @@ impl Bibiman { .expect("Couldn't parse fetched entry into string"); self.popup_area.popup_sel_item = entry; self.popup_area.popup_kind = Some(PopupKind::AppendToFile); - self.append_to_file(args); + self.append_to_file(); self.former_area = Some(FormerArea::EntryArea); self.current_area = CurrentArea::PopupArea; self.popup_area.popup_state.select(Some(0)) @@ -441,14 +444,21 @@ impl Bibiman { } } - pub fn append_to_file(&mut self, args: &CLIArgs) { + pub fn append_to_file(&mut self) { let mut items = vec!["Create new file".to_owned()]; - if args.files.len() > 1 { - for f in args.files.clone() { + if self.main_bibfiles.len() > 1 { + for f in self.main_bibfiles.clone() { items.push(f.to_str().unwrap().to_owned()); } } else { - items.push(args.files.first().unwrap().to_str().unwrap().to_owned()); + items.push( + self.main_bibfiles + .first() + .unwrap() + .to_str() + .unwrap() + .to_owned(), + ); } self.popup_area.popup_selection(items); } @@ -472,8 +482,8 @@ impl Bibiman { let mut file = if self.popup_area.popup_list[popup_idx].contains("Create new file") { let citekey = PathBuf::from(&citekey); // Get path of current files - let path: PathBuf = if args.files[0].is_file() { - args.files[0].parent().unwrap().to_owned() + let path: PathBuf = if self.main_bibfiles[0].is_file() { + self.main_bibfiles[0].parent().unwrap().to_owned() } else { dirs::home_dir().unwrap() // home dir as fallback }; @@ -482,11 +492,11 @@ impl Bibiman { let newfile = path.join(citekey); - args.files.push(newfile.clone()); + self.main_bibfiles.push(newfile.clone()); File::create_new(newfile).unwrap() } else { - let file_path = &args.files[popup_idx - 1]; + let file_path = &self.main_bibfiles[popup_idx - 1]; // Check if similar citekey already exists let file_string = read_to_string(&file_path).unwrap(); @@ -522,7 +532,7 @@ impl Bibiman { // Write content to file file.write_all(self.popup_area.popup_sel_item.as_bytes())?; // Update the database and the lists to reflect the new content - self.update_lists(args); + self.update_lists(); self.close_popup(); // Select newly created entry -- cgit v1.2.3 From de0e6fcde0f4fdd9a08255dac52629bec28a0ca3 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Mon, 17 Feb 2025 21:43:18 +0100 Subject: Update README --- README.md | 39 ++++++++++++++++++++++++++++++++++----- example-config.toml | 4 ++-- src/app.rs | 16 +++++++++++----- src/bibiman.rs | 3 ++- src/cliargs.rs | 2 -- src/main.rs | 2 +- 6 files changed, 50 insertions(+), 16 deletions(-) (limited to 'src/bibiman.rs') diff --git a/README.md b/README.md index 8285e37..deb65d8 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,35 @@ Here is how the light terminal scheme looks: ![bibiman-light-theme.png](https://codeberg.org/attachments/7fe9d58d-7e90-4043-9402-5e4664c4e22a) +## Configuration + +### Location of Config File + +`bibiman` can be configured through a config file. The standard location is the user's config dir following the XDG scheme. On Linux systems this defaults to: + +```bash +# XDG scheme: +$XDG_CONFIG_HOME/bibiman/bibiman.toml + +# Fallback: +$HOME/.config/bibiman/bibiman.toml + +``` + +### Values + +At the moment, the following values can be set through the config file: + +```toml +[general] +# Default files/dirs which are loaded on startup +bibfiles = [ "/path/to/bibfile", "path/to/dir/with/bibfiles" ] +# Default editor to use when editing files. Arguments are possible +editor = "vim" # with args: "vim -y" +``` + +Paths to bibfiles/dirs passed through the CLI will be added to the ones provided by the config file. + ## Features These are the current features, the list will be updated: @@ -113,9 +142,9 @@ These are the current features, the list will be updated: position in bibfile. - [x] **Load multiple files** into one session. - [x] **Add Entry via DOI**. -- [ ] **Open related notes file** for specific entry. -- [ ] **Implement config file** for setting some default values like main +- [x] **Implement config file** for setting some default values like main bibfile, PDF-opener, or editor +- [ ] **Open related notes file** for specific entry. - [ ] **Support Hayagriva(`.yaml`)** format as input (_on hold for now_, because the Hayagriva Yaml style doesn't offer keywords; s. issue in [Hayagriva repo](https://github.com/typst/hayagriva/issues/240)). @@ -158,10 +187,10 @@ enabled by default. You can use some special chars to alter pattern matching: ## Edit bib entry -For now, the TUI only supports editors set through the environment variables -`VISUAL` and `EDITOR` in this order. The fallback solution is `vi`. +The main editor can be set through the [config file](#values). Otherwise, the environment variables +`VISUAL` and `EDITOR` will be used in this order. The last fallback solution is `vi`. -I've tested the following editors (set as value of `VISUAL`): +I've tested the following editors (set as value of `VISUAL` and through the config file): - [x] **Helix**: `export VISUAL="hx"` - [x] **Vim/Neovim**: `export VISUAL="vim/nvim"` diff --git a/example-config.toml b/example-config.toml index 8a4aef6..989350e 100644 --- a/example-config.toml +++ b/example-config.toml @@ -1,3 +1,3 @@ [general] -bibfiles = ["./tests/biblatex-test.bib"] -editor = "vi" +bibfiles = ["./tests/biblatex-test.bib"] # files and dirs are possible +editor = "vim" # arguments are possible: "vim -y" diff --git a/src/app.rs b/src/app.rs index c60d81e..b49e883 100644 --- a/src/app.rs +++ b/src/app.rs @@ -60,7 +60,7 @@ impl App { }) } - pub async fn run(&mut self, args: &mut CLIArgs) -> Result<()> { + pub async fn run(&mut self, args: &mut CLIArgs, cfg: &BibiConfig) -> Result<()> { let mut tui = tui::Tui::new()?; tui.enter()?; @@ -86,10 +86,10 @@ impl App { } else { CmdAction::from(key_event) }; - self.run_command(command, args, &mut tui)? + self.run_command(command, args, cfg, &mut tui)? } Event::Mouse(mouse_event) => { - self.run_command(CmdAction::from(mouse_event), args, &mut tui)? + self.run_command(CmdAction::from(mouse_event), args, cfg, &mut tui)? } Event::Resize(_, _) => {} @@ -111,7 +111,13 @@ impl App { self.running = false; } - pub fn run_command(&mut self, cmd: CmdAction, args: &mut CLIArgs, tui: &mut Tui) -> Result<()> { + pub fn run_command( + &mut self, + cmd: CmdAction, + args: &mut CLIArgs, + cfg: &BibiConfig, + tui: &mut Tui, + ) -> Result<()> { match cmd { CmdAction::Input(cmd) => match cmd { InputCmdAction::Nothing => {} @@ -304,7 +310,7 @@ impl App { } CmdAction::EditFile => { if let CurrentArea::EntryArea = self.bibiman.current_area { - self.bibiman.run_editor(args, tui)?; + self.bibiman.run_editor(cfg, args, tui)?; } } CmdAction::Open => { diff --git a/src/bibiman.rs b/src/bibiman.rs index 6aa138d..20cdfc6 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -328,7 +328,7 @@ impl Bibiman { self.entry_table.entry_table_state.select(Some(idx_count)); } - pub fn run_editor(&mut self, args: &CLIArgs, tui: &mut Tui) -> Result<()> { + pub fn run_editor(&mut self, cfg: &BibiConfig, args: &CLIArgs, tui: &mut Tui) -> Result<()> { // get filecontent and citekey for calculating line number let citekey: &str = &self.entry_table.entry_table_items [self.entry_table.entry_table_state.selected().unwrap()] @@ -379,6 +379,7 @@ impl Bibiman { tui.exit()?; // Use VISUAL or EDITOR. Set "vi" as last fallback let mut cmd: Command = EditorBuilder::new() + .source(cfg.general.editor.clone()) .environment() .source(Some("vi")) .build() diff --git a/src/cliargs.rs b/src/cliargs.rs index 50ed6f5..895f116 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -65,8 +65,6 @@ impl CLIArgs { } } - // args.files = parse_files(args.pos_args.clone()); - Ok(args) } } diff --git a/src/main.rs b/src/main.rs index 94f5042..37bead0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,6 +56,6 @@ async fn main() -> Result<()> { // Create an application. let mut app = App::new(&mut parsed_args, &mut cfg)?; - app.run(&mut parsed_args).await?; + app.run(&mut parsed_args, &cfg).await?; Ok(()) } -- cgit v1.2.3 From dc5ded8160177864963a31476c2a7afe8ca8e834 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Wed, 19 Feb 2025 21:13:50 +0100 Subject: resource opener in config + implement config field `pdf_opener` for setting app to open PDFs/Epubs + implement config field `url_opener` for setting app to open URLs/DOIs + function to select fallback if no field is provided in config --- README.md | 2 ++ example-config.toml | 2 ++ src/app.rs | 55 +++++++++++++++++++++++++++++++++++------------------ src/bibiman.rs | 10 ++++++---- src/config.rs | 26 +++++++++++++++++++++---- src/main.rs | 2 +- 6 files changed, 69 insertions(+), 28 deletions(-) (limited to 'src/bibiman.rs') diff --git a/README.md b/README.md index 725cd8e..47d57de 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ POSITIONAL ARGS: FLAGS: -h, --help Show this help and exit -v, --version Show the version and exit + -c, --config-file Path to config file for current session + Takes precedence over standard config file --light-terminal Enable color mode for light terminal background ``` diff --git a/example-config.toml b/example-config.toml index 989350e..9d110ed 100644 --- a/example-config.toml +++ b/example-config.toml @@ -1,3 +1,5 @@ [general] bibfiles = ["./tests/biblatex-test.bib"] # files and dirs are possible editor = "vim" # arguments are possible: "vim -y" +# pdf_opener = "xdg-open" +# url_opener = "xdg-open" diff --git a/src/app.rs b/src/app.rs index b49e883..e03f8d7 100644 --- a/src/app.rs +++ b/src/app.rs @@ -275,7 +275,7 @@ impl App { if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind { self.bibiman.close_popup(); } else if let Some(PopupKind::OpenRes) = self.bibiman.popup_area.popup_kind { - self.bibiman.open_connected_res()?; + self.bibiman.open_connected_res(cfg)?; } else if let Some(PopupKind::AppendToFile) = self.bibiman.popup_area.popup_kind { self.bibiman.append_entry_to_file(args)? @@ -362,16 +362,20 @@ impl App { } } -pub fn open_connected_file(file: &OsStr) -> Result<()> { +pub fn open_connected_file(cfg: &BibiConfig, file: &OsStr) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard // TODO: make custom opener command possible through config - let cmd = { - match std::env::consts::OS { - "linux" => String::from("xdg-open"), - "macos" => String::from("open"), - "windows" => String::from("start"), - _ => panic!("Couldn't detect OS for setting correct opener"), - } + // let cmd = { + // match std::env::consts::OS { + // "linux" => String::from("xdg-open"), + // "macos" => String::from("open"), + // "windows" => String::from("start"), + // _ => panic!("Couldn't detect OS for setting correct opener"), + // } + // }; + let cmd = match &cfg.general.pdf_opener { + Some(c) => c, + None => &select_opener(), }; // If necessary, replace ~ with /home dir @@ -381,7 +385,7 @@ pub fn open_connected_file(file: &OsStr) -> Result<()> { // Pass filepath as argument, pipe stdout and stderr to /dev/null // to keep the TUI clean (where is it piped on Windows???) - let _ = Command::new(&cmd) + let _ = Command::new(cmd) .arg(file) .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -391,21 +395,25 @@ pub fn open_connected_file(file: &OsStr) -> Result<()> { Ok(()) } -pub fn open_connected_link(link: &str) -> Result<()> { +pub fn open_connected_link(cfg: &BibiConfig, link: &str) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard // TODO: make custom opener command possible through config - let cmd = { - match std::env::consts::OS { - "linux" => String::from("xdg-open"), - "macos" => String::from("open"), - "windows" => String::from("start"), - _ => panic!("Couldn't detect OS for setting correct opener"), - } + // let cmd = { + // match std::env::consts::OS { + // "linux" => String::from("xdg-open"), + // "macos" => String::from("open"), + // "windows" => String::from("start"), + // _ => panic!("Couldn't detect OS for setting correct opener"), + // } + // }; + let cmd = match &cfg.general.url_opener { + Some(c) => c, + None => &select_opener(), }; // Pass filepath as argument, pipe stdout and stderr to /dev/null // to keep the TUI clean (where is it piped on Windows???) - let _ = Command::new(&cmd) + let _ = Command::new(cmd) .arg(link) .stdout(Stdio::null()) .stderr(Stdio::null()) @@ -437,6 +445,15 @@ fn expand_home(path: &PathBuf) -> PathBuf { } } +fn select_opener() -> String { + match std::env::consts::OS { + "linux" => String::from("xdg-open"), + "macos" => String::from("open"), + "windows" => String::from("start"), + _ => panic!("Couldn't detect OS for setting correct opener"), + } +} + #[cfg(test)] mod test { use super::*; diff --git a/src/bibiman.rs b/src/bibiman.rs index 20cdfc6..ecddc4c 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -85,7 +85,9 @@ impl Bibiman { // Constructs a new instance of [`App`]. pub fn new(args: &mut CLIArgs, cfg: &mut BibiConfig) -> Result { let mut main_bibfiles: Vec = args.pos_args.clone(); - main_bibfiles.append(&mut cfg.general.bibfiles); + if cfg.general.bibfiles.is_some() { + main_bibfiles.append(cfg.general.bibfiles.as_mut().unwrap()) + }; let main_bibfiles = cliargs::parse_files(main_bibfiles); let main_biblio = BibiSetup::new(&main_bibfiles); let tag_list = TagList::new(main_biblio.keyword_list.clone()); @@ -542,7 +544,7 @@ impl Bibiman { Ok(()) } - pub fn open_connected_res(&mut self) -> Result<()> { + pub fn open_connected_res(&mut self, cfg: &BibiConfig) -> Result<()> { // Index of selected entry let entry_idx = self.entry_table.entry_table_state.selected().unwrap(); @@ -553,10 +555,10 @@ impl Bibiman { if self.popup_area.popup_list[popup_idx].contains("Weblink") { let object = self.entry_table.entry_table_items[entry_idx].doi_url(); let url = app::prepare_weblink(object); - app::open_connected_link(&url)?; + app::open_connected_link(cfg, &url)?; } else if self.popup_area.popup_list[popup_idx].contains("File") { let object = self.entry_table.entry_table_items[entry_idx].filepath(); - app::open_connected_file(object)?; + app::open_connected_file(cfg, object)?; } else { eprintln!("Unable to find ressource to open"); }; diff --git a/src/config.rs b/src/config.rs index a80cc13..abb610b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,33 +17,51 @@ use std::path::PathBuf; +use color_eyre::eyre::Result; use config::{ConfigError, FileFormat}; use serde::Deserialize; use crate::cliargs::CLIArgs; +/// Main struct of the config file. Contains substructs/headings in toml #[derive(Debug, Clone, Deserialize)] pub struct BibiConfig { pub general: General, } +/// Substruct [general] in config.toml #[derive(Debug, Clone, Deserialize)] pub struct General { - pub bibfiles: Vec, + pub bibfiles: Option>, pub editor: Option, + pub pdf_opener: Option, + pub url_opener: Option, } impl BibiConfig { - pub fn default(args: &CLIArgs) -> Self { + pub fn default() -> Self { Self { general: General { - bibfiles: args.pos_args.clone(), + bibfiles: None, editor: None, + pdf_opener: None, + url_opener: None, }, } } - pub fn new(args: &CLIArgs) -> Result { + pub fn new(args: &CLIArgs) -> Result { + // let mut cfg = config::Config::builder(); + // cfg = cfg.add_source( + // config::File::from(args.cfg_path.clone()) + // .format(FileFormat::Toml) + // .required(false), + // ); + // cfg.build()?.try_deserialize() + Ok(Self::parse_cfg_file(args)?) + } + + fn parse_cfg_file(args: &CLIArgs) -> Result { let mut cfg = config::Config::builder(); cfg = cfg.add_source( config::File::from(args.cfg_path.clone()) diff --git a/src/main.rs b/src/main.rs index 37bead0..d53aaab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,7 +48,7 @@ async fn main() -> Result<()> { let mut cfg = if parsed_args.cfg_path.is_file() { BibiConfig::new(&parsed_args)? } else { - BibiConfig::default(&parsed_args) + BibiConfig::default() }; init_error_hooks()?; -- cgit v1.2.3 From ddb6326c1896b82b759d930fb08ea46a820e275a Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 21 Feb 2025 20:17:27 +0100 Subject: parse config file + set default values for config fields + merge fields named in the config file with default values + values from file take precedence over default values + to accomplish this, all config values are wrapped in `Option` --- Cargo.lock | 5 +++ Cargo.toml | 2 +- src/app.rs | 12 ++----- src/bibiman.rs | 6 ++-- src/config.rs | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- src/main.rs | 12 ++++--- 6 files changed, 122 insertions(+), 26 deletions(-) (limited to 'src/bibiman.rs') diff --git a/Cargo.lock b/Cargo.lock index f8a062e..342fba4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,6 +146,9 @@ name = "bitflags" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "block2" @@ -263,6 +266,7 @@ dependencies = [ "itoa", "rustversion", "ryu", + "serde", "static_assertions", ] @@ -1366,6 +1370,7 @@ dependencies = [ "itertools", "lru", "paste", + "serde", "strum", "unicode-segmentation", "unicode-truncate", diff --git a/Cargo.toml b/Cargo.toml index 971df49..c2f42a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ rand = "0.8" itertools = "0.13.0" lexopt = "0.3.0" nucleo-matcher = "0.3.1" -ratatui = { version = "0.29.0", features = ["unstable-rendered-line-info"]} +ratatui = { version = "0.29.0", features = ["unstable-rendered-line-info", "serde"]} signal-hook = "0.3.17" tokio = { version = "1.39.3", features = ["full"] } tokio-util = "0.7.12" diff --git a/src/app.rs b/src/app.rs index 55f49de..b3778af 100644 --- a/src/app.rs +++ b/src/app.rs @@ -364,11 +364,7 @@ impl App { pub fn open_connected_file(cfg: &BibiConfig, file: &OsStr) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard - let cmd = match &cfg.general.pdf_opener { - Some(c) => c, - None => &select_opener(), - }; - + let cmd = cfg.general.as_ref().unwrap().pdf_opener.as_ref().unwrap(); // If necessary, replace ~ with /home dir let file = PathBuf::from(file); @@ -388,11 +384,7 @@ pub fn open_connected_file(cfg: &BibiConfig, file: &OsStr) -> Result<()> { pub fn open_connected_link(cfg: &BibiConfig, link: &str) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard - let cmd = match &cfg.general.url_opener { - Some(c) => c, - None => &select_opener(), - }; - + let cmd = cfg.general.as_ref().unwrap().url_opener.as_ref().unwrap(); // Pass filepath as argument, pipe stdout and stderr to /dev/null // to keep the TUI clean (where is it piped on Windows???) let _ = Command::new(cmd) diff --git a/src/bibiman.rs b/src/bibiman.rs index ecddc4c..b68b0fa 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -85,8 +85,8 @@ impl Bibiman { // Constructs a new instance of [`App`]. pub fn new(args: &mut CLIArgs, cfg: &mut BibiConfig) -> Result { let mut main_bibfiles: Vec = args.pos_args.clone(); - if cfg.general.bibfiles.is_some() { - main_bibfiles.append(cfg.general.bibfiles.as_mut().unwrap()) + if cfg.general.as_ref().unwrap().bibfiles.is_some() { + main_bibfiles.append(cfg.general.as_mut().unwrap().bibfiles.as_mut().unwrap()) }; let main_bibfiles = cliargs::parse_files(main_bibfiles); let main_biblio = BibiSetup::new(&main_bibfiles); @@ -381,7 +381,7 @@ impl Bibiman { tui.exit()?; // Use VISUAL or EDITOR. Set "vi" as last fallback let mut cmd: Command = EditorBuilder::new() - .source(cfg.general.editor.clone()) + .source(cfg.general.as_ref().unwrap().editor.clone()) .environment() .source(Some("vi")) .build() diff --git a/src/config.rs b/src/config.rs index abb610b..22873dd 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,6 +19,7 @@ use std::path::PathBuf; use color_eyre::eyre::Result; use config::{ConfigError, FileFormat}; +use ratatui::style::Color; use serde::Deserialize; use crate::cliargs::CLIArgs; @@ -26,7 +27,8 @@ use crate::cliargs::CLIArgs; /// Main struct of the config file. Contains substructs/headings in toml #[derive(Debug, Clone, Deserialize)] pub struct BibiConfig { - pub general: General, + pub general: Option, + pub colors: Option, } /// Substruct [general] in config.toml @@ -38,17 +40,103 @@ pub struct General { pub url_opener: Option, } -impl BibiConfig { - pub fn default() -> Self { +/// Substruct [colors] in config.toml +#[derive(Debug, Clone, Deserialize)] +pub struct Colors { + pub main_text_color: Option, + pub highlight_text_color: Option, + pub entry_color: Option, + pub keyword_color: Option, + pub info_color: Option, + pub confirm_color: Option, + pub warn_color: Option, + pub bar_bg_color: Option, + pub popup_bg_color: Option, + pub selected_row_bg_color: Option, +} + +impl Default for BibiConfig { + fn default() -> Self { Self { - general: General { + general: Some(General { bibfiles: None, editor: None, - pdf_opener: None, - url_opener: None, - }, + pdf_opener: Some(select_opener()), + url_opener: Some(select_opener()), + }), + colors: Some(Colors { + main_text_color: Some(Color::Indexed(250)), + highlight_text_color: Some(Color::Indexed(254)), + entry_color: Some(Color::Indexed(36)), + keyword_color: Some(Color::Indexed(101)), + info_color: Some(Color::Indexed(99)), + confirm_color: Some(Color::Indexed(47)), + warn_color: Some(Color::Indexed(124)), + bar_bg_color: Some(Color::Indexed(234)), + popup_bg_color: Some(Color::Indexed(234)), + selected_row_bg_color: Some(Color::Indexed(237)), + }), } } +} + +impl BibiConfig { + pub fn parse_config(&mut self, args: &CLIArgs) -> Result<()> { + if args.cfg_path.is_file() { + let cfg_file = Self::parse_cfg_file(args)?; + + if let Some(general) = cfg_file.general { + if let Some(bibfiles) = general.bibfiles { + self.general.as_mut().unwrap().bibfiles = Some(bibfiles) + } + if let Some(editor) = general.editor { + self.general.as_mut().unwrap().editor = Some(editor) + } + if let Some(pdf_opener) = general.pdf_opener { + self.general.as_mut().unwrap().pdf_opener = Some(pdf_opener) + } + if let Some(url_opener) = general.url_opener { + self.general.as_mut().unwrap().url_opener = Some(url_opener) + } + } + + if let Some(colors) = cfg_file.colors { + if let Some(main_text_color) = colors.main_text_color { + self.colors.as_mut().unwrap().main_text_color = Some(main_text_color) + } + if let Some(highlight_text_color) = colors.highlight_text_color { + self.colors.as_mut().unwrap().highlight_text_color = Some(highlight_text_color) + } + if let Some(entry_color) = colors.entry_color { + self.colors.as_mut().unwrap().entry_color = Some(entry_color) + } + if let Some(keyword_color) = colors.keyword_color { + self.colors.as_mut().unwrap().keyword_color = Some(keyword_color) + } + if let Some(info_color) = colors.info_color { + self.colors.as_mut().unwrap().info_color = Some(info_color) + } + if let Some(confirm_color) = colors.confirm_color { + self.colors.as_mut().unwrap().confirm_color = Some(confirm_color) + } + if let Some(warn_color) = colors.warn_color { + self.colors.as_mut().unwrap().warn_color = Some(warn_color) + } + if let Some(bar_bg_color) = colors.bar_bg_color { + self.colors.as_mut().unwrap().bar_bg_color = Some(bar_bg_color) + } + if let Some(popup_bg_color) = colors.popup_bg_color { + self.colors.as_mut().unwrap().popup_bg_color = Some(popup_bg_color) + } + if let Some(selected_row_bg_color) = colors.selected_row_bg_color { + self.colors.as_mut().unwrap().selected_row_bg_color = + Some(selected_row_bg_color) + } + } + } + + Ok(()) + } pub fn new(args: &CLIArgs) -> Result { // let mut cfg = config::Config::builder(); @@ -71,3 +159,12 @@ impl BibiConfig { cfg.build()?.try_deserialize() } } + +fn select_opener() -> String { + match std::env::consts::OS { + "linux" => String::from("xdg-open"), + "macos" => String::from("open"), + "windows" => String::from("start"), + _ => panic!("Couldn't detect OS for setting correct opener"), + } +} diff --git a/src/main.rs b/src/main.rs index d53aaab..8ec3b77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,11 +45,13 @@ async fn main() -> Result<()> { std::process::exit(0); } - let mut cfg = if parsed_args.cfg_path.is_file() { - BibiConfig::new(&parsed_args)? - } else { - BibiConfig::default() - }; + // let mut cfg = if parsed_args.cfg_path.is_file() { + // BibiConfig::new(&parsed_args)? + // } else { + // BibiConfig::default() + // }; + let mut cfg = BibiConfig::default(); + cfg.parse_config(&parsed_args)?; init_error_hooks()?; -- cgit v1.2.3 From c34412d9e3725bed48af925646110f2ca34b1bd4 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 21 Feb 2025 21:55:17 +0100 Subject: implement working config file construct, error handling should be improved --- README.md | 58 ++++++++---- example-config.toml | 12 +++ src/app.rs | 32 ++----- src/bibiman.rs | 6 +- src/cliargs.rs | 11 +-- src/config.rs | 26 ++--- src/main.rs | 13 +-- src/tui.rs | 6 +- src/tui/popup.rs | 33 ++++--- src/tui/ui.rs | 266 ++++++++++++++++++++++++++++------------------------ 10 files changed, 255 insertions(+), 208 deletions(-) (limited to 'src/bibiman.rs') diff --git a/README.md b/README.md index d62c847..41ebdfc 100644 --- a/README.md +++ b/README.md @@ -87,16 +87,6 @@ bibman tests/multi-files/ bibiman tests/biblatex-test.bib tests/multi-files/ ``` -Furthermore, in issue #3 it was asked to enable a color customization to run -`bibiman` also in terminal setups with light background. Thus, now it is -possible to enable a light terminal mode with the `--light-terminal` flag. Full -color customization is not possible right now, but maybe will be added with the -implementation of a config file. - -Here is how the light terminal scheme looks: - -![bibiman-light-theme.png](https://codeberg.org/attachments/7fe9d58d-7e90-4043-9402-5e4664c4e22a) - ## Configuration ### Location of Config File @@ -119,13 +109,14 @@ which takes precedence over the standard one for the active session: bibiman --config-file="/path/to/temporary/config" ``` -### Values +### General Configuration -At the moment, the following values can be set through the config file: +The following general values can be set through the config file: ```toml [general] # Default files/dirs which are loaded on startup +# Use absolute paths (~ for HOME works). Otherwise, loading might not work. bibfiles = [ "/path/to/bibfile", "path/to/dir/with/bibfiles" ] # Default editor to use when editing files. Arguments are possible editor = "vim" # with args: "vim -y" @@ -135,11 +126,44 @@ pdf_opener = "xdg-open" url_opener = "xdg-open" ``` -No value *needs* to be set. For every one exists a default value. Only exception -is the `bibfiles` key. If no file or dir is set, you *have to* add a path via -CLI interface. If the `bibfiles` value is set *and* a further path (or multiple) -is provided through the CLI call, the entries of all those files will be opened -in the started `bibiman` session. +If no file or dir is set as `bibfiles` value, you *have to* add a path via CLI +interface. If the `bibfiles` value is set *and* a further path (or multiple) is +provided through the CLI call, the entries of all those files will be opened in +the started `bibiman` session. + +### Color Configuration + +Furthermore, it is now possible to customize the colors. The following values +can be changed: + +```toml +[colors] +# Default values for dark-themed terminal +main_text_color = "250" +highlight_text_color = "254" +entry_color = "36" +keyword_color = "101" +info_color = "99" +confirm_color = "47" +warn_color = "124" +bar_bg_color = "234" +popup_bg_color = "234" +selected_row_bg_color = "237" +``` + +Colors can be set through three different methods: +[ANSI color names](https://docs.rs/ratatui/latest/ratatui/style/enum.Color.html), +[256-color indices](https://en.wikipedia.org/wiki/ANSI_escape_code#8-bit) and +[HEX codes](https://www.w3schools.com/colors/colors_hexadecimal.asp). For +example, the following definitions are all valid: + +```toml +selected_row_bg_color = "darkgray" # ANSI color name (light_black or bright_black would also work) +selected_row_bg_color = "237" # 256-color index +selected_row_bg_color = "#3a3a3a" # HEX code +``` + +To run `bibiman` with some default values for a light-colored terminal use the `--light-terminal` flag. ## Features diff --git a/example-config.toml b/example-config.toml index 50c0467..d6d2aa8 100644 --- a/example-config.toml +++ b/example-config.toml @@ -3,3 +3,15 @@ bibfiles = ["./tests/biblatex-test.bib"] # multiple files and dirs are possible editor = "vim" # arguments are possible: "vim -y" # pdf_opener = "xdg-open" # url_opener = "xdg-open" + +# [colors] +# main_text_color = "250" +# highlight_text_color = "254" +# entry_color = "36" +# keyword_color = "101" +# info_color = "99" +# confirm_color = "47" +# warn_color = "124" +# bar_bg_color = "234" +# popup_bg_color = "234" +# selected_row_bg_color = "237" diff --git a/src/app.rs b/src/app.rs index b3778af..7869304 100644 --- a/src/app.rs +++ b/src/app.rs @@ -24,7 +24,6 @@ use crate::tui::commands::InputCmdAction; use crate::tui::popup::PopupKind; use crate::tui::{self, Tui}; use crate::{bibiman::Bibiman, tui::commands::CmdAction}; -use core::panic; use std::ffi::OsStr; use std::path::PathBuf; use std::process::{Command, Stdio}; @@ -60,14 +59,14 @@ impl App { }) } - pub async fn run(&mut self, args: &mut CLIArgs, cfg: &BibiConfig) -> Result<()> { + pub async fn run(&mut self, cfg: &BibiConfig) -> Result<()> { let mut tui = tui::Tui::new()?; tui.enter()?; // Start the main loop. while self.running { // Render the user interface. - tui.draw(self, args)?; + tui.draw(self, cfg)?; // Handle events. match tui.next().await? { Event::Tick => self.tick(), @@ -86,10 +85,10 @@ impl App { } else { CmdAction::from(key_event) }; - self.run_command(command, args, cfg, &mut tui)? + self.run_command(command, cfg, &mut tui)? } Event::Mouse(mouse_event) => { - self.run_command(CmdAction::from(mouse_event), args, cfg, &mut tui)? + self.run_command(CmdAction::from(mouse_event), cfg, &mut tui)? } Event::Resize(_, _) => {} @@ -111,13 +110,7 @@ impl App { self.running = false; } - pub fn run_command( - &mut self, - cmd: CmdAction, - args: &mut CLIArgs, - cfg: &BibiConfig, - tui: &mut Tui, - ) -> Result<()> { + pub fn run_command(&mut self, cmd: CmdAction, cfg: &BibiConfig, tui: &mut Tui) -> Result<()> { match cmd { CmdAction::Input(cmd) => match cmd { InputCmdAction::Nothing => {} @@ -149,7 +142,7 @@ impl App { || doi.starts_with("http://doi.org") || doi.starts_with("http://dx.doi.org") { - self.bibiman.handle_new_entry_submission(args, doi); + self.bibiman.handle_new_entry_submission(doi); } else { self.bibiman.popup_area.popup_message( "No valid DOI pattern: ", @@ -278,7 +271,7 @@ impl App { self.bibiman.open_connected_res(cfg)?; } else if let Some(PopupKind::AppendToFile) = self.bibiman.popup_area.popup_kind { - self.bibiman.append_entry_to_file(args)? + self.bibiman.append_entry_to_file()? } } } @@ -310,7 +303,7 @@ impl App { } CmdAction::EditFile => { if let CurrentArea::EntryArea = self.bibiman.current_area { - self.bibiman.run_editor(cfg, args, tui)?; + self.bibiman.run_editor(cfg, tui)?; } } CmdAction::Open => { @@ -419,15 +412,6 @@ pub fn expand_home(path: &PathBuf) -> PathBuf { } } -fn select_opener() -> String { - match std::env::consts::OS { - "linux" => String::from("xdg-open"), - "macos" => String::from("open"), - "windows" => String::from("start"), - _ => panic!("Couldn't detect OS for setting correct opener"), - } -} - #[cfg(test)] mod test { use super::*; diff --git a/src/bibiman.rs b/src/bibiman.rs index b68b0fa..b8ef2c6 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -330,7 +330,7 @@ impl Bibiman { self.entry_table.entry_table_state.select(Some(idx_count)); } - pub fn run_editor(&mut self, cfg: &BibiConfig, args: &CLIArgs, tui: &mut Tui) -> Result<()> { + pub fn run_editor(&mut self, cfg: &BibiConfig, tui: &mut Tui) -> Result<()> { // get filecontent and citekey for calculating line number let citekey: &str = &self.entry_table.entry_table_items [self.entry_table.entry_table_state.selected().unwrap()] @@ -418,7 +418,7 @@ impl Bibiman { ///the new entry via `append_to_file()` function. If not, show error popup /// ///The method needs two arguments: the CLIArgs struct and the `str` containing the DOI - pub fn handle_new_entry_submission(&mut self, args: &CLIArgs, doi_string: &str) { + pub fn handle_new_entry_submission(&mut self, doi_string: &str) { let doi_string = if doi_string.starts_with("10.") { "https://doi.org/".to_string() + doi_string } else { @@ -466,7 +466,7 @@ impl Bibiman { self.popup_area.popup_selection(items); } - pub fn append_entry_to_file(&mut self, args: &mut CLIArgs) -> Result<()> { + pub fn append_entry_to_file(&mut self) -> Result<()> { // Index of selected popup field let popup_idx = self.popup_area.popup_state.selected().unwrap(); diff --git a/src/cliargs.rs b/src/cliargs.rs index bb3c8d1..3c302f4 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -24,7 +24,6 @@ use std::path::PathBuf; use walkdir::WalkDir; use crate::app; -use crate::tui::colors::AppColors; // struct for CLIArgs #[derive(Debug, Default, Clone)] @@ -32,11 +31,8 @@ pub struct CLIArgs { pub helparg: bool, pub versionarg: bool, pub pos_args: Vec, - // pub files: Vec, pub cfg_path: PathBuf, - // INFO: AppColors struct later should be moved to config/app struct - // when config file is implemented - pub colors: AppColors, + pub light_theme: bool, } impl CLIArgs { @@ -56,10 +52,7 @@ impl CLIArgs { Short('h') | Long("help") => args.helparg = true, Short('v') | Long("version") => args.versionarg = true, Short('c') | Long("config-file") => args.cfg_path = parser.value()?.parse()?, - Long("light-terminal") => { - args.colors.light_colors(); - args.colors.toggle_color_scheme() - } + Long("light-terminal") => args.light_theme = true, // Value(pos_arg) => parse_files(&mut args, pos_arg), Value(pos_arg) => args.pos_args.push(pos_arg.into()), _ => return Err(arg.unexpected()), diff --git a/src/config.rs b/src/config.rs index 22873dd..faba5d8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -72,7 +72,7 @@ impl Default for BibiConfig { info_color: Some(Color::Indexed(99)), confirm_color: Some(Color::Indexed(47)), warn_color: Some(Color::Indexed(124)), - bar_bg_color: Some(Color::Indexed(234)), + bar_bg_color: Some(Color::Indexed(235)), popup_bg_color: Some(Color::Indexed(234)), selected_row_bg_color: Some(Color::Indexed(237)), }), @@ -138,17 +138,6 @@ impl BibiConfig { Ok(()) } - pub fn new(args: &CLIArgs) -> Result { - // let mut cfg = config::Config::builder(); - // cfg = cfg.add_source( - // config::File::from(args.cfg_path.clone()) - // .format(FileFormat::Toml) - // .required(false), - // ); - // cfg.build()?.try_deserialize() - Ok(Self::parse_cfg_file(args)?) - } - fn parse_cfg_file(args: &CLIArgs) -> Result { let mut cfg = config::Config::builder(); cfg = cfg.add_source( @@ -158,6 +147,19 @@ impl BibiConfig { ); cfg.build()?.try_deserialize() } + + /// Activates the default color scheme for light background terminals + pub fn light_colors(&mut self) { + self.colors.as_mut().unwrap().main_text_color = Some(Color::Indexed(235)); + self.colors.as_mut().unwrap().highlight_text_color = Some(Color::Indexed(232)); + self.colors.as_mut().unwrap().entry_color = Some(Color::Indexed(23)); + self.colors.as_mut().unwrap().keyword_color = Some(Color::Indexed(58)); + self.colors.as_mut().unwrap().info_color = Some(Color::Indexed(57)); + self.colors.as_mut().unwrap().bar_bg_color = Some(Color::Indexed(144)); + self.colors.as_mut().unwrap().popup_bg_color = Some(Color::Indexed(187)); + self.colors.as_mut().unwrap().confirm_color = Some(Color::Indexed(22)); + self.colors.as_mut().unwrap().selected_row_bg_color = Some(Color::Indexed(107)); + } } fn select_opener() -> String { diff --git a/src/main.rs b/src/main.rs index 8ec3b77..3325f80 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,12 +45,13 @@ async fn main() -> Result<()> { std::process::exit(0); } - // let mut cfg = if parsed_args.cfg_path.is_file() { - // BibiConfig::new(&parsed_args)? - // } else { - // BibiConfig::default() - // }; + // Build default config let mut cfg = BibiConfig::default(); + + if parsed_args.light_theme { + cfg.light_colors(); + } + // Merge values from config file if present cfg.parse_config(&parsed_args)?; init_error_hooks()?; @@ -58,6 +59,6 @@ async fn main() -> Result<()> { // Create an application. let mut app = App::new(&mut parsed_args, &mut cfg)?; - app.run(&mut parsed_args, &cfg).await?; + app.run(&cfg).await?; Ok(()) } diff --git a/src/tui.rs b/src/tui.rs index b39b5c4..1e3061f 100644 --- a/src/tui.rs +++ b/src/tui.rs @@ -20,7 +20,7 @@ pub mod commands; pub mod popup; pub mod ui; -use crate::{cliargs::CLIArgs, App}; +use crate::{config::BibiConfig, App}; use crossterm::{ cursor, event::{ @@ -195,11 +195,11 @@ impl Tui { // // [`Draw`]: ratatui::Terminal::draw // [`rendering`]: crate::ui::render - pub fn draw(&mut self, app: &mut App, args: &CLIArgs) -> Result<()> { + pub fn draw(&mut self, app: &mut App, cfg: &BibiConfig) -> Result<()> { // self.terminal.draw(|frame| ui::render(app, frame))?; self.terminal // .draw(|frame| frame.render_widget(app, frame.area()))?; - .draw(|frame| ui::render_ui(app, args, frame))?; + .draw(|frame| ui::render_ui(app, cfg, frame))?; Ok(()) } diff --git a/src/tui/popup.rs b/src/tui/popup.rs index 4ef9fc3..6a2e8ff 100644 --- a/src/tui/popup.rs +++ b/src/tui/popup.rs @@ -16,12 +16,12 @@ ///// use ratatui::{ - style::{Color, Stylize}, + style::Stylize, text::{Line, Span, Text}, widgets::ListState, }; -use crate::cliargs::CLIArgs; +use crate::config::BibiConfig; #[derive(Debug)] pub enum PopupKind { @@ -47,7 +47,7 @@ pub struct PopupArea { } impl PopupArea { - pub fn popup_help<'a>(args: &CLIArgs) -> Text<'a> { + pub fn popup_help<'a>(cfg: &BibiConfig) -> Text<'a> { let help = [ ("General", "first"), ("TAB: ", "Toggle areas (Entries, Keywords)"), @@ -89,22 +89,31 @@ impl PopupArea { for (keys, help) in help { if help == "first" { helptext.push(Line::from( - Span::raw(keys) - .bold() - .fg(Color::Indexed(args.colors.main_text_color)), + Span::raw(keys).bold().fg(cfg + .colors + .as_ref() + .unwrap() + .main_text_color + .unwrap()), )) } else if help == "sub" { helptext.push(Line::from("")); helptext.push(Line::from( - Span::raw(keys) - .bold() - .fg(Color::Indexed(args.colors.main_text_color)), + Span::raw(keys).bold().fg(cfg + .colors + .as_ref() + .unwrap() + .main_text_color + .unwrap()), )) } else { helptext.push(Line::from(vec![ - Span::raw(keys) - .bold() - .fg(Color::Indexed(args.colors.keyword_color)), + Span::raw(keys).bold().fg(cfg + .colors + .as_ref() + .unwrap() + .main_text_color + .unwrap()), Span::raw(help), ])) } diff --git a/src/tui/ui.rs b/src/tui/ui.rs index 52d2d9a..5fbe283 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -17,11 +17,11 @@ use std::path::PathBuf; -use super::colors::AppColorScheme; use super::popup::PopupArea; use crate::bibiman::entries::EntryTableColumn; use crate::bibiman::{CurrentArea, FormerArea}; use crate::cliargs::CLIArgs; +use crate::config::BibiConfig; use crate::tui::popup::PopupKind; use crate::App; use ratatui::layout::{Direction, Position}; @@ -52,8 +52,8 @@ pub fn color_list( highlight: u8, max_diff: i32, ) -> Color { - match args.colors.color_scheme { - AppColorScheme::Dark => { + match args.light_theme { + false => { if list_item == sel_item { Color::Indexed(highlight) } else if (list_item - sel_item) > max_diff @@ -68,7 +68,7 @@ pub fn color_list( Color::Indexed(highlight - (list_item - sel_item) as u8) } } - AppColorScheme::Light => { + true => { if list_item == sel_item { Color::Indexed(highlight) } else if (list_item - sel_item) > max_diff @@ -103,7 +103,7 @@ fn count_files(files: &[PathBuf]) -> u16 { count } -pub fn render_ui(app: &mut App, args: &CLIArgs, frame: &mut Frame) { +pub fn render_ui(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { let [header_area, main_area, footer_area] = Layout::new( Direction::Vertical, [ @@ -128,20 +128,20 @@ pub fn render_ui(app: &mut App, args: &CLIArgs, frame: &mut Frame) { let [tag_area, info_area] = Layout::horizontal([Constraint::Max(25), Constraint::Min(35)]).areas(item_area); - render_header(args, frame, header_area); + render_header(cfg, frame, header_area); if let CurrentArea::SearchArea = app.bibiman.current_area { - render_footer(app, args, frame, footer_area); + render_footer(app, cfg, frame, footer_area); } - render_entrytable(app, args, frame, entry_area); - render_selected_item(app, args, frame, info_area); - render_taglist(app, args, frame, tag_area); - render_file_info(app, args, frame, entry_info_area); + render_entrytable(app, cfg, frame, entry_area); + render_selected_item(app, cfg, frame, info_area); + render_taglist(app, cfg, frame, tag_area); + render_file_info(app, cfg, frame, entry_info_area); if app.bibiman.popup_area.is_popup { - render_popup(app, args, frame); + render_popup(app, cfg, frame); } } -pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { +pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { match app.bibiman.popup_area.popup_kind { Some(PopupKind::Help) => { let block = Block::bordered() @@ -150,13 +150,13 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.popup_bg_color)), + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(Color::Indexed(args.colors.entry_color))); + .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap())); - let text: Text = PopupArea::popup_help(args); + let text: Text = PopupArea::popup_help(cfg); // Calculate max scroll position depending on hight of terminal window // Needed length is number of text lines plus two for borders at bottom and top @@ -191,23 +191,23 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.popup_bg_color)), + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(Color::Indexed(args.colors.entry_color))); + .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap())); // Prepare the input fields let content = vec![Line::from(vec![ Span::styled( "DOI: ", - Style::new().fg(Color::Indexed(args.colors.entry_color)), + Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()), ), Span::raw(app.input.value().to_string().clone()), ])]; let paragraph = Paragraph::new(content) .block(block.clone()) - .style(Style::new().fg(Color::Indexed(args.colors.main_text_color))) + .style(Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap())) .wrap(Wrap { trim: false }); let doi_lines = paragraph.line_count(area.width / 2); @@ -228,18 +228,18 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { .title_top( " Message " .bold() - .fg(Color::Indexed(args.colors.confirm_color)), + .fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap()), ) - .border_style(Style::new().fg(Color::Indexed(args.colors.confirm_color))) + .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap())) .style( Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.popup_bg_color)), + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), ); let content = Paragraph::new(app.bibiman.popup_area.popup_message.clone()) .block(block) - .style(Style::new().fg(Color::Indexed(args.colors.confirm_color))); + .style(Style::new().fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap())); // Calculate popup size. Width is number of string chars plus 2 for border let popup_area = popup_area( @@ -259,18 +259,18 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { .title_top( " Warning " .bold() - .fg(Color::Indexed(args.colors.warn_color)), + .fg(cfg.colors.as_ref().unwrap().warn_color.unwrap()), ) .border_style(Style::new().fg(Color::Red)) .style( Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.popup_bg_color)), + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), ); let content = Paragraph::new(app.bibiman.popup_area.popup_message.clone()) .block(block) - .style(Style::new().fg(Color::Indexed(args.colors.warn_color))); + .style(Style::new().fg(cfg.colors.as_ref().unwrap().warn_color.unwrap())); // Calculate popup size. Width is number of string chars plus 2 for border let popup_area = popup_area( @@ -306,15 +306,15 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.popup_bg_color)), + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(Color::Indexed(args.colors.keyword_color))); + .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap())); let list = List::new(list_items).block(block).highlight_style( Style::new() - // .fg(Color::Indexed(args.colors.entry_color)) + // .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED), ); @@ -330,15 +330,15 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) { } } -pub fn render_header(args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_header(cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let main_header = Paragraph::new("BIBIMAN – BibLaTeX manager TUI") .bold() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .centered(); frame.render_widget(main_header, rect) } -pub fn render_footer(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_footer(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let search_title = { match app.bibiman.former_area { Some(FormerArea::EntryArea) => "Search Entries: ".to_string(), @@ -349,29 +349,36 @@ pub fn render_footer(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rec let title_lenght: u16 = search_title.chars().count() as u16; - let block = Block::new() - .padding(Padding::horizontal(1)) - .bg(Color::Indexed(args.colors.bar_bg_color)); + let block = Block::new().padding(Padding::horizontal(1)).bg(cfg + .colors + .as_ref() + .unwrap() + .bar_bg_color + .unwrap()); let search_string = Paragraph::new(Line::from(vec![ Span::styled( search_title, if let Some(FormerArea::EntryArea) = app.bibiman.former_area { Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD) } else if let Some(FormerArea::TagArea) = app.bibiman.former_area { Style::new() - .fg(Color::Indexed(args.colors.keyword_color)) + .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) .add_modifier(Modifier::BOLD) } else { Style::new() - .fg(Color::Indexed(args.colors.highlight_text_color)) + .fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()) .add_modifier(Modifier::BOLD) }, ), - Span::raw(app.bibiman.search_struct.search_string.clone()) - .fg(Color::Indexed(args.colors.highlight_text_color)), + Span::raw(app.bibiman.search_struct.search_string.clone()).fg(cfg + .colors + .as_ref() + .unwrap() + .highlight_text_color + .unwrap()), ])) .block(block); @@ -383,7 +390,7 @@ pub fn render_footer(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rec // 1. Basename of the currently loaded file // 2. Keyword by which the entries are filtered at the moment // 3. Currently selected entry and total count of entries -pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_file_info(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let block = Block::new() // can also be Block::new // Leave Top empty to simulate one large box with borders of entry list .borders(Borders::LEFT | Borders::RIGHT | Borders::BOTTOM) @@ -393,10 +400,10 @@ pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: symbols::border::PLAIN }) .border_style(if let CurrentArea::EntryArea = app.bibiman.current_area { - Style::new().fg(Color::Indexed(args.colors.highlight_text_color)) + Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()) } else { Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD) }); @@ -415,7 +422,7 @@ pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: { Line::from(vec![ Span::raw("File: ") - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), Span::raw( app.bibiman.main_bibfiles[0] @@ -423,28 +430,33 @@ pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: .unwrap() .to_string_lossy(), ) - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), ]) - .bg(Color::Indexed(args.colors.bar_bg_color)) + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) } else { Line::from(vec![ Span::raw("Multiple files (") - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), Span::raw(count_files(&app.bibiman.main_bibfiles).to_string()) - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), Span::raw(")") - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), ]) - .bg(Color::Indexed(args.colors.bar_bg_color)) + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) }; let cur_keywords = Line::from(if !app.bibiman.tag_list.selected_keywords.is_empty() { vec![ - Span::raw("Selected keywords: ").fg(Color::Indexed(args.colors.main_text_color)), + Span::raw("Selected keywords: ").fg(cfg + .colors + .as_ref() + .unwrap() + .main_text_color + .unwrap()), // Show all keywords in correct order if list is filtered // successively by multiple keywords Span::raw(app.bibiman.tag_list.selected_keywords.join(" → ")) @@ -454,7 +466,7 @@ pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: } else { vec![Span::raw(" ")] }) - .bg(Color::Indexed(args.colors.bar_bg_color)); + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); // .render(keyword_area, buf); let item_count = Line::from( @@ -490,38 +502,42 @@ pub fn render_file_info(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: .to_string() }, ) - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .bold(), - Span::raw("/").fg(Color::Indexed(args.colors.main_text_color)), - Span::raw(app.bibiman.entry_table.entry_table_items.len().to_string()) - .fg(Color::Indexed(args.colors.main_text_color)), + Span::raw("/").fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), + Span::raw(app.bibiman.entry_table.entry_table_items.len().to_string()).fg(cfg + .colors + .as_ref() + .unwrap() + .main_text_color + .unwrap()), ] } else { vec![Span::raw("No entries")] }, ) .right_aligned() - .bg(Color::Indexed(args.colors.bar_bg_color)); + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); frame.render_widget(file_info, file_area); frame.render_widget(cur_keywords, keyword_area); frame.render_widget(item_count, count_area); } -pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let entry_box_selected_border_style: Style = - Style::new().fg(Color::Indexed(args.colors.highlight_text_color)); + Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()); let entry_box_selected_title_style: Style = Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD); let entry_box_unselected_border_style: Style = - Style::new().fg(Color::Indexed(args.colors.main_text_color)); + Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); let entry_box_unselected_title_style: Style = Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD); let selected_table_col_style: Style = Style::new().add_modifier(Modifier::BOLD); let selectec_table_cell_style: Style = Style::new().add_modifier(Modifier::REVERSED); let entry_selected_row_style: Style = Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED); @@ -551,8 +567,8 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: let header_style = Style::default() .bold() - .fg(Color::Indexed(args.colors.main_text_color)) - .bg(Color::Indexed(args.colors.bar_bg_color)); + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); let header = Row::new(vec![ Cell::from( @@ -576,9 +592,9 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: if let EntryTableColumn::Authors = app.bibiman.entry_table.entry_table_selected_column { - Color::Indexed(args.colors.selected_row_bg_color) + cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() } else { - Color::Indexed(args.colors.bar_bg_color) + cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() }, ), ), @@ -602,9 +618,9 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: .bg( if let EntryTableColumn::Title = app.bibiman.entry_table.entry_table_selected_column { - Color::Indexed(args.colors.selected_row_bg_color) + cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() } else { - Color::Indexed(args.colors.bar_bg_color) + cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() }, ), ), @@ -628,9 +644,9 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: .bg( if let EntryTableColumn::Year = app.bibiman.entry_table.entry_table_selected_column { - Color::Indexed(args.colors.selected_row_bg_color) + cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() } else { - Color::Indexed(args.colors.bar_bg_color) + cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() }, ), ), @@ -655,9 +671,9 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: if let EntryTableColumn::Pubtype = app.bibiman.entry_table.entry_table_selected_column { - Color::Indexed(args.colors.selected_row_bg_color) + cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() } else { - Color::Indexed(args.colors.bar_bg_color) + cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() }, ), ), @@ -672,23 +688,24 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: .entry_table_items .iter_mut() .enumerate() - .map(|(i, data)| { + .map(|(_i, data)| { let item = data.ref_vec(); item.into_iter() .map(|content| Cell::from(Text::from(content.to_string()))) .collect::() .style( - Style::new().fg(color_list( - args, - i as i32, - app.bibiman - .entry_table - .entry_table_state - .selected() - .unwrap_or(0) as i32, - args.colors.highlight_text_color, - 20, - )), + // Style::new().fg(color_list( + // args, + // i as i32, + // app.bibiman + // .entry_table + // .entry_table_state + // .selected() + // .unwrap_or(0) as i32, + // args.colors.highlight_text_color, + // 20, + // )), + Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()), ) .height(1) }); @@ -741,11 +758,11 @@ pub fn render_entrytable(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: } } -pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { // We get the info depending on the item's state. let style_value = Style::new() .bold() - .fg(Color::Indexed(args.colors.main_text_color)); + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); let lines = { if app .bibiman @@ -767,7 +784,7 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re // Span::styled(cur_entry.authors.clone(), Style::new().green()), Span::styled( cur_entry.authors(), - Style::new().fg(Color::Indexed(args.colors.info_color)), + Style::new().fg(cfg.colors.as_ref().unwrap().info_color.unwrap()), ), ])); if cur_entry.subtitle.is_some() { @@ -776,19 +793,19 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re Span::styled( cur_entry.title(), Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::ITALIC), ), Span::styled( ": ", Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::ITALIC), ), Span::styled( cur_entry.subtitle(), Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::ITALIC), ), ])); @@ -798,7 +815,7 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re Span::styled( cur_entry.title(), Style::new() - .fg(Color::Indexed(args.colors.entry_color)) + .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) .add_modifier(Modifier::ITALIC), ), ])); @@ -807,7 +824,7 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re Span::styled("Year: ", style_value), Span::styled( cur_entry.year(), - Style::new().fg(Color::Indexed(args.colors.keyword_color)), + Style::new().fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()), ), ])); // Render keywords in info box in Markdown code style @@ -821,11 +838,13 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re let mut content = vec![Span::styled("Keywords: ", style_value)]; for k in kw { // Add half block highlighted in bg color to enlarge block - content.push(Span::raw("▐").fg(Color::Indexed(args.colors.bar_bg_color))); + content.push( + Span::raw("▐").fg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()), + ); content.push(Span::styled( k, Style::default() - .bg(Color::Indexed(args.colors.bar_bg_color)) + .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) .fg( // Highlight selected keyword green if app @@ -837,11 +856,13 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re { Color::Green } else { - Color::Indexed(args.colors.main_text_color) + cfg.colors.as_ref().unwrap().main_text_color.unwrap() }, ), )); - content.push(Span::raw("▌").fg(Color::Indexed(args.colors.bar_bg_color))); + content.push( + Span::raw("▌").fg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()), + ); } lines.push(Line::from(content)) } @@ -854,7 +875,7 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re Span::styled( cur_entry.doi_url(), Style::new() - .fg(Color::Indexed(args.colors.main_text_color)) + .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) .underlined(), ), ])); @@ -864,14 +885,14 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re Span::styled("File: ", style_value), Span::styled( cur_entry.filepath().to_string_lossy(), - Style::new().fg(Color::Indexed(args.colors.main_text_color)), + Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), ), ])); } lines.push(Line::from("")); lines.push(Line::from(vec![Span::styled( cur_entry.abstract_text.clone(), - Style::new().fg(Color::Indexed(args.colors.main_text_color)), + Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), )])); lines } else { @@ -888,7 +909,7 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re let block = Block::bordered() .title(Line::raw(" Entry Information ").centered().bold()) .border_set(symbols::border::PLAIN) - .border_style(Style::new().fg(Color::Indexed(args.colors.main_text_color))) + .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap())) .padding(Padding::horizontal(1)); // INFO: '.line_count' method only possible with unstable-rendered-line-info feature -> API might change: https://github.com/ratatui/ratatui/issues/293#ref-pullrequest-2027056434 @@ -941,19 +962,19 @@ pub fn render_selected_item(app: &mut App, args: &CLIArgs, frame: &mut Frame, re frame.render_widget(item_info, rect); } -pub fn render_taglist(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rect) { +pub fn render_taglist(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let keyword_box_selected_border_style: Style = - Style::new().fg(Color::Indexed(args.colors.highlight_text_color)); + Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()); let keyword_box_selected_title_style: Style = Style::new() - .fg(Color::Indexed(args.colors.keyword_color)) + .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) .add_modifier(Modifier::BOLD); let keyword_box_unselected_border_style: Style = - Style::new().fg(Color::Indexed(args.colors.main_text_color)); + Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); let keyword_box_unselected_title_style: Style = Style::new() - .fg(Color::Indexed(args.colors.keyword_color)) + .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) .add_modifier(Modifier::BOLD); let keyword_selected_row_style: Style = Style::new() - .fg(Color::Indexed(args.colors.keyword_color)) + .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED); @@ -987,18 +1008,19 @@ pub fn render_taglist(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Re .tag_list_items .iter() .enumerate() - .map(|(i, keyword)| { + .map(|(_i, keyword)| { ListItem::from(keyword.to_owned()).style(Style::new().fg( if app.bibiman.tag_list.tag_list_state.selected().is_some() { - color_list( - args, - i as i32, - app.bibiman.tag_list.tag_list_state.selected().unwrap() as i32, - args.colors.highlight_text_color, - 20, - ) + // color_list( + // args, + // i as i32, + // app.bibiman.tag_list.tag_list_state.selected().unwrap() as i32, + // args.colors.highlight_text_color, + // 20, + // ) + cfg.colors.as_ref().unwrap().highlight_text_color.unwrap() } else { - Color::Indexed(args.colors.main_text_color) + cfg.colors.as_ref().unwrap().main_text_color.unwrap() }, )) //.bg(color) }) -- cgit v1.2.3 From 63d4410fdfe7712faec287aee2f5c0ca288dc996 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Sat, 22 Feb 2025 00:48:41 +0100 Subject: replace Config crate with Figment -> better merging of default and config values --- Cargo.lock | 73 ++++++++-------- Cargo.toml | 3 +- example-config.toml | 2 +- src/app.rs | 4 +- src/bibiman.rs | 6 +- src/config.rs | 164 ++++++++++++----------------------- src/main.rs | 13 +-- src/tui/popup.rs | 21 +---- src/tui/ui.rs | 243 +++++++++++++++++++++------------------------------- 9 files changed, 205 insertions(+), 324 deletions(-) (limited to 'src/bibiman.rs') diff --git a/Cargo.lock b/Cargo.lock index 342fba4..9c83245 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -58,14 +58,12 @@ dependencies = [ ] [[package]] -name = "async-trait" -version = "0.1.86" +name = "atomic" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" dependencies = [ - "proc-macro2", - "quote", - "syn", + "bytemuck", ] [[package]] @@ -102,10 +100,10 @@ dependencies = [ "arboard", "biblatex", "color-eyre", - "config", "crossterm", "dirs", "editor-command", + "figment", "futures", "itertools", "lexopt", @@ -270,29 +268,6 @@ dependencies = [ "static_assertions", ] -[[package]] -name = "config" -version = "0.15.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf9dc8d4ef88e27a8cb23e85cb116403dedd57f7971964dc4b18ccead548901" -dependencies = [ - "async-trait", - "convert_case", - "pathdiff", - "serde", - "toml", - "winnow", -] - -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -488,6 +463,19 @@ dependencies = [ "simd-adler32", ] +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic", + "serde", + "toml", + "uncased", + "version_check", +] + [[package]] name = "fixedbitset" version = "0.4.2" @@ -1236,12 +1224,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -1924,6 +1906,15 @@ dependencies = [ "unicode-width 0.2.0", ] +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + [[package]] name = "unicode-ident" version = "1.0.13" @@ -2025,6 +2016,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "walkdir" version = "2.5.0" @@ -2310,9 +2307,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index c2f42a0..2bd6a3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,5 +35,6 @@ tui-input = "0.11.0" walkdir = "2.5.0" regex = "1.11.1" ureq = "2.12.1" -config = { version = "0.15.8", default-features = false, features = ["async", "async-trait", "convert-case", "convert_case", "toml"] } +# config = { version = "0.15.8", default-features = false, features = ["async", "async-trait", "convert-case", "convert_case", "toml"] } serde = { version = "1.0.217", features = ["serde_derive"] } +figment = { version = "0.10.19", features = [ "toml" ]} diff --git a/example-config.toml b/example-config.toml index d6d2aa8..89220df 100644 --- a/example-config.toml +++ b/example-config.toml @@ -13,5 +13,5 @@ editor = "vim" # arguments are possible: "vim -y" # confirm_color = "47" # warn_color = "124" # bar_bg_color = "234" -# popup_bg_color = "234" +# popup_bg_color = "55" # selected_row_bg_color = "237" diff --git a/src/app.rs b/src/app.rs index 7869304..e41defc 100644 --- a/src/app.rs +++ b/src/app.rs @@ -357,7 +357,7 @@ impl App { pub fn open_connected_file(cfg: &BibiConfig, file: &OsStr) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard - let cmd = cfg.general.as_ref().unwrap().pdf_opener.as_ref().unwrap(); + let cmd = &cfg.general.pdf_opener; // If necessary, replace ~ with /home dir let file = PathBuf::from(file); @@ -377,7 +377,7 @@ pub fn open_connected_file(cfg: &BibiConfig, file: &OsStr) -> Result<()> { pub fn open_connected_link(cfg: &BibiConfig, link: &str) -> Result<()> { // Build command to execute pdf-reader. 'xdg-open' is Linux standard - let cmd = cfg.general.as_ref().unwrap().url_opener.as_ref().unwrap(); + let cmd = &cfg.general.url_opener; // Pass filepath as argument, pipe stdout and stderr to /dev/null // to keep the TUI clean (where is it piped on Windows???) let _ = Command::new(cmd) diff --git a/src/bibiman.rs b/src/bibiman.rs index b8ef2c6..e36d268 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -85,8 +85,8 @@ impl Bibiman { // Constructs a new instance of [`App`]. pub fn new(args: &mut CLIArgs, cfg: &mut BibiConfig) -> Result { let mut main_bibfiles: Vec = args.pos_args.clone(); - if cfg.general.as_ref().unwrap().bibfiles.is_some() { - main_bibfiles.append(cfg.general.as_mut().unwrap().bibfiles.as_mut().unwrap()) + if cfg.general.bibfiles.is_some() { + main_bibfiles.append(cfg.general.bibfiles.as_mut().unwrap()) }; let main_bibfiles = cliargs::parse_files(main_bibfiles); let main_biblio = BibiSetup::new(&main_bibfiles); @@ -381,7 +381,7 @@ impl Bibiman { tui.exit()?; // Use VISUAL or EDITOR. Set "vi" as last fallback let mut cmd: Command = EditorBuilder::new() - .source(cfg.general.as_ref().unwrap().editor.clone()) + .source(cfg.general.editor.as_ref()) .environment() .source(Some("vi")) .build() diff --git a/src/config.rs b/src/config.rs index faba5d8..e2c34b9 100644 --- a/src/config.rs +++ b/src/config.rs @@ -18,147 +18,95 @@ use std::path::PathBuf; use color_eyre::eyre::Result; -use config::{ConfigError, FileFormat}; +use figment::{ + providers::{Format, Serialized, Toml}, + Figment, +}; use ratatui::style::Color; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::cliargs::CLIArgs; /// Main struct of the config file. Contains substructs/headings in toml -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct BibiConfig { - pub general: Option, - pub colors: Option, + pub general: General, + pub colors: Colors, } /// Substruct [general] in config.toml -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct General { pub bibfiles: Option>, pub editor: Option, - pub pdf_opener: Option, - pub url_opener: Option, + pub pdf_opener: String, + pub url_opener: String, } /// Substruct [colors] in config.toml -#[derive(Debug, Clone, Deserialize)] +#[derive(Debug, Clone, Deserialize, Serialize)] pub struct Colors { - pub main_text_color: Option, - pub highlight_text_color: Option, - pub entry_color: Option, - pub keyword_color: Option, - pub info_color: Option, - pub confirm_color: Option, - pub warn_color: Option, - pub bar_bg_color: Option, - pub popup_bg_color: Option, - pub selected_row_bg_color: Option, + pub main_text_color: Color, + pub highlight_text_color: Color, + pub entry_color: Color, + pub keyword_color: Color, + pub info_color: Color, + pub confirm_color: Color, + pub warn_color: Color, + pub bar_bg_color: Color, + pub popup_bg_color: Color, + pub selected_row_bg_color: Color, } impl Default for BibiConfig { fn default() -> Self { Self { - general: Some(General { + general: General { bibfiles: None, editor: None, - pdf_opener: Some(select_opener()), - url_opener: Some(select_opener()), - }), - colors: Some(Colors { - main_text_color: Some(Color::Indexed(250)), - highlight_text_color: Some(Color::Indexed(254)), - entry_color: Some(Color::Indexed(36)), - keyword_color: Some(Color::Indexed(101)), - info_color: Some(Color::Indexed(99)), - confirm_color: Some(Color::Indexed(47)), - warn_color: Some(Color::Indexed(124)), - bar_bg_color: Some(Color::Indexed(235)), - popup_bg_color: Some(Color::Indexed(234)), - selected_row_bg_color: Some(Color::Indexed(237)), - }), + pdf_opener: select_opener(), + url_opener: select_opener(), + }, + colors: Colors { + main_text_color: Color::Indexed(250), + highlight_text_color: Color::Indexed(254), + entry_color: Color::Indexed(36), + keyword_color: Color::Indexed(101), + info_color: Color::Indexed(99), + confirm_color: Color::Indexed(47), + warn_color: Color::Indexed(124), + bar_bg_color: Color::Indexed(235), + popup_bg_color: Color::Indexed(234), + selected_row_bg_color: Color::Indexed(237), + }, } } } impl BibiConfig { - pub fn parse_config(&mut self, args: &CLIArgs) -> Result<()> { - if args.cfg_path.is_file() { - let cfg_file = Self::parse_cfg_file(args)?; + pub fn parse_config(args: &CLIArgs) -> Result { + let cfg_file: BibiConfig = if args.cfg_path.is_file() { + Figment::from(Serialized::defaults(BibiConfig::default())) + .merge(Toml::file(&args.cfg_path)) + .extract()? + } else { + BibiConfig::default() + }; - if let Some(general) = cfg_file.general { - if let Some(bibfiles) = general.bibfiles { - self.general.as_mut().unwrap().bibfiles = Some(bibfiles) - } - if let Some(editor) = general.editor { - self.general.as_mut().unwrap().editor = Some(editor) - } - if let Some(pdf_opener) = general.pdf_opener { - self.general.as_mut().unwrap().pdf_opener = Some(pdf_opener) - } - if let Some(url_opener) = general.url_opener { - self.general.as_mut().unwrap().url_opener = Some(url_opener) - } - } - - if let Some(colors) = cfg_file.colors { - if let Some(main_text_color) = colors.main_text_color { - self.colors.as_mut().unwrap().main_text_color = Some(main_text_color) - } - if let Some(highlight_text_color) = colors.highlight_text_color { - self.colors.as_mut().unwrap().highlight_text_color = Some(highlight_text_color) - } - if let Some(entry_color) = colors.entry_color { - self.colors.as_mut().unwrap().entry_color = Some(entry_color) - } - if let Some(keyword_color) = colors.keyword_color { - self.colors.as_mut().unwrap().keyword_color = Some(keyword_color) - } - if let Some(info_color) = colors.info_color { - self.colors.as_mut().unwrap().info_color = Some(info_color) - } - if let Some(confirm_color) = colors.confirm_color { - self.colors.as_mut().unwrap().confirm_color = Some(confirm_color) - } - if let Some(warn_color) = colors.warn_color { - self.colors.as_mut().unwrap().warn_color = Some(warn_color) - } - if let Some(bar_bg_color) = colors.bar_bg_color { - self.colors.as_mut().unwrap().bar_bg_color = Some(bar_bg_color) - } - if let Some(popup_bg_color) = colors.popup_bg_color { - self.colors.as_mut().unwrap().popup_bg_color = Some(popup_bg_color) - } - if let Some(selected_row_bg_color) = colors.selected_row_bg_color { - self.colors.as_mut().unwrap().selected_row_bg_color = - Some(selected_row_bg_color) - } - } - } - - Ok(()) - } - - fn parse_cfg_file(args: &CLIArgs) -> Result { - let mut cfg = config::Config::builder(); - cfg = cfg.add_source( - config::File::from(args.cfg_path.clone()) - .format(FileFormat::Toml) - .required(false), - ); - cfg.build()?.try_deserialize() + Ok(cfg_file) } /// Activates the default color scheme for light background terminals pub fn light_colors(&mut self) { - self.colors.as_mut().unwrap().main_text_color = Some(Color::Indexed(235)); - self.colors.as_mut().unwrap().highlight_text_color = Some(Color::Indexed(232)); - self.colors.as_mut().unwrap().entry_color = Some(Color::Indexed(23)); - self.colors.as_mut().unwrap().keyword_color = Some(Color::Indexed(58)); - self.colors.as_mut().unwrap().info_color = Some(Color::Indexed(57)); - self.colors.as_mut().unwrap().bar_bg_color = Some(Color::Indexed(144)); - self.colors.as_mut().unwrap().popup_bg_color = Some(Color::Indexed(187)); - self.colors.as_mut().unwrap().confirm_color = Some(Color::Indexed(22)); - self.colors.as_mut().unwrap().selected_row_bg_color = Some(Color::Indexed(107)); + self.colors.main_text_color = Color::Indexed(235); + self.colors.highlight_text_color = Color::Indexed(232); + self.colors.entry_color = Color::Indexed(23); + self.colors.keyword_color = Color::Indexed(58); + self.colors.info_color = Color::Indexed(57); + self.colors.bar_bg_color = Color::Indexed(144); + self.colors.popup_bg_color = Color::Indexed(187); + self.colors.confirm_color = Color::Indexed(22); + self.colors.selected_row_bg_color = Color::Indexed(107); } } diff --git a/src/main.rs b/src/main.rs index 3325f80..302ba7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -46,14 +46,15 @@ async fn main() -> Result<()> { } // Build default config - let mut cfg = BibiConfig::default(); + // let mut cfg = BibiConfig::default(); - if parsed_args.light_theme { - cfg.light_colors(); - } - // Merge values from config file if present - cfg.parse_config(&parsed_args)?; + // if parsed_args.light_theme { + // cfg.light_colors(); + // } + // // Merge values from config file if present + // cfg.parse_config(&parsed_args)?; + let mut cfg = BibiConfig::parse_config(&parsed_args)?; init_error_hooks()?; // Create an application. diff --git a/src/tui/popup.rs b/src/tui/popup.rs index 6a2e8ff..f226429 100644 --- a/src/tui/popup.rs +++ b/src/tui/popup.rs @@ -89,31 +89,16 @@ impl PopupArea { for (keys, help) in help { if help == "first" { helptext.push(Line::from( - Span::raw(keys).bold().fg(cfg - .colors - .as_ref() - .unwrap() - .main_text_color - .unwrap()), + Span::raw(keys).bold().fg(cfg.colors.main_text_color), )) } else if help == "sub" { helptext.push(Line::from("")); helptext.push(Line::from( - Span::raw(keys).bold().fg(cfg - .colors - .as_ref() - .unwrap() - .main_text_color - .unwrap()), + Span::raw(keys).bold().fg(cfg.colors.main_text_color), )) } else { helptext.push(Line::from(vec![ - Span::raw(keys).bold().fg(cfg - .colors - .as_ref() - .unwrap() - .main_text_color - .unwrap()), + Span::raw(keys).bold().fg(cfg.colors.main_text_color), Span::raw(help), ])) } diff --git a/src/tui/ui.rs b/src/tui/ui.rs index 5fbe283..2d58aec 100644 --- a/src/tui/ui.rs +++ b/src/tui/ui.rs @@ -150,11 +150,11 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.popup_bg_color), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap())); + .border_style(Style::new().fg(cfg.colors.entry_color)); let text: Text = PopupArea::popup_help(cfg); @@ -191,23 +191,20 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.popup_bg_color), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap())); + .border_style(Style::new().fg(cfg.colors.entry_color)); // Prepare the input fields let content = vec![Line::from(vec![ - Span::styled( - "DOI: ", - Style::new().fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()), - ), + Span::styled("DOI: ", Style::new().fg(cfg.colors.entry_color)), Span::raw(app.input.value().to_string().clone()), ])]; let paragraph = Paragraph::new(content) .block(block.clone()) - .style(Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap())) + .style(Style::new().fg(cfg.colors.main_text_color)) .wrap(Wrap { trim: false }); let doi_lines = paragraph.line_count(area.width / 2); @@ -225,21 +222,17 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { let area = frame.area(); let block = Block::bordered() - .title_top( - " Message " - .bold() - .fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap()), - ) - .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap())) + .title_top(" Message ".bold().fg(cfg.colors.confirm_color)) + .border_style(Style::new().fg(cfg.colors.confirm_color)) .style( Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.popup_bg_color), ); let content = Paragraph::new(app.bibiman.popup_area.popup_message.clone()) .block(block) - .style(Style::new().fg(cfg.colors.as_ref().unwrap().confirm_color.unwrap())); + .style(Style::new().fg(cfg.colors.confirm_color)); // Calculate popup size. Width is number of string chars plus 2 for border let popup_area = popup_area( @@ -256,21 +249,17 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { let area = frame.area(); let block = Block::bordered() - .title_top( - " Warning " - .bold() - .fg(cfg.colors.as_ref().unwrap().warn_color.unwrap()), - ) + .title_top(" Warning ".bold().fg(cfg.colors.warn_color)) .border_style(Style::new().fg(Color::Red)) .style( Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.popup_bg_color), ); let content = Paragraph::new(app.bibiman.popup_area.popup_message.clone()) .block(block) - .style(Style::new().fg(cfg.colors.as_ref().unwrap().warn_color.unwrap())); + .style(Style::new().fg(cfg.colors.warn_color)); // Calculate popup size. Width is number of string chars plus 2 for border let popup_area = popup_area( @@ -306,15 +295,15 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { .title_alignment(Alignment::Center) .style( Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().popup_bg_color.unwrap()), + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.popup_bg_color), ) .border_set(symbols::border::THICK) - .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap())); + .border_style(Style::new().fg(cfg.colors.keyword_color)); let list = List::new(list_items).block(block).highlight_style( Style::new() - // .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + // .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED), ); @@ -333,7 +322,7 @@ pub fn render_popup(app: &mut App, cfg: &BibiConfig, frame: &mut Frame) { pub fn render_header(cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { let main_header = Paragraph::new("BIBIMAN – BibLaTeX manager TUI") .bold() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .centered(); frame.render_widget(main_header, rect) } @@ -349,36 +338,29 @@ pub fn render_footer(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: R let title_lenght: u16 = search_title.chars().count() as u16; - let block = Block::new().padding(Padding::horizontal(1)).bg(cfg - .colors - .as_ref() - .unwrap() - .bar_bg_color - .unwrap()); + let block = Block::new() + .padding(Padding::horizontal(1)) + .bg(cfg.colors.bar_bg_color); let search_string = Paragraph::new(Line::from(vec![ Span::styled( search_title, if let Some(FormerArea::EntryArea) = app.bibiman.former_area { Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD) } else if let Some(FormerArea::TagArea) = app.bibiman.former_area { Style::new() - .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) + .fg(cfg.colors.keyword_color) .add_modifier(Modifier::BOLD) } else { Style::new() - .fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()) + .fg(cfg.colors.highlight_text_color) .add_modifier(Modifier::BOLD) }, ), - Span::raw(app.bibiman.search_struct.search_string.clone()).fg(cfg - .colors - .as_ref() - .unwrap() - .highlight_text_color - .unwrap()), + Span::raw(app.bibiman.search_struct.search_string.clone()) + .fg(cfg.colors.highlight_text_color), ])) .block(block); @@ -400,10 +382,10 @@ pub fn render_file_info(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect symbols::border::PLAIN }) .border_style(if let CurrentArea::EntryArea = app.bibiman.current_area { - Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()) + Style::new().fg(cfg.colors.highlight_text_color) } else { Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD) }); @@ -421,42 +403,33 @@ pub fn render_file_info(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect && app.bibiman.main_bibfiles.first().unwrap().is_file() { Line::from(vec![ - Span::raw("File: ") - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bold(), + Span::raw("File: ").fg(cfg.colors.main_text_color).bold(), Span::raw( app.bibiman.main_bibfiles[0] .file_name() .unwrap() .to_string_lossy(), ) - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .fg(cfg.colors.main_text_color) .bold(), ]) - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) + .bg(cfg.colors.bar_bg_color) } else { Line::from(vec![ Span::raw("Multiple files (") - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .fg(cfg.colors.main_text_color) .bold(), Span::raw(count_files(&app.bibiman.main_bibfiles).to_string()) - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bold(), - Span::raw(")") - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .fg(cfg.colors.main_text_color) .bold(), + Span::raw(")").fg(cfg.colors.main_text_color).bold(), ]) - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) + .bg(cfg.colors.bar_bg_color) }; let cur_keywords = Line::from(if !app.bibiman.tag_list.selected_keywords.is_empty() { vec![ - Span::raw("Selected keywords: ").fg(cfg - .colors - .as_ref() - .unwrap() - .main_text_color - .unwrap()), + Span::raw("Selected keywords: ").fg(cfg.colors.main_text_color), // Show all keywords in correct order if list is filtered // successively by multiple keywords Span::raw(app.bibiman.tag_list.selected_keywords.join(" → ")) @@ -466,7 +439,7 @@ pub fn render_file_info(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect } else { vec![Span::raw(" ")] }) - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); + .bg(cfg.colors.bar_bg_color); // .render(keyword_area, buf); let item_count = Line::from( @@ -502,42 +475,36 @@ pub fn render_file_info(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect .to_string() }, ) - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) + .fg(cfg.colors.main_text_color) .bold(), - Span::raw("/").fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), - Span::raw(app.bibiman.entry_table.entry_table_items.len().to_string()).fg(cfg - .colors - .as_ref() - .unwrap() - .main_text_color - .unwrap()), + Span::raw("/").fg(cfg.colors.main_text_color), + Span::raw(app.bibiman.entry_table.entry_table_items.len().to_string()) + .fg(cfg.colors.main_text_color), ] } else { vec![Span::raw("No entries")] }, ) .right_aligned() - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); + .bg(cfg.colors.bar_bg_color); frame.render_widget(file_info, file_area); frame.render_widget(cur_keywords, keyword_area); frame.render_widget(item_count, count_area); } pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { - let entry_box_selected_border_style: Style = - Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()); + let entry_box_selected_border_style: Style = Style::new().fg(cfg.colors.highlight_text_color); let entry_box_selected_title_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD); - let entry_box_unselected_border_style: Style = - Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); + let entry_box_unselected_border_style: Style = Style::new().fg(cfg.colors.main_text_color); let entry_box_unselected_title_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD); let selected_table_col_style: Style = Style::new().add_modifier(Modifier::BOLD); let selectec_table_cell_style: Style = Style::new().add_modifier(Modifier::REVERSED); let entry_selected_row_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED); @@ -567,8 +534,8 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec let header_style = Style::default() .bold() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()); + .fg(cfg.colors.main_text_color) + .bg(cfg.colors.bar_bg_color); let header = Row::new(vec![ Cell::from( @@ -592,9 +559,9 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec if let EntryTableColumn::Authors = app.bibiman.entry_table.entry_table_selected_column { - cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() + cfg.colors.selected_row_bg_color } else { - cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() + cfg.colors.bar_bg_color }, ), ), @@ -618,9 +585,9 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec .bg( if let EntryTableColumn::Title = app.bibiman.entry_table.entry_table_selected_column { - cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() + cfg.colors.selected_row_bg_color } else { - cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() + cfg.colors.bar_bg_color }, ), ), @@ -644,9 +611,9 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec .bg( if let EntryTableColumn::Year = app.bibiman.entry_table.entry_table_selected_column { - cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() + cfg.colors.selected_row_bg_color } else { - cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() + cfg.colors.bar_bg_color }, ), ), @@ -671,9 +638,9 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec if let EntryTableColumn::Pubtype = app.bibiman.entry_table.entry_table_selected_column { - cfg.colors.as_ref().unwrap().selected_row_bg_color.unwrap() + cfg.colors.selected_row_bg_color } else { - cfg.colors.as_ref().unwrap().bar_bg_color.unwrap() + cfg.colors.bar_bg_color }, ), ), @@ -705,7 +672,7 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec // args.colors.highlight_text_color, // 20, // )), - Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()), + Style::new().fg(cfg.colors.highlight_text_color), ) .height(1) }); @@ -760,9 +727,7 @@ pub fn render_entrytable(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rec pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { // We get the info depending on the item's state. - let style_value = Style::new() - .bold() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); + let style_value = Style::new().bold().fg(cfg.colors.main_text_color); let lines = { if app .bibiman @@ -782,10 +747,7 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, lines.push(Line::from(vec![ Span::styled("Authors: ", style_value), // Span::styled(cur_entry.authors.clone(), Style::new().green()), - Span::styled( - cur_entry.authors(), - Style::new().fg(cfg.colors.as_ref().unwrap().info_color.unwrap()), - ), + Span::styled(cur_entry.authors(), Style::new().fg(cfg.colors.info_color)), ])); if cur_entry.subtitle.is_some() { lines.push(Line::from(vec![ @@ -793,19 +755,19 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, Span::styled( cur_entry.title(), Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::ITALIC), ), Span::styled( ": ", Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::ITALIC), ), Span::styled( cur_entry.subtitle(), Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::ITALIC), ), ])); @@ -815,17 +777,14 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, Span::styled( cur_entry.title(), Style::new() - .fg(cfg.colors.as_ref().unwrap().entry_color.unwrap()) + .fg(cfg.colors.entry_color) .add_modifier(Modifier::ITALIC), ), ])); } lines.push(Line::from(vec![ Span::styled("Year: ", style_value), - Span::styled( - cur_entry.year(), - Style::new().fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()), - ), + Span::styled(cur_entry.year(), Style::new().fg(cfg.colors.keyword_color)), ])); // Render keywords in info box in Markdown code style if !cur_entry.keywords.is_empty() { @@ -838,31 +797,25 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, let mut content = vec![Span::styled("Keywords: ", style_value)]; for k in kw { // Add half block highlighted in bg color to enlarge block - content.push( - Span::raw("▐").fg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()), - ); + content.push(Span::raw("▐").fg(cfg.colors.bar_bg_color)); content.push(Span::styled( k, - Style::default() - .bg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()) - .fg( - // Highlight selected keyword green - if app - .bibiman - .tag_list - .selected_keywords - .iter() - .any(|e| e == k) - { - Color::Green - } else { - cfg.colors.as_ref().unwrap().main_text_color.unwrap() - }, - ), + Style::default().bg(cfg.colors.bar_bg_color).fg( + // Highlight selected keyword green + if app + .bibiman + .tag_list + .selected_keywords + .iter() + .any(|e| e == k) + { + Color::Green + } else { + cfg.colors.main_text_color + }, + ), )); - content.push( - Span::raw("▌").fg(cfg.colors.as_ref().unwrap().bar_bg_color.unwrap()), - ); + content.push(Span::raw("▌").fg(cfg.colors.bar_bg_color)); } lines.push(Line::from(content)) } @@ -874,9 +827,7 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, Span::styled("DOI/URL: ", style_value), Span::styled( cur_entry.doi_url(), - Style::new() - .fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()) - .underlined(), + Style::new().fg(cfg.colors.main_text_color).underlined(), ), ])); } @@ -885,14 +836,14 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, Span::styled("File: ", style_value), Span::styled( cur_entry.filepath().to_string_lossy(), - Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), + Style::new().fg(cfg.colors.main_text_color), ), ])); } lines.push(Line::from("")); lines.push(Line::from(vec![Span::styled( cur_entry.abstract_text.clone(), - Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()), + Style::new().fg(cfg.colors.main_text_color), )])); lines } else { @@ -909,7 +860,7 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, let block = Block::bordered() .title(Line::raw(" Entry Information ").centered().bold()) .border_set(symbols::border::PLAIN) - .border_style(Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap())) + .border_style(Style::new().fg(cfg.colors.main_text_color)) .padding(Padding::horizontal(1)); // INFO: '.line_count' method only possible with unstable-rendered-line-info feature -> API might change: https://github.com/ratatui/ratatui/issues/293#ref-pullrequest-2027056434 @@ -963,18 +914,16 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, } pub fn render_taglist(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: Rect) { - let keyword_box_selected_border_style: Style = - Style::new().fg(cfg.colors.as_ref().unwrap().highlight_text_color.unwrap()); + let keyword_box_selected_border_style: Style = Style::new().fg(cfg.colors.highlight_text_color); let keyword_box_selected_title_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) + .fg(cfg.colors.keyword_color) .add_modifier(Modifier::BOLD); - let keyword_box_unselected_border_style: Style = - Style::new().fg(cfg.colors.as_ref().unwrap().main_text_color.unwrap()); + let keyword_box_unselected_border_style: Style = Style::new().fg(cfg.colors.main_text_color); let keyword_box_unselected_title_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) + .fg(cfg.colors.keyword_color) .add_modifier(Modifier::BOLD); let keyword_selected_row_style: Style = Style::new() - .fg(cfg.colors.as_ref().unwrap().keyword_color.unwrap()) + .fg(cfg.colors.keyword_color) .add_modifier(Modifier::BOLD) .add_modifier(Modifier::REVERSED); @@ -1018,9 +967,9 @@ pub fn render_taglist(app: &mut App, cfg: &BibiConfig, frame: &mut Frame, rect: // args.colors.highlight_text_color, // 20, // ) - cfg.colors.as_ref().unwrap().highlight_text_color.unwrap() + cfg.colors.highlight_text_color } else { - cfg.colors.as_ref().unwrap().main_text_color.unwrap() + cfg.colors.main_text_color }, )) //.bg(color) }) -- cgit v1.2.3