diff options
Diffstat (limited to 'src/bibiman.rs')
| -rw-r--r-- | src/bibiman.rs | 233 |
1 files changed, 169 insertions, 64 deletions
diff --git a/src/bibiman.rs b/src/bibiman.rs index c90905f..ea9dbf5 100644 --- a/src/bibiman.rs +++ b/src/bibiman.rs @@ -15,6 +15,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. ///// +use crate::app::expand_home; use crate::bibiman::entries::EntryTableColumn; use crate::bibiman::{bibisetup::*, search::BibiSearch}; use crate::cliargs::CLIArgs; @@ -24,10 +25,11 @@ use crate::tui::Tui; use crate::{app, cliargs}; use crate::{bibiman::entries::EntryTable, bibiman::keywords::TagList}; use arboard::Clipboard; -use color_eyre::eyre::Result; +use color_eyre::eyre::{Error, Result}; use editor_command::EditorBuilder; use ratatui::widgets::ScrollbarState; use regex::Regex; +use std::ffi::OsString; use std::fs::{self, read_to_string}; use std::fs::{File, OpenOptions}; use std::io::Write; @@ -89,7 +91,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()); @@ -118,6 +120,7 @@ impl Bibiman { self.popup_area.popup_kind = Some(PopupKind::Help); } + /// Close all current popups and select former tab of main app pub fn close_popup(&mut self) { // Reset all popup fields to default values self.popup_area = PopupArea::default(); @@ -133,8 +136,112 @@ impl Bibiman { self.former_area = None; } - pub fn update_lists(&mut self) { - self.main_biblio = BibiSetup::new(&self.main_bibfiles); + /// Open a popup + /// + /// Necessary arguments are: + /// + /// - `popup_kind`: a valid value of the `PopupKind` `enum`. This determines the + /// further behaviour of the popup. + /// - `message`: A message shown in the popup. This is needed for the `PopupKind` + /// values `MessageConfirm` and `MessageError`. If not needed, set it to `None`. + /// - `object`: An object passed as `&str` which might explain the current popup + /// action. Its not needed, but very useful. Can be used with the `PopupKind` + /// values `MessageConfirm`, `MessageError` and `YankItem`. If not needed, set it + /// to `None`. + /// - `items`: A vector of items which are needed if a selectable list is rendered. + /// The vector consists of tuples including a pair of `String`. The second item of + /// the tuple is considered kind of an object which can be used e.g. to open + /// the given filepath etc. If not needed, set it to `None`. + /// + /// The function will panic if a needed argument for the particular `PopupKind` + /// is missing + pub fn open_popup( + &mut self, + popup_kind: PopupKind, + message: Option<&str>, + object: Option<&str>, + items: Option<Vec<(String, String)>>, + ) -> Result<()> { + if let CurrentArea::EntryArea = self.current_area { + self.former_area = Some(FormerArea::EntryArea); + } else if let CurrentArea::TagArea = self.current_area { + self.former_area = Some(FormerArea::TagArea); + } + self.popup_area.is_popup = true; + self.current_area = CurrentArea::PopupArea; + + match popup_kind { + PopupKind::Help => { + self.popup_area.popup_kind = Some(PopupKind::Help); + Ok(()) + } + PopupKind::MessageConfirm => { + self.popup_area.popup_kind = Some(PopupKind::MessageConfirm); + if object.is_some() && message.is_some() { + self.popup_area.popup_message = message.unwrap().to_owned() + object.unwrap(); + Ok(()) + } else if object.is_none() && message.is_some() { + self.popup_area.popup_message = message.unwrap().to_owned(); + Ok(()) + } else { + Err(Error::msg("You need to past at least a message via Some(&str) to create a message popup")) + } + } + PopupKind::MessageError => { + self.popup_area.popup_kind = Some(PopupKind::MessageError); + if object.is_some() && message.is_some() { + self.popup_area.popup_message = message.unwrap().to_owned() + object.unwrap(); + Ok(()) + } else if object.is_none() && message.is_some() { + self.popup_area.popup_message = message.unwrap().to_owned(); + Ok(()) + } else { + Err(Error::msg("You need to past at least a message via Some(&str) to create a message popup")) + } + } + PopupKind::OpenRes => { + if items.is_some() { + self.popup_area.popup_kind = Some(PopupKind::OpenRes); + self.popup_area.popup_selection(items.unwrap()); + self.popup_area.popup_state.select(Some(0)); + Ok(()) + } else { + Err(Error::msg( + "No Vec<(String, String)> passed as argument to generate the items list", + )) + } + } + PopupKind::AppendToFile => { + if items.is_some() { + self.popup_area.popup_kind = Some(PopupKind::AppendToFile); + Ok(()) + } else { + Err(Error::msg( + "No Vec<(String, String)> passed as argument to generate the items list", + )) + } + } + PopupKind::AddEntry => { + self.popup_area.popup_kind = Some(PopupKind::AddEntry); + Ok(()) + } + PopupKind::YankItem => { + if items.is_some() { + self.popup_area.popup_kind = Some(PopupKind::YankItem); + self.popup_area.popup_selection(items.unwrap()); + self.popup_area.popup_state.select(Some(0)); + Ok(()) + } else { + Err(Error::msg( + "No Vec<(String, String)> passed as argument to generate the items list", + )) + } + } + } + } + + 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 +504,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); @@ -418,7 +525,7 @@ impl Bibiman { ///the new entry via `append_to_file()` function. If not, show error popup /// ///The method needs two arguments: the CLIArgs struct and the `str` containing the DOI - pub fn handle_new_entry_submission(&mut self, doi_string: &str) { + pub fn handle_new_entry_submission(&mut self, doi_string: &str) -> Result<()> { let doi_string = if doi_string.starts_with("10.") { "https://doi.org/".to_string() + doi_string } else { @@ -442,31 +549,39 @@ impl Bibiman { self.current_area = CurrentArea::PopupArea; self.popup_area.popup_state.select(Some(0)) } else { - self.popup_area - .popup_message("Can't find DOI: ", &doi_string, false); + self.open_popup( + PopupKind::MessageError, + Some("Can't find DOI: "), + Some(&doi_string), + None, + )?; + // self.popup_area + // .popup_message("Can't find DOI: ", &doi_string, false); } + Ok(()) } pub fn append_to_file(&mut self) { - let mut items = vec!["Create new file".to_owned()]; + let mut items = vec![("Create new file".to_owned(), "".to_string())]; if self.main_bibfiles.len() > 1 { for f in self.main_bibfiles.clone() { - items.push(f.to_str().unwrap().to_owned()); + items.push(("File: ".into(), f.to_str().unwrap().to_owned())); } } else { - items.push( + items.push(( + "File: ".into(), self.main_bibfiles .first() .unwrap() .to_str() .unwrap() .to_owned(), - ); + )); } 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(); @@ -482,7 +597,10 @@ impl Bibiman { .to_string(); // Check if new file or existing file was choosen - let mut file = if self.popup_area.popup_list[popup_idx].contains("Create new file") { + let mut file = if self.popup_area.popup_list[popup_idx] + .0 + .contains("Create new file") + { let citekey = PathBuf::from(&citekey); // Get path of current files let path: PathBuf = if self.main_bibfiles[0].is_file() { @@ -535,7 +653,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 @@ -550,73 +668,60 @@ impl Bibiman { // Index of selected popup field let popup_idx = self.popup_area.popup_state.selected().unwrap(); + let popup_entry = self.popup_area.popup_list[popup_idx].1.clone(); // Choose ressource depending an selected popup field - if self.popup_area.popup_list[popup_idx].contains("Weblink") { + if self.popup_area.popup_list[popup_idx].0.contains("Weblink") { let object = self.entry_table.entry_table_items[entry_idx].doi_url(); 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(); - app::open_connected_file(cfg, object)?; + self.close_popup(); + } else if self.popup_area.popup_list[popup_idx].0.contains("File") { + // TODO: Selection for multiple files + // let object = self.entry_table.entry_table_items[entry_idx].filepath()[0]; + let file = expand_home(&PathBuf::from(popup_entry.clone())); + let object: OsString = popup_entry.into(); + if file.is_file() { + app::open_connected_file(cfg, &object)?; + self.close_popup(); + } else { + self.open_popup( + PopupKind::MessageError, + Some("No valid file path: "), + Some(object.to_str().unwrap()), + None, + )?; + } } else { eprintln!("Unable to find ressource to open"); }; // run command to open file/Url - self.close_popup(); Ok(()) } pub fn yank_entry_field(&mut self) -> Result<()> { - // Index of selected entry - let entry_idx = self.entry_table.entry_table_state.selected().unwrap(); - // Index of selected popup field let popup_idx = self.popup_area.popup_state.selected().unwrap(); + let popup_entry = self.popup_area.popup_list[popup_idx].1.clone(); - match self.popup_area.popup_list[popup_idx] + let kind = self.popup_area.popup_list[popup_idx] + .0 .to_lowercase() - .as_str() - { - "citekey" => { - let citekey = &self.entry_table.entry_table_items[entry_idx].citekey; - Bibiman::yank_text(citekey); - self.popup_area.popup_message( - "Yanked citekey to clipboard: ", - citekey, // self.bibiman.get_selected_citekey(), - true, - ); - } - "weblink" => { - let link = &self.entry_table.entry_table_items[entry_idx].doi_url; - if let Some(l) = link { - Bibiman::yank_text(l); - self.popup_area.popup_message( - "Yanked weblink to clipboard: ", - l, // self.bibiman.get_selected_link(), - true, - ); - } - } - "filepath" => { - let path = self.entry_table.entry_table_items[entry_idx] - .filepath - .clone(); - if let Some(p) = path { - let p = p.as_os_str().to_str(); - if let Some(p) = p { - Bibiman::yank_text(p); - self.popup_area.popup_message( - "Yanked filepath to clipboard: ", - p, // self.bibiman.get_selected_link(), - true, - ); - } - } - } - _ => {} - }; + .split(":") + .next() + .unwrap() + .to_owned(); + + let msg = format!("Yanked {} to clipboard: ", &kind); + + Bibiman::yank_text(&popup_entry); + self.open_popup( + PopupKind::MessageConfirm, + Some(&msg), + Some(&popup_entry), + None, + )?; Ok(()) } |
