diff options
| author | lukeflo | 2024-10-20 18:14:17 +0200 |
|---|---|---|
| committer | lukeflo | 2024-10-20 18:14:17 +0200 |
| commit | 735264bb3d673c943e2e8c4898dba0609f49b3f4 (patch) | |
| tree | 675710467f814f611c416b56730a8760c9a15349 /src/frontend | |
| parent | 730055489a660b0cdff950f6c7037fe7a07545ae (diff) | |
| download | bibiman-735264bb3d673c943e2e8c4898dba0609f49b3f4.tar.gz bibiman-735264bb3d673c943e2e8c4898dba0609f49b3f4.zip | |
Implement Sorting, jumping multiple entries
- Select a column with `j` and `l`
- Sort selected column with `s` (toggles regular and reversed order)
- Jump list up/down by 5 entries Vim-style using `C-d` and `C-u`
Diffstat (limited to 'src/frontend')
| -rw-r--r-- | src/frontend/entries.rs | 88 | ||||
| -rw-r--r-- | src/frontend/handler.rs | 49 | ||||
| -rw-r--r-- | src/frontend/keywords.rs | 8 | ||||
| -rw-r--r-- | src/frontend/ui.rs | 101 |
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), ], ) |
