deja-vu/boot_diags/src/components/logview.rs

168 lines
5.5 KiB
Rust

// This file is part of Deja-Vu.
//
// Deja-Vu is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Deja-Vu is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Deja-Vu. If not, see <https://www.gnu.org/licenses/>.
//
use color_eyre::Result;
use ratatui::{
Frame,
layout::Rect,
widgets::{Block, Clear, Padding, Paragraph, Wrap},
};
use tokio::sync::mpsc::UnboundedSender;
use core::{
action::Action,
components::{Component, state::StatefulList},
config::Config,
state::Mode,
};
use std::{
cmp::min,
sync::{Arc, Mutex},
};
use crate::diags::DiagGroup;
#[derive(Default, Debug, Clone)]
pub struct LogView {
command_tx: Option<UnboundedSender<Action>>,
config: Config,
line_index: u16,
list: StatefulList<String>,
mode: Mode,
diag_groups: Arc<Mutex<Vec<DiagGroup>>>,
}
impl LogView {
#[must_use]
pub fn new(diag_groups: Arc<Mutex<Vec<DiagGroup>>>) -> Self {
LogView {
diag_groups,
..Default::default()
}
}
}
impl Component for LogView {
fn register_action_handler(&mut self, tx: UnboundedSender<Action>) -> Result<()> {
self.command_tx = Some(tx);
Ok(())
}
fn register_config_handler(&mut self, config: Config) -> Result<()> {
self.config = config;
Ok(())
}
fn update(&mut self, action: Action) -> Result<Option<Action>> {
match action {
Action::KeyUp => {
if self.mode == Mode::LogView {
if self.line_index > 0 {
self.line_index = self.line_index - 1;
}
} else {
self.list.previous();
}
}
Action::KeyDown => {
if self.mode == Mode::LogView {
let new_index = self.line_index + 1;
if let Some(log_text) = self.list.get_selected() {
let lines: Vec<&str> = log_text.split('\n').collect();
if new_index as usize > lines.len() {
self.line_index = lines.len() as u16;
} else {
self.line_index = new_index;
}
}
} else {
self.list.next();
}
}
Action::KeyPageUp => {
if self.mode == Mode::LogView {
if self.line_index > 10 {
self.line_index -= 10;
} else {
self.line_index = 0;
}
}
}
Action::KeyPageDown => {
if self.mode == Mode::LogView {
let new_index = self.line_index + 10;
if let Some(log_text) = self.list.get_selected() {
let lines: Vec<&str> = log_text.split('\n').collect();
let new_index: u16 = min((lines.len() - 3) as u16, new_index);
self.line_index = new_index;
}
}
}
Action::KeyHome => {
if self.mode == Mode::LogView {
self.line_index = 0;
}
}
Action::KeyEnd => {
if self.mode == Mode::LogView {
if let Some(log_text) = self.list.get_selected() {
let lines: Vec<&str> = log_text.split('\n').collect();
self.line_index = (lines.len() - 3) as u16;
}
}
}
Action::Process => {
if self.mode == Mode::LogView {
if let Some(command_tx) = self.command_tx.clone() {
command_tx.send(Action::SetMode(Mode::BootDiags))?;
}
}
}
Action::SetMode(new_mode) => {
self.line_index = 0;
self.mode = new_mode;
if self.mode == Mode::BootDiags {
self.list.clear_items();
if let Ok(diag_groups) = self.diag_groups.lock() {
let raw_logs = diag_groups
.iter()
.map(|group| group.get_logs_raw())
.collect();
self.list.set_items(raw_logs);
}
}
}
_ => {}
};
Ok(None)
}
fn draw(&mut self, frame: &mut Frame, rect: Rect) -> Result<()> {
if self.mode != Mode::LogView {
return Ok(());
}
if let Some(log_text) = self.list.get_selected() {
let paragraph = Paragraph::new(log_text)
.wrap(Wrap { trim: true })
.scroll((self.line_index, 0))
.block(Block::bordered().padding(Padding::horizontal(1)));
frame.render_widget(Clear, rect);
frame.render_widget(paragraph, rect);
}
Ok(())
}
}