1use std::error;
2
3use getset::{Getters, Setters};
4use ratatui::{layout::Rect, Frame};
5
6use crate::{
7 cli::{Cli, FileFormat},
8 csv_data::CsvData,
9 log_view::LogView,
10 LogData, LogViewState, TxtData, ViewPort,
11};
12
13pub type AppResult<T> = std::result::Result<T, Box<dyn error::Error>>;
15
16#[derive(Debug, Getters, Setters)]
18#[getset(get = "pub", set = "pub")]
19pub struct App {
20 running: bool,
22
23 cli: Cli,
24
25 data: Box<dyn LogData>,
26
27 viewstate: LogViewState,
28
29 page_size: u16,
30}
31
32impl App {
33 pub fn new(cli: Cli) -> anyhow::Result<Self> {
35 let data: Box<dyn LogData> = match cli.file_format() {
36 FileFormat::Csv => Box::new(CsvData::try_from(cli.file().path())?),
37 FileFormat::Txt => Box::new(TxtData::load_from(cli.file().path(), *cli.delimiter())?),
38 };
39
40 let viewstate = LogViewState::default();
41 Ok(Self {
42 running: true,
43 cli,
44 data,
45 viewstate,
46 page_size: 1,
47 })
48 }
49
50 pub fn tick(&self) {}
52
53 pub fn quit(&mut self) {
55 self.running = false;
56 }
57
58 pub fn forward(&mut self, steps: usize) {
59 if !self.data().is_empty() {
60 self.viewstate.set_vscroll_offset(usize::min(
61 *self.viewstate().vscroll_offset() + steps,
62 self.data().len() - 1,
63 ));
64 }
65 }
66
67 pub fn backward(&mut self, steps: usize) {
68 self.viewstate
69 .set_vscroll_offset(usize::max(*self.viewstate.vscroll_offset(), steps) - steps);
70 }
71
72 pub fn begin(&mut self) {
73 self.viewstate.set_vscroll_offset(0);
74 }
75
76 pub fn end(&mut self) {
77 if !self.data().is_empty() {
78 self.viewstate.set_vscroll_offset(self.data().len() - 1);
79 }
80 }
81
82 pub fn right(&mut self, steps: usize) {
83 let viewport = ViewPort::new(self.viewstate.hscroll_offset() + steps, 0, 44, 55);
84 let width: usize = self.data.data_widths(&viewport).sum();
85 if width > 0 {
86 self.viewstate
87 .set_hscroll_offset(self.viewstate.hscroll_offset() + steps);
88 }
89 }
90
91 pub fn left(&mut self, steps: usize) {
92 if *self.viewstate.hscroll_offset() >= steps {
93 self.viewstate
94 .set_hscroll_offset(self.viewstate.hscroll_offset() - steps);
95 } else {
96 self.viewstate.set_hscroll_offset(0);
97 }
98 }
99
100 pub fn render_log_contents(&mut self, frame: &mut Frame, area: Rect) {
101 let mut viewstate = *self.csv_viewstate();
102 frame.render_stateful_widget(
103 LogView::from(self.data.as_ref()).with_mask_unicode(*self.cli.mask_unicode()),
104 area,
105 &mut viewstate,
106 );
107 self.viewstate = viewstate;
108 }
109
110 pub fn csv_viewstate(&self) -> &LogViewState {
111 &self.viewstate
112 }
113}