aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs116
-rw-r--r--src/bibiman.rs288
-rw-r--r--src/main.rs4
-rw-r--r--src/tui/commands.rs10
-rw-r--r--src/tui/popup.rs10
-rw-r--r--src/tui/ui.rs59
6 files changed, 416 insertions, 71 deletions
diff --git a/src/app.rs b/src/app.rs
index 54d42b6..2240e8f 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -23,6 +23,7 @@ use crate::tui::commands::InputCmdAction;
use crate::tui::popup::PopupKind;
use crate::tui::{self, Tui};
use crate::{bibiman::Bibiman, tui::commands::CmdAction};
+use core::panic;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::{Command, Stdio};
@@ -58,7 +59,7 @@ impl App {
})
}
- pub async fn run(&mut self, args: &CLIArgs) -> Result<()> {
+ pub async fn run(&mut self, args: &mut CLIArgs) -> Result<()> {
let mut tui = tui::Tui::new()?;
tui.enter()?;
@@ -109,29 +110,61 @@ impl App {
self.running = false;
}
- pub fn run_command(&mut self, cmd: CmdAction, args: &CLIArgs, tui: &mut Tui) -> Result<()> {
+ pub fn run_command(&mut self, cmd: CmdAction, args: &mut CLIArgs, tui: &mut Tui) -> Result<()> {
match cmd {
CmdAction::Input(cmd) => match cmd {
InputCmdAction::Nothing => {}
InputCmdAction::Handle(event) => {
self.input.handle_event(&event);
- self.bibiman.search_list_by_pattern(&self.input);
+ if let CurrentArea::SearchArea = self.bibiman.current_area {
+ self.bibiman.search_list_by_pattern(&self.input);
+ }
}
InputCmdAction::Enter => {
self.input_mode = true;
// Logic for TABS to be added
- self.bibiman.enter_search_area();
+ // self.bibiman.enter_search_area();
}
InputCmdAction::Confirm => {
+ // Logic for TABS to be added
+ if let CurrentArea::SearchArea = self.bibiman.current_area {
+ self.bibiman.confirm_search();
+ } else if let CurrentArea::PopupArea = self.bibiman.current_area {
+ match self.bibiman.popup_area.popup_kind {
+ Some(PopupKind::AddEntry) => {
+ let doi = self.input.value();
+ self.bibiman.close_popup();
+ self.input_mode = false;
+ // Check if the DOI pattern is valid. If not, show warning and break
+ if doi.starts_with("10.")
+ || doi.starts_with("https://doi.org")
+ || doi.starts_with("https://dx.doi.org")
+ || doi.starts_with("http://doi.org")
+ || doi.starts_with("http://dx.doi.org")
+ {
+ self.bibiman.handle_new_entry_submission(args, doi);
+ } else {
+ self.bibiman.popup_area.popup_message(
+ "No valid DOI pattern: ",
+ doi,
+ false,
+ );
+ }
+ }
+ _ => {}
+ }
+ }
self.input = Input::default();
self.input_mode = false;
- // Logic for TABS to be added
- self.bibiman.confirm_search();
}
InputCmdAction::Exit => {
self.input = Input::default();
self.input_mode = false;
- self.bibiman.break_search();
+ if let CurrentArea::SearchArea = self.bibiman.current_area {
+ self.bibiman.break_search();
+ } else if let CurrentArea::PopupArea = self.bibiman.current_area {
+ self.bibiman.close_popup();
+ }
}
},
CmdAction::SelectNextRow(amount) => match self.bibiman.current_area {
@@ -142,13 +175,15 @@ impl App {
CurrentArea::TagArea => {
self.bibiman.select_next_tag(amount);
}
- CurrentArea::PopupArea => {
- if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind {
+ CurrentArea::PopupArea => match self.bibiman.popup_area.popup_kind {
+ Some(PopupKind::Help) => {
self.bibiman.popup_area.popup_scroll_down();
- } else if let Some(PopupKind::Selection) = self.bibiman.popup_area.popup_kind {
+ }
+ Some(PopupKind::OpenRes) | Some(PopupKind::AppendToFile) => {
self.bibiman.popup_area.popup_state.scroll_down_by(1)
}
- }
+ _ => {}
+ },
_ => {}
},
CmdAction::SelectPrevRow(amount) => match self.bibiman.current_area {
@@ -159,13 +194,15 @@ impl App {
CurrentArea::TagArea => {
self.bibiman.select_previous_tag(amount);
}
- CurrentArea::PopupArea => {
- if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind {
+ CurrentArea::PopupArea => match self.bibiman.popup_area.popup_kind {
+ Some(PopupKind::Help) => {
self.bibiman.popup_area.popup_scroll_up();
- } else if let Some(PopupKind::Selection) = self.bibiman.popup_area.popup_kind {
+ }
+ Some(PopupKind::OpenRes) | Some(PopupKind::AppendToFile) => {
self.bibiman.popup_area.popup_state.scroll_up_by(1)
}
- }
+ _ => {}
+ },
_ => {}
},
CmdAction::SelectNextCol => {
@@ -205,14 +242,20 @@ impl App {
CmdAction::ToggleArea => {
self.bibiman.toggle_area();
}
- CmdAction::SearchList => {}
+ CmdAction::SearchList => {
+ self.input_mode = true;
+ self.bibiman.enter_search_area();
+ }
CmdAction::Reset => {
if let CurrentArea::PopupArea = self.bibiman.current_area {
if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind {
self.bibiman.popup_area.popup_scroll_pos = 0;
self.bibiman.close_popup()
- } else if let Some(PopupKind::Selection) = self.bibiman.popup_area.popup_kind {
+ } else if let Some(PopupKind::OpenRes) = self.bibiman.popup_area.popup_kind {
self.bibiman.close_popup()
+ } else if let Some(PopupKind::AppendToFile) = self.bibiman.popup_area.popup_kind
+ {
+ self.bibiman.close_popup();
}
} else {
self.bibiman.reset_current_list();
@@ -224,33 +267,11 @@ impl App {
} else if let CurrentArea::PopupArea = self.bibiman.current_area {
if let Some(PopupKind::Help) = self.bibiman.popup_area.popup_kind {
self.bibiman.close_popup();
- } else if let Some(PopupKind::Selection) = self.bibiman.popup_area.popup_kind {
- // Index of selected entry
- let entry_idx = self
- .bibiman
- .entry_table
- .entry_table_state
- .selected()
- .unwrap();
-
- // Index of selected popup field
- let popup_idx = self.bibiman.popup_area.popup_state.selected().unwrap();
-
- // Choose ressource depending an selected popup field
- if self.bibiman.popup_area.popup_list[popup_idx].contains("Weblink") {
- let object =
- self.bibiman.entry_table.entry_table_items[entry_idx].doi_url();
- let url = prepare_weblink(object);
- open_connected_link(&url)?;
- } else if self.bibiman.popup_area.popup_list[popup_idx].contains("File") {
- let object =
- self.bibiman.entry_table.entry_table_items[entry_idx].filepath();
- open_connected_file(object)?;
- } else {
- eprintln!("Unable to find ressource to open");
- };
- // run command to open file/Url
- self.bibiman.close_popup()
+ } else if let Some(PopupKind::OpenRes) = self.bibiman.popup_area.popup_kind {
+ self.bibiman.open_connected_res()?;
+ } else if let Some(PopupKind::AppendToFile) = self.bibiman.popup_area.popup_kind
+ {
+ self.bibiman.append_entry_to_file(args)?
}
}
}
@@ -299,6 +320,7 @@ impl App {
if entry.filepath.is_some() {
items.push("File (PDF/EPUB)".to_owned())
}
+ self.bibiman.popup_area.popup_kind = Some(PopupKind::OpenRes);
self.bibiman.popup_area.popup_selection(items);
self.bibiman.former_area = Some(FormerArea::EntryArea);
self.bibiman.current_area = CurrentArea::PopupArea;
@@ -312,6 +334,12 @@ impl App {
}
}
}
+ CmdAction::AddEntry => {
+ if let CurrentArea::EntryArea = self.bibiman.current_area {
+ self.input_mode = true;
+ self.bibiman.add_entry();
+ }
+ }
CmdAction::ShowHelp => {
self.bibiman.show_help();
}
diff --git a/src/bibiman.rs b/src/bibiman.rs
index bba3eec..0c0d99b 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;
use crate::bibiman::entries::EntryTableColumn;
use crate::bibiman::{bibisetup::*, search::BibiSearch};
use crate::cliargs::CLIArgs;
@@ -22,11 +23,17 @@ use crate::tui::popup::{PopupArea, PopupKind};
use crate::tui::Tui;
use crate::{bibiman::entries::EntryTable, bibiman::keywords::TagList};
use arboard::Clipboard;
-use color_eyre::eyre::{Ok, Result};
+use color_eyre::eyre::Result;
use editor_command::EditorBuilder;
+use futures::executor::block_on;
use ratatui::widgets::ScrollbarState;
+use regex::Regex;
use std::fs;
+use std::fs::{File, OpenOptions};
+use std::io::Write;
+use std::path::PathBuf;
use std::process::Command;
+use std::result::Result::Ok;
use tui_input::Input;
pub mod bibisetup;
@@ -107,6 +114,48 @@ impl Bibiman {
self.popup_area.popup_kind = Some(PopupKind::Help);
}
+ pub fn add_entry(&mut self) {
+ if let CurrentArea::EntryArea = self.current_area {
+ self.former_area = Some(FormerArea::EntryArea);
+ }
+ self.popup_area.is_popup = true;
+ self.current_area = CurrentArea::PopupArea;
+ self.popup_area.popup_kind = Some(PopupKind::AddEntry);
+ }
+
+ ///Try to resolve entered DOI. If successfull, choose file where to append
+ ///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, args: &CLIArgs, doi_string: &str) {
+ let doi_string = if doi_string.starts_with("10.") {
+ "https://doi.org/".to_string() + doi_string
+ } else {
+ doi_string.to_owned()
+ };
+
+ // Send GET request to doi resolver
+ let doi_entry = ureq::get(&doi_string)
+ .set("Accept", "application/x-bibtex")
+ .call();
+
+ if let Ok(entry) = doi_entry {
+ // Save generated bibtex entry in structs field
+ let entry = entry
+ .into_string()
+ .expect("Couldn't parse fetched entry into string");
+ self.popup_area.popup_sel_item = entry;
+ self.popup_area.popup_kind = Some(PopupKind::AppendToFile);
+ self.append_to_file(args);
+ self.former_area = Some(FormerArea::EntryArea);
+ 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);
+ }
+ }
+
pub fn close_popup(&mut self) {
// Reset all popup fields to default values
self.popup_area = PopupArea::default();
@@ -299,6 +348,26 @@ impl Bibiman {
}
}
+ pub fn select_entry_by_citekey(&mut self, citekey: &str) {
+ // Search for entry by matching citekeys
+ let mut idx_count = 0;
+ loop {
+ if idx_count == self.entry_table.entry_table_items.len() {
+ idx_count = 0;
+ break;
+ } else if self.entry_table.entry_table_items[idx_count]
+ .citekey
+ .contains(citekey)
+ {
+ break;
+ }
+ idx_count += 1
+ }
+
+ // Set selected entry to vec-index of match
+ self.entry_table.entry_table_state.select(Some(idx_count));
+ }
+
pub fn run_editor(&mut self, args: &CLIArgs, tui: &mut Tui) -> Result<()> {
// get filecontent and citekey for calculating line number
let citekey: &str = &self.entry_table.entry_table_items
@@ -367,25 +436,205 @@ impl Bibiman {
// Update the database and the lists to show changes
Self::update_lists(self, args);
- // Search for entry, selected before editing, by matching citekeys
- // Use earlier saved copy of citekey to match
- let mut idx_count = 0;
- loop {
- if self.entry_table.entry_table_items[idx_count]
- .citekey
- .contains(citekey)
- {
- break;
+ // Select entry which was selected before entering editor
+ self.select_entry_by_citekey(citekey);
+
+ Ok(())
+ }
+
+ pub fn append_to_file(&mut self, args: &CLIArgs) {
+ let mut items = vec!["Create new file".to_owned()];
+ if args.files.len() > 1 {
+ for f in args.files.clone() {
+ items.push(f.to_str().unwrap().to_owned());
}
- idx_count += 1
+ } else {
+ items.push(args.files.first().unwrap().to_str().unwrap().to_owned());
}
+ self.popup_area.popup_selection(items);
+ }
- // Set selected entry to vec-index of match
- self.entry_table.entry_table_state.select(Some(idx_count));
+ pub fn append_entry_to_file(&mut self, args: &mut CLIArgs) -> Result<()> {
+ // Index of selected popup field
+ let popup_idx = self.popup_area.popup_state.selected().unwrap();
+
+ // regex pattern to match citekey in fetched bibtexstring
+ let pattern = Regex::new(r"\{([^\{\},]*),").unwrap();
+
+ let citekey = pattern
+ .captures(&self.popup_area.popup_sel_item)
+ .unwrap()
+ .get(1)
+ .unwrap()
+ .as_str()
+ .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 citekey = PathBuf::from(&citekey);
+ // Get path of current files
+ let path: PathBuf = if args.files[0].is_file() {
+ args.files[0].parent().unwrap().to_owned()
+ } else {
+ dirs::home_dir().unwrap() // home dir as fallback
+ };
+
+ let citekey = citekey.with_extension("bib");
+
+ let newfile = path.join(citekey);
+
+ args.files.push(newfile.clone());
+
+ File::create_new(newfile).unwrap()
+ } else {
+ let file_path = &args.files[popup_idx - 1];
+ OpenOptions::new().append(true).open(file_path).unwrap()
+ };
+ // Optionally, add a newline before the content
+ file.write_all(b"\n")?;
+ // 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(args);
+ self.close_popup();
+
+ // Select newly created entry
+ self.select_entry_by_citekey(&citekey);
+
+ Ok(())
+ }
+
+ pub fn open_connected_res(&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();
+
+ // Choose ressource depending an selected popup field
+ if self.popup_area.popup_list[popup_idx].contains("Weblink") {
+ let object = self.entry_table.entry_table_items[entry_idx].doi_url();
+ let url = app::prepare_weblink(object);
+ app::open_connected_link(&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(object)?;
+ } else {
+ eprintln!("Unable to find ressource to open");
+ };
+ // run command to open file/Url
+ self.close_popup();
Ok(())
}
+ /// Formats a raw BibTeX entry string for better readability.
+ pub fn format_bibtex_entry(entry: &str, file_path: &str) -> String {
+ let mut formatted = String::new();
+
+ // Find the position of the first '{'
+ if let Some(start_brace_pos) = entry.find('{') {
+ // Extract the preamble (e.g., '@article{')
+ let preamble = &entry[..start_brace_pos + 1];
+ let preamble = preamble.trim_start();
+ formatted.push_str(preamble);
+ // formatted.push('\n'); // Add newline
+
+ // Get the content inside the braces
+ let rest = &entry[start_brace_pos + 1..];
+ // Remove the last '}' at the end, if present
+ let rest = rest.trim_end();
+ let rest = if rest.ends_with('}') {
+ &rest[..rest.len() - 1]
+ } else {
+ rest
+ };
+
+ // Parse the fields, considering braces and quotes
+ let mut fields = Vec::new();
+ let mut current_field = String::new();
+ let mut brace_level = 0;
+ let mut in_quotes = false;
+ for c in rest.chars() {
+ match c {
+ '{' if !in_quotes => {
+ brace_level += 1;
+ current_field.push(c);
+ }
+ '}' if !in_quotes => {
+ brace_level -= 1;
+ current_field.push(c);
+ }
+ '"' => {
+ in_quotes = !in_quotes;
+ current_field.push(c);
+ }
+ ',' if brace_level == 0 && !in_quotes => {
+ // Outside of braces and quotes, comma separates fields
+ fields.push(current_field.trim().to_string());
+ current_field.clear();
+ }
+ _ => {
+ current_field.push(c);
+ }
+ }
+ }
+ // Add the last field
+ if !current_field.trim().is_empty() {
+ fields.push(current_field.trim().to_string());
+ }
+
+ // **Conditionally Clean the Citation Key**
+ if let Some(citation_key) = fields.get_mut(0) {
+ // Check if the citation key contains any non-alphanumerical characters except underscores
+ let needs_cleaning = citation_key
+ .chars()
+ .any(|c| !c.is_alphanumeric() && c != '_');
+ if needs_cleaning {
+ // Retain only alphanumerical characters and underscores
+ let cleaned_key: String = citation_key
+ .chars()
+ .filter(|c| c.is_alphanumeric() || *c == '_')
+ .collect();
+ // If the cleaned key is longer than 14 characters, retain only the last 14
+ let limited_key = if cleaned_key.len() > 14 {
+ cleaned_key
+ .chars()
+ .rev()
+ .take(14)
+ .collect::<String>()
+ .chars()
+ .rev()
+ .collect()
+ } else {
+ cleaned_key
+ };
+ // Replace the original citation key with the cleaned and possibly limited key
+ *citation_key = limited_key;
+ }
+ }
+
+ // Add the new 'file' field
+ let file_field = format!("file = {{{}}}", file_path);
+ fields.push(file_field);
+
+ // Reconstruct the entry with proper indentation
+ for (i, field) in fields.iter().enumerate() {
+ formatted.push_str(" ");
+ formatted.push_str(field);
+ // Add a comma if it's not the last field
+ if i < fields.len() - 1 {
+ formatted.push(',');
+ }
+ formatted.push('\n');
+ }
+ formatted.push('}'); // Close the entry
+ formatted
+ } else {
+ // No opening brace found, return the entry as is
+ entry.to_string()
+ }
+ }
// Search entry list
pub fn search_entries(&mut self) {
// Use snapshot of entry list saved when starting the search
@@ -594,7 +843,7 @@ impl Bibiman {
#[cfg(test)]
mod tests {
- // use super::*;
+ use super::*;
#[test]
fn citekey_pattern() {
@@ -602,4 +851,15 @@ mod tests {
assert_eq!(citekey, "{a_key_2001,")
}
+
+ #[test]
+ fn regex_capture_citekey() {
+ let re = Regex::new(r"\{([^\{\},]*),").unwrap();
+
+ let bibstring = String::from("@article{citekey77_2001:!?, author = {Hanks, Tom}, title = {A great book}, year = {2001}}");
+
+ let result = re.captures(&bibstring).unwrap();
+
+ assert_eq!(result.get(1).unwrap().as_str(), "citekey77_2001:!?")
+ }
}
diff --git a/src/main.rs b/src/main.rs
index b1160e2..78c5075 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -29,7 +29,7 @@ pub mod tui;
#[tokio::main]
async fn main() -> Result<()> {
// Parse CLI arguments
- let parsed_args = CLIArgs::parse_args().unwrap();
+ let mut parsed_args = CLIArgs::parse_args().unwrap();
// Print help if -h/--help flag is passed and exit
if parsed_args.helparg {
@@ -48,6 +48,6 @@ async fn main() -> Result<()> {
// Create an application.
let mut app = App::new(&parsed_args)?;
- app.run(&parsed_args).await?;
+ app.run(&mut parsed_args).await?;
Ok(())
}
diff --git a/src/tui/commands.rs b/src/tui/commands.rs
index a3049ee..0e00f95 100644
--- a/src/tui/commands.rs
+++ b/src/tui/commands.rs
@@ -69,6 +69,8 @@ pub enum CmdAction {
Exit,
// Show keybindings
ShowHelp,
+ // Add new entry
+ AddEntry,
// Do nothing.
Nothing,
}
@@ -110,7 +112,6 @@ impl From<KeyEvent> for CmdAction {
Self::SelectPrevRow(5)
} else {
Self::Nothing
- // Self::Open(OpenRessource::WebLink)
}
}
// Scroll info/preview area
@@ -118,6 +119,8 @@ impl From<KeyEvent> for CmdAction {
KeyCode::PageUp => Self::ScrollInfoUp,
// Exit App
KeyCode::Char('q') => Self::Exit,
+ // Add new entry
+ KeyCode::Char('a') => Self::AddEntry,
KeyCode::Char('c') | KeyCode::Char('C') => {
if key_event.modifiers == KeyModifiers::CONTROL {
Self::Exit
@@ -129,15 +132,14 @@ impl From<KeyEvent> for CmdAction {
KeyCode::Tab => Self::ToggleArea,
KeyCode::BackTab => Self::ToggleArea,
// Enter search mode
- KeyCode::Char('/') => Self::Input(InputCmdAction::Enter),
+ KeyCode::Char('/') => Self::SearchList,
KeyCode::Char('f') => {
if key_event.modifiers == KeyModifiers::CONTROL {
- Self::Input(InputCmdAction::Enter)
+ Self::SearchList
} else {
Self::Nothing
}
}
- // KeyCode::Backspace => Self::Input(InputCommand::Resume(Event::Key(key_event))),
// Confirm selection
KeyCode::Enter => Self::Confirm,
// Reset lists/tables
diff --git a/src/tui/popup.rs b/src/tui/popup.rs
index 890e5c8..78a0719 100644
--- a/src/tui/popup.rs
+++ b/src/tui/popup.rs
@@ -28,7 +28,9 @@ pub enum PopupKind {
Help,
MessageConfirm,
MessageError,
- Selection,
+ OpenRes,
+ AppendToFile,
+ AddEntry,
}
#[derive(Debug, Default)]
@@ -39,6 +41,9 @@ pub struct PopupArea {
pub popup_scroll_pos: u16,
pub popup_list: Vec<String>,
pub popup_state: ListState,
+ pub popup_sel_item: String,
+ // pub add_entry_input: String,
+ // pub add_entry_cursor_position: usize,
}
impl PopupArea {
@@ -60,6 +65,7 @@ impl PopupArea {
("e: ", "Open editor at selected entry"),
("o: ", "Open with selected entry associated PDF"),
("u: ", "Open DOI/URL of selected entry"),
+ ("a: ", "Add new entry"),
("ESC: ", "Reset all lists"),
("Keyword List", "sub"),
("j,k|↓,↑: ", "Select next/previous item"),
@@ -119,7 +125,7 @@ impl PopupArea {
pub fn popup_selection(&mut self, items: Vec<String>) {
self.popup_list = items;
- self.popup_kind = Some(PopupKind::Selection);
+ // self.popup_kind = Some(PopupKind::SelectRes);
self.is_popup = true;
}
diff --git a/src/tui/ui.rs b/src/tui/ui.rs
index cca87ce..4f64338 100644
--- a/src/tui/ui.rs
+++ b/src/tui/ui.rs
@@ -181,6 +181,46 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) {
frame.render_widget(Clear, popup_area);
frame.render_widget(par, popup_area)
}
+
+ Some(PopupKind::AddEntry) => {
+ let area = frame.area();
+
+ let block = Block::bordered()
+ .title_top(" Add Entry ".bold())
+ .title_bottom(" (ESC) ━ (ENTER) ".bold())
+ .title_alignment(Alignment::Center)
+ .style(
+ Style::new()
+ .fg(Color::Indexed(args.colors.main_text_color))
+ .bg(Color::Indexed(args.colors.popup_bg_color)),
+ )
+ .border_set(symbols::border::THICK)
+ .border_style(Style::new().fg(Color::Indexed(args.colors.entry_color)));
+
+ // Prepare the input fields
+ let content = vec![Line::from(vec![
+ Span::styled(
+ "DOI: ",
+ Style::new().fg(Color::Indexed(args.colors.entry_color)),
+ ),
+ Span::raw(app.input.value().to_string().clone()),
+ ])];
+ let paragraph = Paragraph::new(content)
+ .block(block.clone())
+ .style(Style::new().fg(Color::Indexed(args.colors.main_text_color)))
+ .wrap(Wrap { trim: false });
+
+ let doi_lines = paragraph.line_count(area.width / 2);
+ // Calculate popup size
+ let popup_width = area.width / 4 * 3;
+ let popup_height = doi_lines as u16; // Adjust as needed
+ let popup_area = popup_area(area, popup_width, popup_height);
+
+ // Render the popup
+ frame.render_widget(Clear, popup_area);
+ render_cursor(app, frame, popup_area, 6, doi_lines as u16 - 1);
+ frame.render_widget(paragraph, popup_area);
+ }
Some(PopupKind::MessageConfirm) => {
let area = frame.area();
@@ -243,7 +283,7 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) {
frame.render_widget(Clear, popup_area);
frame.render_widget(&content, popup_area)
}
- Some(PopupKind::Selection) => {
+ Some(PopupKind::OpenRes) | Some(PopupKind::AppendToFile) => {
let list_items: Vec<ListItem> = app
.bibiman
.popup_area
@@ -252,8 +292,16 @@ pub fn render_popup(app: &mut App, args: &CLIArgs, frame: &mut Frame) {
.map(|item| ListItem::from(item.to_owned()))
.collect();
+ let title = if let Some(PopupKind::OpenRes) = app.bibiman.popup_area.popup_kind {
+ " Open "
+ } else if let Some(PopupKind::AppendToFile) = app.bibiman.popup_area.popup_kind {
+ " Select file to append entry "
+ } else {
+ " Select "
+ };
+
let block = Block::bordered()
- .title_top(" Open ".bold())
+ .title_top(title.bold())
.title_bottom(" (j,k|↓,↑) ━ (ENTER) ━ (ESC) ".bold())
.title_alignment(Alignment::Center)
.style(
@@ -327,7 +375,7 @@ pub fn render_footer(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Rec
]))
.block(block);
- render_cursor(app, frame, rect, title_lenght + 1);
+ render_cursor(app, frame, rect, title_lenght + 1, 1);
frame.render_widget(search_string, rect);
}
@@ -986,12 +1034,13 @@ pub fn render_taglist(app: &mut App, args: &CLIArgs, frame: &mut Frame, rect: Re
}
/// Render the cursor when in InputMode
-fn render_cursor(app: &mut App, frame: &mut Frame, area: Rect, x_offset: u16) {
+fn render_cursor(app: &mut App, frame: &mut Frame, area: Rect, x_offset: u16, y_offset: u16) {
let scroll = app.input.visual_scroll(area.width as usize);
if app.input_mode {
let (x, y) = (
area.x + ((app.input.visual_cursor()).max(scroll) - scroll) as u16 + x_offset,
- area.bottom().saturating_sub(1),
+ // area.bottom().saturating_sub(1) + y_offset,
+ area.bottom().saturating_sub(y_offset),
);
frame.render_widget(
Clear,