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:

+## 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:
-
-
-
## 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