From 2263f1e14a671c93aa045b5649befbf250712020 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Sun, 2 Mar 2025 22:13:19 +0100 Subject: implement test if config file exists, otherwise creation of default file will be offered --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 5 +++ files/bibiman.toml | 2 +- src/cliargs.rs | 10 +++-- src/config.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 20 ++++++---- 7 files changed, 137 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 809c437..1ac748e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -95,7 +95,7 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "bibiman" -version = "0.11.1" +version = "0.11.2" dependencies = [ "arboard", "biblatex", diff --git a/Cargo.toml b/Cargo.toml index e7c4117..2b56dcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bibiman" -version = "0.11.1" +version = "0.11.2" authors = ["lukeflo "] license = "GPL-3.0-or-later" repository = "https://codeberg.org/lukeflo/bibiman" diff --git a/README.md b/README.md index 25fcaf2..f40f2ee 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,11 @@ which takes precedence over the standard one for the active session: bibiman --config-file="/path/to/temporary/config" ``` +If neither a file exists at the default location, nor a temporary config file is +set through the CLI, `bibiman` will offer to create a default config file at the +standard location. This will very likely happen on the first run of `bibiman` +after installation. If rejected, you probably will be asked again next time. + ### General Configuration The following general values can be set through the config file: diff --git a/files/bibiman.toml b/files/bibiman.toml index 987e780..df260fe 100644 --- a/files/bibiman.toml +++ b/files/bibiman.toml @@ -14,7 +14,7 @@ ## Prefix which is prepended to the filepath from the `file` field ## Use absolute paths (~ for HOME works). Otherwise, loading might not work. -# file_prefix = [ "/some/path/prefix" ] +# file_prefix = "/some/path/prefix" # [colors] ## Default values for dark-themed terminal diff --git a/src/cliargs.rs b/src/cliargs.rs index 3c302f4..d4fac46 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -31,7 +31,7 @@ pub struct CLIArgs { pub helparg: bool, pub versionarg: bool, pub pos_args: Vec, - pub cfg_path: PathBuf, + pub cfg_path: Option, pub light_theme: bool, } @@ -42,16 +42,18 @@ impl CLIArgs { // Default config args.cfg_path = if config_dir().is_some() { - config_dir().unwrap().join("bibiman/bibiman.toml") + Some(config_dir().unwrap().join("bibiman/bibiman.toml")) + } else if home_dir().is_some() { + Some(home_dir().unwrap().join(".config/bibiman/bibiman.toml")) } else { - home_dir().unwrap().join(".config/bibiman/bibiman.toml") + None }; while let Some(arg) = parser.next()? { match arg { 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()?, + Short('c') | Long("config-file") => args.cfg_path = Some(parser.value()?.parse()?), 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()), diff --git a/src/config.rs b/src/config.rs index f1ac3ca..cd55b5c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -15,9 +15,13 @@ // along with this program. If not, see . ///// -use std::path::PathBuf; +use std::{ + fs::File, + io::{stdin, Write}, + path::PathBuf, +}; -use color_eyre::eyre::Result; +use color_eyre::{eyre::Result, owo_colors::OwoColorize}; use figment::{ providers::{Format, Serialized, Toml}, Figment, @@ -27,6 +31,43 @@ use serde::{Deserialize, Serialize}; use crate::cliargs::CLIArgs; +const DEFAULT_CONFIG: &str = r##" +# [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" + +## Default app to open PDFs/Epubs +# pdf_opener = "xdg-open" + +## Default app to open URLs/DOIs +# url_opener = "xdg-open" + +## Prefix which is prepended to the filepath from the `file` field +## Use absolute paths (~ for HOME works). Otherwise, loading might not work. +# file_prefix = "/some/path/prefix" + +# [colors] +## Default values for dark-themed terminal +## Possible values are: +## ANSI color names. E.g. "bright-black" +## 256-colors indices. E.g. "250" +## Hex color codes. E.g. "#3a3a3a" +# 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" +"##; + /// Main struct of the config file. Contains substructs/headings in toml #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub struct BibiConfig { @@ -87,9 +128,9 @@ impl Default for BibiConfig { impl BibiConfig { pub fn parse_config(args: &CLIArgs) -> Result { - let cfg_file: BibiConfig = if args.cfg_path.is_file() { + let cfg_file: BibiConfig = if args.cfg_path.as_ref().unwrap().is_file() { Figment::from(Serialized::defaults(BibiConfig::default())) - .merge(Toml::file(&args.cfg_path)) + .merge(Toml::file(&args.cfg_path.as_ref().unwrap())) .extract()? } else { BibiConfig::default() @@ -110,6 +151,72 @@ impl BibiConfig { self.colors.confirm_color = Color::Indexed(22); self.colors.selected_row_bg_color = Color::Indexed(107); } + + /// Function which offers the user to create a default config + /// if no exists at the standard config path. + pub fn create_default_config(args: &CLIArgs) { + let path = args.cfg_path.as_ref().unwrap().to_str(); + let mut input_str = String::new(); + + match path { + Some(p) => { + println!("It seems no config file {} exists.", p.bold()); + } + None => { + println!( + "Can't parse config file path. Running {} without any config file.", + "bibiman".bold() + ); + return; + } + } + + loop { + println!( + "\nDo you want to create a default config? {}", + "[Y|N]".bold() + ); + + stdin() + .read_line(&mut input_str) + .expect("Couldn't read input"); + + match input_str.trim().to_lowercase().as_str() { + "y" | "yes" => { + break; + } + "n" | "no" => { + println!("\nNo config file will be created."); + return; + } + v => { + println!("\nInvalid value {}.", v.red()); + println!("Please type {} or {}.", "[Y]es".bold(), "[N]o".bold()); + input_str.clear(); + continue; + } + } + } + + let cfg_file = File::create_new(path.unwrap()); + + match cfg_file { + Ok(mut file) => { + file.write_all(DEFAULT_CONFIG.as_bytes()).unwrap(); + println!("\nCreated default config file {}", path.unwrap().bold()); + println!( + "Check {} for explanations how to configure it.", + "https://codeberg.org/lukeflo/bibiman#configuration".bright_yellow() + ) + } + Err(e) => { + println!( + "\nCouldn't create default config due to the following error:\n{}", + e.red() + ) + } + } + } } fn select_opener() -> String { diff --git a/src/main.rs b/src/main.rs index 302ba7a..b218f9b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -45,16 +45,20 @@ async fn main() -> Result<()> { std::process::exit(0); } - // Build default config - // let mut cfg = BibiConfig::default(); + if parsed_args + .cfg_path + .as_ref() + .is_some_and(|f| !f.try_exists().unwrap() || !f.is_file()) + { + BibiConfig::create_default_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 = if parsed_args.cfg_path.is_some() { + BibiConfig::parse_config(&parsed_args)? + } else { + BibiConfig::default() + }; - let mut cfg = BibiConfig::parse_config(&parsed_args)?; init_error_hooks()?; // Create an application. -- cgit v1.2.3