diff --git a/Cargo.toml b/Cargo.toml index 2d611a8..f0cdfce 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,4 @@ crossterm = "0.28.0" ratatui = "0.29.0" unicode-width = "0.2.0" chrono = "0.4.38" -cleverlib = "0.1.4" +cleverlib = { path = "../cleverlib/" } diff --git a/src/app.rs b/src/app.rs index 7c7e9a9..c6009a3 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1,5 +1,7 @@ +use std::error::Error; + use crate::event_log_level::EventLogLevel; -use cleverlib::event_collection::EventCollection; +use cleverlib::{clever_parser_options::CleverParserOptions, event_collection::EventCollection}; use ratatui::widgets::{ListState, Row, TableState}; #[derive(Debug, Default)] @@ -29,8 +31,16 @@ impl<'a> App<'a> { pub fn tick(&self) {} - pub fn load_lines(&mut self, lines: &Vec) { - self.event_collection = EventCollection::create(lines).unwrap(); + pub fn load_lines(&mut self, lines: &Vec) -> Result<(), Box> { + let parsing_options = CleverParserOptions { + ignore_errors: Some(false), + debug: Some(false), + }; + self.event_collection = match EventCollection::create(lines, Some(&parsing_options)) { + Ok(collection) => collection, + Err(e) => return Err(e.into()), + }; + Ok(()) } pub fn get_event_types(&mut self) { @@ -51,7 +61,7 @@ impl<'a> App<'a> { pub fn move_row_up(&mut self, range: usize) { if let Some(selected) = self.event_table_state.selected() { - if selected >= range + 1 { + if selected > range { self.event_table_state.select(Some(selected - range)); } else { self.event_table_state diff --git a/src/event.rs b/src/event.rs index 34148fc..7d1694a 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,13 +1,17 @@ -use std::{sync::mpsc::{self, RecvError}, thread, time::{Duration, Instant}}; +use std::{ + sync::mpsc::{self, RecvError}, + thread, + time::{Duration, Instant}, +}; -use crossterm::event::{self, KeyEvent, MouseEvent, Event as CrosstermEvent}; +use crossterm::event::{self, Event as CrosstermEvent, KeyEvent, MouseEvent}; -#[derive(Clone,Copy,Debug)] +#[derive(Clone, Copy, Debug)] pub enum Event { Tick, Key(KeyEvent), Mouse(MouseEvent), - Resize(u16,u16) + Resize(u16, u16), } #[derive(Debug)] @@ -16,51 +20,51 @@ pub struct EventHandler { sender: mpsc::Sender, receiver: mpsc::Receiver, #[allow(dead_code)] - handler: thread::JoinHandle<()> + handler: thread::JoinHandle<()>, } -impl EventHandler { +impl EventHandler { pub fn new(tick_rate: u64) -> Self { let tick_rate = Duration::from_millis(tick_rate); - let (sender,receiver) = mpsc::channel(); + let (sender, receiver) = mpsc::channel(); let handler = { let sender = sender.clone(); thread::spawn(move || { - let mut last_tick = Instant::now(); + let mut last_tick = Instant::now(); loop { - let timeout = tick_rate.checked_sub(last_tick.elapsed()).unwrap_or(tick_rate); - if event::poll(timeout).expect("Unable to poll for event") { + let timeout = tick_rate + .checked_sub(last_tick.elapsed()) + .unwrap_or(tick_rate); + if event::poll(timeout).expect("Unable to poll for event") { match event::read().expect("Unable to read event") { CrosstermEvent::Key(e) => { if e.kind == event::KeyEventKind::Press { sender.send(Event::Key(e)) - }else { + } else { Ok(()) } - }, - CrosstermEvent::Mouse(e) => { - sender.send(Event::Mouse(e)) - }, - CrosstermEvent::Resize(w,h ) => { - sender.send(Event::Resize(w, h)) - }, - _ => unimplemented!() + } + CrosstermEvent::Mouse(e) => sender.send(Event::Mouse(e)), + CrosstermEvent::Resize(w, h) => sender.send(Event::Resize(w, h)), + _ => unimplemented!(), } .expect("Failed to send terminal event") - } - if last_tick.elapsed() >= tick_rate { + } + if last_tick.elapsed() >= tick_rate { sender.send(Event::Tick).expect("failed to send tick event"); last_tick = Instant::now(); - } + } } }) }; Self { - sender, receiver, handler + sender, + receiver, + handler, } } - pub fn next(&self) -> Result { + pub fn next(&self) -> Result { Ok(self.receiver.recv()?) } -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 145ede9..a86f19f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,12 +9,12 @@ pub mod ui; /// Terminal user interface. pub mod tui; +pub mod event_log_level; /// Application updater. pub mod update; -pub mod event_log_level; - use std::{ + error::Error, fs, io::{self}, }; @@ -23,6 +23,7 @@ use update::update; #[command(author, version, about)] struct Args { file: Option, + ignore_parsing_erros: Option, } use app::App; @@ -37,16 +38,21 @@ use tui::Tui; fn main() -> Result<(), Box> { let args = Args::parse(); - let path: String; - match args.file { - Some(p) => path = p, + let path = match args.file { + Some(p) => p, None => { println!("No file path provided"); return Ok(()); } }; // Create an application. - let mut app = create_app(path)?; + let mut app = match create_app(path) { + Ok(app) => app, + Err(e) => { + println!("Could not create Application {}", e); + return Err(e); + } + }; // Initialize the terminal user interface. let backend = CrosstermBackend::new(std::io::stderr()); let terminal = Terminal::new(backend)?; @@ -71,7 +77,7 @@ fn main() -> Result<(), Box> { Ok(()) } -fn create_app(path: String) -> Result, io::Error> { +fn create_app(path: String) -> Result, Box> { let lines = read_file(path.as_str())?; let mut app = App::new(); app.file_path = path; @@ -79,7 +85,7 @@ fn create_app(path: String) -> Result, io::Error> { app.filter_list_state = ListState::default(); app.filter_list_state.select(Some(0)); app.event_table_state.select(Some(0)); - app.load_lines(&lines); + app.load_lines(&lines)?; app.get_event_types(); Ok(app) } diff --git a/src/ui.rs b/src/ui.rs index c88a629..a98a4b2 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -1,16 +1,16 @@ -use std::{str::FromStr, vec}; - use chrono::DateTime; use cleverlib::event::Event; use ratatui::{ layout::{Constraint, Direction, Layout, Rect}, - style::{Color, Modifier, Style, Styled, Stylize}, + style::{Color, Modifier, Style, Stylize}, + text::Line, widgets::{ - block::{self, Title}, + block::{self}, Block, Borders, Clear, List, ListDirection, Paragraph, Row, Table, Wrap, }, Frame, }; +use std::vec; struct Detail { timestap: String, @@ -30,7 +30,7 @@ pub fn render(app: &mut App, f: &mut Frame) { let main = Layout::default() .direction(Direction::Vertical) .constraints([Constraint::Percentage(70), Constraint::Percentage(30)]) - .split(f.size()); + .split(f.area()); let detail_area = Layout::default() .direction(Direction::Vertical) @@ -47,7 +47,7 @@ pub fn render(app: &mut App, f: &mut Frame) { .constraints([Constraint::Percentage(100)]) .split(detail_area[1]); for line in app.event_collection.events.iter() { - if app.event_types.len() >= 1 { + if !app.event_types.is_empty() { let event_level = line.level.clone().unwrap_or_default().to_string(); if app .event_types @@ -66,18 +66,18 @@ pub fn render(app: &mut App, f: &mut Frame) { ), line.message.clone().unwrap_or_default().to_string(), ]); - clef_rows.push((&line, row)); + clef_rows.push((line, row)); } } } - if clef_rows.len() >= 1 { + if !clef_rows.is_empty() { let mut selected_row_index = app.event_table_state.selected().unwrap(); let selected_row: &Event = match clef_rows.get(selected_row_index) { None => { app.event_table_state.select(Some(0)); selected_row_index = 0; - clef_rows.get(0).unwrap().0 + clef_rows.first().unwrap().0 } Some(val) => val.0, }; @@ -100,16 +100,8 @@ pub fn render(app: &mut App, f: &mut Frame) { .block( Block::default() .title("Clever") - .title( - block::Title::from(app.file_path.as_str()) - .position(block::Position::Top) - .alignment(ratatui::layout::Alignment::Left), - ) - .title( - block::Title::from(selection_text) - .position(block::Position::Bottom) - .alignment(ratatui::layout::Alignment::Center), - ) + .title_top(Line::from(app.file_path.as_str()).left_aligned()) + .title_bottom(Line::from(selection_text.as_str()).centered()) .title_position(ratatui::widgets::block::Position::Top) .title_alignment(ratatui::layout::Alignment::Center) .borders(Borders::ALL) @@ -117,7 +109,7 @@ pub fn render(app: &mut App, f: &mut Frame) { .title_style(Style::default().fg(ratatui::style::Color::White)), ) .style(Style::default().fg(ratatui::style::Color::White)) - .highlight_style(Style::default().reversed()); + .row_highlight_style(Style::default().reversed()); f.render_stateful_widget(table, main[0], &mut app.event_table_state); let log_level_detail = if detail.level.is_empty() { @@ -159,7 +151,7 @@ pub fn render(app: &mut App, f: &mut Frame) { } let stats = Block::default() .borders(Borders::ALL) - .title(block::Title::from("Detail").position(block::Position::Top)) + .title_top(Line::from("Detail")) .border_type(ratatui::widgets::BorderType::Rounded) .title("Quit:'Q' Filter:'F") .title_position(ratatui::widgets::block::Position::Bottom) @@ -172,8 +164,8 @@ pub fn render(app: &mut App, f: &mut Frame) { f.render_widget(stats, main[1]); } AppState::FILTERING => { - f.render_widget(Clear, f.size()); - let area = centered_rect(40, 30, f.size()); + f.render_widget(Clear, f.area()); + let area = centered_rect(40, 30, f.area()); let type_list: Vec = app .event_types .iter() @@ -197,11 +189,7 @@ pub fn render(app: &mut App, f: &mut Frame) { .borders(Borders::ALL) .style(Style::default().fg(Color::White)) .border_type(block::BorderType::Rounded) - .title( - Title::from("Select: Spc | Close: F") - .alignment(ratatui::layout::Alignment::Center) - .position(block::Position::Bottom), - ), + .title_bottom(Line::from("Select: Spc | Close: F").centered()), ) .style(Style::default().fg(Color::White)) .highlight_style(Style::default().add_modifier(Modifier::BOLD))