168 lines
5.5 KiB
Rust
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(())
|
|
}
|
|
}
|