From 4a7817a2392a02f64f66817d3d9d13e7c3d96ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 25 Feb 2026 13:06:25 +0100 Subject: [PATCH] errors --- src/tui/mod.rs | 23 ++++++++++++---- src/tui/widgets/items.rs | 16 ++++++++--- src/tui/widgets/last_error.rs | 50 +++++++++++++++++++++++++++++++++++ src/tui/widgets/mod.rs | 1 + 4 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 src/tui/widgets/last_error.rs diff --git a/src/tui/mod.rs b/src/tui/mod.rs index e6b6e6b..4c62981 100644 --- a/src/tui/mod.rs +++ b/src/tui/mod.rs @@ -1,20 +1,20 @@ use ratatui_themes::{Theme, ThemeName}; -use regex::bytes::Regex; use std::{ + cell::RefCell, fs::{self, DirEntry}, io, ops::ControlFlow, path::{Path, PathBuf}, process::exit, rc::Rc, + time::Instant, }; use tui_widget_list::{ListBuilder, ListView}; use crate::tui::{ filter::FilterKind, log_viewer::{InputState, InputTarget, LogViewer}, - model::pretty_print_value, - widgets::{hyperlink::Hyperlink, items::Items, line_text::Highlighted}, + widgets::{hyperlink::Hyperlink, items::Items, last_error::LastError}, }; use crate::tui::{ filter::{Filter, Matcher}, @@ -27,7 +27,7 @@ use ratatui::{ buffer::Buffer, crossterm::event::{self, Event, KeyCode, KeyEvent, KeyModifiers}, layout::{Constraint, HorizontalAlignment, Layout, Rect}, - style::Style, + style::{self, Style}, text::Line, widgets::{ Block, Clear, List, ListItem, ListState, Padding, Paragraph, StatefulWidget, Widget, Wrap, @@ -116,6 +116,8 @@ struct App { compiler_root: Option, current_file: Option, theme: Theme, + + last_error: LastError, } impl App { @@ -126,6 +128,7 @@ impl App { logs_dir, compiler_root, theme, + last_error: LastError::new(), }; res.replace_tab(res.choose_file()); res @@ -356,6 +359,8 @@ impl App { fn run(mut self, mut terminal: DefaultTerminal) -> io::Result<()> { loop { + self.last_error.check_expired(); + terminal.draw(|frame| frame.render_widget(&mut self, frame.area()))?; if let Event::Key(key) = event::read()? { @@ -376,12 +381,14 @@ impl App { let highlighted = Style::new().fg(palette.accent).bg(palette.selection); let border = Style::new().fg(palette.fg).bg(palette.bg); let border_highlighted = Style::new().fg(palette.secondary).bg(palette.bg); + let error = Style::new().fg(palette.error).bg(palette.bg); Styles { default, highlighted, border, border_highlighted, + error, } } @@ -400,11 +407,12 @@ impl App { } } -struct Styles { +pub struct Styles { default: Style, highlighted: Style, border: Style, border_highlighted: Style, + error: Style, } impl Widget for &mut App { @@ -471,6 +479,8 @@ impl Widget for &mut App { .style(styles.default) .render(middle, buf); + let [right, error] = + Layout::vertical([Constraint::Length(1), Constraint::Length(1)]).areas(right); Paragraph::new("").style(styles.default).render(right, buf); for tab in &mut self.tabs { @@ -533,6 +543,7 @@ impl Widget for &mut App { .get(idx) .map(|(a, b)| (a.clone(), b.clone())) }), + self.last_error.clone(), ) .styled_ref(&styles) .render(main_area, buf); @@ -575,6 +586,8 @@ impl Widget for &mut App { Paragraph::new(HELP_TEXT).render(popup_area, buf); } } + + self.last_error.clone().styled(&styles).render(error, buf); } } } diff --git a/src/tui/widgets/items.rs b/src/tui/widgets/items.rs index dc030a6..4e91248 100644 --- a/src/tui/widgets/items.rs +++ b/src/tui/widgets/items.rs @@ -1,4 +1,4 @@ -use std::rc::Rc; +use std::{cell::OnceCell, rc::Rc}; use itertools::Itertools; use ratatui::widgets::{List, ListItem, Widget}; @@ -8,6 +8,7 @@ use crate::tui::{ log_viewer::{FieldMatcher, InputState, InputTarget}, model::LogEntry, widgets::{ + last_error::LastError, line_text::Highlighted, styled::{IntoStyled, Styled}, }, @@ -92,6 +93,7 @@ pub struct Items<'a> { input_state: &'a InputState, selected_footer_field: Option<(String, String)>, + last_error: LastError, } impl<'a> Items<'a> { @@ -100,12 +102,14 @@ impl<'a> Items<'a> { selected_offset: usize, input_state: &'a InputState, selected_footer_field: Option<(String, String)>, + last_error: LastError, ) -> Self { Self { items, selected_offset, input_state, selected_footer_field, + last_error, } } @@ -120,6 +124,7 @@ impl Widget for Styled<'_, &Items<'_>> { Self: Sized, { let ts = TreeState::from_items(&self.items); + let regex_cache = OnceCell::new(); let list = List::new( self.inner @@ -161,8 +166,13 @@ impl Widget for Styled<'_, &Items<'_>> { } } FieldMatcher::Regex(r) => { - if let Ok(regex) = Regex::new(r) - && let Some(start_offset) = line.message.find(msg) + if let Ok(regex) = regex_cache.get_or_init(|| { + let regex = Regex::new(r); + if let Err(e) = ®ex { + self.last_error.set(format!("{e}")); + } + regex + }) && let Some(start_offset) = line.message.find(msg) && let Some(m) = regex.find(msg) { let from = start_offset + m.start(); diff --git a/src/tui/widgets/last_error.rs b/src/tui/widgets/last_error.rs new file mode 100644 index 0000000..83fbddb --- /dev/null +++ b/src/tui/widgets/last_error.rs @@ -0,0 +1,50 @@ +use std::{cell::RefCell, rc::Rc, time::Instant}; + +use ratatui::widgets::{Paragraph, Widget}; + +use crate::tui::widgets::styled::Styled; + +#[derive(Clone)] +pub struct LastError { + inner: Rc>>, +} + +impl LastError { + pub fn new() -> Self { + Self { + inner: Rc::new(RefCell::new(None)), + } + } + + pub fn set(&self, s: String) { + *self.inner.borrow_mut() = Some((s, Instant::now())); + } + + pub fn check_expired(&self) { + let inner = self.inner.borrow(); + if let Some((_, time)) = *inner { + if Instant::now().duration_since(time).as_secs_f64() > 1.0 { + drop(inner); + *self.inner.borrow_mut() = None; + } + } + } +} + +impl Widget for Styled<'_, LastError> { + fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer) + where + Self: Sized, + { + Paragraph::new( + self.inner + .inner + .borrow() + .as_ref() + .map(|i| i.0.replace("\n", "")) + .unwrap_or_default(), + ) + .style(self.styles.error) + .render(area, buf); + } +} diff --git a/src/tui/widgets/mod.rs b/src/tui/widgets/mod.rs index 90da227..bb56e95 100644 --- a/src/tui/widgets/mod.rs +++ b/src/tui/widgets/mod.rs @@ -1,4 +1,5 @@ pub mod hyperlink; pub mod items; +pub mod last_error; pub mod line_text; pub mod styled;