mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-10 14:44:18 +00:00
Optimizing processes...
This commit is contained in:
parent
67ff2f28eb
commit
0bf7f32473
9 changed files with 305 additions and 408 deletions
|
@ -80,7 +80,9 @@ Run using `btm`.
|
|||
|
||||
- `-g`, `--group` will group together processes with the same name by default (equivalent to pressing `Tab`).
|
||||
|
||||
- `-i`, `--case_insensitive` will default to not matching case when searching processes.
|
||||
- `-i`, `--case_insensitive` will default to not matching case
|
||||
|
||||
when searching processes.
|
||||
|
||||
### Keybindings
|
||||
|
||||
|
|
186
src/app.rs
186
src/app.rs
|
@ -5,12 +5,12 @@ use std::time::Instant;
|
|||
pub mod data_farmer;
|
||||
use data_farmer::*;
|
||||
|
||||
use crate::{canvas, constants, data_conversion::ConvertedProcessHarvest, utils::error::Result};
|
||||
use crate::{canvas, constants, data_conversion::ConvertedProcessData, utils::error::Result};
|
||||
|
||||
mod process_killer;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ApplicationPosition {
|
||||
pub enum WidgetPosition {
|
||||
Cpu,
|
||||
Mem,
|
||||
Disk,
|
||||
|
@ -68,7 +68,7 @@ pub struct App {
|
|||
pub temperature_type: temperature::TemperatureType,
|
||||
pub update_rate_in_milliseconds: u64,
|
||||
pub show_average_cpu: bool,
|
||||
pub current_application_position: ApplicationPosition,
|
||||
pub current_widget_selected: WidgetPosition,
|
||||
pub data: data_harvester::Data,
|
||||
awaiting_second_char: bool,
|
||||
second_char: char,
|
||||
|
@ -76,12 +76,12 @@ pub struct App {
|
|||
pub show_help: bool,
|
||||
pub show_dd: bool,
|
||||
pub dd_err: Option<String>,
|
||||
to_delete_process_list: Option<Vec<ConvertedProcessHarvest>>,
|
||||
to_delete_process_list: Option<Vec<ConvertedProcessData>>,
|
||||
pub is_frozen: bool,
|
||||
pub left_legend: bool,
|
||||
pub use_current_cpu_total: bool,
|
||||
last_key_press: Instant,
|
||||
pub canvas_data: canvas::CanvasData,
|
||||
pub canvas_data: canvas::DisplayableData,
|
||||
enable_grouping: bool,
|
||||
enable_searching: bool,
|
||||
current_search_query: String,
|
||||
|
@ -105,7 +105,7 @@ impl App {
|
|||
temperature_type,
|
||||
update_rate_in_milliseconds,
|
||||
show_average_cpu,
|
||||
current_application_position: ApplicationPosition::Process,
|
||||
current_widget_selected: WidgetPosition::Process,
|
||||
scroll_direction: ScrollDirection::DOWN,
|
||||
currently_selected_process_position: 0,
|
||||
currently_selected_disk_position: 0,
|
||||
|
@ -127,7 +127,7 @@ impl App {
|
|||
left_legend,
|
||||
use_current_cpu_total,
|
||||
last_key_press: Instant::now(),
|
||||
canvas_data: canvas::CanvasData::default(),
|
||||
canvas_data: canvas::DisplayableData::default(),
|
||||
enable_grouping: false,
|
||||
enable_searching: false,
|
||||
current_search_query: String::default(),
|
||||
|
@ -144,7 +144,7 @@ impl App {
|
|||
self.show_help = false;
|
||||
self.show_dd = false;
|
||||
if self.enable_searching {
|
||||
self.current_application_position = ApplicationPosition::Process;
|
||||
self.current_widget_selected = WidgetPosition::Process;
|
||||
self.enable_searching = false;
|
||||
}
|
||||
self.current_search_query = String::new();
|
||||
|
@ -161,7 +161,7 @@ impl App {
|
|||
self.to_delete_process_list = None;
|
||||
self.dd_err = None;
|
||||
} else if self.enable_searching {
|
||||
self.current_application_position = ApplicationPosition::Process;
|
||||
self.current_widget_selected = WidgetPosition::Process;
|
||||
self.enable_searching = false;
|
||||
}
|
||||
}
|
||||
|
@ -178,16 +178,17 @@ impl App {
|
|||
pub fn toggle_grouping(&mut self) {
|
||||
// Disallow usage whilst in a dialog and only in processes
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::Process = self.current_application_position {
|
||||
if let WidgetPosition::Process = self.current_widget_selected {
|
||||
self.enable_grouping = !(self.enable_grouping);
|
||||
self.update_process_gui = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_tab(&mut self) {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => self.toggle_grouping(),
|
||||
ApplicationPosition::Disk => {}
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process => self.toggle_grouping(),
|
||||
WidgetPosition::Disk => {}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -198,11 +199,11 @@ impl App {
|
|||
|
||||
pub fn enable_searching(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process | ApplicationPosition::ProcessSearch => {
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process | WidgetPosition::ProcessSearch => {
|
||||
// Toggle on
|
||||
self.enable_searching = true;
|
||||
self.current_application_position = ApplicationPosition::ProcessSearch;
|
||||
self.current_widget_selected = WidgetPosition::ProcessSearch;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -214,7 +215,7 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn is_in_search_widget(&self) -> bool {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
|
@ -223,7 +224,7 @@ impl App {
|
|||
|
||||
pub fn search_with_pid(&mut self) {
|
||||
if !self.is_in_dialog() && self.is_searching() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.searching_pid = true;
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +232,7 @@ impl App {
|
|||
|
||||
pub fn search_with_name(&mut self) {
|
||||
if !self.is_in_dialog() && self.is_searching() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.searching_pid = false;
|
||||
}
|
||||
}
|
||||
|
@ -247,7 +248,7 @@ impl App {
|
|||
|
||||
pub fn toggle_simple_search(&mut self) {
|
||||
if !self.is_in_dialog() && self.is_searching() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.use_simple = !self.use_simple;
|
||||
|
||||
// Update to latest (when simple is on this is not updated)
|
||||
|
@ -287,7 +288,7 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn on_backspace(&mut self) {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
if self.current_cursor_position > 0 {
|
||||
self.current_cursor_position -= 1;
|
||||
self.current_search_query
|
||||
|
@ -311,7 +312,7 @@ impl App {
|
|||
|
||||
pub fn on_up_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
} else {
|
||||
self.decrement_position_count();
|
||||
}
|
||||
|
@ -320,7 +321,7 @@ impl App {
|
|||
|
||||
pub fn on_down_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
} else {
|
||||
self.increment_position_count();
|
||||
}
|
||||
|
@ -329,7 +330,7 @@ impl App {
|
|||
|
||||
pub fn on_left_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
if self.current_cursor_position > 0 {
|
||||
self.current_cursor_position -= 1;
|
||||
}
|
||||
|
@ -339,7 +340,7 @@ impl App {
|
|||
|
||||
pub fn on_right_key(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
if self.current_cursor_position < self.current_search_query.len() {
|
||||
self.current_cursor_position += 1;
|
||||
}
|
||||
|
@ -349,7 +350,7 @@ impl App {
|
|||
|
||||
pub fn skip_cursor_beginning(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.current_cursor_position = 0;
|
||||
}
|
||||
}
|
||||
|
@ -357,7 +358,7 @@ impl App {
|
|||
|
||||
pub fn skip_cursor_end(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.current_cursor_position = self.current_search_query.len();
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +376,7 @@ impl App {
|
|||
}
|
||||
self.last_key_press = current_key_press_inst;
|
||||
|
||||
if let ApplicationPosition::ProcessSearch = self.current_application_position {
|
||||
if let WidgetPosition::ProcessSearch = self.current_widget_selected {
|
||||
self.current_search_query
|
||||
.insert(self.current_cursor_position, caught_char);
|
||||
self.current_cursor_position += 1;
|
||||
|
@ -394,31 +395,14 @@ impl App {
|
|||
self.enable_searching();
|
||||
}
|
||||
'd' => {
|
||||
if let ApplicationPosition::Process = self.current_application_position {
|
||||
if let WidgetPosition::Process = self.current_widget_selected {
|
||||
if self.awaiting_second_char && self.second_char == 'd' {
|
||||
self.awaiting_second_char = false;
|
||||
self.second_char = ' ';
|
||||
let current_process = if self.is_grouped() {
|
||||
let mut res: Vec<ConvertedProcessHarvest> = Vec::new();
|
||||
for pid in &self.canvas_data.grouped_process_data
|
||||
[self.currently_selected_process_position as usize]
|
||||
.group
|
||||
{
|
||||
let result = self
|
||||
.canvas_data
|
||||
.process_data
|
||||
.iter()
|
||||
.find(|p| p.pid == *pid);
|
||||
if let Some(process) = result {
|
||||
res.push((*process).clone());
|
||||
}
|
||||
}
|
||||
res
|
||||
} else {
|
||||
vec![self.canvas_data.process_data
|
||||
[self.currently_selected_process_position as usize]
|
||||
.clone()]
|
||||
};
|
||||
let current_process = Vec::new();
|
||||
|
||||
// TODO: FIX THIS SHITTTTTT
|
||||
|
||||
self.to_delete_process_list = Some(current_process);
|
||||
self.show_dd = true;
|
||||
self.reset_multi_tap_keys();
|
||||
|
@ -513,7 +497,7 @@ impl App {
|
|||
|
||||
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 WidgetPosition::Process = self.current_widget_selected {
|
||||
if let Some(current_selected_processes) = &(self.to_delete_process_list) {
|
||||
for current_selected_process in current_selected_processes {
|
||||
process_killer::kill_process_given_pid(current_selected_process.pid)?;
|
||||
|
@ -524,7 +508,7 @@ impl App {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_current_highlighted_process_list(&self) -> Option<Vec<ConvertedProcessHarvest>> {
|
||||
pub fn get_current_highlighted_process_list(&self) -> Option<Vec<ConvertedProcessData>> {
|
||||
self.to_delete_process_list.clone()
|
||||
}
|
||||
|
||||
|
@ -540,12 +524,12 @@ impl App {
|
|||
// PROC_SEARCH -(up)> Disk, -(down)> PROC, -(left)> Network
|
||||
pub fn move_left(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Process => ApplicationPosition::Network,
|
||||
ApplicationPosition::ProcessSearch => ApplicationPosition::Network,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Mem,
|
||||
_ => self.current_application_position,
|
||||
self.current_widget_selected = match self.current_widget_selected {
|
||||
WidgetPosition::Process => WidgetPosition::Network,
|
||||
WidgetPosition::ProcessSearch => WidgetPosition::Network,
|
||||
WidgetPosition::Disk => WidgetPosition::Mem,
|
||||
WidgetPosition::Temp => WidgetPosition::Mem,
|
||||
_ => self.current_widget_selected,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
@ -553,10 +537,10 @@ impl App {
|
|||
|
||||
pub fn move_right(&mut self) {
|
||||
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.current_widget_selected = match self.current_widget_selected {
|
||||
WidgetPosition::Mem => WidgetPosition::Temp,
|
||||
WidgetPosition::Network => WidgetPosition::Process,
|
||||
_ => self.current_widget_selected,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
@ -564,20 +548,20 @@ impl App {
|
|||
|
||||
pub fn move_up(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
self.current_application_position = match self.current_application_position {
|
||||
ApplicationPosition::Mem => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Network => ApplicationPosition::Mem,
|
||||
ApplicationPosition::Process => {
|
||||
self.current_widget_selected = match self.current_widget_selected {
|
||||
WidgetPosition::Mem => WidgetPosition::Cpu,
|
||||
WidgetPosition::Network => WidgetPosition::Mem,
|
||||
WidgetPosition::Process => {
|
||||
if self.is_searching() {
|
||||
ApplicationPosition::ProcessSearch
|
||||
WidgetPosition::ProcessSearch
|
||||
} else {
|
||||
ApplicationPosition::Disk
|
||||
WidgetPosition::Disk
|
||||
}
|
||||
}
|
||||
ApplicationPosition::ProcessSearch => ApplicationPosition::Disk,
|
||||
ApplicationPosition::Temp => ApplicationPosition::Cpu,
|
||||
ApplicationPosition::Disk => ApplicationPosition::Temp,
|
||||
_ => self.current_application_position,
|
||||
WidgetPosition::ProcessSearch => WidgetPosition::Disk,
|
||||
WidgetPosition::Temp => WidgetPosition::Cpu,
|
||||
WidgetPosition::Disk => WidgetPosition::Temp,
|
||||
_ => self.current_widget_selected,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
@ -585,19 +569,19 @@ impl App {
|
|||
|
||||
pub fn move_down(&mut self) {
|
||||
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 => {
|
||||
self.current_widget_selected = match self.current_widget_selected {
|
||||
WidgetPosition::Cpu => WidgetPosition::Mem,
|
||||
WidgetPosition::Mem => WidgetPosition::Network,
|
||||
WidgetPosition::Temp => WidgetPosition::Disk,
|
||||
WidgetPosition::Disk => {
|
||||
if self.is_searching() {
|
||||
ApplicationPosition::ProcessSearch
|
||||
WidgetPosition::ProcessSearch
|
||||
} else {
|
||||
ApplicationPosition::Process
|
||||
WidgetPosition::Process
|
||||
}
|
||||
}
|
||||
ApplicationPosition::ProcessSearch => ApplicationPosition::Process,
|
||||
_ => self.current_application_position,
|
||||
WidgetPosition::ProcessSearch => WidgetPosition::Process,
|
||||
_ => self.current_widget_selected,
|
||||
};
|
||||
self.reset_multi_tap_keys();
|
||||
}
|
||||
|
@ -605,11 +589,11 @@ impl App {
|
|||
|
||||
pub fn skip_to_first(&mut self) {
|
||||
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,
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process => self.currently_selected_process_position = 0,
|
||||
WidgetPosition::Temp => self.currently_selected_temperature_position = 0,
|
||||
WidgetPosition::Disk => self.currently_selected_disk_position = 0,
|
||||
WidgetPosition::Cpu => self.currently_selected_cpu_table_position = 0,
|
||||
|
||||
_ => {}
|
||||
}
|
||||
|
@ -620,19 +604,19 @@ impl App {
|
|||
|
||||
pub fn skip_to_last(&mut self) {
|
||||
if !self.is_in_dialog() {
|
||||
match self.current_application_position {
|
||||
ApplicationPosition::Process => {
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process => {
|
||||
self.currently_selected_process_position =
|
||||
self.data.list_of_processes.len() as i64 - 1
|
||||
}
|
||||
ApplicationPosition::Temp => {
|
||||
WidgetPosition::Temp => {
|
||||
self.currently_selected_temperature_position =
|
||||
self.data.temperature_sensors.len() as i64 - 1
|
||||
}
|
||||
ApplicationPosition::Disk => {
|
||||
WidgetPosition::Disk => {
|
||||
self.currently_selected_disk_position = self.data.disks.len() as i64 - 1
|
||||
}
|
||||
ApplicationPosition::Cpu => {
|
||||
WidgetPosition::Cpu => {
|
||||
self.currently_selected_cpu_table_position =
|
||||
self.canvas_data.cpu_data.len() as i64 - 1;
|
||||
}
|
||||
|
@ -645,11 +629,11 @@ impl App {
|
|||
|
||||
pub fn decrement_position_count(&mut self) {
|
||||
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
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process => self.change_process_position(-1),
|
||||
WidgetPosition::Temp => self.change_temp_position(-1),
|
||||
WidgetPosition::Disk => self.change_disk_position(-1),
|
||||
WidgetPosition::Cpu => self.change_cpu_table_position(-1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::UP;
|
||||
|
@ -659,11 +643,11 @@ impl App {
|
|||
|
||||
pub fn increment_position_count(&mut self) {
|
||||
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
|
||||
match self.current_widget_selected {
|
||||
WidgetPosition::Process => self.change_process_position(1),
|
||||
WidgetPosition::Temp => self.change_temp_position(1),
|
||||
WidgetPosition::Disk => self.change_disk_position(1),
|
||||
WidgetPosition::Cpu => self.change_cpu_table_position(1), // TODO: Temporary, may change if we add scaling
|
||||
_ => {}
|
||||
}
|
||||
self.scroll_direction = ScrollDirection::DOWN;
|
||||
|
|
|
@ -49,7 +49,7 @@ pub struct DataCollection {
|
|||
pub memory_harvest: mem::MemHarvest,
|
||||
pub swap_harvest: mem::MemHarvest,
|
||||
pub cpu_harvest: cpu::CPUHarvest,
|
||||
pub process_harvest: processes::ProcessHarvest,
|
||||
pub process_harvest: Vec<processes::ProcessHarvest>,
|
||||
pub disk_harvest: Vec<disks::DiskHarvest>,
|
||||
pub io_harvest: disks::IOHarvest,
|
||||
pub io_labels: Vec<(u64, u64)>,
|
||||
|
@ -66,7 +66,7 @@ impl Default for DataCollection {
|
|||
memory_harvest: mem::MemHarvest::default(),
|
||||
swap_harvest: mem::MemHarvest::default(),
|
||||
cpu_harvest: cpu::CPUHarvest::default(),
|
||||
process_harvest: processes::ProcessHarvest::default(),
|
||||
process_harvest: Vec::default(),
|
||||
disk_harvest: Vec::default(),
|
||||
io_harvest: disks::IOHarvest::default(),
|
||||
io_labels: Vec::default(),
|
||||
|
@ -106,14 +106,15 @@ impl DataCollection {
|
|||
self.eat_cpu(&harvested_data, &harvested_time, &mut new_entry);
|
||||
|
||||
// Temp
|
||||
self.eat_temp(&harvested_data, &harvested_time, &mut new_entry);
|
||||
self.eat_temp(&harvested_data);
|
||||
|
||||
// Disks
|
||||
self.eat_disks(&harvested_data, &harvested_time, &mut new_entry);
|
||||
self.eat_disks(&harvested_data, &harvested_time);
|
||||
|
||||
// Processes
|
||||
self.eat_proc(&harvested_data);
|
||||
|
||||
// And we're done eating.
|
||||
// And we're done eating. Update time and push the new entry!
|
||||
self.current_instant = harvested_time;
|
||||
self.timed_data_vec.push((harvested_time, new_entry));
|
||||
}
|
||||
|
@ -212,16 +213,12 @@ impl DataCollection {
|
|||
self.cpu_harvest = harvested_data.cpu.clone();
|
||||
}
|
||||
|
||||
fn eat_temp(
|
||||
&mut self, harvested_data: &Data, _harvested_time: &Instant, _new_entry: &mut TimedData,
|
||||
) {
|
||||
fn eat_temp(&mut self, harvested_data: &Data) {
|
||||
// TODO: [PO] To implement
|
||||
self.temp_harvest = harvested_data.temperature_sensors.clone();
|
||||
}
|
||||
|
||||
fn eat_disks(
|
||||
&mut self, harvested_data: &Data, harvested_time: &Instant, _new_entry: &mut TimedData,
|
||||
) {
|
||||
fn eat_disks(&mut self, harvested_data: &Data, harvested_time: &Instant) {
|
||||
// TODO: [PO] To implement
|
||||
|
||||
let time_since_last_harvest = harvested_time
|
||||
|
@ -256,6 +253,10 @@ impl DataCollection {
|
|||
self.disk_harvest = harvested_data.disks.clone();
|
||||
self.io_harvest = harvested_data.io.clone();
|
||||
}
|
||||
|
||||
fn eat_proc(&mut self, harvested_data: &Data) {
|
||||
self.process_harvest = harvested_data.list_of_processes.clone();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_joining_points(
|
||||
|
|
|
@ -25,7 +25,6 @@ pub struct Data {
|
|||
pub temperature_sensors: Vec<temperature::TempHarvest>,
|
||||
pub network: network::NetworkHarvest,
|
||||
pub list_of_processes: Vec<processes::ProcessHarvest>,
|
||||
pub grouped_list_of_processes: Option<Vec<processes::ProcessHarvest>>,
|
||||
pub disks: Vec<disks::DiskHarvest>,
|
||||
pub io: disks::IOHarvest,
|
||||
pub last_collection_time: Instant,
|
||||
|
@ -39,7 +38,6 @@ impl Default for Data {
|
|||
swap: mem::MemHarvest::default(),
|
||||
temperature_sensors: Vec::default(),
|
||||
list_of_processes: Vec::default(),
|
||||
grouped_list_of_processes: None,
|
||||
disks: Vec::default(),
|
||||
io: disks::IOHarvest::default(),
|
||||
network: network::NetworkHarvest::default(),
|
||||
|
@ -53,7 +51,6 @@ impl Data {
|
|||
self.io = disks::IOHarvest::default();
|
||||
self.temperature_sensors = Vec::new();
|
||||
self.list_of_processes = Vec::new();
|
||||
self.grouped_list_of_processes = None;
|
||||
self.disks = Vec::new();
|
||||
|
||||
self.network.first_run_cleanup();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
use crate::utils::error;
|
||||
use std::cmp::Ordering;
|
||||
use std::{collections::HashMap, process::Command, time::Instant};
|
||||
use sysinfo::{ProcessExt, System, SystemExt};
|
||||
|
||||
|
@ -23,7 +22,6 @@ pub struct ProcessHarvest {
|
|||
pub cpu_usage_percent: f64,
|
||||
pub mem_usage_percent: f64,
|
||||
pub name: String,
|
||||
pub pid_vec: Option<Vec<u32>>,
|
||||
}
|
||||
|
||||
fn cpu_usage_calculation(
|
||||
|
@ -100,31 +98,6 @@ fn cpu_usage_calculation(
|
|||
Ok((result, cpu_percentage))
|
||||
}
|
||||
|
||||
fn get_ordering<T: std::cmp::PartialOrd>(
|
||||
a_val: T, b_val: T, reverse_order: bool,
|
||||
) -> std::cmp::Ordering {
|
||||
match a_val.partial_cmp(&b_val) {
|
||||
Some(x) => match x {
|
||||
Ordering::Greater => {
|
||||
if reverse_order {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
}
|
||||
Ordering::Less => {
|
||||
if reverse_order {
|
||||
std::cmp::Ordering::Greater
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
}
|
||||
Ordering::Equal => Ordering::Equal,
|
||||
},
|
||||
None => Ordering::Equal,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_process_cpu_stats(pid: u32) -> std::io::Result<f64> {
|
||||
let mut path = std::path::PathBuf::new();
|
||||
path.push("/proc");
|
||||
|
@ -188,7 +161,6 @@ fn convert_ps(
|
|||
name: "".to_string(),
|
||||
mem_usage_percent: 0.0,
|
||||
cpu_usage_percent: 0.0,
|
||||
pid_vec: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -217,7 +189,6 @@ fn convert_ps(
|
|||
use_current_cpu_total,
|
||||
curr_time,
|
||||
)?,
|
||||
pid_vec: None,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -292,36 +263,9 @@ pub fn get_sorted_processes_list(
|
|||
name,
|
||||
mem_usage_percent: process_val.memory() as f64 * 100.0 / mem_total_kb as f64,
|
||||
cpu_usage_percent: f64::from(process_val.cpu_usage()),
|
||||
pid_vec: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(process_vector)
|
||||
}
|
||||
|
||||
pub fn sort_processes(
|
||||
process_vector: &mut Vec<ProcessHarvest>, sorting_method: &ProcessSorting, reverse_order: bool,
|
||||
) {
|
||||
// Always sort alphabetically first!
|
||||
process_vector.sort_by(|a, b| get_ordering(&a.name, &b.name, false));
|
||||
|
||||
match sorting_method {
|
||||
ProcessSorting::CPU => {
|
||||
process_vector.sort_by(|a, b| {
|
||||
get_ordering(a.cpu_usage_percent, b.cpu_usage_percent, reverse_order)
|
||||
});
|
||||
}
|
||||
ProcessSorting::MEM => {
|
||||
process_vector.sort_by(|a, b| {
|
||||
get_ordering(a.mem_usage_percent, b.mem_usage_percent, reverse_order)
|
||||
});
|
||||
}
|
||||
ProcessSorting::PID => {
|
||||
process_vector.sort_by(|a, b| get_ordering(a.pid, b.pid, reverse_order));
|
||||
}
|
||||
ProcessSorting::NAME => {
|
||||
process_vector.sort_by(|a, b| get_ordering(&a.name, &b.name, reverse_order))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
100
src/canvas.rs
100
src/canvas.rs
|
@ -1,9 +1,11 @@
|
|||
use crate::{
|
||||
app, constants,
|
||||
data_conversion::{ConvertedCpuData, ConvertedProcessHarvest},
|
||||
app::{self, data_harvester::processes::ProcessHarvest},
|
||||
constants,
|
||||
data_conversion::{ConvertedCpuData, ConvertedProcessData},
|
||||
utils::{error, gen_util::*},
|
||||
};
|
||||
use std::cmp::max;
|
||||
use std::collections::HashMap;
|
||||
use tui::{
|
||||
backend,
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
|
@ -85,7 +87,7 @@ lazy_static! {
|
|||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CanvasData {
|
||||
pub struct DisplayableData {
|
||||
pub rx_display: String,
|
||||
pub tx_display: String,
|
||||
pub total_rx_display: String,
|
||||
|
@ -94,8 +96,9 @@ 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<ConvertedProcessHarvest>,
|
||||
pub grouped_process_data: Vec<ConvertedProcessHarvest>,
|
||||
pub process_data: HashMap<u32, ProcessHarvest>, // Not final
|
||||
pub grouped_process_data: Vec<ConvertedProcessData>, // Not final
|
||||
pub finalized_process_data: Vec<ConvertedProcessData>, // What's actually displayed
|
||||
pub mem_label: String,
|
||||
pub swap_label: String,
|
||||
pub mem_data: Vec<(f64, f64)>,
|
||||
|
@ -441,8 +444,8 @@ fn draw_cpu_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App, d
|
|||
Block::default()
|
||||
.title("CPU")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
@ -485,8 +488,8 @@ fn draw_cpu_legend<B: backend::Backend>(
|
|||
.map(|(itx, cpu_string_row)| {
|
||||
Row::StyledData(
|
||||
cpu_string_row.iter(),
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Cpu => {
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Cpu => {
|
||||
if cpu_row_counter
|
||||
== app_state.currently_selected_cpu_table_position - start_position
|
||||
{
|
||||
|
@ -515,8 +518,8 @@ fn draw_cpu_legend<B: backend::Backend>(
|
|||
// Draw
|
||||
Table::new(CPU_LEGEND_HEADER.iter(), cpu_rows)
|
||||
.block(Block::default().borders(Borders::ALL).border_style(
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Cpu => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
},
|
||||
))
|
||||
|
@ -554,8 +557,8 @@ fn draw_memory_table<B: backend::Backend>(
|
|||
// Draw
|
||||
Table::new(MEM_HEADERS.iter(), mapped_mem_rows)
|
||||
.block(Block::default().borders(Borders::ALL).border_style(
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Mem => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Mem => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
},
|
||||
))
|
||||
|
@ -576,9 +579,11 @@ fn draw_memory_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App
|
|||
let x_axis: Axis<String> = Axis::default()
|
||||
.style(Style::default().fg(GRAPH_COLOUR))
|
||||
.bounds([0.0, constants::TIME_STARTS_FROM as f64]);
|
||||
let y_axis = Axis::default()
|
||||
|
||||
// Offset as the zero value isn't drawn otherwise...
|
||||
let y_axis: Axis<&str> = Axis::default()
|
||||
.style(Style::default().fg(GRAPH_COLOUR))
|
||||
.bounds([-0.5, 100.5]) // Offset as the zero value isn't drawn otherwise...
|
||||
.bounds([-0.5, 100.5])
|
||||
.labels(&["0%", "100%"]);
|
||||
|
||||
let mut mem_canvas_vec: Vec<Dataset> = vec![Dataset::default()
|
||||
|
@ -610,8 +615,8 @@ fn draw_memory_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::App
|
|||
Block::default()
|
||||
.title("Memory")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Mem => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Mem => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
@ -637,8 +642,8 @@ fn draw_network_graph<B: backend::Backend>(f: &mut Frame<B>, app_state: &app::Ap
|
|||
Block::default()
|
||||
.title("Network")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
@ -715,8 +720,8 @@ fn draw_network_labels<B: backend::Backend>(
|
|||
mapped_network,
|
||||
)
|
||||
.block(Block::default().borders(Borders::ALL).border_style(
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Network => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
},
|
||||
))
|
||||
|
@ -749,8 +754,8 @@ fn draw_temp_table<B: backend::Backend>(
|
|||
let temperature_rows = sliced_vec.iter().map(|temp_row| {
|
||||
Row::StyledData(
|
||||
temp_row.iter(),
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Temp => {
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Temp => {
|
||||
if temp_row_counter
|
||||
== app_state.currently_selected_temperature_position - start_position
|
||||
{
|
||||
|
@ -782,8 +787,8 @@ fn draw_temp_table<B: backend::Backend>(
|
|||
Block::default()
|
||||
.title("Temperatures")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Temp => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Temp => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
@ -815,8 +820,8 @@ fn draw_disk_table<B: backend::Backend>(
|
|||
let disk_rows = sliced_vec.iter().map(|disk| {
|
||||
Row::StyledData(
|
||||
disk.iter(),
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Disk => {
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Disk => {
|
||||
if disk_counter == app_state.currently_selected_disk_position - start_position {
|
||||
disk_counter = -1;
|
||||
Style::default().fg(Color::Black).bg(Color::Cyan)
|
||||
|
@ -847,8 +852,8 @@ fn draw_disk_table<B: backend::Backend>(
|
|||
Block::default()
|
||||
.title("Disk")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Disk => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Disk => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
@ -881,8 +886,7 @@ fn draw_search_field<B: backend::Backend>(
|
|||
.chars()
|
||||
.enumerate()
|
||||
.map(|(itx, c)| {
|
||||
if let app::ApplicationPosition::ProcessSearch = app_state.current_application_position
|
||||
{
|
||||
if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected {
|
||||
if itx == cursor_position {
|
||||
return Text::styled(
|
||||
c.to_string(),
|
||||
|
@ -893,7 +897,7 @@ fn draw_search_field<B: backend::Backend>(
|
|||
Text::styled(c.to_string(), Style::default().fg(TEXT_COLOUR))
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
if let app::ApplicationPosition::ProcessSearch = app_state.current_application_position {
|
||||
if let app::WidgetPosition::ProcessSearch = app_state.current_widget_selected {
|
||||
if cursor_position >= query.len() {
|
||||
query_with_cursor.push(Text::styled(
|
||||
" ".to_string(),
|
||||
|
@ -926,8 +930,8 @@ fn draw_search_field<B: backend::Backend>(
|
|||
.border_style(if app_state.get_current_regex_matcher().is_err() {
|
||||
Style::default().fg(Color::Red)
|
||||
} else {
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::ProcessSearch => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::ProcessSearch => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}
|
||||
}),
|
||||
|
@ -941,16 +945,15 @@ fn draw_search_field<B: backend::Backend>(
|
|||
fn draw_processes_table<B: backend::Backend>(
|
||||
f: &mut Frame<B>, app_state: &mut app::App, draw_loc: Rect,
|
||||
) {
|
||||
let process_data: &[ConvertedProcessHarvest] = if app_state.is_grouped() {
|
||||
&app_state.canvas_data.grouped_process_data
|
||||
} else {
|
||||
&app_state.canvas_data.process_data
|
||||
};
|
||||
let process_data: &[ConvertedProcessData] = &app_state.canvas_data.finalized_process_data;
|
||||
|
||||
// Admittedly this is kinda a hack... but we need to:
|
||||
// * Scroll
|
||||
// * Show/hide elements based on scroll position
|
||||
// As such, we use a process_counter to know when we've hit the process we've currently scrolled to. We also need to move the list - we can
|
||||
//
|
||||
// As such, we use a process_counter to know when we've
|
||||
// hit the process we've currently scrolled to.
|
||||
// We also need to move the list - we can
|
||||
// do so by hiding some elements!
|
||||
let num_rows = i64::from(draw_loc.height) - 5;
|
||||
|
||||
|
@ -961,26 +964,25 @@ fn draw_processes_table<B: backend::Backend>(
|
|||
app_state.currently_selected_process_position,
|
||||
);
|
||||
|
||||
let sliced_vec: Vec<ConvertedProcessHarvest> =
|
||||
(&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;
|
||||
|
||||
// Draw!
|
||||
let process_rows = sliced_vec.iter().map(|process| {
|
||||
let stringified_process_vec: Vec<String> = vec![
|
||||
if app_state.is_grouped() {
|
||||
process.group.len().to_string()
|
||||
process.group_pids.len().to_string()
|
||||
} else {
|
||||
process.pid.to_string()
|
||||
},
|
||||
process.name.clone(),
|
||||
process.cpu_usage.clone(),
|
||||
process.mem_usage.clone(),
|
||||
format!("{:.1}%", process.cpu_usage),
|
||||
format!("{:.1}%", process.mem_usage),
|
||||
];
|
||||
Row::StyledData(
|
||||
stringified_process_vec.into_iter(),
|
||||
match app_state.current_application_position {
|
||||
app::ApplicationPosition::Process => {
|
||||
match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Process => {
|
||||
if process_counter
|
||||
== app_state.currently_selected_process_position - start_position
|
||||
{
|
||||
|
@ -1042,8 +1044,8 @@ fn draw_processes_table<B: backend::Backend>(
|
|||
Block::default()
|
||||
.title("Processes")
|
||||
.borders(Borders::ALL)
|
||||
.border_style(match app_state.current_application_position {
|
||||
app::ApplicationPosition::Process => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
.border_style(match app_state.current_widget_selected {
|
||||
app::WidgetPosition::Process => *CANVAS_HIGHLIGHTED_BORDER_STYLE,
|
||||
_ => *CANVAS_BORDER_STYLE,
|
||||
}),
|
||||
)
|
||||
|
|
|
@ -2,14 +2,16 @@
|
|||
//! can actually handle.
|
||||
|
||||
use crate::{
|
||||
app::data_farmer,
|
||||
app::data_harvester,
|
||||
app::App,
|
||||
app::{
|
||||
data_farmer,
|
||||
data_harvester::{self, processes::ProcessHarvest},
|
||||
App,
|
||||
},
|
||||
constants,
|
||||
utils::gen_util::{get_exact_byte_values, get_simple_byte_values},
|
||||
};
|
||||
use constants::*;
|
||||
use regex::Regex;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ConvertedNetworkData {
|
||||
|
@ -22,12 +24,12 @@ pub struct ConvertedNetworkData {
|
|||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
pub struct ConvertedProcessHarvest {
|
||||
pub struct ConvertedProcessData {
|
||||
pub pid: u32,
|
||||
pub name: String,
|
||||
pub cpu_usage: String,
|
||||
pub mem_usage: String,
|
||||
pub group: Vec<u32>,
|
||||
pub cpu_usage: f64,
|
||||
pub mem_usage: f64,
|
||||
pub group_pids: Vec<u32>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug)]
|
||||
|
@ -117,103 +119,6 @@ pub fn update_disk_row(current_data: &data_farmer::DataCollection) -> Vec<Vec<St
|
|||
disk_vector
|
||||
}
|
||||
|
||||
pub fn simple_update_process_row(
|
||||
app_data: &data_harvester::Data, matching_string: &str, use_pid: bool,
|
||||
) -> (Vec<ConvertedProcessHarvest>, Vec<ConvertedProcessHarvest>) {
|
||||
let process_vector: Vec<ConvertedProcessHarvest> = app_data
|
||||
.list_of_processes
|
||||
.iter()
|
||||
.filter(|process| {
|
||||
if use_pid {
|
||||
process
|
||||
.pid
|
||||
.to_string()
|
||||
.to_ascii_lowercase()
|
||||
.contains(matching_string)
|
||||
} else {
|
||||
process.name.to_ascii_lowercase().contains(matching_string)
|
||||
}
|
||||
})
|
||||
.map(|process| return_mapped_process(process))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut grouped_process_vector: Vec<ConvertedProcessHarvest> = Vec::new();
|
||||
if let Some(grouped_list_of_processes) = &app_data.grouped_list_of_processes {
|
||||
grouped_process_vector = grouped_list_of_processes
|
||||
.iter()
|
||||
.filter(|process| {
|
||||
if use_pid {
|
||||
process
|
||||
.pid
|
||||
.to_string()
|
||||
.to_ascii_lowercase()
|
||||
.contains(matching_string)
|
||||
} else {
|
||||
process.name.to_ascii_lowercase().contains(matching_string)
|
||||
}
|
||||
})
|
||||
.map(|process| return_mapped_process(process))
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
(process_vector, grouped_process_vector)
|
||||
}
|
||||
|
||||
pub fn regex_update_process_row(
|
||||
app_data: &data_harvester::Data, regex_matcher: &std::result::Result<Regex, regex::Error>,
|
||||
use_pid: bool,
|
||||
) -> (Vec<ConvertedProcessHarvest>, Vec<ConvertedProcessHarvest>) {
|
||||
let process_vector: Vec<ConvertedProcessHarvest> = app_data
|
||||
.list_of_processes
|
||||
.iter()
|
||||
.filter(|process| {
|
||||
if let Ok(matcher) = regex_matcher {
|
||||
if use_pid {
|
||||
matcher.is_match(&process.pid.to_string())
|
||||
} else {
|
||||
matcher.is_match(&process.name)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.map(|process| return_mapped_process(process))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let mut grouped_process_vector: Vec<ConvertedProcessHarvest> = Vec::new();
|
||||
if let Some(grouped_list_of_processes) = &app_data.grouped_list_of_processes {
|
||||
grouped_process_vector = grouped_list_of_processes
|
||||
.iter()
|
||||
.filter(|process| {
|
||||
if let Ok(matcher) = regex_matcher {
|
||||
if use_pid {
|
||||
matcher.is_match(&process.pid.to_string())
|
||||
} else {
|
||||
matcher.is_match(&process.name)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.map(|process| return_mapped_process(process))
|
||||
.collect::<Vec<_>>();
|
||||
}
|
||||
|
||||
(process_vector, grouped_process_vector)
|
||||
}
|
||||
|
||||
fn return_mapped_process(
|
||||
process: &data_harvester::processes::ProcessHarvest,
|
||||
) -> ConvertedProcessHarvest {
|
||||
ConvertedProcessHarvest {
|
||||
pid: process.pid,
|
||||
name: process.name.to_string(),
|
||||
cpu_usage: format!("{:.1}%", process.cpu_usage_percent),
|
||||
mem_usage: format!("{:.1}%", process.mem_usage_percent),
|
||||
group: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_cpu_data_points(
|
||||
show_avg_cpu: bool, current_data: &data_farmer::DataCollection,
|
||||
) -> Vec<ConvertedCpuData> {
|
||||
|
@ -432,3 +337,45 @@ pub fn convert_network_data_points(
|
|||
total_tx_display,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn convert_process_data(
|
||||
current_data: &data_farmer::DataCollection,
|
||||
) -> (HashMap<u32, ProcessHarvest>, Vec<ConvertedProcessData>) {
|
||||
let mut single_list = HashMap::new();
|
||||
|
||||
// cpu, mem, pids
|
||||
let mut grouped_hashmap: HashMap<String, (u32, f64, f64, Vec<u32>)> =
|
||||
std::collections::HashMap::new();
|
||||
|
||||
// Go through every single process in the list... and build a hashmap + single list
|
||||
for process in &(current_data).process_harvest {
|
||||
let entry = grouped_hashmap.entry(process.name.clone()).or_insert((
|
||||
process.pid,
|
||||
0.0,
|
||||
0.0,
|
||||
Vec::new(),
|
||||
));
|
||||
|
||||
(*entry).1 += process.cpu_usage_percent;
|
||||
(*entry).2 += process.mem_usage_percent;
|
||||
(*entry).3.push(process.pid);
|
||||
|
||||
single_list.insert(process.pid, process.clone());
|
||||
}
|
||||
|
||||
let grouped_list: Vec<ConvertedProcessData> = grouped_hashmap
|
||||
.iter()
|
||||
.map(|(name, process_details)| {
|
||||
let p = process_details.clone();
|
||||
ConvertedProcessData {
|
||||
pid: p.0,
|
||||
name: name.to_string(),
|
||||
cpu_usage: p.1,
|
||||
mem_usage: p.2,
|
||||
group_pids: p.3,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(single_list, grouped_list)
|
||||
}
|
||||
|
|
158
src/main.rs
158
src/main.rs
|
@ -35,11 +35,9 @@ mod canvas;
|
|||
mod constants;
|
||||
mod data_conversion;
|
||||
|
||||
use app::data_harvester;
|
||||
use app::data_harvester::processes::ProcessHarvest;
|
||||
use app::data_harvester::{self, processes::ProcessSorting};
|
||||
use constants::TICK_RATE_IN_MILLISECONDS;
|
||||
use data_conversion::*;
|
||||
use std::collections::BTreeMap;
|
||||
use utils::error::{self, BottomError};
|
||||
|
||||
enum Event<I, J> {
|
||||
|
@ -267,7 +265,7 @@ fn main() -> error::Result<()> {
|
|||
}
|
||||
|
||||
if app.update_process_gui {
|
||||
handle_process_sorting(&mut app);
|
||||
update_final_process_list(&mut app);
|
||||
app.update_process_gui = false;
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +277,6 @@ fn main() -> error::Result<()> {
|
|||
Event::Update(data) => {
|
||||
if !app.is_frozen {
|
||||
app.data_collection.eat_data(&data);
|
||||
app.data = *data; // TODO: [OPT] remove this
|
||||
|
||||
// Convert all data into tui-compliant components
|
||||
|
||||
|
@ -309,7 +306,10 @@ fn main() -> error::Result<()> {
|
|||
update_cpu_data_points(app.show_average_cpu, &app.data_collection);
|
||||
|
||||
// Processes
|
||||
handle_process_sorting(&mut app);
|
||||
let (single, grouped) = convert_process_data(&app.data_collection);
|
||||
app.canvas_data.process_data = single;
|
||||
app.canvas_data.grouped_process_data = grouped;
|
||||
update_final_process_list(&mut app);
|
||||
}
|
||||
}
|
||||
Event::Clean => {
|
||||
|
@ -339,82 +339,6 @@ fn main() -> error::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
type TempProcess = (f64, f64, Vec<u32>);
|
||||
|
||||
fn handle_process_sorting(app: &mut app::App) {
|
||||
// Handle combining multi-pid processes to form one entry in table.
|
||||
// This was done this way to save time and avoid code
|
||||
// duplication... sorry future me. Really.
|
||||
|
||||
// First, convert this all into a BTreeMap. The key is by name. This
|
||||
// pulls double duty by allowing us to combine entries AND it sorts!
|
||||
|
||||
// Fields for tuple: CPU%, MEM%, MEM_KB, PID_VEC
|
||||
let mut process_map: BTreeMap<String, TempProcess> = BTreeMap::new();
|
||||
for process in &app.data.list_of_processes {
|
||||
let entry_val = process_map
|
||||
.entry(process.name.clone())
|
||||
.or_insert((0.0, 0.0, vec![]));
|
||||
entry_val.0 += process.cpu_usage_percent;
|
||||
entry_val.1 += process.mem_usage_percent;
|
||||
entry_val.2.push(process.pid);
|
||||
}
|
||||
|
||||
// Now... turn this back into the exact same vector... but now with merged processes!
|
||||
app.data.grouped_list_of_processes = Some(
|
||||
process_map
|
||||
.iter()
|
||||
.map(|(name, data)| {
|
||||
ProcessHarvest {
|
||||
pid: 0, // Irrelevant
|
||||
cpu_usage_percent: data.0,
|
||||
mem_usage_percent: data.1,
|
||||
name: name.clone(),
|
||||
pid_vec: Some(data.2.clone()),
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
|
||||
if let Some(grouped_list_of_processes) = &mut app.data.grouped_list_of_processes {
|
||||
if let data_harvester::processes::ProcessSorting::PID = &app.process_sorting_type {
|
||||
data_harvester::processes::sort_processes(
|
||||
grouped_list_of_processes,
|
||||
&data_harvester::processes::ProcessSorting::CPU, // Go back to default, negate PID for group
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
data_harvester::processes::sort_processes(
|
||||
grouped_list_of_processes,
|
||||
&app.process_sorting_type,
|
||||
app.process_sorting_reverse,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
data_harvester::processes::sort_processes(
|
||||
&mut app.data.list_of_processes,
|
||||
&app.process_sorting_type,
|
||||
app.process_sorting_reverse,
|
||||
);
|
||||
|
||||
let tuple_results = if app.use_simple {
|
||||
simple_update_process_row(
|
||||
&app.data,
|
||||
&(app.get_current_search_query().to_ascii_lowercase()),
|
||||
app.is_searching_with_pid(),
|
||||
)
|
||||
} else {
|
||||
regex_update_process_row(
|
||||
&app.data,
|
||||
app.get_current_regex_matcher(),
|
||||
app.is_searching_with_pid(),
|
||||
)
|
||||
};
|
||||
app.canvas_data.process_data = tuple_results.0;
|
||||
app.canvas_data.grouped_process_data = tuple_results.1;
|
||||
}
|
||||
|
||||
fn cleanup(
|
||||
terminal: &mut tui::terminal::Terminal<tui::backend::CrosstermBackend<std::io::Stdout>>,
|
||||
) -> error::Result<()> {
|
||||
|
@ -425,3 +349,73 @@ fn cleanup(
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_final_process_list(app: &mut app::App) {
|
||||
let mut filtered_process_data: Vec<ConvertedProcessData> = if app.is_grouped() {
|
||||
app.canvas_data
|
||||
.grouped_process_data
|
||||
.clone()
|
||||
.into_iter()
|
||||
.filter(|process| {
|
||||
if let Ok(matcher) = app.get_current_regex_matcher() {
|
||||
matcher.is_match(&process.name)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.collect::<Vec<ConvertedProcessData>>()
|
||||
} else {
|
||||
app.canvas_data
|
||||
.process_data
|
||||
.iter()
|
||||
.filter(|(_pid, process)| {
|
||||
if let Ok(matcher) = app.get_current_regex_matcher() {
|
||||
if app.is_searching_with_pid() {
|
||||
matcher.is_match(&process.pid.to_string())
|
||||
} else {
|
||||
matcher.is_match(&process.name)
|
||||
}
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.map(|(_pid, process)| ConvertedProcessData {
|
||||
pid: process.pid,
|
||||
name: process.name.clone(),
|
||||
cpu_usage: process.cpu_usage_percent,
|
||||
mem_usage: process.mem_usage_percent,
|
||||
group_pids: vec![process.pid],
|
||||
})
|
||||
.collect::<Vec<ConvertedProcessData>>()
|
||||
};
|
||||
|
||||
sort_process_data(&mut filtered_process_data, app);
|
||||
app.canvas_data.finalized_process_data = filtered_process_data;
|
||||
}
|
||||
|
||||
fn sort_process_data(to_sort_vec: &mut Vec<ConvertedProcessData>, app: &app::App) {
|
||||
to_sort_vec.sort_by(|a, b| utils::gen_util::get_ordering(&a.name, &b.name, false));
|
||||
|
||||
match app.process_sorting_type {
|
||||
ProcessSorting::CPU => {
|
||||
to_sort_vec.sort_by(|a, b| {
|
||||
utils::gen_util::get_ordering(a.cpu_usage, b.cpu_usage, app.process_sorting_reverse)
|
||||
});
|
||||
}
|
||||
ProcessSorting::MEM => {
|
||||
to_sort_vec.sort_by(|a, b| {
|
||||
utils::gen_util::get_ordering(a.mem_usage, b.mem_usage, app.process_sorting_reverse)
|
||||
});
|
||||
}
|
||||
ProcessSorting::NAME => to_sort_vec.sort_by(|a, b| {
|
||||
utils::gen_util::get_ordering(&a.name, &b.name, app.process_sorting_reverse)
|
||||
}),
|
||||
ProcessSorting::PID => {
|
||||
if !app.is_grouped() {
|
||||
to_sort_vec.sort_by(|a, b| {
|
||||
utils::gen_util::get_ordering(a.pid, b.pid, app.process_sorting_reverse)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,3 +59,29 @@ pub fn get_simple_byte_values(bytes: u64, spacing: bool) -> (f64, String) {
|
|||
_ => (bytes as f64 / 1_000_000_000_000.0, "TB".to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gotta get partial ordering? No problem, here's something to deal with it~
|
||||
pub fn get_ordering<T: std::cmp::PartialOrd>(
|
||||
a_val: T, b_val: T, reverse_order: bool,
|
||||
) -> std::cmp::Ordering {
|
||||
match a_val.partial_cmp(&b_val) {
|
||||
Some(x) => match x {
|
||||
Ordering::Greater => {
|
||||
if reverse_order {
|
||||
std::cmp::Ordering::Less
|
||||
} else {
|
||||
std::cmp::Ordering::Greater
|
||||
}
|
||||
}
|
||||
Ordering::Less => {
|
||||
if reverse_order {
|
||||
std::cmp::Ordering::Greater
|
||||
} else {
|
||||
std::cmp::Ordering::Less
|
||||
}
|
||||
}
|
||||
Ordering::Equal => Ordering::Equal,
|
||||
},
|
||||
None => Ordering::Equal,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue