aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--devbox.json.back26
-rw-r--r--devbox.lock4
-rw-r--r--src/app.rs73
-rw-r--r--src/bibiman.rs28
-rw-r--r--src/tui/commands.rs4
-rw-r--r--src/tui/popup.rs4
-rw-r--r--src/tui/ui.rs49
8 files changed, 183 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 42009cb..ba75650 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,5 +7,6 @@
res/*.gif
res/*.png
.direnv
+.devbox
.envrc
devbox.json
diff --git a/devbox.json.back b/devbox.json.back
new file mode 100644
index 0000000..ff6dc1e
--- /dev/null
+++ b/devbox.json.back
@@ -0,0 +1,26 @@
+{
+ "packages": [
+ "rustup@latest",
+ "libiconv@latest",
+ "openssl@latest"
+ ],
+ "shell": {
+ "init_hook": [
+ "projectDir=$PWD/.devbox",
+ "echo $projectDir",
+ "rustupHomeDir=\"$projectDir\"/.rustup",
+ "mkdir -p $rustupHomeDir",
+ "export RUSTUP_HOME=$rustupHomeDir",
+ "export LIBRARY_PATH=$LIBRARY_PATH:\"$projectDir/nix/profile/default/lib\"",
+ "rustup default stable",
+ "rustup component add rust-src",
+ "rustup component add rust-analyzer",
+ "cargo fetch"
+ ],
+ "scripts": {
+ "test": "cargo test -- --show-output",
+ "start": "cargo run",
+ "build-docs": "cargo doc"
+ }
+ }
+}
diff --git a/devbox.lock b/devbox.lock
new file mode 100644
index 0000000..4206f37
--- /dev/null
+++ b/devbox.lock
@@ -0,0 +1,4 @@
+{
+ "lockfile_version": "1",
+ "packages": {}
+}
diff --git a/src/app.rs b/src/app.rs
index 54d42b6..ae45355 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 ratatui::crossterm::event::KeyCode;
use std::ffi::OsStr;
use std::path::PathBuf;
use std::process::{Command, Stdio};
@@ -78,14 +79,71 @@ impl App {
} else if let Some(PopupKind::MessageError) = self.bibiman.popup_area.popup_kind
{
self.bibiman.close_popup()
- }
- let command = if self.input_mode {
- CmdAction::Input(InputCmdAction::parse(key_event, &self.input))
+ } else if let Some(PopupKind::AddEntry) = self.bibiman.popup_area.popup_kind {
+ // Handle key events for AddEntry popup
+ match key_event.code {
+ KeyCode::Char(c) => {
+ let index = self.bibiman.popup_area.add_entry_cursor_position;
+ self.bibiman.popup_area.add_entry_input.insert(index, c);
+ self.bibiman.popup_area.add_entry_cursor_position += 1;
+ }
+ KeyCode::Backspace => {
+ if self.bibiman.popup_area.add_entry_cursor_position > 0 {
+ self.bibiman.popup_area.add_entry_cursor_position -= 1;
+ let index = self.bibiman.popup_area.add_entry_cursor_position;
+ self.bibiman.popup_area.add_entry_input.remove(index);
+ }
+ }
+ KeyCode::Left => {
+ if self.bibiman.popup_area.add_entry_cursor_position > 0 {
+ self.bibiman.popup_area.add_entry_cursor_position -= 1;
+ }
+ }
+ KeyCode::Right => {
+ if self.bibiman.popup_area.add_entry_cursor_position
+ < self.bibiman.popup_area.add_entry_input.len()
+ {
+ self.bibiman.popup_area.add_entry_cursor_position += 1;
+ }
+ }
+ KeyCode::Enter => {
+ // Handle submission of the new entry
+ self.bibiman.handle_new_entry_submission();
+ self.bibiman.close_popup();
+ self.input_mode = false;
+ }
+ KeyCode::Esc => {
+ // Close the popup without saving
+ self.bibiman.close_popup();
+ self.input_mode = false;
+ }
+ _ => {}
+ }
} else {
- CmdAction::from(key_event)
- };
- self.run_command(command, args, &mut tui)?
+ let command = if self.input_mode {
+ CmdAction::Input(InputCmdAction::parse(key_event, &self.input))
+ } else {
+ CmdAction::from(key_event)
+ };
+ self.run_command(command, args, &mut tui)?
+ }
}
+ // Event::Key(key_event) => {
+ // // Automatically close message popups on next keypress
+ // if let Some(PopupKind::MessageConfirm) = self.bibiman.popup_area.popup_kind {
+ // self.bibiman.close_popup()
+ // } else if let Some(PopupKind::MessageError) = self.bibiman.popup_area.popup_kind
+ // {
+ // self.bibiman.close_popup()
+ // }
+
+ // let command = if self.input_mode {
+ // CmdAction::Input(InputCmdAction::parse(key_event, &self.input))
+ // } else {
+ // CmdAction::from(key_event)
+ // };
+ // self.run_command(command, args, &mut tui)?
+ // }
Event::Mouse(mouse_event) => {
self.run_command(CmdAction::from(mouse_event), args, &mut tui)?
}
@@ -312,6 +370,9 @@ impl App {
}
}
}
+ CmdAction::AddEntry => {
+ self.bibiman.add_entry();
+ }
CmdAction::ShowHelp => {
self.bibiman.show_help();
}
diff --git a/src/bibiman.rs b/src/bibiman.rs
index bba3eec..ee52207 100644
--- a/src/bibiman.rs
+++ b/src/bibiman.rs
@@ -23,10 +23,13 @@ use crate::tui::Tui;
use crate::{bibiman::entries::EntryTable, bibiman::keywords::TagList};
use arboard::Clipboard;
use color_eyre::eyre::{Ok, Result};
+use doi2bib;
use editor_command::EditorBuilder;
+use futures::executor::block_on;
use ratatui::widgets::ScrollbarState;
use std::fs;
use std::process::Command;
+use std::result::Result::Ok as AOk;
use tui_input::Input;
pub mod bibisetup;
@@ -107,6 +110,31 @@ 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);
+ } 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;
+ self.popup_area.popup_kind = Some(PopupKind::AddEntry);
+ }
+
+ pub fn handle_new_entry_submission(&mut self) {
+ let new_entry_title = self.popup_area.add_entry_input.trim();
+ let doi2bib = doi2bib::Doi2Bib::new().unwrap();
+ let new_entry_future = doi2bib.resolve_doi(new_entry_title);
+ let new_entry = block_on(new_entry_future);
+
+ if let AOk(entry) = new_entry {
+ println!("New entry: {:?}", entry);
+ // Add logic here to integrate the new entry into your application
+ } else {
+ self.popup_area.popup_kind = Some(PopupKind::MessageError);
+ self.popup_area.popup_message = "Failed to add new entry".to_string();
+ }
+ }
pub fn close_popup(&mut self) {
// Reset all popup fields to default values
self.popup_area = PopupArea::default();
diff --git a/src/tui/commands.rs b/src/tui/commands.rs
index a3049ee..626b11b 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,
}
@@ -118,6 +120,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
diff --git a/src/tui/popup.rs b/src/tui/popup.rs
index 890e5c8..9b91801 100644
--- a/src/tui/popup.rs
+++ b/src/tui/popup.rs
@@ -29,6 +29,7 @@ pub enum PopupKind {
MessageConfirm,
MessageError,
Selection,
+ AddEntry,
}
#[derive(Debug, Default)]
@@ -39,6 +40,8 @@ pub struct PopupArea {
pub popup_scroll_pos: u16,
pub popup_list: Vec<String>,
pub popup_state: ListState,
+ pub add_entry_input: String,
+ pub add_entry_cursor_position: usize,
}
impl PopupArea {
@@ -48,6 +51,7 @@ impl PopupArea {
("TAB: ", "Toggle areas (Entries, Keywords)"),
("/|Ctrl+f: ", "Enter search mode"),
("q|Ctrl+c: ", "Quit bibiman"),
+ ("a: ", "Add new entry"),
("?: ", "Show help"),
("Entry Table", "sub"),
("j,k|↓,↑: ", "Select next/previous entry"),
diff --git a/src/tui/ui.rs b/src/tui/ui.rs
index cca87ce..8d7498a 100644
--- a/src/tui/ui.rs
+++ b/src/tui/ui.rs
@@ -181,6 +181,55 @@ 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)),
+ )]),
+ Line::from(app.bibiman.popup_area.add_entry_input.clone()),
+ ];
+ let paragraph = Paragraph::new(content)
+ .block(block.clone())
+ .style(Style::new().fg(Color::Indexed(args.colors.main_text_color)))
+ .wrap(Wrap { trim: false });
+
+ // Calculate popup size
+ let popup_width = area.width / 2;
+ let popup_height = 5; // Adjust as needed
+ let popup_area = popup_area(area, popup_width, popup_height);
+
+ // Render the popup
+ frame.render_widget(Clear, popup_area);
+ frame.render_widget(paragraph, popup_area);
+
+ // Set the cursor position
+ if app.input_mode {
+ // Calculate cursor x and y
+ let input_prefix_len = "Title: ".len() as u16 + 1; // +1 for padding
+ let cursor_x = popup_area.x
+ + input_prefix_len
+ + app.bibiman.popup_area.add_entry_cursor_position as u16;
+ let cursor_y = popup_area.y + 1; // Line after 'Title: '
+ frame.set_cursor_position(Position::new(cursor_x, cursor_y));
+ }
+ }
Some(PopupKind::MessageConfirm) => {
let area = frame.area();