aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorlukeflo2024-10-20 18:14:40 +0200
committerlukeflo2024-10-20 18:14:40 +0200
commit0c1232fe6d54cf3592d0bf9b5ae29bf048f5444c (patch)
tree675710467f814f611c416b56730a8760c9a15349 /src/frontend
parent730055489a660b0cdff950f6c7037fe7a07545ae (diff)
parent735264bb3d673c943e2e8c4898dba0609f49b3f4 (diff)
downloadbibiman-0c1232fe6d54cf3592d0bf9b5ae29bf048f5444c.tar.gz
bibiman-0c1232fe6d54cf3592d0bf9b5ae29bf048f5444c.zip
Merge branch 'sorting-by-column'
- Column selection for sorting - Jump up/down multiple entries in a list
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/entries.rs88
-rw-r--r--src/frontend/handler.rs49
-rw-r--r--src/frontend/keywords.rs8
-rw-r--r--src/frontend/ui.rs101
4 files changed, 192 insertions, 54 deletions
diff --git a/src/frontend/entries.rs b/src/frontend/entries.rs
index 6c227df..d5b0d8c 100644
--- a/src/frontend/entries.rs
+++ b/src/frontend/entries.rs
@@ -24,11 +24,20 @@ use editor_command::EditorBuilder;
use ratatui::widgets::{ScrollbarState, TableState};
use std::process::{Command, Stdio};
+#[derive(Debug)]
+pub enum EntryTableColumn {
+ Authors,
+ Title,
+ Year,
+ Pubtype,
+}
+
// Define list containing entries as table
#[derive(Debug)]
pub struct EntryTable {
pub entry_table_items: Vec<EntryTableItem>,
pub entry_table_at_search_start: Vec<EntryTableItem>,
+ pub entry_table_selected_column: EntryTableColumn,
pub entry_table_reversed_sort: bool,
pub entry_table_state: TableState,
pub entry_scroll_state: ScrollbarState,
@@ -45,6 +54,7 @@ impl EntryTable {
Self {
entry_table_items,
entry_table_at_search_start: Vec::new(),
+ entry_table_selected_column: EntryTableColumn::Authors,
entry_table_reversed_sort: false,
entry_table_state,
entry_scroll_state,
@@ -76,35 +86,39 @@ impl EntryTable {
// Sort entry table by specific column.
// Toggle sorting by hitting same key again
- pub fn sort_entry_table(&mut self, sorting: &str, toggle: bool) {
+ pub fn sort_entry_table(&mut self, toggle: bool) {
if toggle {
self.entry_table_reversed_sort = !self.entry_table_reversed_sort;
}
if self.entry_table_reversed_sort {
- match sorting {
- "author" => self
+ match self.entry_table_selected_column {
+ EntryTableColumn::Authors => self
.entry_table_items
.sort_by(|a, b| b.authors.to_lowercase().cmp(&a.authors.to_lowercase())),
- "title" => self
+ EntryTableColumn::Title => self
.entry_table_items
.sort_by(|a, b| b.title.to_lowercase().cmp(&a.title.to_lowercase())),
- "year" => self
+ EntryTableColumn::Year => self
.entry_table_items
.sort_by(|a, b| b.year.to_lowercase().cmp(&a.year.to_lowercase())),
- _ => {}
+ EntryTableColumn::Pubtype => self
+ .entry_table_items
+ .sort_by(|a, b| b.pubtype.to_lowercase().cmp(&a.pubtype.to_lowercase())),
}
} else if !self.entry_table_reversed_sort {
- match sorting {
- "author" => self
+ match self.entry_table_selected_column {
+ EntryTableColumn::Authors => self
.entry_table_items
.sort_by(|a, b| a.authors.to_lowercase().cmp(&b.authors.to_lowercase())),
- "title" => self
+ EntryTableColumn::Title => self
.entry_table_items
.sort_by(|a, b| a.title.to_lowercase().cmp(&b.title.to_lowercase())),
- "year" => self
+ EntryTableColumn::Year => self
.entry_table_items
.sort_by(|a, b| a.year.to_lowercase().cmp(&b.year.to_lowercase())),
- _ => {}
+ EntryTableColumn::Pubtype => self
+ .entry_table_items
+ .sort_by(|a, b| a.pubtype.to_lowercase().cmp(&b.pubtype.to_lowercase())),
}
}
}
@@ -189,22 +203,22 @@ impl App {
// Entry Table commands
// Movement
- pub fn select_next_entry(&mut self) {
+ pub fn select_next_entry(&mut self, entries: u16) {
self.entry_table.entry_info_scroll = 0;
self.entry_table.entry_info_scroll_state =
self.entry_table.entry_info_scroll_state.position(0);
- self.entry_table.entry_table_state.select_next();
+ self.entry_table.entry_table_state.scroll_down_by(entries);
self.entry_table.entry_scroll_state = self
.entry_table
.entry_scroll_state
.position(self.entry_table.entry_table_state.selected().unwrap());
}
- pub fn select_previous_entry(&mut self) {
+ pub fn select_previous_entry(&mut self, entries: u16) {
self.entry_table.entry_info_scroll = 0;
self.entry_table.entry_info_scroll_state =
self.entry_table.entry_info_scroll_state.position(0);
- self.entry_table.entry_table_state.select_previous();
+ self.entry_table.entry_table_state.scroll_up_by(entries);
self.entry_table.entry_scroll_state = self
.entry_table
.entry_scroll_state
@@ -230,6 +244,48 @@ impl App {
.position(self.entry_table.entry_table_items.len());
}
+ pub fn select_next_column(&mut self) {
+ match self.entry_table.entry_table_selected_column {
+ EntryTableColumn::Authors => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Title;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Title => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Year;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Year => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Pubtype;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Pubtype => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Authors;
+ self.entry_table.sort_entry_table(false);
+ }
+ }
+ }
+
+ pub fn select_prev_column(&mut self) {
+ match self.entry_table.entry_table_selected_column {
+ EntryTableColumn::Authors => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Pubtype;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Title => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Authors;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Year => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Title;
+ self.entry_table.sort_entry_table(false);
+ }
+ EntryTableColumn::Pubtype => {
+ self.entry_table.entry_table_selected_column = EntryTableColumn::Year;
+ self.entry_table.sort_entry_table(false);
+ }
+ }
+ }
+
// Get the citekey of the selected entry
pub fn get_selected_citekey(&self) -> &str {
let idx = self.entry_table.entry_table_state.selected().unwrap();
@@ -312,7 +368,7 @@ impl App {
BibiSearch::search_entry_list(&mut self.search_struct.search_string, orig_list.clone());
self.entry_table.entry_table_items = filtered_list;
if self.entry_table.entry_table_reversed_sort {
- self.entry_table.sort_entry_table("author", false);
+ self.entry_table.sort_entry_table(false);
}
self.entry_table.entry_scroll_state = ScrollbarState::content_length(
self.entry_table.entry_scroll_state,
diff --git a/src/frontend/handler.rs b/src/frontend/handler.rs
index ec1647e..39ec7a2 100644
--- a/src/frontend/handler.rs
+++ b/src/frontend/handler.rs
@@ -49,23 +49,33 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R
// Keycodes for the tag area
CurrentArea::TagArea => match key_event.code {
KeyCode::Down => {
- app.select_next_tag();
+ app.select_next_tag(1);
}
KeyCode::Up => {
- app.select_previous_tag();
+ app.select_previous_tag(1);
}
KeyCode::Char('j') => {
if key_event.modifiers == KeyModifiers::ALT {
app.scroll_info_down();
} else {
- app.select_next_tag();
+ app.select_next_tag(1);
}
}
KeyCode::Char('k') => {
if key_event.modifiers == KeyModifiers::ALT {
app.scroll_info_up();
} else {
- app.select_previous_tag();
+ app.select_previous_tag(1);
+ }
+ }
+ KeyCode::Char('d') => {
+ if key_event.modifiers == KeyModifiers::CONTROL {
+ app.select_next_tag(5)
+ }
+ }
+ KeyCode::Char('u') => {
+ if key_event.modifiers == KeyModifiers::CONTROL {
+ app.select_previous_tag(5)
}
}
KeyCode::Char('g') | KeyCode::Home => {
@@ -96,23 +106,35 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R
// Keycodes for the entry area
CurrentArea::EntryArea => match key_event.code {
KeyCode::Down => {
- app.select_next_entry();
+ app.select_next_entry(1);
}
KeyCode::Up => {
- app.select_previous_entry();
+ app.select_previous_entry(1);
}
KeyCode::Char('j') => {
if key_event.modifiers == KeyModifiers::ALT {
app.scroll_info_down();
} else {
- app.select_next_entry();
+ app.select_next_entry(1);
}
}
KeyCode::Char('k') => {
if key_event.modifiers == KeyModifiers::ALT {
app.scroll_info_up();
} else {
- app.select_previous_entry();
+ app.select_previous_entry(1);
+ }
+ }
+ KeyCode::Char('d') => {
+ if key_event.modifiers == KeyModifiers::CONTROL {
+ app.select_next_entry(5);
+ }
+ }
+ KeyCode::Char('u') => {
+ if key_event.modifiers == KeyModifiers::CONTROL {
+ app.select_previous_entry(5);
+ } else {
+ app.open_doi_url()?;
}
}
KeyCode::Char('g') | KeyCode::Home => {
@@ -121,8 +143,14 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R
KeyCode::Char('G') | KeyCode::End => {
app.select_last_entry();
}
+ KeyCode::Char('h') => {
+ app.select_prev_column();
+ }
+ KeyCode::Char('l') => {
+ app.select_next_column();
+ }
KeyCode::Char('s') => {
- app.entry_table.sort_entry_table("author", true);
+ app.entry_table.sort_entry_table(true);
}
KeyCode::Char('y') => {
App::yank_text(&app.get_selected_citekey());
@@ -133,9 +161,6 @@ pub fn handle_key_events(key_event: KeyEvent, app: &mut App, tui: &mut Tui) -> R
KeyCode::Char('o') => {
app.open_connected_file()?;
}
- KeyCode::Char('u') => {
- app.open_doi_url()?;
- }
KeyCode::Char('/') => {
app.enter_search_area();
}
diff --git a/src/frontend/keywords.rs b/src/frontend/keywords.rs
index ba74b02..8f13230 100644
--- a/src/frontend/keywords.rs
+++ b/src/frontend/keywords.rs
@@ -60,16 +60,16 @@ impl App {
// Tag List commands
// Movement
- pub fn select_next_tag(&mut self) {
- self.tag_list.tag_list_state.select_next();
+ pub fn select_next_tag(&mut self, keywords: u16) {
+ self.tag_list.tag_list_state.scroll_down_by(keywords);
self.tag_list.tag_scroll_state = self
.tag_list
.tag_scroll_state
.position(self.tag_list.tag_list_state.selected().unwrap());
}
- pub fn select_previous_tag(&mut self) {
- self.tag_list.tag_list_state.select_previous();
+ pub fn select_previous_tag(&mut self, keywords: u16) {
+ self.tag_list.tag_list_state.scroll_up_by(keywords);
self.tag_list.tag_scroll_state = self
.tag_list
.tag_scroll_state
diff --git a/src/frontend/ui.rs b/src/frontend/ui.rs
index 4ea275d..d4fbba1 100644
--- a/src/frontend/ui.rs
+++ b/src/frontend/ui.rs
@@ -30,7 +30,10 @@ use ratatui::{
use crate::frontend::{app::App, keywords::TagListItem};
-use super::app::{CurrentArea, FormerArea};
+use super::{
+ app::{CurrentArea, FormerArea},
+ entries::EntryTableColumn,
+};
const MAIN_BLUE_COLOR: Color = Color::Indexed(39);
// const MAIN_PURPLE_COLOR: Color = Color::Indexed(129);
@@ -49,6 +52,7 @@ const TEXT_FG_COLOR: Color = Color::Indexed(252);
const TEXT_UNSELECTED_FG_COLOR: Color = Color::Indexed(245);
const SORTED_ENTRIES: &str = "▼";
const SORTED_ENTRIES_REVERSED: &str = "▲";
+const HEADER_FOOTER_BG: Color = Color::Indexed(235);
const SCROLLBAR_UPPER_CORNER: Option<&str> = Some("┓");
const SCROLLBAR_LOWER_CORNER: Option<&str> = Some("┛");
@@ -183,8 +187,6 @@ impl App {
BOX_UNSELECTED_BORDER_STYLE
});
- let background_style = Color::Indexed(235);
-
let [file_area, keyword_area, count_area] = Layout::horizontal([
Constraint::Fill(4),
Constraint::Fill(2),
@@ -197,7 +199,7 @@ impl App {
Span::raw("File: ").bold(),
Span::raw(self.main_bibfile.file_name().unwrap().to_string_lossy()).bold(),
])
- .bg(background_style)
+ .bg(HEADER_FOOTER_BG)
.render(file_area, buf);
Line::from(if !self.tag_list.selected_keyword.is_empty() {
@@ -210,7 +212,7 @@ impl App {
} else {
vec![Span::raw(" ")]
})
- .bg(background_style)
+ .bg(HEADER_FOOTER_BG)
.render(keyword_area, buf);
Line::from(if self.entry_table.entry_table_state.selected().is_some() {
@@ -224,7 +226,7 @@ impl App {
vec![Span::raw("No entries")]
})
.right_aligned()
- .bg(background_style)
+ .bg(HEADER_FOOTER_BG)
.render(count_area, buf);
// Paragraph::new(Line::from(vec![Span::raw(
// self.main_bibfile.display().to_string(),
@@ -259,23 +261,72 @@ impl App {
BOX_UNSELECTED_BORDER_STYLE
});
- let header_style = Style::default().bold().fg(TEXT_FG_COLOR);
+ let header_style = Style::default()
+ .bold()
+ .fg(TEXT_FG_COLOR)
+ .bg(HEADER_FOOTER_BG);
let header = Row::new(vec![
- Cell::from(Line::from(vec![
- Span::raw("Author").underlined(),
- Span::raw(format!(
- " {}",
- if self.entry_table.entry_table_reversed_sort {
- SORTED_ENTRIES_REVERSED
- } else {
- SORTED_ENTRIES
- }
- )),
- ])),
- Cell::from("Title".to_string().underlined()),
- Cell::from("Year".to_string().underlined()),
- Cell::from("Type".to_string().underlined()),
+ if let EntryTableColumn::Authors = self.entry_table.entry_table_selected_column {
+ Cell::from(Line::from(vec![
+ Span::raw("Author").underlined(),
+ Span::raw(format!(
+ " {}",
+ if self.entry_table.entry_table_reversed_sort {
+ SORTED_ENTRIES_REVERSED
+ } else {
+ SORTED_ENTRIES
+ }
+ )),
+ ]))
+ } else {
+ Cell::from("Author".to_string())
+ },
+ if let EntryTableColumn::Title = self.entry_table.entry_table_selected_column {
+ Cell::from(Line::from(vec![
+ Span::raw("Title").underlined(),
+ Span::raw(format!(
+ " {}",
+ if self.entry_table.entry_table_reversed_sort {
+ SORTED_ENTRIES_REVERSED
+ } else {
+ SORTED_ENTRIES
+ }
+ )),
+ ]))
+ } else {
+ Cell::from("Title".to_string())
+ },
+ if let EntryTableColumn::Year = self.entry_table.entry_table_selected_column {
+ Cell::from(Line::from(vec![
+ Span::raw("Year").underlined(),
+ Span::raw(format!(
+ " {}",
+ if self.entry_table.entry_table_reversed_sort {
+ SORTED_ENTRIES_REVERSED
+ } else {
+ SORTED_ENTRIES
+ }
+ )),
+ ]))
+ } else {
+ Cell::from("Year".to_string())
+ },
+ if let EntryTableColumn::Pubtype = self.entry_table.entry_table_selected_column {
+ Cell::from(Line::from(vec![
+ Span::raw("Pubtype").underlined(),
+ Span::raw(format!(
+ " {}",
+ if self.entry_table.entry_table_reversed_sort {
+ SORTED_ENTRIES_REVERSED
+ } else {
+ SORTED_ENTRIES
+ }
+ )),
+ ]))
+ } else {
+ Cell::from("Pubtype".to_string())
+ },
])
.style(header_style)
.height(1);
@@ -299,7 +350,13 @@ impl App {
[
Constraint::Percentage(20),
Constraint::Fill(1),
- Constraint::Length(4),
+ Constraint::Length(
+ if let EntryTableColumn::Year = self.entry_table.entry_table_selected_column {
+ 6
+ } else {
+ 4
+ },
+ ),
Constraint::Percentage(10),
],
)