Improve error reporting

This commit is contained in:
Patrick Auernig 2023-08-16 14:33:55 +02:00
parent f17d128518
commit 18a0abcd62
4 changed files with 55 additions and 26 deletions

View File

@ -17,7 +17,7 @@ use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
}; };
use ratatui::backend::CrosstermBackend; use ratatui::backend::CrosstermBackend;
use tracing::{debug, error, info}; use tracing::{debug, info};
use self::state::{Mode, State}; 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)?; events::handle(&mut msg_tx, &mut state)?;
state.clear_expired_error_message();
match msg_rx.try_recv() { match msg_rx.try_recv() {
Ok(Message::Exit) => { Ok(Message::Exit) => {
debug!("Exiting..."); debug!("Exiting...");
@ -111,8 +113,7 @@ fn run(terminal: &mut Terminal, mut state: State) -> Result<()> {
} }
Ok(message) => { Ok(message) => {
if let Err(err) = handle_message(&mut state, &mut msg_tx, message) { if let Err(err) = handle_message(&mut state, &mut msg_tx, message) {
error!(message = ?err); state.show_error_message(err);
state.mode = Mode::ShowError(format!("{}", err));
} }
} }
Err(TryRecvError::Empty) => (), Err(TryRecvError::Empty) => (),
@ -174,18 +175,18 @@ fn handle_message(
Message::StartEditEntry => state.start_editing_entry(), Message::StartEditEntry => state.start_editing_entry(),
Message::CommitEditEntry => { Message::CommitEditEntry => {
if let Err(err) = state.commit_entry_edit() { if let Err(err) = state.commit_entry_edit() {
error!(%err); state.show_error_message(err);
} }
} }
Message::CancelEditEntry => state.cancel_editing_entry(), Message::CancelEditEntry => state.cancel_editing_entry(),
Message::NextEntryValue => { Message::NextEntryValue => {
if let Err(err) = state.next_entry_value() { if let Err(err) = state.next_entry_value() {
error!(%err); state.show_error_message(err);
} }
} }
Message::PreviousEntryValue => { Message::PreviousEntryValue => {
if let Err(err) = state.previous_entry_value() { if let Err(err) = state.previous_entry_value() {
error!(%err); state.show_error_message(err);
} }
} }
_ => (), _ => (),

View File

@ -57,10 +57,6 @@ fn handle_keyboard_input(
msg_tx.send(Message::SetMode(Mode::Normal))?; msg_tx.send(Message::SetMode(Mode::Normal))?;
} }
(Mode::ShowError(_), _) => {
msg_tx.send(Message::SetMode(Mode::Normal))?;
}
(Mode::SelectFile, KeyCode::Enter) => { (Mode::SelectFile, KeyCode::Enter) => {
msg_tx.send(Message::LoadFile)?; msg_tx.send(Message::LoadFile)?;
} }
@ -147,5 +143,7 @@ fn handle_keyboard_input(
_ => (), _ => (),
}; };
state.clear_error_message();
Ok(()) Ok(())
} }

View File

@ -1,12 +1,14 @@
use core::fmt;
use std::fs::{self, create_dir_all, read_to_string}; use std::fs::{self, create_dir_all, read_to_string};
use std::io::Write; use std::io::Write;
use std::os::unix::prelude::OsStrExt; use std::os::unix::prelude::OsStrExt;
use std::path::Path; use std::path::Path;
use std::time::{Duration, Instant};
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use jrny_save::{RobeColor, Savefile, LEVEL_NAMES}; use jrny_save::{RobeColor, Savefile, LEVEL_NAMES};
use ratatui::widgets::TableState; use ratatui::widgets::TableState;
use tracing::debug; use tracing::{debug, error};
use tui_input::Input; use tui_input::Input;
use super::view::info::glyphs::TABLE_RANGE as GLYPHS_TABLE_RANGE; use super::view::info::glyphs::TABLE_RANGE as GLYPHS_TABLE_RANGE;
@ -27,8 +29,6 @@ pub enum Mode {
Insert, Insert,
ShowError(String),
SelectFile, SelectFile,
} }
@ -57,6 +57,7 @@ pub struct State {
pub stats_table: TableState, pub stats_table: TableState,
pub glyphs_table: TableState, pub glyphs_table: TableState,
pub murals_table: TableState, pub murals_table: TableState,
pub error_msg: Option<(Instant, String)>,
pub mode: Mode, pub mode: Mode,
pub edit_input: Option<Input>, pub edit_input: Option<Input>,
pub file_select: Input, pub file_select: Input,
@ -66,6 +67,29 @@ pub struct State {
impl State { impl State {
const ERROR_MSG_DURATION: Duration = Duration::new(3, 0);
pub fn show_error_message<S>(&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<Self> { pub fn load() -> Result<Self> {
let data_dir = DIRS.data_local_dir(); let data_dir = DIRS.data_local_dir();

View File

@ -6,21 +6,28 @@ use crate::tui::view::Frame;
use crate::tui::{Mode, State}; 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)); let status_block = Block::default().padding(Padding::horizontal(2));
match &state.mode { match &state.error_msg {
Mode::ShowError(error_msg) => { Some((_, msg)) => render_error_message(&msg, frame, status_block, area),
let error_msg = Paragraph::new(error_msg.clone()) None => render_status(state, frame, status_block, area),
.style(Style::default().fg(ratatui::style::Color::LightRed)) }
.block(status_block); }
frame.render_widget(error_msg, 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 => { Mode::Edit | Mode::Insert => {
if let Some(savefile) = &state.savefile { if let Some(savefile) = &state.savefile {
let text = format!("Editing file: {}", savefile.path.display()); 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); 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() => { Mode::Normal if state.is_watching_file() => {
if let Some(savefile) = &state.savefile { if let Some(savefile) = &state.savefile {
let text = format!("Watching file: {}", savefile.path.display()); 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); 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 { if let Some(savefile) = &state.savefile {
let text = format!("Showing file: {}", savefile.path.display()); 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); frame.render_widget(status, area);
} }
} }
} }
} }
fn render_file_select(state: &State, frame: &mut Frame, block: Block, area: Rect) { fn render_file_select(state: &State, frame: &mut Frame, block: Block, area: Rect) {
const PROMPT: &str = "Open file:"; const PROMPT: &str = "Open file:";
const PADDING: usize = 2; const PADDING: usize = 2;