2026-01-21 20:28:24 -05:00
|
|
|
use crate::tui::app::{AppComponents, ComponentOf};
|
2026-01-22 19:23:21 -05:00
|
|
|
use crate::tui::component::{Action, Component, ComponentState, Focus};
|
2026-01-20 20:14:25 -05:00
|
|
|
use ratatui::buffer::Buffer;
|
|
|
|
|
use ratatui::crossterm::event::{Event, KeyCode, KeyEvent};
|
|
|
|
|
use ratatui::layout::Rect;
|
|
|
|
|
use ratatui::style::{Color, Style};
|
|
|
|
|
use ratatui::widgets::Widget;
|
|
|
|
|
use tui_logger::{TuiLoggerLevelOutput, TuiLoggerSmartWidget, TuiWidgetEvent, TuiWidgetState};
|
|
|
|
|
|
|
|
|
|
/// Any log written as info!(target:self.id(), "message") will work with this logger.
|
|
|
|
|
/// The logger is bound to info!, debug!, error!, trace! macros within Tui::new().
|
|
|
|
|
pub struct Logger {
|
|
|
|
|
state: TuiWidgetState,
|
2026-01-22 19:23:21 -05:00
|
|
|
pub(crate) component_state: ComponentState,
|
2026-01-20 20:14:25 -05:00
|
|
|
}
|
|
|
|
|
|
2026-01-21 20:28:24 -05:00
|
|
|
impl<'a> ComponentOf<Logger> for AppComponents<'a> {
|
|
|
|
|
fn as_ref(&self) -> Option<&Logger> {
|
|
|
|
|
if let AppComponents::AppLogger(ref e) = *self {
|
|
|
|
|
return Some(e);
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
fn as_mut(&mut self) -> Option<&mut Logger> {
|
|
|
|
|
if let AppComponents::AppLogger(ref mut e) = *self {
|
|
|
|
|
return Some(e);
|
|
|
|
|
}
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 20:14:25 -05:00
|
|
|
impl Logger {
|
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
state: TuiWidgetState::new(),
|
2026-01-22 19:23:21 -05:00
|
|
|
component_state: Default::default(),
|
2026-01-20 20:14:25 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Widget for &Logger {
|
|
|
|
|
fn render(self, area: Rect, buf: &mut Buffer)
|
|
|
|
|
where
|
|
|
|
|
Self: Sized,
|
|
|
|
|
{
|
|
|
|
|
// TODO: Use output_file?
|
|
|
|
|
TuiLoggerSmartWidget::default()
|
|
|
|
|
.style_error(Style::default().fg(Color::Red))
|
|
|
|
|
.style_debug(Style::default().fg(Color::Green))
|
|
|
|
|
.style_warn(Style::default().fg(Color::Yellow))
|
|
|
|
|
.style_trace(Style::default().fg(Color::Magenta))
|
|
|
|
|
.style_info(Style::default().fg(Color::Cyan))
|
|
|
|
|
.output_separator(':')
|
|
|
|
|
.output_timestamp(Some("%H:%M:%S".to_string()))
|
|
|
|
|
.output_level(Some(TuiLoggerLevelOutput::Abbreviated))
|
|
|
|
|
.output_target(true)
|
|
|
|
|
.output_file(true)
|
|
|
|
|
.output_line(true)
|
|
|
|
|
.state(&self.state)
|
|
|
|
|
.render(area, buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Component for Logger {
|
|
|
|
|
fn id(&self) -> &str {
|
|
|
|
|
"Logger"
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-22 19:23:21 -05:00
|
|
|
fn is_active(&self) -> bool {
|
|
|
|
|
self.component_state.focus == Focus::Active
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 20:14:25 -05:00
|
|
|
fn handle_event(&mut self, event: Event) -> anyhow::Result<Action> {
|
|
|
|
|
if let Some(key_event) = event.as_key_event() {
|
|
|
|
|
return self.handle_key_events(key_event);
|
|
|
|
|
}
|
|
|
|
|
Ok(Action::Noop)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn handle_key_events(&mut self, key: KeyEvent) -> anyhow::Result<Action> {
|
|
|
|
|
match key.code {
|
|
|
|
|
KeyCode::Char(' ') => self.state.transition(TuiWidgetEvent::SpaceKey),
|
|
|
|
|
KeyCode::Esc => self.state.transition(TuiWidgetEvent::EscapeKey),
|
|
|
|
|
KeyCode::PageUp => self.state.transition(TuiWidgetEvent::PrevPageKey),
|
|
|
|
|
KeyCode::PageDown => self.state.transition(TuiWidgetEvent::NextPageKey),
|
|
|
|
|
KeyCode::Up => self.state.transition(TuiWidgetEvent::UpKey),
|
|
|
|
|
KeyCode::Down => self.state.transition(TuiWidgetEvent::DownKey),
|
|
|
|
|
KeyCode::Left => self.state.transition(TuiWidgetEvent::LeftKey),
|
|
|
|
|
KeyCode::Right => self.state.transition(TuiWidgetEvent::RightKey),
|
|
|
|
|
KeyCode::Char('+') => self.state.transition(TuiWidgetEvent::PlusKey),
|
|
|
|
|
KeyCode::Char('-') => self.state.transition(TuiWidgetEvent::MinusKey),
|
|
|
|
|
KeyCode::Char('h') => self.state.transition(TuiWidgetEvent::HideKey),
|
|
|
|
|
KeyCode::Char('f') => self.state.transition(TuiWidgetEvent::FocusKey),
|
|
|
|
|
_ => (),
|
|
|
|
|
}
|
|
|
|
|
Ok(Action::Pass)
|
|
|
|
|
}
|
|
|
|
|
}
|