diff options
| author | lukeflo | 2025-07-07 15:17:19 +0200 |
|---|---|---|
| committer | lukeflo | 2025-07-07 15:17:19 +0200 |
| commit | d55cfd8617410545335aeaf895120044c46dde45 (patch) | |
| tree | bb4a41d32a3715610b8429047a12ec9a6540ee08 /src/app.rs | |
| parent | 2e4ae7a05a73cb1df63343e14fbb8a5fd3c7bf41 (diff) | |
| parent | c0970da999e222cadbcc2242fb67686ed5b00ca4 (diff) | |
| download | bibiman-d55cfd8617410545335aeaf895120044c46dde45.tar.gz bibiman-d55cfd8617410545335aeaf895120044c46dde45.zip | |
Merge pull request 'bibnotes' (#49) from bibnotes into main
- connect bibentries with notes through citekey<>basename matching
- use multiple file extensions for note files (plain-text heavily recommended)
- create notes for bibentries inside notes dir
- use custom symbols as marker for files/links/notes attached to a bibentry
Diffstat (limited to 'src/app.rs')
| -rw-r--r-- | src/app.rs | 156 |
1 files changed, 132 insertions, 24 deletions
@@ -16,14 +16,14 @@ ///// use crate::bibiman::CurrentArea; -use crate::config::BibiConfig; -use color_eyre::eyre::{Context, Ok, Result}; -// use super::Event; use crate::cliargs::CLIArgs; +use crate::config::BibiConfig; use crate::tui::commands::InputCmdAction; -use crate::tui::popup::PopupKind; +use crate::tui::popup::{PopupItem, PopupKind}; use crate::tui::{self, Tui}; use crate::{bibiman::Bibiman, tui::commands::CmdAction}; +use color_eyre::eyre::{Context, Ok, Result}; +use crossterm::event::KeyCode; use std::ffi::OsStr; use std::path::PathBuf; use std::process::{Command, Stdio}; @@ -82,7 +82,13 @@ impl App { } else if let Some(PopupKind::YankItem) | Some(PopupKind::OpenRes) = self.bibiman.popup_area.popup_kind { - self.bibiman.fast_selection(cfg, key_event.code)?; + self.bibiman.fast_selection(cfg, &mut tui, key_event.code)?; + // if a fast match char was used, restart event-loop. + // otherwise, the fast match char will be executed as command + match key_event.code { + KeyCode::Char('o' | 'l' | 'n' | 'y') => continue, + _ => {} + } } let command = if self.input_mode { CmdAction::Input(InputCmdAction::parse(key_event, &self.input)) @@ -186,7 +192,8 @@ impl App { } Some(PopupKind::OpenRes) | Some(PopupKind::AppendToFile) - | Some(PopupKind::YankItem) => { + | Some(PopupKind::YankItem) + | Some(PopupKind::CreateNote) => { self.bibiman.popup_area.popup_state.scroll_down_by(1) } _ => {} @@ -207,7 +214,8 @@ impl App { } Some(PopupKind::OpenRes) | Some(PopupKind::AppendToFile) - | Some(PopupKind::YankItem) => { + | Some(PopupKind::YankItem) + | Some(PopupKind::CreateNote) => { self.bibiman.popup_area.popup_state.scroll_up_by(1) } _ => {} @@ -267,6 +275,8 @@ impl App { self.bibiman.close_popup(); } else if let Some(PopupKind::YankItem) = self.bibiman.popup_area.popup_kind { self.bibiman.close_popup(); + } else if let Some(PopupKind::CreateNote) = self.bibiman.popup_area.popup_kind { + self.bibiman.close_popup(); } } else { self.bibiman.reset_current_list(); @@ -279,12 +289,14 @@ 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(cfg)?; + self.bibiman.open_connected_res(cfg, tui)?; } else if let Some(PopupKind::AppendToFile) = self.bibiman.popup_area.popup_kind { self.bibiman.append_entry_to_file(cfg)? } else if let Some(PopupKind::YankItem) = self.bibiman.popup_area.popup_kind { self.bibiman.yank_entry_field()? + } else if let Some(PopupKind::CreateNote) = self.bibiman.popup_area.popup_kind { + self.bibiman.create_note(cfg)? } } } @@ -305,13 +317,25 @@ impl App { .selected() .unwrap(); let entry = self.bibiman.entry_table.entry_table_items[idx].clone(); - let mut items = vec![("Citekey: ".to_string(), entry.citekey.clone())]; + let mut items = vec![( + "Citekey: ".to_string(), + entry.citekey.clone(), + PopupItem::Citekey, + )]; if entry.doi_url.is_some() { - items.push(("Weblink: ".into(), entry.doi_url.unwrap().clone())) + items.push(( + "Weblink: ".into(), + entry.doi_url.unwrap().clone(), + PopupItem::Link, + )) } if entry.filepath.is_some() { entry.filepath.unwrap().iter().for_each(|p| { - items.push(("Filepath: ".into(), p.clone().into_string().unwrap())) + items.push(( + "Filepath: ".into(), + p.clone().into_string().unwrap(), + PopupItem::Entryfile, + )) }); // items.push(( // "Filepath: ".into(), @@ -342,18 +366,20 @@ impl App { .selected() .unwrap(); let entry = self.bibiman.entry_table.entry_table_items[idx].clone(); - let mut items: Vec<(String, String)> = vec![]; - if entry.filepath.is_some() || entry.doi_url.is_some() { + let mut items: Vec<(String, String, PopupItem)> = vec![]; + if entry.filepath.is_some() || entry.doi_url.is_some() || entry.notes.is_some() + { if entry.doi_url.is_some() { items.push(( - "Weblink (DOI/URL): ".into(), + "Link: ".into(), entry.doi_url.unwrap().clone(), + PopupItem::Link, )) } if entry.filepath.is_some() { entry.filepath.unwrap().iter().for_each(|p| { items.push(( - "File (PDF/EPUB): ".into(), + "File: ".into(), // p.clone().into_string().unwrap(), if entry.file_field && cfg.general.file_prefix.is_some() { cfg.general @@ -367,9 +393,19 @@ impl App { } else { p.clone().into_string().unwrap() }, + PopupItem::Entryfile, )) }); } + if entry.notes.is_some() { + entry.notes.unwrap().iter().for_each(|n| { + items.push(( + "Note: ".into(), + n.clone().into_string().unwrap(), + PopupItem::Notefile, + )); + }); + } self.bibiman .open_popup(PopupKind::OpenRes, None, None, Some(items))?; @@ -389,6 +425,87 @@ impl App { self.bibiman.add_entry(); } } + CmdAction::CreateNote => { + if let CurrentArea::EntryArea = self.bibiman.current_area { + let citekey = self.bibiman.entry_table.entry_table_items[self + .bibiman + .entry_table + .entry_table_state + .selected() + .unwrap()] + .citekey + .clone(); + // disallow chars which can cause other shell executions + if citekey.contains("/") + | citekey.contains("|") + | citekey.contains("#") + | citekey.contains("\\") + | citekey.contains("*") + | citekey.contains("\"") + | citekey.contains(";") + | citekey.contains("!") + | citekey.contains("\'") + { + self.bibiman.open_popup( + PopupKind::MessageError, + Some("Selected entrys citekey contains special char: "), + Some(&citekey), + None, + )?; + } else if cfg.general.note_path.is_some() + && cfg.general.note_extensions.is_some() + && self.bibiman.entry_table.entry_table_items[self + .bibiman + .entry_table + .entry_table_state + .selected() + .unwrap()] + .notes + .is_none() + { + let mut items = vec![]; + for ex in cfg.general.note_extensions.as_ref().unwrap() { + items.push(( + self.bibiman.entry_table.entry_table_items[self + .bibiman + .entry_table + .entry_table_state + .selected() + .unwrap()] + .citekey() + .to_string(), + ex.clone(), + PopupItem::Notefile, + )); + } + self.bibiman + .open_popup(PopupKind::CreateNote, None, None, Some(items))?; + } else if cfg.general.note_path.is_some() + && self.bibiman.entry_table.entry_table_items[self + .bibiman + .entry_table + .entry_table_state + .selected() + .unwrap()] + .notes + .is_some() + { + self.bibiman.open_popup( + PopupKind::MessageError, + Some("Selected entry already has a connected note"), + None, + None, + )?; + } else { + self.bibiman.open_popup( + PopupKind::MessageError, + Some("No note path found. Set it in config file."), + None, + None, + )?; + } + } + } CmdAction::ShowHelp => { self.bibiman.open_popup(PopupKind::Help, None, None, None)?; } @@ -404,15 +521,6 @@ 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.pdf_opener; - // If necessary, replace ~ with /home dir - // let file = if cfg.general.file_prefix.is_some() { - // cfg.general.file_prefix.clone().unwrap().join(file) - // } else { - // PathBuf::from(file) - // }; - // let file = PathBuf::from(file); - - // let file = expand_home(&file).into_os_string(); // Pass filepath as argument, pipe stdout and stderr to /dev/null // to keep the TUI clean (where is it piped on Windows???) |
