aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlukeflo2025-05-25 14:21:17 +0200
committerlukeflo2025-05-25 14:21:17 +0200
commit06782b5ed1527b1d4eb6e26feb5a260415efe1af (patch)
tree33fa4c6d0eeb7ceef3dcf83d8bd034af6e74c6be /src
parentd112312c3fcf79c679e2aa4a47a60b69f83cbce9 (diff)
downloadbibiman-06782b5ed1527b1d4eb6e26feb5a260415efe1af.tar.gz
bibiman-06782b5ed1527b1d4eb6e26feb5a260415efe1af.zip
enhancement from PR \#28 discussion
+ Collect basenames and filepaths from pdf dir into HashMap + Identical basenames in different subdirs are possible + Collected into Vector + TODO: implement selection for multiple files (yank and open)
Diffstat (limited to 'src')
-rw-r--r--src/bibiman.rs5
-rw-r--r--src/bibiman/bibisetup.rs140
-rw-r--r--src/tui/ui.rs14
3 files changed, 122 insertions, 37 deletions
diff --git a/src/bibiman.rs b/src/bibiman.rs
index ef5dfe3..646a078 100644
--- a/src/bibiman.rs
+++ b/src/bibiman.rs
@@ -557,7 +557,8 @@ impl Bibiman {
let url = app::prepare_weblink(object);
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();
+ // TODO: Selection for multiple files
+ let object = self.entry_table.entry_table_items[entry_idx].filepath()[0];
app::open_connected_file(cfg, object)?;
} else {
eprintln!("Unable to find ressource to open");
@@ -604,7 +605,7 @@ impl Bibiman {
.filepath
.clone();
if let Some(p) = path {
- let p = p.as_os_str().to_str();
+ let p = p[0].as_os_str().to_str();
if let Some(p) = p {
Bibiman::yank_text(p);
self.popup_area.popup_message(
diff --git a/src/bibiman/bibisetup.rs b/src/bibiman/bibisetup.rs
index aa0640c..0914f7c 100644
--- a/src/bibiman/bibisetup.rs
+++ b/src/bibiman/bibisetup.rs
@@ -19,12 +19,13 @@ use biblatex::{self, Bibliography};
use biblatex::{ChunksExt, Type};
use color_eyre::owo_colors::OwoColorize;
use itertools::Itertools;
+use std::collections::HashMap;
use std::ffi::{OsStr, OsString};
use std::{fs, path::PathBuf};
use walkdir::WalkDir;
use crate::app;
-use crate::cliargs::{self, CLIArgs};
+use crate::cliargs::{self};
use crate::config::BibiConfig;
// Set necessary fields
@@ -51,7 +52,7 @@ pub struct BibiData {
pub citekey: String,
pub abstract_text: String,
pub doi_url: Option<String>,
- pub filepath: Option<OsString>,
+ pub filepath: Option<Vec<OsString>>,
pub subtitle: Option<String>,
}
@@ -114,8 +115,17 @@ impl BibiData {
self.doi_url.as_ref().unwrap()
}
- pub fn filepath(&self) -> &OsStr {
- self.filepath.as_ref().unwrap()
+ // pub fn filepath(&self) -> &OsStr {
+ // self.filepath.as_ref().unwrap()
+ // }
+
+ pub fn filepath(&mut self) -> Vec<&OsStr> {
+ self.filepath
+ .as_mut()
+ .unwrap()
+ .iter_mut()
+ .map(|p| p.as_os_str())
+ .collect_vec()
}
pub fn subtitle(&self) -> &str {
@@ -190,7 +200,7 @@ impl BibiSetup {
cfg: &BibiConfig,
) -> Vec<BibiData> {
let mut pdf_files = if cfg.general.pdf_path.is_some() {
- collect_pdf_files(cfg.general.pdf_path.as_ref().unwrap())
+ collect_pdf_file_paths(cfg.general.pdf_path.as_ref().unwrap())
} else {
None
};
@@ -343,10 +353,16 @@ impl BibiSetup {
pub fn get_filepath(
citekey: &str,
biblio: &Bibliography,
- pdf_files: &mut Option<Vec<PathBuf>>,
- ) -> Option<OsString> {
+ pdf_files: &mut Option<HashMap<String, Vec<PathBuf>>>,
+ ) -> Option<Vec<OsString>> {
if biblio.get(citekey).unwrap().file().is_ok() {
- Some(biblio.get(citekey).unwrap().file().unwrap().trim().into())
+ Some(vec![biblio
+ .get(citekey)
+ .unwrap()
+ .file()
+ .unwrap()
+ .trim()
+ .into()])
} else if pdf_files.is_some() {
Self::merge_filepath_or_none(&citekey, pdf_files)
} else {
@@ -371,11 +387,10 @@ impl BibiSetup {
fn merge_filepath_or_none(
citekey: &str,
- pdf_files: &mut Option<Vec<PathBuf>>,
- ) -> Option<OsString> {
- // Oder n Loop???
+ pdf_files: &mut Option<HashMap<String, Vec<PathBuf>>>,
+ ) -> Option<Vec<OsString>> {
let pdf_file = {
- let mut idx = 0;
+ // 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() {
@@ -384,27 +399,27 @@ impl BibiSetup {
// }
// }
- loop {
- if idx + 1 > pdf_files.as_ref().unwrap().len() {
- break None;
- }
- let cur_entry = pdf_files.as_ref().unwrap()[idx].clone();
- if cur_entry.is_file()
- && cur_entry
- .file_name()
- .unwrap()
- .to_ascii_lowercase()
- .to_str()
- .unwrap()
- == citekey
- {
- let path = cur_entry.to_owned().into_os_string();
- pdf_files.as_mut().unwrap().swap_remove(idx);
- break Some(path);
- } else {
- idx += 1
- }
- }
+ // loop {
+ // if idx + 1 > pdf_files.as_ref().unwrap().len() {
+ // break None;
+ // }
+ // let cur_entry = pdf_files.as_ref().unwrap()[idx].clone();
+ // if cur_entry.is_file()
+ // && cur_entry
+ // .file_name()
+ // .unwrap()
+ // .to_ascii_lowercase()
+ // .to_str()
+ // .unwrap()
+ // == citekey
+ // {
+ // let path = cur_entry.to_owned().into_os_string();
+ // pdf_files.as_mut().unwrap().swap_remove(idx);
+ // break Some(path);
+ // } else {
+ // idx += 1
+ // }
+ // }
// for file in pdf_files.as_ref().unwrap().iter() {
// let filename = file.file_name().unwrap().to_ascii_lowercase();
@@ -422,6 +437,18 @@ impl BibiSetup {
// } else {
// None
// }
+
+ if pdf_files.as_ref().unwrap().contains_key(&citekey) {
+ let path_vec = pdf_files
+ .as_ref()
+ .unwrap()
+ .get(&citekey)
+ .unwrap()
+ .to_owned();
+ Some(path_vec.into_iter().map(|p| p.into_os_string()).collect())
+ } else {
+ None
+ }
};
pdf_file
@@ -458,3 +485,50 @@ pub fn collect_pdf_files(pdf_dir: &PathBuf) -> Option<Vec<PathBuf>> {
Some(files)
}
}
+
+/// This function walks the given dir and collects all pdf files into a `HashMap`
+/// of the format `[String, Vec<PathBuf>]`, where `String` represents the basename
+/// of the file and the `Vec<PathBuf>` holds all filepaths ending with this basename.
+///
+/// In most cases the latter is only a single path, but there might be some concepts
+/// with subdirs were some entries have multiple files associated with them.
+pub fn collect_pdf_file_paths(pdf_dir: &PathBuf) -> Option<HashMap<String, Vec<PathBuf>>> {
+ let mut files: HashMap<String, Vec<PathBuf>> = HashMap::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 hashmap
+ 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"
+ {
+ let filename = f
+ .file_name()
+ .unwrap()
+ .to_ascii_lowercase()
+ .into_string()
+ .unwrap();
+
+ if let Some(paths) = files.get_mut(&filename) {
+ paths.push(f);
+ } else {
+ files.insert(filename, vec![f]);
+ }
+ }
+ }
+ }
+
+ if files.is_empty() {
+ None
+ } else {
+ Some(files)
+ }
+}
diff --git a/src/tui/ui.rs b/src/tui/ui.rs
index 921cbb1..883e4df 100644
--- a/src/tui/ui.rs
+++ b/src/tui/ui.rs
@@ -24,6 +24,7 @@ use crate::cliargs::CLIArgs;
use crate::config::BibiConfig;
use crate::tui::popup::PopupKind;
use crate::App;
+use itertools::Itertools;
use ratatui::layout::{Direction, Position};
use ratatui::widgets::Clear;
use ratatui::Frame;
@@ -833,15 +834,24 @@ pub fn render_selected_item(app: &mut App, cfg: &BibiConfig, frame: &mut Frame,
),
]));
}
- if cur_entry.filepath.is_some() {
+ if let Some(p) = &cur_entry.filepath {
lines.push(Line::from(vec![
Span::styled("File: ", style_value),
Span::styled(
- cur_entry.filepath().to_string_lossy(),
+ p.iter().map(|f| f.to_str().unwrap()).join("; "),
Style::new().fg(cfg.colors.main_text_color),
),
]));
}
+ // if cur_entry.filepath.is_some() {
+ // lines.push(Line::from(vec![
+ // Span::styled("File: ", style_value),
+ // Span::styled(
+ // cur_entry.filepath().to_string_lossy(),
+ // Style::new().fg(cfg.colors.main_text_color),
+ // ),
+ // ]));
+ // }
lines.push(Line::from(""));
lines.push(Line::from(vec![Span::styled(
cur_entry.abstract_text.clone(),