From 7266a14753ed5d572aeed584b66b07d1b9921ca7 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Thu, 9 Oct 2025 14:28:55 +0200 Subject: rewrite cli parsing; need to implement format-citekeys cli parsing --- src/cliargs.rs | 52 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) (limited to 'src/cliargs.rs') diff --git a/src/cliargs.rs b/src/cliargs.rs index 082ecda..3b12fc3 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -18,20 +18,19 @@ use color_eyre::eyre::Result; use dirs::{config_dir, home_dir}; use lexopt::prelude::*; +use owo_colors::OwoColorize; use owo_colors::colors::css::LightGreen; use owo_colors::colors::*; -use owo_colors::OwoColorize; use std::env; use std::path::PathBuf; use walkdir::WalkDir; use crate::app; +use crate::config::BibiConfig; // struct for CLIArgs #[derive(Debug, Default, Clone)] pub struct CLIArgs { - pub helparg: bool, - pub versionarg: bool, pub pos_args: Vec, pub cfg_path: Option, pub light_theme: bool, @@ -39,7 +38,7 @@ pub struct CLIArgs { } impl CLIArgs { - pub fn parse_args() -> Result { + pub fn parse_args() -> color_eyre::Result<(CLIArgs, BibiConfig)> { let mut args = CLIArgs::default(); let mut parser = lexopt::Parser::from_env(); @@ -52,22 +51,57 @@ impl CLIArgs { None }; + // if parser + // .raw_args() + // .is_ok_and(|mut arg| arg.next_if(|a| a == "format-citekeys").is_some()) + // { + // todo!("Format citekeys options"); + // } + while let Some(arg) = parser.next()? { match arg { - Short('h') | Long("help") => args.helparg = true, - Short('v') | Long("version") => args.versionarg = true, + Short('h') | Long("help") => { + println!("{}", help_func()); + std::process::exit(0); + } + Short('v') | Long("version") => { + println!("{}", version_func()); + std::process::exit(0); + } Short('c') | Long("config-file") => args.cfg_path = Some(parser.value()?.parse()?), Long("light-terminal") => args.light_theme = true, Long("pdf-path") => { args.pdf_path = Some(parser.value()?.parse()?); } // Value(pos_arg) => parse_files(&mut args, pos_arg), - Value(pos_arg) => args.pos_args.push(pos_arg.into()), - _ => return Err(arg.unexpected()), + Value(pos_arg) => { + if args.pos_args.is_empty() && pos_arg == "format-citekeys" { + todo!("Write format citekeys function"); + } else { + args.pos_args.push(parser.value()?.into()); + } + } + _ => return Err(arg.unexpected().into()), } } - Ok(args) + if args + .cfg_path + .as_ref() + .is_some_and(|f| !f.try_exists().unwrap() || !f.is_file()) + { + BibiConfig::create_default_config(&args); + } + + let mut cfg = if args.cfg_path.is_some() { + BibiConfig::parse_config(&args)? + } else { + BibiConfig::new(&args) + }; + + cfg.cli_overwrite(&args); + + Ok((args, cfg)) } } -- cgit v1.2.3 From 669936a8e4ff99012e8b32ae15616f8fe206ab2d Mon Sep 17 00:00:00 2001 From: lukeflo Date: Thu, 9 Oct 2025 16:48:54 +0200 Subject: subcommand test for pure cli operations --- src/cliargs.rs | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) (limited to 'src/cliargs.rs') diff --git a/src/cliargs.rs b/src/cliargs.rs index 3b12fc3..26a07af 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -15,7 +15,6 @@ // along with this program. If not, see . ///// -use color_eyre::eyre::Result; use dirs::{config_dir, home_dir}; use lexopt::prelude::*; use owo_colors::OwoColorize; @@ -41,6 +40,7 @@ impl CLIArgs { pub fn parse_args() -> color_eyre::Result<(CLIArgs, BibiConfig)> { let mut args = CLIArgs::default(); let mut parser = lexopt::Parser::from_env(); + let mut subcommand = None; // Default config args.cfg_path = if config_dir().is_some() { @@ -73,12 +73,22 @@ impl CLIArgs { Long("pdf-path") => { args.pdf_path = Some(parser.value()?.parse()?); } - // Value(pos_arg) => parse_files(&mut args, pos_arg), Value(pos_arg) => { - if args.pos_args.is_empty() && pos_arg == "format-citekeys" { - todo!("Write format citekeys function"); + if args.pos_args.is_empty() { + let value = pos_arg + .into_string() + .unwrap_or_else(|os| os.to_string_lossy().to_string()); + match value.as_str() { + "format-citekeys" => { + subcommand = Some(value); + break; + } + _ => { + args.pos_args.push(value.into()); + } + } } else { - args.pos_args.push(parser.value()?.into()); + args.pos_args.push(pos_arg.into()); } } _ => return Err(arg.unexpected().into()), @@ -88,7 +98,7 @@ impl CLIArgs { if args .cfg_path .as_ref() - .is_some_and(|f| !f.try_exists().unwrap() || !f.is_file()) + .is_some_and(|f| f.try_exists().is_err() || !f.is_file()) { BibiConfig::create_default_config(&args); } @@ -99,6 +109,13 @@ impl CLIArgs { BibiConfig::new(&args) }; + if let Some(cmd) = subcommand { + match cmd.as_str() { + "format-citekeys" => todo!("write citekey formatting"), + _ => {} + } + } + cfg.cli_overwrite(&args); Ok((args, cfg)) -- cgit v1.2.3 From f9548af5c7693edf536b4ad45564a964338e2c2e Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 10 Oct 2025 10:31:45 +0200 Subject: set up citekey formatting cli, reformat help output --- Cargo.lock | 1 + Cargo.toml | 1 + src/bibiman/citekeys.rs | 87 ++++++++++++++++++++++++++++++++++++++- src/cliargs.rs | 106 ++++++++++++++++++++++++++++++++---------------- src/main.rs | 14 ++++--- 5 files changed, 168 insertions(+), 41 deletions(-) (limited to 'src/cliargs.rs') diff --git a/Cargo.lock b/Cargo.lock index 49f65b4..a27636e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "editor-command", "figment", "futures", + "indoc", "itertools", "lexopt", "logos", diff --git a/Cargo.toml b/Cargo.toml index 098848e..abf1eee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ figment = { version = "0.10.19", features = [ "toml", "test" ]} owo-colors = "4.2.2" logos = "0.15.1" phf = { version = "0.13.1", features = ["macros"] } +indoc = "2.0.6" [workspace.metadata.cross.target.aarch64-unknown-linux-gnu] # Install libssl-dev:arm64, see diff --git a/src/bibiman/citekeys.rs b/src/bibiman/citekeys.rs index b7995ac..cafd124 100644 --- a/src/bibiman/citekeys.rs +++ b/src/bibiman/citekeys.rs @@ -23,7 +23,12 @@ use std::{ use biblatex::{Bibliography, ChunksExt, Entry, Type}; use color_eyre::eyre::eyre; -use owo_colors::OwoColorize; +use indoc::formatdoc; +use lexopt::Arg::{Long, Short}; +use owo_colors::{ + OwoColorize, + colors::{BrightBlue, Green, White}, +}; use serde::{Deserialize, Serialize}; use crate::{bibiman::sanitize::sanitize_single_string_fully, config::BibiConfig}; @@ -48,6 +53,30 @@ pub(crate) struct CitekeyFormatting { } impl CitekeyFormatting { + pub(crate) fn parse_citekey_cli( + parser: &mut lexopt::Parser, + cfg: &BibiConfig, + ) -> color_eyre::Result<()> { + let mut formatter = CitekeyFormatting::default(); + + while let Some(arg) = parser.next()? { + match arg { + Short('h') | Long("help") => { + formatting_help(); + return Ok(()); + } + Short('s') | Short('f') | Long("source") | Long("file") => { + formatter.bibfile_path.0 = parser.value()?.into() + } + Short('t') | Short('o') | Long("target") | Long("output") => { + formatter.bibfile_path.1 = Some(parser.value()?.into()) + } + _ => return Err(arg.unexpected().into()), + } + } + + Ok(()) + } /// Start Citekey formatting with building a new instance of `CitekeyFormatting` /// Formatting is processed file by file, because `bibman` can handle /// multi-file setups. @@ -136,6 +165,62 @@ impl CitekeyFormatting { } } +fn formatting_help() { + let help = vec![ + formatdoc!( + "{} {}\n", + env!("CARGO_PKG_NAME").fg::().bold(), + env!("CARGO_PKG_VERSION") + ), + formatdoc!("{}", "USAGE".bold()), + formatdoc!( + "\t{} {} {} {}\n", + env!("CARGO_PKG_NAME").fg::().bold(), + "format-citekeys".bold(), + "--source=".bold(), + "--output=".bold() + ), + formatdoc!( + " + \tThis help describes the CLI usage for the citekey formatting + \tfunctionality of bibiman. The definition of patterns how the + \tcitekeys should be formatted must be set in the config file. + \tFor further informations how to use this patterns etc. see: + \t{} + ", + "https://codeberg.org/lukeflo/bibiman/src/branch/main#bibiman" + .italic() + .fg::() + ), + formatdoc!("{}", "OPTIONS".bold()), + formatdoc!( + " + \t{} + \tShow this help and exit + ", + "-h, --help".fg::().bold() + ), + formatdoc! {" + \t{} + \tThe bibfile for which the citekey formatting should be processed. + \tTakes a path as argument. + ", "-s, -f, --source=, --file=".fg::().bold()}, + formatdoc!( + " + \t{} + \tThe bibfile to which the updated content should be written. + \tTakes a path as argument. If the file doesn't exist, it will be + \tcreated. + \tIf the argument isn't used, the original file will be {}! + ", + "-t, -o, --target=, --output=".fg::().bold(), + "overwritten".italic(), + ), + ]; + let help = help.join("\n"); + println!("{}", help); +} + /// Build the citekey from the patterns defined in the config file fn build_citekey(entry: &Entry, pattern_fields: &[String], case: Option<&CitekeyCase>) -> String { let mut new_citekey = String::new(); diff --git a/src/cliargs.rs b/src/cliargs.rs index 26a07af..e766e77 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -16,6 +16,7 @@ ///// use dirs::{config_dir, home_dir}; +use indoc::formatdoc; use lexopt::prelude::*; use owo_colors::OwoColorize; use owo_colors::colors::css::LightGreen; @@ -25,6 +26,7 @@ use std::path::PathBuf; use walkdir::WalkDir; use crate::app; +use crate::bibiman::citekeys::CitekeyFormatting; use crate::config::BibiConfig; // struct for CLIArgs @@ -37,10 +39,16 @@ pub struct CLIArgs { } impl CLIArgs { - pub fn parse_args() -> color_eyre::Result<(CLIArgs, BibiConfig)> { + /// This struct parses the command line and initializes and returns the + /// necessary structs `CLIArgs` and `BibiConfig`. + /// + /// Additionally, it returns a bool which defines if the TUI should be run + /// or not. The latter is the case for pure CLI processes as `format-citekeys`. + pub fn parse_args() -> color_eyre::Result<(CLIArgs, BibiConfig, bool)> { let mut args = CLIArgs::default(); let mut parser = lexopt::Parser::from_env(); let mut subcommand = None; + let mut run_tui = true; // Default config args.cfg_path = if config_dir().is_some() { @@ -81,6 +89,7 @@ impl CLIArgs { match value.as_str() { "format-citekeys" => { subcommand = Some(value); + run_tui = false; break; } _ => { @@ -111,14 +120,16 @@ impl CLIArgs { if let Some(cmd) = subcommand { match cmd.as_str() { - "format-citekeys" => todo!("write citekey formatting"), + "format-citekeys" => { + CitekeyFormatting::parse_citekey_cli(&mut parser, &cfg)?; + } _ => {} } } cfg.cli_overwrite(&args); - Ok((args, cfg)) + Ok((args, cfg, run_tui)) } } @@ -172,14 +183,21 @@ pub fn help_func() -> String { env!("CARGO_PKG_VERSION").fg::(), ), format!( - "{}:\n\t{} [Flags] [files/dirs]\n", + "{}\n\t{} [OPTIONS] [SUBCOMMAND | POSITIONAL ARGUMENTS]\n", "USAGE".bold(), - "bibiman".bold() + env!("CARGO_PKG_NAME").fg::().bold() + ), + formatdoc!( + " + \tYou can either use a {} or {}, not both! + ", + "subcommand".bold(), + "positional arguments".bold() ), format!( - "{}:\n\t{}\t\tPath to {} file", + "{}\n\t{}\t\tPath to {} file", "POSITIONAL ARGUMENTS".bold(), - "".fg::().bold(), + "".fg::().bold(), ".bib".fg::().bold() ), format!( @@ -188,38 +206,58 @@ pub fn help_func() -> String { ".bib".fg::().bold() ), format!("\n\t{}", "Both can be passed multiple times".italic()), - format!("\n{}:", "FLAGS".bold()), - format!("\t{}", "-h, --help".bold().fg::()), - format!("\t\t{}", "Show this help and exit"), - format!("\t{}", "-v, --version".bold().fg::()), - format!("\t\t{}", "Show the version and exit"), - format!("\t{}", "--light-terminal".bold().fg::()), - format!( - "\t\t{}", - "Enable default colors for light terminal background" + format!("\n{}", "SUBCOMMANDS".bold()), + formatdoc!( + " + \t{} + \tRun the citekey formatting procedure on a specified bibfile. + \tFor further infos run {} + ", + "format-citekeys".fg::().bold(), + "bibiman format-citekeys --help".fg::().bold() ), - format!( - "\t{}{}", - "-c, --config-file=".bold().fg::(), - "".bold().italic().fg::() + format!("{}", "OPTIONS".bold()), + formatdoc!( + " + \t{} + \tShow this help and exit + ", + "-h, --help".bold().fg::() ), - format!("\t\t{}", "Path to config file used for current session."), - format!("\t\t{}", "Takes precedence over standard config file."), - format!( - "\t{}{}", - "--pdf-path=".bold().fg::(), - "".bold().italic().fg::() + formatdoc!( + " + \t{} + \tShow the version and exit + ", + "-v, --version".bold().fg::() ), - format!("\t\t{}", "Path to directory containing PDF files."), - format!( - "\t\t{}", - "If the pdf files basename matches an entrys citekey," + formatdoc!( + " + \t{} + \tEnable default colors for light terminal background + ", + "--light-terminal".bold().fg::() ), - format!( - "\t\t{}", - "its attached as connected PDF file for the current session." + formatdoc!( + " + \t{}{} + \tPath to config file used for current session. + \tTakes precedence over standard config file. + ", + "-c, --config-file=".bold().fg::(), + "".bold().italic().fg::() + ), + formatdoc!( + " + \t{}{} + \tPath to directory containing PDF files. + \tIf the pdf files basename matches an entrys citekey, + \tits attached as connected PDF file for the current session. + \tDoes not edit the bibfile itself! + ", + "--pdf-path=".bold().fg::(), + "".bold().italic().fg::() ), - format!("\t\t{}", "Does not edit the bibfile itself!"), ]; let help = help.join("\n"); help diff --git a/src/main.rs b/src/main.rs index 58805d5..e735eb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,6 @@ use app::App; use cliargs::CLIArgs; use color_eyre::eyre::Result; -use config::BibiConfig; use errorsetup::init_error_hooks; pub mod app; @@ -31,13 +30,16 @@ pub mod tui; #[tokio::main] async fn main() -> Result<()> { // Parse CLI arguments - let (mut parsed_args, mut cfg) = CLIArgs::parse_args()?; + let (mut parsed_args, mut cfg, run_tui) = CLIArgs::parse_args()?; - init_error_hooks()?; + if run_tui { + init_error_hooks()?; - // Create an application. - let mut app = App::new(&mut parsed_args, &mut cfg)?; + // Create an application. + let mut app = App::new(&mut parsed_args, &mut cfg)?; + + app.run(&cfg).await?; + } - app.run(&cfg).await?; Ok(()) } -- cgit v1.2.3