From 18a0abcd62835e05c2b66e984f8862199938807c Mon Sep 17 00:00:00 2001 From: Patrick Auernig Date: Wed, 16 Aug 2023 14:33:55 +0200 Subject: [PATCH] Improve error reporting --- crates/wayfarer/src/tui.rs | 13 +++++---- crates/wayfarer/src/tui/events.rs | 6 ++-- crates/wayfarer/src/tui/state.rs | 30 ++++++++++++++++++-- crates/wayfarer/src/tui/view/status_bar.rs | 32 +++++++++++++--------- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/crates/wayfarer/src/tui.rs b/crates/wayfarer/src/tui.rs index 36fd15e..4c7b5d2 100644 --- a/crates/wayfarer/src/tui.rs +++ b/crates/wayfarer/src/tui.rs @@ -17,7 +17,7 @@ use crossterm::terminal::{ disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, }; use ratatui::backend::CrosstermBackend; -use tracing::{debug, error, info}; +use tracing::{debug, info}; use self::state::{Mode, State}; @@ -104,6 +104,8 @@ fn run(terminal: &mut Terminal, mut state: State) -> Result<()> { events::handle(&mut msg_tx, &mut state)?; + state.clear_expired_error_message(); + match msg_rx.try_recv() { Ok(Message::Exit) => { debug!("Exiting..."); @@ -111,8 +113,7 @@ fn run(terminal: &mut Terminal, mut state: State) -> Result<()> { } Ok(message) => { if let Err(err) = handle_message(&mut state, &mut msg_tx, message) { - error!(message = ?err); - state.mode = Mode::ShowError(format!("{}", err)); + state.show_error_message(err); } } Err(TryRecvError::Empty) => (), @@ -174,18 +175,18 @@ fn handle_message( Message::StartEditEntry => state.start_editing_entry(), Message::CommitEditEntry => { if let Err(err) = state.commit_entry_edit() { - error!(%err); + state.show_error_message(err); } } Message::CancelEditEntry => state.cancel_editing_entry(), Message::NextEntryValue => { if let Err(err) = state.next_entry_value() { - error!(%err); + state.show_error_message(err); } } Message::PreviousEntryValue => { if let Err(err) = state.previous_entry_value() { - error!(%err); + state.show_error_message(err); } } _ => (), diff --git a/crates/wayfarer/src/tui/events.rs b/crates/wayfarer/src/tui/events.rs index 5b1012b..0b980f7 100644 --- a/crates/wayfarer/src/tui/events.rs +++ b/crates/wayfarer/src/tui/events.rs @@ -57,10 +57,6 @@ fn handle_keyboard_input( msg_tx.send(Message::SetMode(Mode::Normal))?; } - (Mode::ShowError(_), _) => { - msg_tx.send(Message::SetMode(Mode::Normal))?; - } - (Mode::SelectFile, KeyCode::Enter) => { msg_tx.send(Message::LoadFile)?; } @@ -147,5 +143,7 @@ fn handle_keyboard_input( _ => (), }; + state.clear_error_message(); + Ok(()) } diff --git a/crates/wayfarer/src/tui/state.rs b/crates/wayfarer/src/tui/state.rs index c9ab44b..ef45cc1 100644 --- a/crates/wayfarer/src/tui/state.rs +++ b/crates/wayfarer/src/tui/state.rs @@ -1,12 +1,14 @@ +use core::fmt; use std::fs::{self, create_dir_all, read_to_string}; use std::io::Write; use std::os::unix::prelude::OsStrExt; use std::path::Path; +use std::time::{Duration, Instant}; use anyhow::{bail, Context, Result}; use jrny_save::{RobeColor, Savefile, LEVEL_NAMES}; use ratatui::widgets::TableState; -use tracing::debug; +use tracing::{debug, error}; use tui_input::Input; use super::view::info::glyphs::TABLE_RANGE as GLYPHS_TABLE_RANGE; @@ -27,8 +29,6 @@ pub enum Mode { Insert, - ShowError(String), - SelectFile, } @@ -57,6 +57,7 @@ pub struct State { pub stats_table: TableState, pub glyphs_table: TableState, pub murals_table: TableState, + pub error_msg: Option<(Instant, String)>, pub mode: Mode, pub edit_input: Option, pub file_select: Input, @@ -66,6 +67,29 @@ pub struct State { impl State { + const ERROR_MSG_DURATION: Duration = Duration::new(3, 0); + + pub fn show_error_message(&mut self, msg: S) + where + S: fmt::Display, + { + let until = Instant::now() + Self::ERROR_MSG_DURATION; + error!(%msg); + self.error_msg = Some((until, msg.to_string())); + } + + pub fn clear_expired_error_message(&mut self) { + if let Some((until, _)) = self.error_msg { + if Instant::now() >= until { + self.error_msg = None; + } + } + } + + pub fn clear_error_message(&mut self) { + self.error_msg.take(); + } + pub fn load() -> Result { let data_dir = DIRS.data_local_dir(); diff --git a/crates/wayfarer/src/tui/view/status_bar.rs b/crates/wayfarer/src/tui/view/status_bar.rs index 2441167..e9f0851 100644 --- a/crates/wayfarer/src/tui/view/status_bar.rs +++ b/crates/wayfarer/src/tui/view/status_bar.rs @@ -6,21 +6,28 @@ use crate::tui::view::Frame; use crate::tui::{Mode, State}; -pub fn render(state: &State, mut frame: &mut Frame, area: Rect) { +pub fn render(state: &State, frame: &mut Frame, area: Rect) { let status_block = Block::default().padding(Padding::horizontal(2)); - match &state.mode { - Mode::ShowError(error_msg) => { - let error_msg = Paragraph::new(error_msg.clone()) - .style(Style::default().fg(ratatui::style::Color::LightRed)) - .block(status_block); - frame.render_widget(error_msg, area); - } + match &state.error_msg { + Some((_, msg)) => render_error_message(&msg, frame, status_block, area), + None => render_status(state, frame, status_block, area), + } +} +fn render_error_message(msg: &str, frame: &mut Frame, block: Block, area: Rect) { + let error_msg = Paragraph::new(msg) + .style(Style::default().fg(ratatui::style::Color::LightRed)) + .block(block); + frame.render_widget(error_msg, area); +} + +pub fn render_status(state: &State, mut frame: &mut Frame, block: Block, area: Rect) { + match &state.mode { Mode::Edit | Mode::Insert => { if let Some(savefile) = &state.savefile { let text = format!("Editing file: {}", savefile.path.display()); - let status = Paragraph::new(text).block(status_block); + let status = Paragraph::new(text).block(block); frame.render_widget(status, area); } } @@ -29,24 +36,23 @@ pub fn render(state: &State, mut frame: &mut Frame, area: Rect) { Mode::Normal if state.is_watching_file() => { if let Some(savefile) = &state.savefile { let text = format!("Watching file: {}", savefile.path.display()); - let status = Paragraph::new(text).block(status_block); + let status = Paragraph::new(text).block(block); frame.render_widget(status, area); } } - Mode::SelectFile => render_file_select(&state, &mut frame, status_block, area), + Mode::SelectFile => render_file_select(&state, &mut frame, block, area), _ => { if let Some(savefile) = &state.savefile { let text = format!("Showing file: {}", savefile.path.display()); - let status = Paragraph::new(text).block(status_block); + let status = Paragraph::new(text).block(block); frame.render_widget(status, area); } } } } - fn render_file_select(state: &State, frame: &mut Frame, block: Block, area: Rect) { const PROMPT: &str = "Open file:"; const PADDING: usize = 2;