Improve error reporting
This commit is contained in:
parent
f17d128518
commit
18a0abcd62
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user