diff options
Diffstat (limited to 'src/list.rs')
| -rw-r--r-- | src/list.rs | 147 |
1 files changed, 75 insertions, 72 deletions
diff --git a/src/list.rs b/src/list.rs index 6ff6959..a8e5225 100644 --- a/src/list.rs +++ b/src/list.rs @@ -1,95 +1,96 @@ use anyhow::{Context, Result}; -use ratatui::{ - backend::CrosstermBackend, - crossterm::{ - event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind}, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, - QueueableCommand, +use crossterm::{ + cursor, + event::{ + self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, MouseEventKind, }, - Terminal, + terminal::{ + disable_raw_mode, enable_raw_mode, DisableLineWrap, EnableLineWrap, EnterAlternateScreen, + LeaveAlternateScreen, + }, + QueueableCommand, }; use std::io::{self, StdoutLock, Write}; use crate::app_state::AppState; -use self::state::{Filter, UiState}; +use self::state::{Filter, ListState}; mod state; fn handle_list(app_state: &mut AppState, stdout: &mut StdoutLock) -> Result<()> { - let mut terminal = Terminal::new(CrosstermBackend::new(stdout))?; - terminal.clear()?; - - let mut ui_state = UiState::new(app_state); - - 'outer: loop { - terminal.try_draw(|frame| ui_state.draw(frame).map_err(io::Error::other))?; - - let key = loop { - match event::read().context("Failed to read terminal event")? { - Event::Key(key) => match key.kind { - KeyEventKind::Press | KeyEventKind::Repeat => break key, - KeyEventKind::Release => (), - }, - // Redraw - Event::Resize(_, _) => continue 'outer, - // Ignore - Event::FocusGained | Event::FocusLost | Event::Mouse(_) | Event::Paste(_) => (), - } - }; - - ui_state.message.clear(); - - match key.code { - KeyCode::Char('q') => break, - KeyCode::Down | KeyCode::Char('j') => ui_state.select_next(), - KeyCode::Up | KeyCode::Char('k') => ui_state.select_previous(), - KeyCode::Home | KeyCode::Char('g') => ui_state.select_first(), - KeyCode::End | KeyCode::Char('G') => ui_state.select_last(), - KeyCode::Char('d') => { - let message = if ui_state.filter == Filter::Done { - ui_state.filter = Filter::None; - "Disabled filter DONE" - } else { - ui_state.filter = Filter::Done; - "Enabled filter DONE │ Press d again to disable the filter" - }; - - ui_state = ui_state.with_updated_rows(); - ui_state.message.push_str(message); + let mut list_state = ListState::new(app_state, stdout)?; + + loop { + match event::read().context("Failed to read terminal event")? { + Event::Key(key) => { + match key.kind { + KeyEventKind::Release => continue, + KeyEventKind::Press | KeyEventKind::Repeat => (), + } + + list_state.message.clear(); + + match key.code { + KeyCode::Char('q') => return Ok(()), + KeyCode::Down | KeyCode::Char('j') => list_state.select_next(), + KeyCode::Up | KeyCode::Char('k') => list_state.select_previous(), + KeyCode::Home | KeyCode::Char('g') => list_state.select_first(), + KeyCode::End | KeyCode::Char('G') => list_state.select_last(), + KeyCode::Char('d') => { + if list_state.filter() == Filter::Done { + list_state.set_filter(Filter::None); + list_state.message.push_str("Disabled filter DONE"); + } else { + list_state.set_filter(Filter::Done); + list_state.message.push_str( + "Enabled filter DONE │ Press d again to disable the filter", + ); + } + } + KeyCode::Char('p') => { + let message = if list_state.filter() == Filter::Pending { + list_state.set_filter(Filter::None); + "Disabled filter PENDING" + } else { + list_state.set_filter(Filter::Pending); + "Enabled filter PENDING │ Press p again to disable the filter" + }; + + list_state.message.push_str(message); + } + KeyCode::Char('r') => list_state.reset_selected()?, + KeyCode::Char('c') => { + if list_state.selected_to_current_exercise()? { + return Ok(()); + } + } + // Redraw to remove the message. + KeyCode::Esc => (), + _ => continue, + } } - KeyCode::Char('p') => { - let message = if ui_state.filter == Filter::Pending { - ui_state.filter = Filter::None; - "Disabled filter PENDING" - } else { - ui_state.filter = Filter::Pending; - "Enabled filter PENDING │ Press p again to disable the filter" - }; - - ui_state = ui_state.with_updated_rows(); - ui_state.message.push_str(message); - } - KeyCode::Char('r') => { - ui_state = ui_state.with_reset_selected()?; - } - KeyCode::Char('c') => { - ui_state.selected_to_current_exercise()?; - break; - } - _ => (), + Event::Mouse(event) => match event.kind { + MouseEventKind::ScrollDown => list_state.select_next(), + MouseEventKind::ScrollUp => list_state.select_previous(), + _ => continue, + }, + Event::Resize(width, height) => list_state.set_term_size(width, height), + // Ignore + Event::FocusGained | Event::FocusLost => continue, } - } - Ok(()) + list_state.draw(stdout)?; + } } pub fn list(app_state: &mut AppState) -> Result<()> { let mut stdout = io::stdout().lock(); stdout .queue(EnterAlternateScreen)? - .queue(EnableMouseCapture)? - .flush()?; + .queue(cursor::Hide)? + .queue(DisableLineWrap)? + .queue(EnableMouseCapture)?; enable_raw_mode()?; let res = handle_list(app_state, &mut stdout); @@ -97,6 +98,8 @@ pub fn list(app_state: &mut AppState) -> Result<()> { // Restore the terminal even if we got an error. stdout .queue(LeaveAlternateScreen)? + .queue(cursor::Show)? + .queue(EnableLineWrap)? .queue(DisableMouseCapture)? .flush()?; disable_raw_mode()?; |
