mirror of
https://github.com/ClementTsang/bottom
synced 2025-02-15 12:48:28 +00:00
Added dialog for dd, added error message if fail to dd, cleaned up some stuff
This commit is contained in:
parent
7208908413
commit
b22c07aba2
5 changed files with 289 additions and 168 deletions
214
src/app.rs
214
src/app.rs
|
@ -2,7 +2,7 @@ pub mod data_collection;
|
|||
use data_collection::{processes, temperature};
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::constants;
|
||||
use crate::{canvas, constants, data_conversion::ConvertedProcessData, utils::error::Result};
|
||||
|
||||
mod process_killer;
|
||||
|
||||
|
@ -47,10 +47,14 @@ pub struct App {
|
|||
second_char: char,
|
||||
pub use_dot: bool,
|
||||
pub show_help: bool,
|
||||
pub show_dd: bool,
|
||||
pub dd_err: Option<String>,
|
||||
to_delete_process: Option<ConvertedProcessData>,
|
||||
pub is_frozen: bool,
|
||||
pub left_legend: bool,
|
||||
pub use_current_cpu_total: bool,
|
||||
last_key_press: Instant,
|
||||
pub canvas_data: canvas::CanvasData,
|
||||
}
|
||||
|
||||
impl App {
|
||||
|
@ -80,15 +84,23 @@ impl App {
|
|||
second_char: ' ',
|
||||
use_dot,
|
||||
show_help: false,
|
||||
show_dd: false,
|
||||
dd_err: None,
|
||||
to_delete_process: None,
|
||||
is_frozen: false,
|
||||
left_legend,
|
||||
use_current_cpu_total,
|
||||
last_key_press: Instant::now(),
|
||||
canvas_data: canvas::CanvasData::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.reset_multi_tap_keys();
|
||||
self.show_help = false;
|
||||
self.show_dd = false;
|
||||
self.to_delete_process = None;
|
||||
self.dd_err = None;
|
||||
}
|
||||
|
||||
fn reset_multi_tap_keys(&mut self) {
|
||||
|
@ -96,18 +108,30 @@ impl App {
|
|||
self.second_char = ' ';
|
||||
}
|
||||
|
||||
pub fn on_enter(&mut self) {}
|
||||
|
||||
pub fn on_esc(&mut self) {
|
||||
if self.show_help {
|
||||
self.show_help = false;
|
||||
}
|
||||
self.reset_multi_tap_keys();
|
||||
fn is_in_dialog(&self) -> bool {
|
||||
self.show_help || self.show_dd
|
||||
}
|
||||
|
||||
// TODO: How should we make it for process panel specific hotkeys? Only if we're on process panel? Or what?
|
||||
pub fn on_key(&mut self, caught_char: char) {
|
||||
if !self.show_help {
|
||||
/// One of two functions allowed to run while in a dialog...
|
||||
pub fn on_enter(&mut self) {
|
||||
if self.show_dd {
|
||||
// If within dd...
|
||||
if self.dd_err.is_none() {
|
||||
// Also ensure that we didn't just fail a dd...
|
||||
let dd_result = self.kill_highlighted_process();
|
||||
if let Err(dd_err) = dd_result {
|
||||
// There was an issue... inform the user...
|
||||
self.dd_err = Some(dd_err.to_string());
|
||||
} else {
|
||||
self.show_dd = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_char_key(&mut self, caught_char: char) {
|
||||
// Forbid any char key presses when showing a dialog box...
|
||||
if !self.is_in_dialog() {
|
||||
let current_key_press_inst = Instant::now();
|
||||
if current_key_press_inst.duration_since(self.last_key_press).as_millis() > constants::MAX_KEY_TIMEOUT_IN_MILLISECONDS {
|
||||
self.reset_multi_tap_keys();
|
||||
|
@ -120,7 +144,11 @@ impl App {
|
|||
if self.awaiting_second_char && self.second_char == 'd' {
|
||||
self.awaiting_second_char = false;
|
||||
self.second_char = ' ';
|
||||
self.kill_highlighted_process().unwrap_or(()); // TODO: Return error to user? We have a dialog box...
|
||||
|
||||
let current_process = &self.canvas_data.process_data[self.currently_selected_process_position as usize];
|
||||
self.to_delete_process = Some(current_process.clone());
|
||||
self.show_dd = true;
|
||||
self.reset_multi_tap_keys();
|
||||
} else {
|
||||
self.awaiting_second_char = true;
|
||||
self.second_char = 'd';
|
||||
|
@ -196,12 +224,21 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
fn kill_highlighted_process(&self) -> crate::utils::error::Result<()> {
|
||||
let current_pid = u64::from(self.data.list_of_processes[self.currently_selected_process_position as usize].pid);
|
||||
process_killer::kill_process_given_pid(current_pid)?;
|
||||
pub fn kill_highlighted_process(&mut self) -> Result<()> {
|
||||
// Technically unnecessary but this is a good check...
|
||||
if let ApplicationPosition::Process = self.current_application_position {
|
||||
if let Some(current_selected_process) = &(self.to_delete_process) {
|
||||
process_killer::kill_process_given_pid(current_selected_process.pid)?;
|
||||
}
|
||||
self.to_delete_process = None;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_current_highlighted_process(&self) -> Option<ConvertedProcessData> {
|
||||
self.to_delete_process.clone()
|
||||
}
|
||||
|
||||
// For now, these are hard coded --- in the future, they shouldn't be!
|
||||
//
|
||||
// General idea for now:
|
||||
|
@ -212,91 +249,118 @@ impl App {
|
|||
// Network -(up)> MEM, -(right)> PROC
|
||||
// PROC -(up)> Disk, -(left)> Network
|
||||
pub fn on_left(&mut self) {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Process => ApplicationPosition::Network,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Mem,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Process => ApplicationPosition::Network,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Mem,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_right(&mut self) {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Mem => ApplicationPosition::Temp,
|
||||
ApplicationPosition::Network => ApplicationPosition::Process,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Mem => ApplicationPosition::Temp,
|
||||
ApplicationPosition::Network => ApplicationPosition::Process,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_up(&mut self) {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Mem => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Network => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Process => ApplicationPosition::Disk,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Temp,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Mem => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Network => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Process => ApplicationPosition::Disk,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Temp,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_down(&mut self) {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Cpu => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Mem => ApplicationPosition::Network,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Disk,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Process,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Cpu => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Mem => ApplicationPosition::Network,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Disk,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Process,
|
||||
_ => self.current_application_position,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_to_first(&mut self) {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.currently_selected_process_position = 0,
|
||||
ApplicationPosition::Temp => self.currently_selected_temperature_position = 0,
|
||||
ApplicationPosition::Disk => self.currently_selected_disk_position = 0,
|
||||
_ => {}
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.currently_selected_process_position = 0,
|
||||
ApplicationPosition::Temp => self.currently_selected_temperature_position = 0,
|
||||
ApplicationPosition::Disk => self.currently_selected_disk_position = 0,
|
||||
ApplicationPosition::Cpu => self.currently_selected_cpu_table_position = 0,
|
||||
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::UP;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::UP;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
pub fn skip_to_last(&mut self) {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.currently_selected_process_position = self.data.list_of_processes.len() as i64 - 1,
|
||||
ApplicationPosition::Temp => self.currently_selected_temperature_position = self.data.list_of_temperature_sensor.len() as i64 - 1,
|
||||
ApplicationPosition::Disk => self.currently_selected_disk_position = self.data.list_of_disks.len() as i64 - 1,
|
||||
_ => {}
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.currently_selected_process_position = self.data.list_of_processes.len() as i64 - 1,
|
||||
ApplicationPosition::Temp => self.currently_selected_temperature_position = self.data.list_of_temperature_sensor.len() as i64 - 1,
|
||||
ApplicationPosition::Disk => self.currently_selected_disk_position = self.data.list_of_disks.len() as i64 - 1,
|
||||
ApplicationPosition::Cpu => {
|
||||
if let Some(cpu_package) = self.data.list_of_cpu_packages.last() {
|
||||
if self.show_average_cpu {
|
||||
self.currently_selected_cpu_table_position = cpu_package.cpu_vec.len() as i64;
|
||||
} else {
|
||||
self.currently_selected_cpu_table_position = cpu_package.cpu_vec.len() as i64 - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::DOWN;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::DOWN;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
pub fn decrement_position_count(&mut self) {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.change_process_position(-1),
|
||||
ApplicationPosition::Temp => self.change_temp_position(-1),
|
||||
ApplicationPosition::Disk => self.change_disk_position(-1),
|
||||
ApplicationPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.change_process_position(-1),
|
||||
ApplicationPosition::Temp => self.change_temp_position(-1),
|
||||
ApplicationPosition::Disk => self.change_disk_position(-1),
|
||||
ApplicationPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::UP;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::UP;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
pub fn increment_position_count(&mut self) {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.change_process_position(1),
|
||||
ApplicationPosition::Temp => self.change_temp_position(1),
|
||||
ApplicationPosition::Disk => self.change_disk_position(1),
|
||||
ApplicationPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.change_process_position(1),
|
||||
ApplicationPosition::Temp => self.change_temp_position(1),
|
||||
ApplicationPosition::Disk => self.change_disk_position(1),
|
||||
ApplicationPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::DOWN;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::DOWN;
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
||||
fn change_cpu_table_position(&mut self, num_to_change_by: i64) {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
/// This file is meant to house (OS specific) implementations on how to kill processes.
|
||||
use crate::utils::error::{BottomError, Result};
|
||||
use std::process::Command;
|
||||
|
||||
// TODO: Make it update process list on freeze.
|
||||
|
||||
// Copied from SO: https://stackoverflow.com/a/55231715
|
||||
#[cfg(target_os = "windows")]
|
||||
use winapi::{
|
||||
|
@ -33,7 +32,7 @@ impl Process {
|
|||
}
|
||||
|
||||
/// Kills a process, given a PID.
|
||||
pub fn kill_process_given_pid(pid: u64) -> crate::utils::error::Result<()> {
|
||||
pub fn kill_process_given_pid(pid: u32) -> Result<()> {
|
||||
if cfg!(target_os = "linux") {
|
||||
// Linux
|
||||
Command::new("kill").arg(pid.to_string()).output()?;
|
||||
|
@ -45,10 +44,14 @@ pub fn kill_process_given_pid(pid: u64) -> crate::utils::error::Result<()> {
|
|||
} else if cfg!(target_os = "macos") {
|
||||
// TODO: macOS
|
||||
// See how sysinfo does it... https://docs.rs/sysinfo/0.9.5/sysinfo/trait.ProcessExt.html
|
||||
debug!("Sorry, macOS support is not implemented yet!");
|
||||
return Err(BottomError::GenericError {
|
||||
message: "Sorry, macOS support is not implemented yet!".to_string(),
|
||||
});
|
||||
} else {
|
||||
// TODO: Others?
|
||||
debug!("Sorry, other support this is not implemented yet!");
|
||||
return Err(BottomError::GenericError {
|
||||
message: "Sorry, support operating systems outside the main three is not implemented yet!".to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
151
src/canvas.rs
151
src/canvas.rs
|
@ -1,4 +1,4 @@
|
|||
use crate::{app, constants, utils::error, utils::gen_util::*};
|
||||
use crate::{app, constants, data_conversion::ConvertedProcessData, utils::error, utils::gen_util::*};
|
||||
use tui::{
|
||||
backend,
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
|
@ -46,7 +46,7 @@ pub struct CanvasData {
|
|||
pub network_data_tx: Vec<(f64, f64)>,
|
||||
pub disk_data: Vec<Vec<String>>,
|
||||
pub temp_sensor_data: Vec<Vec<String>>,
|
||||
pub process_data: Vec<Vec<String>>,
|
||||
pub process_data: Vec<ConvertedProcessData>,
|
||||
pub memory_labels: Vec<(u64, u64)>,
|
||||
pub mem_data: Vec<(f64, f64)>,
|
||||
pub swap_data: Vec<(f64, f64)>,
|
||||
|
@ -93,11 +93,11 @@ fn gen_n_colours(num_to_gen: i32) -> Vec<Color> {
|
|||
colour_vec
|
||||
}
|
||||
|
||||
pub fn draw_data<B: backend::Backend>(terminal: &mut Terminal<B>, app_state: &mut app::App, canvas_data: &CanvasData) -> error::Result<()> {
|
||||
pub fn draw_data<B: backend::Backend>(terminal: &mut Terminal<B>, app_state: &mut app::App) -> error::Result<()> {
|
||||
terminal.autoresize()?;
|
||||
terminal.draw(|mut f| {
|
||||
if app_state.show_help {
|
||||
// Only for the dialog (help, dd) menus
|
||||
// Only for the help
|
||||
let vertical_dialog_chunk = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(1)
|
||||
|
@ -116,6 +116,52 @@ pub fn draw_data<B: backend::Backend>(terminal: &mut Terminal<B>, app_state: &mu
|
|||
.alignment(Alignment::Left)
|
||||
.wrap(true)
|
||||
.render(&mut f, middle_dialog_chunk[1]);
|
||||
} else if app_state.show_dd {
|
||||
let vertical_dialog_chunk = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
.margin(1)
|
||||
.constraints([Constraint::Percentage(40), Constraint::Percentage(20), Constraint::Percentage(40)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let middle_dialog_chunk = Layout::default()
|
||||
.direction(Direction::Horizontal)
|
||||
.margin(0)
|
||||
.constraints([Constraint::Percentage(30), Constraint::Percentage(40), Constraint::Percentage(30)].as_ref())
|
||||
.split(vertical_dialog_chunk[1]);
|
||||
|
||||
if let Some(dd_err) = app_state.dd_err.clone() {
|
||||
let dd_text = [Text::raw(format!("\nFailure to properly kill the process - {}", dd_err))];
|
||||
|
||||
Paragraph::new(dd_text.iter())
|
||||
.block(Block::default().title("Kill Process Error (Press Esc to close)").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.alignment(Alignment::Center)
|
||||
.wrap(true)
|
||||
.render(&mut f, middle_dialog_chunk[1]);
|
||||
} else if let Some(process) = app_state.get_current_highlighted_process() {
|
||||
let dd_text = [
|
||||
Text::raw(format!(
|
||||
"\nAre you sure you want to kill process {} with PID {}?",
|
||||
process.name, process.pid
|
||||
)),
|
||||
Text::raw("\n\nPress ENTER to proceed, ESC to exit."),
|
||||
Text::raw("\nNote that if bottom is frozen, it must be unfrozen for changes to be shown."),
|
||||
];
|
||||
|
||||
Paragraph::new(dd_text.iter())
|
||||
.block(
|
||||
Block::default()
|
||||
.title("Kill Process Confirmation (Press Esc to close)")
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.alignment(Alignment::Center)
|
||||
.wrap(true)
|
||||
.render(&mut f, middle_dialog_chunk[1]);
|
||||
} else {
|
||||
// This is a bit nasty, but it works well... I guess.
|
||||
app_state.show_dd = false;
|
||||
}
|
||||
} else {
|
||||
let vertical_chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
|
@ -174,27 +220,18 @@ pub fn draw_data<B: backend::Backend>(terminal: &mut Terminal<B>, app_state: &mu
|
|||
|
||||
// Set up blocks and their components
|
||||
// CPU graph
|
||||
draw_cpu_graph(&mut f, &app_state, &canvas_data.cpu_data, cpu_chunk[graph_index]);
|
||||
draw_cpu_graph(&mut f, &app_state, cpu_chunk[graph_index]);
|
||||
|
||||
// CPU legend
|
||||
draw_cpu_legend(&mut f, app_state, &canvas_data.cpu_data, cpu_chunk[legend_index]);
|
||||
draw_cpu_legend(&mut f, app_state, cpu_chunk[legend_index]);
|
||||
|
||||
//Memory usage graph
|
||||
draw_memory_graph(
|
||||
&mut f,
|
||||
&app_state,
|
||||
&canvas_data.memory_labels,
|
||||
&canvas_data.mem_data,
|
||||
&canvas_data.swap_data,
|
||||
middle_chunks[0],
|
||||
);
|
||||
draw_memory_graph(&mut f, &app_state, middle_chunks[0]);
|
||||
|
||||
// Network graph
|
||||
draw_network_graph(
|
||||
&mut f,
|
||||
&app_state,
|
||||
&canvas_data.network_data_rx,
|
||||
&canvas_data.network_data_tx,
|
||||
if cfg!(not(target_os = "windows")) {
|
||||
network_chunk[0]
|
||||
} else {
|
||||
|
@ -202,45 +239,26 @@ pub fn draw_data<B: backend::Backend>(terminal: &mut Terminal<B>, app_state: &mu
|
|||
},
|
||||
);
|
||||
|
||||
if cfg!(not(target_os = "windows")) {
|
||||
draw_network_labels(
|
||||
&mut f,
|
||||
app_state,
|
||||
canvas_data.rx_display.clone(),
|
||||
canvas_data.tx_display.clone(),
|
||||
canvas_data.total_rx_display.clone(),
|
||||
canvas_data.total_tx_display.clone(),
|
||||
network_chunk[1],
|
||||
);
|
||||
} else {
|
||||
draw_network_labels(
|
||||
&mut f,
|
||||
app_state,
|
||||
canvas_data.rx_display.clone(),
|
||||
canvas_data.tx_display.clone(),
|
||||
"N/A".to_string(),
|
||||
"N/A".to_string(),
|
||||
network_chunk[1],
|
||||
);
|
||||
}
|
||||
draw_network_labels(&mut f, app_state, network_chunk[1]);
|
||||
|
||||
// Temperature table
|
||||
draw_temp_table(&mut f, app_state, &canvas_data.temp_sensor_data, middle_divided_chunk_2[0]);
|
||||
draw_temp_table(&mut f, app_state, middle_divided_chunk_2[0]);
|
||||
|
||||
// Disk usage table
|
||||
draw_disk_table(&mut f, app_state, &canvas_data.disk_data, middle_divided_chunk_2[1]);
|
||||
draw_disk_table(&mut f, app_state, middle_divided_chunk_2[1]);
|
||||
|
||||
// Processes table
|
||||
draw_processes_table(&mut f, app_state, &canvas_data.process_data, bottom_chunks[1]);
|
||||
draw_processes_table(&mut f, app_state, bottom_chunks[1]);
|
||||
}
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn draw_cpu_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, cpu_data: &[(String, Vec<(f64, f64)>)], draw_loc: Rect) {
|
||||
// CPU usage graph
|
||||
fn draw_cpu_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, draw_loc: Rect) {
|
||||
let cpu_data: &[(String, Vec<(f64, f64)>)] = &app_state.canvas_data.cpu_data;
|
||||
|
||||
// CPU usage graph
|
||||
let x_axis: Axis<String> = Axis::default()
|
||||
.style(Style::default().fg(GRAPH_COLOUR))
|
||||
.bounds([0.0, constants::TIME_STARTS_FROM as f64 * 10.0]);
|
||||
|
@ -296,7 +314,9 @@ fn draw_cpu_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, c
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_cpu_legend<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, cpu_data: &[(String, Vec<(f64, f64)>)], draw_loc: Rect) {
|
||||
fn draw_cpu_legend<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect) {
|
||||
let cpu_data: &[(String, Vec<(f64, f64)>)] = &(app_state.canvas_data.cpu_data);
|
||||
|
||||
let num_rows = i64::from(draw_loc.height) - 4;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
|
@ -345,9 +365,11 @@ fn draw_cpu_legend<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::A
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_memory_graph<B: backend::Backend>(
|
||||
f: &mut Frame<B>, app_state: &app::App, memory_labels: &[(u64, u64)], mem_data: &[(f64, f64)], swap_data: &[(f64, f64)], draw_loc: Rect,
|
||||
) {
|
||||
fn draw_memory_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, draw_loc: Rect) {
|
||||
let mem_data: &[(f64, f64)] = &(app_state.canvas_data.mem_data);
|
||||
let swap_data: &[(f64, f64)] = &(app_state.canvas_data.swap_data);
|
||||
let memory_labels: &[(u64, u64)] = &(app_state.canvas_data.memory_labels);
|
||||
|
||||
let x_axis: Axis<String> = Axis::default()
|
||||
.style(Style::default().fg(GRAPH_COLOUR))
|
||||
.bounds([0.0, constants::TIME_STARTS_FROM as f64 * 10.0]);
|
||||
|
@ -408,9 +430,10 @@ fn draw_memory_graph<B: backend::Backend>(
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_network_graph<B: backend::Backend>(
|
||||
f: &mut Frame<B>, app_state: &app::App, network_data_rx: &[(f64, f64)], network_data_tx: &[(f64, f64)], draw_loc: Rect,
|
||||
) {
|
||||
fn draw_network_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, draw_loc: Rect) {
|
||||
let network_data_rx: &[(f64, f64)] = &(app_state.canvas_data.network_data_rx);
|
||||
let network_data_tx: &[(f64, f64)] = &(app_state.canvas_data.network_data_tx);
|
||||
|
||||
let x_axis: Axis<String> = Axis::default().style(Style::default().fg(GRAPH_COLOUR)).bounds([0.0, 600_000.0]);
|
||||
let y_axis = Axis::default()
|
||||
.style(Style::default().fg(GRAPH_COLOUR))
|
||||
|
@ -441,10 +464,12 @@ fn draw_network_graph<B: backend::Backend>(
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_network_labels<B: backend::Backend>(
|
||||
f: &mut Frame<B>, app_state: &mut app::App, rx_display: String, tx_display: String, total_rx_display: String, total_tx_display: String,
|
||||
draw_loc: Rect,
|
||||
) {
|
||||
fn draw_network_labels<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect) {
|
||||
let rx_display: String = app_state.canvas_data.rx_display.clone();
|
||||
let tx_display: String = app_state.canvas_data.tx_display.clone();
|
||||
let total_rx_display: String = app_state.canvas_data.total_rx_display.clone();
|
||||
let total_tx_display: String = app_state.canvas_data.total_tx_display.clone();
|
||||
|
||||
// Gross but I need it to work...
|
||||
let total_network = vec![vec![rx_display, tx_display, total_rx_display, total_tx_display]];
|
||||
let mapped_network = total_network.iter().map(|val| Row::Data(val.iter()));
|
||||
|
@ -468,7 +493,9 @@ fn draw_network_labels<B: backend::Backend>(
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_temp_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, temp_sensor_data: &[Vec<String>], draw_loc: Rect) {
|
||||
fn draw_temp_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect) {
|
||||
let temp_sensor_data: &[Vec<String>] = &(app_state.canvas_data.temp_sensor_data);
|
||||
|
||||
let num_rows = i64::from(draw_loc.height) - 4;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
|
@ -511,7 +538,8 @@ fn draw_temp_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::A
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_disk_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, disk_data: &[Vec<String>], draw_loc: Rect) {
|
||||
fn draw_disk_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect) {
|
||||
let disk_data: &[Vec<String>] = &(app_state.canvas_data.disk_data);
|
||||
let num_rows = i64::from(draw_loc.height) - 4;
|
||||
let start_position = get_start_position(
|
||||
num_rows,
|
||||
|
@ -563,7 +591,8 @@ fn draw_disk_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::A
|
|||
.render(f, draw_loc);
|
||||
}
|
||||
|
||||
fn draw_processes_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, process_data: &[Vec<String>], draw_loc: Rect) {
|
||||
fn draw_processes_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect) {
|
||||
let process_data: &[ConvertedProcessData] = &(app_state.canvas_data.process_data);
|
||||
let width = f64::from(draw_loc.width);
|
||||
|
||||
// Admittedly this is kinda a hack... but we need to:
|
||||
|
@ -580,12 +609,18 @@ fn draw_processes_table<B: backend::Backend>(f: &mut Frame<B>, app_state: &mut a
|
|||
&mut app_state.currently_selected_process_position,
|
||||
);
|
||||
|
||||
let sliced_vec: Vec<Vec<String>> = (&process_data[start_position as usize..]).to_vec();
|
||||
let sliced_vec: Vec<ConvertedProcessData> = (&process_data[start_position as usize..]).to_vec();
|
||||
let mut process_counter = 0;
|
||||
|
||||
let process_rows = sliced_vec.iter().map(|process| {
|
||||
let stringified_process_vec: Vec<String> = vec![
|
||||
process.pid.to_string(),
|
||||
process.name.clone(),
|
||||
process.cpu_usage.clone(),
|
||||
process.mem_usage.clone(),
|
||||
];
|
||||
Row::StyledData(
|
||||
process.iter(),
|
||||
stringified_process_vec.into_iter(),
|
||||
if process_counter == app_state.currently_selected_process_position - start_position {
|
||||
process_counter = -1;
|
||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
};
|
||||
use constants::*;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ConvertedNetworkData {
|
||||
pub rx: Vec<(f64, f64)>,
|
||||
pub tx: Vec<(f64, f64)>,
|
||||
|
@ -14,6 +15,14 @@ pub struct ConvertedNetworkData {
|
|||
pub total_tx_display: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct ConvertedProcessData {
|
||||
pub pid: u32,
|
||||
pub name: String,
|
||||
pub cpu_usage: String,
|
||||
pub mem_usage: String,
|
||||
}
|
||||
|
||||
pub fn update_temp_row(app_data: &data_collection::Data, temp_type: &data_collection::temperature::TemperatureType) -> Vec<Vec<String>> {
|
||||
let mut sensor_vector: Vec<Vec<String>> = Vec::new();
|
||||
|
||||
|
@ -84,15 +93,15 @@ pub fn update_disk_row(app_data: &data_collection::Data) -> Vec<Vec<String>> {
|
|||
disk_vector
|
||||
}
|
||||
|
||||
pub fn update_process_row(app_data: &data_collection::Data) -> Vec<Vec<String>> {
|
||||
let mut process_vector: Vec<Vec<String>> = Vec::new();
|
||||
pub fn update_process_row(app_data: &data_collection::Data) -> Vec<ConvertedProcessData> {
|
||||
let mut process_vector: Vec<ConvertedProcessData> = Vec::new();
|
||||
|
||||
for process in &app_data.list_of_processes {
|
||||
process_vector.push(vec![
|
||||
process.pid.to_string(),
|
||||
process.command.to_string(),
|
||||
format!("{:.1}%", process.cpu_usage_percent),
|
||||
format!(
|
||||
process_vector.push(ConvertedProcessData {
|
||||
pid: process.pid,
|
||||
name: process.command.to_string(),
|
||||
cpu_usage: format!("{:.1}%", process.cpu_usage_percent),
|
||||
mem_usage: format!(
|
||||
"{:.1}%",
|
||||
if let Some(mem_usage) = process.mem_usage_percent {
|
||||
mem_usage
|
||||
|
@ -106,7 +115,7 @@ pub fn update_process_row(app_data: &data_collection::Data) -> Vec<Vec<String>>
|
|||
0_f64
|
||||
}
|
||||
),
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
process_vector
|
||||
|
@ -300,7 +309,11 @@ pub fn convert_network_data_points(network_data: &[data_collection::network::Net
|
|||
total_rx_converted_result = get_exact_byte_values(0, false);
|
||||
}
|
||||
let rx_display = format!("{:.*}{}", 1, rx_converted_result.0, rx_converted_result.1);
|
||||
let total_rx_display = format!("{:.*}{}", 1, total_rx_converted_result.0, total_rx_converted_result.1);
|
||||
let total_rx_display = if cfg!(not(target_os = "windows")) {
|
||||
format!("{:.*}{}", 1, total_rx_converted_result.0, total_rx_converted_result.1)
|
||||
} else {
|
||||
"N/A".to_string()
|
||||
};
|
||||
|
||||
if let Some(last_num_bytes_entry) = network_data.last() {
|
||||
tx_converted_result = get_exact_byte_values(last_num_bytes_entry.tx, false);
|
||||
|
@ -310,7 +323,11 @@ pub fn convert_network_data_points(network_data: &[data_collection::network::Net
|
|||
total_tx_converted_result = get_exact_byte_values(0, false);
|
||||
}
|
||||
let tx_display = format!("{:.*}{}", 1, tx_converted_result.0, tx_converted_result.1);
|
||||
let total_tx_display = format!("{:.*}{}", 1, total_tx_converted_result.0, total_tx_converted_result.1);
|
||||
let total_tx_display = if cfg!(not(target_os = "windows")) {
|
||||
format!("{:.*}{}", 1, total_tx_converted_result.0, total_tx_converted_result.1)
|
||||
} else {
|
||||
"N/A".to_string()
|
||||
};
|
||||
|
||||
ConvertedNetworkData {
|
||||
rx,
|
||||
|
|
42
src/main.rs
42
src/main.rs
|
@ -177,7 +177,7 @@ fn main() -> error::Result<()> {
|
|||
if let Ok(message) = rrx.try_recv() {
|
||||
match message {
|
||||
ResetEvent::Reset => {
|
||||
debug!("Received reset message");
|
||||
//debug!("Received reset message");
|
||||
first_run = true;
|
||||
data_state.data = app::data_collection::Data::default();
|
||||
}
|
||||
|
@ -197,7 +197,6 @@ fn main() -> error::Result<()> {
|
|||
});
|
||||
}
|
||||
|
||||
let mut canvas_data = canvas::CanvasData::default();
|
||||
loop {
|
||||
if let Ok(recv) = rx.recv_timeout(Duration::from_millis(TICK_RATE_IN_MILLISECONDS)) {
|
||||
match recv {
|
||||
|
@ -213,8 +212,9 @@ fn main() -> error::Result<()> {
|
|||
KeyCode::Char('j') => app.on_down(),
|
||||
KeyCode::Up => app.decrement_position_count(),
|
||||
KeyCode::Down => app.increment_position_count(),
|
||||
KeyCode::Char(uncaught_char) => app.on_key(uncaught_char),
|
||||
KeyCode::Esc => app.on_esc(),
|
||||
KeyCode::Char(uncaught_char) => app.on_char_key(uncaught_char),
|
||||
KeyCode::Esc => app.reset(),
|
||||
KeyCode::Enter => app.on_enter(),
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
|
@ -260,7 +260,7 @@ fn main() -> error::Result<()> {
|
|||
&app.process_sorting_type,
|
||||
app.process_sorting_reverse,
|
||||
);
|
||||
canvas_data.process_data = update_process_row(&app.data);
|
||||
app.canvas_data.process_data = update_process_row(&app.data);
|
||||
app.to_be_resorted = false;
|
||||
}
|
||||
}
|
||||
|
@ -270,6 +270,8 @@ fn main() -> error::Result<()> {
|
|||
_ => {}
|
||||
},
|
||||
Event::Update(data) => {
|
||||
// NOTE TO SELF - data is refreshed into app state HERE! That means, if it is
|
||||
// frozen, then, app.data is never refreshed, until unfrozen!
|
||||
if !app.is_frozen {
|
||||
app.data = *data;
|
||||
|
||||
|
@ -280,28 +282,28 @@ fn main() -> error::Result<()> {
|
|||
);
|
||||
|
||||
// Convert all data into tui components
|
||||
// TODO: Note that we might want to move this the canvas' side... consider.
|
||||
let network_data = update_network_data_points(&app.data);
|
||||
canvas_data.network_data_rx = network_data.rx;
|
||||
canvas_data.network_data_tx = network_data.tx;
|
||||
canvas_data.rx_display = network_data.rx_display;
|
||||
canvas_data.tx_display = network_data.tx_display;
|
||||
canvas_data.total_rx_display = network_data.total_rx_display;
|
||||
canvas_data.total_tx_display = network_data.total_tx_display;
|
||||
canvas_data.disk_data = update_disk_row(&app.data);
|
||||
canvas_data.temp_sensor_data = update_temp_row(&app.data, &app.temperature_type);
|
||||
canvas_data.process_data = update_process_row(&app.data);
|
||||
canvas_data.mem_data = update_mem_data_points(&app.data);
|
||||
canvas_data.memory_labels = update_mem_data_values(&app.data);
|
||||
canvas_data.swap_data = update_swap_data_points(&app.data);
|
||||
canvas_data.cpu_data = update_cpu_data_points(app.show_average_cpu, &app.data);
|
||||
|
||||
app.canvas_data.network_data_rx = network_data.rx;
|
||||
app.canvas_data.network_data_tx = network_data.tx;
|
||||
app.canvas_data.rx_display = network_data.rx_display;
|
||||
app.canvas_data.tx_display = network_data.tx_display;
|
||||
app.canvas_data.total_rx_display = network_data.total_rx_display;
|
||||
app.canvas_data.total_tx_display = network_data.total_tx_display;
|
||||
app.canvas_data.disk_data = update_disk_row(&app.data);
|
||||
app.canvas_data.temp_sensor_data = update_temp_row(&app.data, &app.temperature_type);
|
||||
app.canvas_data.process_data = update_process_row(&app.data);
|
||||
app.canvas_data.mem_data = update_mem_data_points(&app.data);
|
||||
app.canvas_data.memory_labels = update_mem_data_values(&app.data);
|
||||
app.canvas_data.swap_data = update_swap_data_points(&app.data);
|
||||
app.canvas_data.cpu_data = update_cpu_data_points(app.show_average_cpu, &app.data);
|
||||
//debug!("Update event complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Draw!
|
||||
if let Err(err) = canvas::draw_data(&mut terminal, &mut app, &canvas_data) {
|
||||
if let Err(err) = canvas::draw_data(&mut terminal, &mut app) {
|
||||
disable_raw_mode()?;
|
||||
execute!(terminal.backend_mut(), LeaveAlternateScreen)?;
|
||||
terminal.show_cursor()?;
|
||||
|
|
Loading…
Add table
Reference in a new issue