This commit is contained in:
Jana Dönszelmann 2026-02-25 13:06:25 +01:00
parent d8e445b5f7
commit 4a7817a239
No known key found for this signature in database
4 changed files with 82 additions and 8 deletions

View file

@ -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<PathBuf>,
current_file: Option<LogfileReader>,
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);
}
}
}

View file

@ -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) = &regex {
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();

View file

@ -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<RefCell<Option<(String, Instant)>>>,
}
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);
}
}

View file

@ -1,4 +1,5 @@
pub mod hyperlink;
pub mod items;
pub mod last_error;
pub mod line_text;
pub mod styled;