From 7fe5acb85b9e665ec83f590942ee78b8c90d6aae Mon Sep 17 00:00:00 2001 From: lukeflo Date: Sun, 18 May 2025 22:44:36 +0200 Subject: first tests for pdf folder --- src/cliargs.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'src/cliargs.rs') diff --git a/src/cliargs.rs b/src/cliargs.rs index d4fac46..6fd30e1 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -33,6 +33,7 @@ pub struct CLIArgs { pub pos_args: Vec, pub cfg_path: Option, pub light_theme: bool, + pub pdf_files: Option>, } impl CLIArgs { @@ -55,6 +56,10 @@ impl CLIArgs { Short('v') | Long("version") => args.versionarg = true, Short('c') | Long("config-file") => args.cfg_path = Some(parser.value()?.parse()?), Long("light-terminal") => args.light_theme = true, + Long("merge-pdf-paths") => { + let pdf_dir: PathBuf = parser.value()?.parse()?; + args.pdf_files = collect_pdf_files(pdf_dir); + } // Value(pos_arg) => parse_files(&mut args, pos_arg), Value(pos_arg) => args.pos_args.push(pos_arg.into()), _ => return Err(arg.unexpected()), @@ -65,6 +70,37 @@ impl CLIArgs { } } +/// This function walks the given dir and collects all pdf files into a `Vec` +pub fn collect_pdf_files(pdf_dir: PathBuf) -> Option> { + let mut files: Vec = Vec::new(); + + // Expand tilde to /home/user + let pdf_dir = if pdf_dir.starts_with("~") { + app::expand_home(&pdf_dir) + } else { + pdf_dir + }; + + // Walk the passed dir and collect all pdf files into vec + if pdf_dir.is_dir() { + for file in WalkDir::new(pdf_dir) { + let f = file.unwrap().into_path(); + if f.is_file() + && f.extension().is_some() + && f.extension().unwrap_or_default().to_ascii_lowercase() == "pdf" + { + files.push(f); + } + } + } + + if files.is_empty() { + None + } else { + Some(files) + } +} + /// This function maps a vector containing paths to another vector containing paths. /// But it will walk all entries of the first vec which are directories /// and put only valid file paths with `.bib` ending to the resulting vec. @@ -126,7 +162,10 @@ FLAGS: -v, --version Show the version and exit -c, --config-file Path to config file used for current session. Takes precedence over standard config file. - --light-terminal Enable color mode for light terminal background", + --light-terminal Enable color mode for light terminal background + --merge-pdf-paths Merge PDF files named by citekey at the given path into + the `file` field of the entry matching the citekey + (might not work with citekeys containing special chars)", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), ); -- cgit v1.2.3 From 28030fd0830478872be2b9e86b74e0c054a96111 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Sat, 24 May 2025 17:31:33 +0200 Subject: implemented a workflow, but citekey matching still buggy --- src/app.rs | 2 +- src/bibiman.rs | 12 ++--- src/bibiman/bibisetup.rs | 95 +++++++++++++++++++++++++++------ src/cliargs.rs | 36 +------------ src/config.rs | 15 ++++++ src/main.rs | 2 + tests/pdf-files/aristotle:rhetoric.pdf | Bin 0 -> 674743 bytes tests/test-config.toml | 5 ++ 8 files changed, 110 insertions(+), 57 deletions(-) create mode 100644 tests/pdf-files/aristotle:rhetoric.pdf (limited to 'src/cliargs.rs') diff --git a/src/app.rs b/src/app.rs index 88f37b0..e0c149c 100644 --- a/src/app.rs +++ b/src/app.rs @@ -277,7 +277,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()? + self.bibiman.append_entry_to_file(cfg)? } else if let Some(PopupKind::YankItem) = self.bibiman.popup_area.popup_kind { self.bibiman.yank_entry_field()? } diff --git a/src/bibiman.rs b/src/bibiman.rs index c90905f..ef5dfe3 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -89,7 +89,7 @@ impl Bibiman { 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 main_biblio = BibiSetup::new(&main_bibfiles, cfg); 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()); @@ -133,8 +133,8 @@ impl Bibiman { self.former_area = None; } - pub fn update_lists(&mut self) { - self.main_biblio = BibiSetup::new(&self.main_bibfiles); + pub fn update_lists(&mut self, cfg: &BibiConfig) { + self.main_biblio = BibiSetup::new(&self.main_bibfiles, cfg); self.tag_list = TagList::new(self.main_biblio.keyword_list.clone()); self.entry_table = EntryTable::new(self.main_biblio.entry_list.clone()); } @@ -397,7 +397,7 @@ impl Bibiman { tui.terminal.clear()?; // Update the database and the lists to show changes - Self::update_lists(self); + Self::update_lists(self, cfg); // Select entry which was selected before entering editor self.select_entry_by_citekey(citekey); @@ -466,7 +466,7 @@ impl Bibiman { self.popup_area.popup_selection(items); } - pub fn append_entry_to_file(&mut self) -> Result<()> { + pub fn append_entry_to_file(&mut self, cfg: &BibiConfig) -> Result<()> { // Index of selected popup field let popup_idx = self.popup_area.popup_state.selected().unwrap(); @@ -535,7 +535,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(); + self.update_lists(cfg); self.close_popup(); // Select newly created entry diff --git a/src/bibiman/bibisetup.rs b/src/bibiman/bibisetup.rs index 92731b5..b09747a 100644 --- a/src/bibiman/bibisetup.rs +++ b/src/bibiman/bibisetup.rs @@ -21,8 +21,11 @@ use color_eyre::owo_colors::OwoColorize; use itertools::Itertools; use std::ffi::{OsStr, OsString}; use std::{fs, path::PathBuf}; +use walkdir::WalkDir; +use crate::app; use crate::cliargs::{self, CLIArgs}; +use crate::config::BibiConfig; // Set necessary fields // TODO: can surely be made more efficient/simpler @@ -121,14 +124,14 @@ impl BibiData { } impl BibiSetup { - pub fn new(main_bibfiles: &[PathBuf]) -> Self { + pub fn new(main_bibfiles: &[PathBuf], cfg: &BibiConfig) -> Self { // TODO: Needs check for config file path as soon as config file is impl Self::check_files(main_bibfiles); let bibfilestring = Self::bibfiles_to_string(main_bibfiles); let bibliography = biblatex::Bibliography::parse(&bibfilestring).unwrap(); let citekeys = Self::get_citekeys(&bibliography); let keyword_list = Self::collect_tag_list(&citekeys, &bibliography); - let entry_list = Self::create_entry_list(&citekeys, &bibliography); + let entry_list = Self::create_entry_list(&citekeys, &bibliography, cfg); Self { // bibfile, bibfilestring, @@ -181,7 +184,16 @@ impl BibiSetup { file_strings.join("\n") } - fn create_entry_list(citekeys: &[String], bibliography: &Bibliography) -> Vec { + fn create_entry_list( + citekeys: &[String], + bibliography: &Bibliography, + cfg: &BibiConfig, + ) -> Vec { + let pdf_files = if cfg.general.pdf_path.is_some() { + collect_pdf_files(cfg.general.pdf_path.as_ref().unwrap()) + } else { + None + }; citekeys .iter() .enumerate() @@ -196,7 +208,7 @@ impl BibiSetup { citekey: k.to_owned(), abstract_text: Self::get_abstract(k, bibliography), doi_url: Self::get_weblink(k, bibliography), - filepath: Self::get_filepath(k, bibliography), + filepath: Self::get_filepath(k, bibliography, &pdf_files), subtitle: Self::get_subtitle(k, bibliography), }) .collect() @@ -328,11 +340,15 @@ impl BibiSetup { } } - pub fn get_filepath(citekey: &str, biblio: &Bibliography, args: &CLIArgs) -> Option { + pub fn get_filepath( + citekey: &str, + biblio: &Bibliography, + pdf_files: &Option>, + ) -> Option { if biblio.get(citekey).unwrap().file().is_ok() { Some(biblio.get(citekey).unwrap().file().unwrap().trim().into()) - } else if args.pdf_files.is_some() { - Self::merge_filepath_or_none(&citekey, &biblio, &args) + } else if pdf_files.is_some() { + Self::merge_filepath_or_none(&citekey, pdf_files) } else { None } @@ -353,19 +369,66 @@ impl BibiSetup { } } - fn merge_filepath_or_none( - citekey: &str, - biblio: &Bibliography, - args: &CLIArgs, - ) -> Option { + fn merge_filepath_or_none(citekey: &str, pdf_files: &Option>) -> Option { // Oder n Loop??? let pdf_file = { - let filename = citekey.to_owned() + ".pdf"; - for f in args.pdf_files.unwrap().iter() { - if f.file_name().unwrap().to_str().unwrap() == &filename { - break f; + let mut idx = 0; + let citekey = citekey.to_owned().to_ascii_lowercase() + ".pdf"; + // let filename = citekey.to_owned() + ".pdf"; + // for f in args.pdf_files.unwrap().iter() { + // if f.file_name().unwrap().to_str().unwrap() == &filename { + // break f; + // } + // } + for file in pdf_files.as_ref().unwrap().iter() { + let filename = file.file_name().unwrap().to_ascii_lowercase(); + if filename.to_str().unwrap() == citekey { + break; + } else if pdf_files.as_ref().unwrap().len() > idx { + break; + } else { + idx += 1; } } + + if pdf_files.as_ref().unwrap()[idx].is_file() { + Some(pdf_files.as_ref().unwrap()[idx].to_owned().into_os_string()) + } else { + None + } }; + + pdf_file + } +} + +/// This function walks the given dir and collects all pdf files into a `Vec` +pub fn collect_pdf_files(pdf_dir: &PathBuf) -> Option> { + let mut files: Vec = Vec::new(); + + // Expand tilde to /home/user + let pdf_dir = if pdf_dir.starts_with("~") { + &app::expand_home(&pdf_dir) + } else { + pdf_dir + }; + + // Walk the passed dir and collect all pdf files into vec + if pdf_dir.is_dir() { + for file in WalkDir::new(pdf_dir) { + let f = file.unwrap().into_path(); + if f.is_file() + && f.extension().is_some() + && f.extension().unwrap_or_default().to_ascii_lowercase() == "pdf" + { + files.push(f); + } + } + } + + if files.is_empty() { + None + } else { + Some(files) } } diff --git a/src/cliargs.rs b/src/cliargs.rs index 6fd30e1..a9b12fd 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -33,7 +33,7 @@ pub struct CLIArgs { pub pos_args: Vec, pub cfg_path: Option, pub light_theme: bool, - pub pdf_files: Option>, + pub pdf_path: Option, } impl CLIArgs { @@ -57,8 +57,7 @@ impl CLIArgs { Short('c') | Long("config-file") => args.cfg_path = Some(parser.value()?.parse()?), Long("light-terminal") => args.light_theme = true, Long("merge-pdf-paths") => { - let pdf_dir: PathBuf = parser.value()?.parse()?; - args.pdf_files = collect_pdf_files(pdf_dir); + 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()), @@ -70,37 +69,6 @@ impl CLIArgs { } } -/// This function walks the given dir and collects all pdf files into a `Vec` -pub fn collect_pdf_files(pdf_dir: PathBuf) -> Option> { - let mut files: Vec = Vec::new(); - - // Expand tilde to /home/user - let pdf_dir = if pdf_dir.starts_with("~") { - app::expand_home(&pdf_dir) - } else { - pdf_dir - }; - - // Walk the passed dir and collect all pdf files into vec - if pdf_dir.is_dir() { - for file in WalkDir::new(pdf_dir) { - let f = file.unwrap().into_path(); - if f.is_file() - && f.extension().is_some() - && f.extension().unwrap_or_default().to_ascii_lowercase() == "pdf" - { - files.push(f); - } - } - } - - if files.is_empty() { - None - } else { - Some(files) - } -} - /// This function maps a vector containing paths to another vector containing paths. /// But it will walk all entries of the first vec which are directories /// and put only valid file paths with `.bib` ending to the resulting vec. diff --git a/src/config.rs b/src/config.rs index d554c58..1532d31 100644 --- a/src/config.rs +++ b/src/config.rs @@ -51,6 +51,11 @@ const DEFAULT_CONFIG: &str = r##" ## Use absolute paths (~ for HOME works). Otherwise, loading might not work. # file_prefix = "/some/path/prefix" +## Path to folder (with subfolders) containing PDF files with the basename +## of the format "citekey.pdf". Other PDF basenames are not accepted. +## Use absolute paths (~ for HOME works). Otherwise, loading might not work. +# pdf_path = "/path/to/pdf/folder" + # [colors] ## Default values for dark-themed terminal ## Possible values are: @@ -84,6 +89,7 @@ pub struct General { pub pdf_opener: String, pub url_opener: String, pub file_prefix: Option, + pub pdf_path: Option, } /// Substruct [colors] in config.toml @@ -110,6 +116,7 @@ impl Default for BibiConfig { pdf_opener: select_opener(), url_opener: select_opener(), file_prefix: None, + pdf_path: None, }, colors: Colors { main_text_color: Color::Indexed(250), @@ -140,6 +147,14 @@ impl BibiConfig { Ok(cfg_file) } + /// overwright config values with values set explicitly through the + /// command line interface + pub fn cli_overwright(&mut self, args: &CLIArgs) { + if args.pdf_path.is_some() { + self.general.pdf_path = args.pdf_path.clone(); + } + } + /// Activates the default color scheme for light background terminals pub fn light_colors(&mut self) { self.colors.main_text_color = Color::Indexed(235); diff --git a/src/main.rs b/src/main.rs index b218f9b..dd82c0f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,6 +59,8 @@ async fn main() -> Result<()> { BibiConfig::default() }; + cfg.cli_overwright(&parsed_args); + init_error_hooks()?; // Create an application. diff --git a/tests/pdf-files/aristotle:rhetoric.pdf b/tests/pdf-files/aristotle:rhetoric.pdf new file mode 100644 index 0000000..a6d6eff Binary files /dev/null and b/tests/pdf-files/aristotle:rhetoric.pdf differ diff --git a/tests/test-config.toml b/tests/test-config.toml index 3913f16..1b60acd 100644 --- a/tests/test-config.toml +++ b/tests/test-config.toml @@ -16,6 +16,11 @@ bibfiles = [ "tests/biblatex-test.bib" ] ## Use absolute paths (~ for HOME works). Otherwise, loading might not work. # file_prefix = "/some/path/prefix" +## Path to folder (with subfolders) containing PDF files with the basename +## of the format "citekey.pdf". Other PDF basenames are not accepted. +## Use absolute paths (~ for HOME works). Otherwise, loading might not work. +pdf_path = "tests/pdf-files" + # [colors] ## Default values for dark-themed terminal ## Possible values are: -- cgit v1.2.3 From c0dcbcd18a3fba111885fd0eaf8ef18f71cf693a Mon Sep 17 00:00:00 2001 From: lukeflo Date: Mon, 26 May 2025 14:55:21 +0200 Subject: some more doc strings --- src/cliargs.rs | 20 +++++++++++--------- src/config.rs | 2 +- src/main.rs | 2 +- src/tui/popup.rs | 17 +++++++++++++++++ 4 files changed, 30 insertions(+), 11 deletions(-) (limited to 'src/cliargs.rs') diff --git a/src/cliargs.rs b/src/cliargs.rs index a9b12fd..c7a0eb1 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -56,7 +56,7 @@ impl CLIArgs { Short('v') | Long("version") => args.versionarg = true, Short('c') | Long("config-file") => args.cfg_path = Some(parser.value()?.parse()?), Long("light-terminal") => args.light_theme = true, - Long("merge-pdf-paths") => { + Long("pdf-dir") => { args.pdf_path = Some(parser.value()?.parse()?); } // Value(pos_arg) => parse_files(&mut args, pos_arg), @@ -126,14 +126,16 @@ POSITIONAL ARGS: Both can be passed multiple times FLAGS: - -h, --help Show this help and exit - -v, --version Show the version and exit - -c, --config-file Path to config file used for current session. - Takes precedence over standard config file. - --light-terminal Enable color mode for light terminal background - --merge-pdf-paths Merge PDF files named by citekey at the given path into - the `file` field of the entry matching the citekey - (might not work with citekeys containing special chars)", + -h, --help Show this help and exit + -v, --version Show the version and exit + -c, --config-file= Path to config file used for current session. + Takes precedence over standard config file. + --light-terminal= Enable color mode for light terminal background + --pdf-dir= Use PDF files named by citekey at the given path and its + subdirs as value for the `file` field of the entry matching + the citekey for the current session. + Does not overwrite or change the original file. + (might not work with citekeys containing special chars)", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), ); diff --git a/src/config.rs b/src/config.rs index 1532d31..8d50d93 100644 --- a/src/config.rs +++ b/src/config.rs @@ -149,7 +149,7 @@ impl BibiConfig { /// overwright config values with values set explicitly through the /// command line interface - pub fn cli_overwright(&mut self, args: &CLIArgs) { + pub fn cli_overwrite(&mut self, args: &CLIArgs) { if args.pdf_path.is_some() { self.general.pdf_path = args.pdf_path.clone(); } diff --git a/src/main.rs b/src/main.rs index dd82c0f..add1f2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,7 @@ async fn main() -> Result<()> { BibiConfig::default() }; - cfg.cli_overwright(&parsed_args); + cfg.cli_overwrite(&parsed_args); init_error_hooks()?; diff --git a/src/tui/popup.rs b/src/tui/popup.rs index 2a6f18a..a0a61a4 100644 --- a/src/tui/popup.rs +++ b/src/tui/popup.rs @@ -26,11 +26,17 @@ use crate::config::BibiConfig; #[derive(Debug)] pub enum PopupKind { Help, + /// use for a confirmation message MessageConfirm, + /// use for a warning message MessageError, + /// open a resource connected to the entry OpenRes, + /// select file to append entry to AppendToFile, + /// append entry to a bibfile (selected in `AppendToFile` popup) AddEntry, + /// select an item of the current entry to yank to clipboard YankItem, } @@ -108,6 +114,14 @@ impl PopupArea { Text::from(helptext) } + /// Creates a popup message. The needed arguments are: + /// + /// - `message` as `str`: The message displayed in the popup. + /// - `object` as `str`: A possible object added to the message. E.g. the content + /// which gets copied to the clipboard. + /// - `msg_confirm` as `bool`: if `true` its a confirmation message displayed in + /// in the set `confirm_color` (default: green), if `false` its a warning + /// message displayed in the set `warn_color` (default: red). pub fn popup_message(&mut self, message: &str, object: &str, msg_confirm: bool) { if object.is_empty() { self.popup_message = message.to_owned(); @@ -122,6 +136,9 @@ impl PopupArea { self.is_popup = true; } + /// Opens a popup with a selectable list + /// + /// The list items are passed as argument of the kind `Vec`. pub fn popup_selection(&mut self, items: Vec) { self.popup_list = items; // self.popup_kind = Some(PopupKind::SelectRes); -- cgit v1.2.3 From 62580d8cc537808c34b0d9a0fe5554b4806a7aa6 Mon Sep 17 00:00:00 2001 From: lukeflo Date: Fri, 30 May 2025 17:36:50 +0200 Subject: typo in --help function --- README.md | 2 +- src/cliargs.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/cliargs.rs') diff --git a/README.md b/README.md index 01268a7..d2827b4 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ FLAGS: -v, --version Show the version and exit -c, --config-file= Path to config file used for current session. Takes precedence over standard config file. - --light-terminal= Enable color mode for light terminal background + --light-terminal Enable color mode for light terminal background --pdf-dir= Use PDF files named by citekey at the given path and its subdirs as value for the `file` field of the entry matching the citekey for the current session. diff --git a/src/cliargs.rs b/src/cliargs.rs index c7a0eb1..04886d1 100644 --- a/src/cliargs.rs +++ b/src/cliargs.rs @@ -130,7 +130,7 @@ FLAGS: -v, --version Show the version and exit -c, --config-file= Path to config file used for current session. Takes precedence over standard config file. - --light-terminal= Enable color mode for light terminal background + --light-terminal Enable color mode for light terminal background --pdf-dir= Use PDF files named by citekey at the given path and its subdirs as value for the `file` field of the entry matching the citekey for the current session. -- cgit v1.2.3