summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs71
-rw-r--r--src/app/data_farmer.rs33
-rw-r--r--src/app/data_harvester.rs2
-rw-r--r--src/app/data_harvester/batteries.rs12
-rw-r--r--src/app/data_harvester/disks.rs10
-rw-r--r--src/app/data_harvester/network.rs13
-rw-r--r--src/app/data_harvester/processes.rs26
-rw-r--r--src/app/data_harvester/temperature.rs6
-rw-r--r--src/app/query.rs6
-rw-r--r--src/app/states.rs26
-rw-r--r--src/bin/main.rs7
-rw-r--r--src/canvas.rs4
-rw-r--r--src/canvas/dialogs/dd_dialog.rs8
-rw-r--r--src/canvas/drawing_utils.rs17
-rw-r--r--src/canvas/widgets/cpu_graph.rs81
-rw-r--r--src/canvas/widgets/mem_graph.rs106
-rw-r--r--src/canvas/widgets/network_graph.rs577
-rw-r--r--src/clap.rs28
-rw-r--r--src/constants.rs6
-rw-r--r--src/data_conversion.rs198
-rw-r--r--src/lib.rs36
-rw-r--r--src/options.rs71
-rw-r--r--src/units.rs1
-rw-r--r--src/units/data_units.rs5
-rw-r--r--src/utils/error.rs4
-rw-r--r--src/utils/gen_util.rs99
26 files changed, 1102 insertions, 351 deletions
diff --git a/src/app.rs b/src/app.rs
index 3c0fc9d5..e1f61b7c 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -21,6 +21,7 @@ use crate::{
options::Config,
options::ConfigFlags,
options::WidgetIdEnabled,
+ units::data_units::DataUnit,
utils::error::{BottomError, Result},
Pid,
};
@@ -34,6 +35,12 @@ pub mod states;
const MAX_SEARCH_LENGTH: usize = 200;
+#[derive(Debug, Clone)]
+pub enum AxisScaling {
+ Log,
+ Linear,
+}
+
/// AppConfigFields is meant to cover basic fields that would normally be set
/// by config files or launch options.
#[derive(Debug)]
@@ -55,6 +62,10 @@ pub struct AppConfigFields {
pub no_write: bool,
pub show_table_scroll_position: bool,
pub is_advanced_kill: bool,
+ // TODO: Remove these, move network details state-side.
+ pub network_unit_type: DataUnit,
+ pub network_scale_type: AxisScaling,
+ pub network_use_binary_prefix: bool,
}
/// For filtering out information
@@ -708,7 +719,7 @@ impl App {
if self.delete_dialog_state.is_showing_dd {
if self.dd_err.is_some() {
self.close_dd();
- } else if self.delete_dialog_state.selected_signal != KillSignal::CANCEL {
+ } else if self.delete_dialog_state.selected_signal != KillSignal::Cancel {
// If within dd...
if self.dd_err.is_none() {
// Also ensure that we didn't just fail a dd...
@@ -886,7 +897,7 @@ impl App {
if kbd_signal > 31 {
kbd_signal %= 10;
}
- self.delete_dialog_state.selected_signal = KillSignal::KILL(kbd_signal);
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(kbd_signal);
if kbd_signal < 10 {
self.delete_dialog_state.keyboard_signal_select = kbd_signal;
} else {
@@ -991,15 +1002,15 @@ impl App {
{
if self.app_config_fields.is_advanced_kill {
match self.delete_dialog_state.selected_signal {
- KillSignal::KILL(prev_signal) => {
+ KillSignal::Kill(prev_signal) => {
self.delete_dialog_state.selected_signal = match prev_signal - 1 {
- 0 => KillSignal::CANCEL,
+ 0 => KillSignal::Cancel,
// 32+33 are skipped
- 33 => KillSignal::KILL(31),
- signal => KillSignal::KILL(signal),
+ 33 => KillSignal::Kill(31),
+ signal => KillSignal::Kill(signal),
};
}
- KillSignal::CANCEL => {}
+ KillSignal::Cancel => {}
};
} else {
self.delete_dialog_state.selected_signal = KillSignal::default();
@@ -1007,7 +1018,7 @@ impl App {
}
#[cfg(target_os = "windows")]
{
- self.delete_dialog_state.selected_signal = KillSignal::KILL(1);
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(1);
}
}
}
@@ -1067,23 +1078,23 @@ impl App {
{
if self.app_config_fields.is_advanced_kill {
let new_signal = match self.delete_dialog_state.selected_signal {
- KillSignal::CANCEL => 1,
+ KillSignal::Cancel => 1,
// 32+33 are skipped
#[cfg(target_os = "linux")]
- KillSignal::KILL(31) => 34,
+ KillSignal::Kill(31) => 34,
#[cfg(target_os = "macos")]
- KillSignal::KILL(31) => 31,
- KillSignal::KILL(64) => 64,
- KillSignal::KILL(signal) => signal + 1,
+ KillSignal::Kill(31) => 31,
+ KillSignal::Kill(64) => 64,
+ KillSignal::Kill(signal) => signal + 1,
};
- self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal);
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(new_signal);
} else {
- self.delete_dialog_state.selected_signal = KillSignal::CANCEL;
+ self.delete_dialog_state.selected_signal = KillSignal::Cancel;
}
}
#[cfg(target_os = "windows")]
{
- self.delete_dialog_state.selected_signal = KillSignal::CANCEL;
+ self.delete_dialog_state.selected_signal = KillSignal::Cancel;
}
}
}
@@ -1091,15 +1102,15 @@ impl App {
pub fn on_page_up(&mut self) {
if self.delete_dialog_state.is_showing_dd {
let mut new_signal = match self.delete_dialog_state.selected_signal {
- KillSignal::CANCEL => 0,
- KillSignal::KILL(signal) => max(signal, 8) - 8,
+ KillSignal::Cancel => 0,
+ KillSignal::Kill(signal) => max(signal, 8) - 8,
};
if new_signal > 23 && new_signal < 33 {
new_signal -= 2;
}
self.delete_dialog_state.selected_signal = match new_signal {
- 0 => KillSignal::CANCEL,
- sig => KillSignal::KILL(sig),
+ 0 => KillSignal::Cancel,
+ sig => KillSignal::Kill(sig),
};
}
}
@@ -1107,13 +1118,13 @@ impl App {
pub fn on_page_down(&mut self) {
if self.delete_dialog_state.is_showing_dd {
let mut new_signal = match self.delete_dialog_state.selected_signal {
- KillSignal::CANCEL => 8,
- KillSignal::KILL(signal) => min(signal + 8, MAX_SIGNAL),
+ KillSignal::Cancel => 8,
+ KillSignal::Kill(signal) => min(signal + 8, MAX_SIGNAL),
};
if new_signal > 31 && new_signal < 42 {
new_signal += 2;
}
- self.delete_dialog_state.selected_signal = KillSignal::KILL(new_signal);
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(new_signal);
}
}
@@ -1672,8 +1683,8 @@ impl App {
if let Some(current_selected_processes) = &self.to_delete_process_list {
#[cfg(target_family = "unix")]
let signal = match self.delete_dialog_state.selected_signal {
- KillSignal::KILL(sig) => sig,
- KillSignal::CANCEL => 15, // should never happen, so just TERM
+ KillSignal::Kill(sig) => sig,
+ KillSignal::Cancel => 15, // should never happen, so just TERM
};
for pid in &current_selected_processes.1 {
#[cfg(target_family = "unix")]
@@ -2229,7 +2240,7 @@ impl App {
} else if self.help_dialog_state.is_showing_help {
self.help_dialog_state.scroll_state.current_scroll_index = 0;
} else if self.delete_dialog_state.is_showing_dd {
- self.delete_dialog_state.selected_signal = KillSignal::CANCEL;
+ self.delete_dialog_state.selected_signal = KillSignal::Cancel;
}
}
@@ -2312,7 +2323,7 @@ impl App {
.max_scroll_index
.saturating_sub(1);
} else if self.delete_dialog_state.is_showing_dd {
- self.delete_dialog_state.selected_signal = KillSignal::KILL(MAX_SIGNAL);
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(MAX_SIGNAL);
}
}
@@ -2871,13 +2882,13 @@ impl App {
},
) {
Some((_, _, _, _, 0)) => {
- self.delete_dialog_state.selected_signal = KillSignal::CANCEL
+ self.delete_dialog_state.selected_signal = KillSignal::Cancel
}
Some((_, _, _, _, idx)) => {
if *idx > 31 {
- self.delete_dialog_state.selected_signal = KillSignal::KILL(*idx + 2)
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(*idx + 2)
} else {
- self.delete_dialog_state.selected_signal = KillSignal::KILL(*idx)
+ self.delete_dialog_state.selected_signal = KillSignal::Kill(*idx)
}
}
_ => {}
diff --git a/src/app/data_farmer.rs b/src/app/data_farmer.rs
index bfc7ae8d..4a2f470e 100644
--- a/src/app/data_farmer.rs
+++ b/src/app/data_farmer.rs
@@ -19,7 +19,7 @@ use std::{time::Instant, vec::Vec};
use crate::app::data_harvester::load_avg::LoadAvgHarvest;
use crate::{
data_harvester::{batteries, cpu, disks, load_avg, mem, network, processes, temperature, Data},
- utils::gen_util::get_simple_byte_values,
+ utils::gen_util::get_decimal_bytes,
};
use regex::Regex;
@@ -57,7 +57,7 @@ pub struct DataCollection {
pub load_avg_harvest: load_avg::LoadAvgHarvest,
pub process_harvest: Vec<processes::ProcessHarvest>,
pub disk_harvest: Vec<disks::DiskHarvest>,
- pub io_harvest: disks::IOHarvest,
+ pub io_harvest: disks::IoHarvest,
pub io_labels_and_prev: Vec<((u64, u64), (u64, u64))>,
pub io_labels: Vec<(String, String)>,
pub temp_harvest: Vec<temperature::TempHarvest>,
@@ -77,7 +77,7 @@ impl Default for DataCollection {
load_avg_harvest: load_avg::LoadAvgHarvest::default(),
process_harvest: Vec::default(),
disk_harvest: Vec::default(),
- io_harvest: disks::IOHarvest::default(),
+ io_harvest: disks::IoHarvest::default(),
io_labels_and_prev: Vec::default(),
io_labels: Vec::default(),
temp_harvest: Vec::default(),
@@ -95,7 +95,7 @@ impl DataCollection {
self.cpu_harvest = cpu::CpuHarvest::default();
self.process_harvest = Vec::default();
self.disk_harvest = Vec::default();
- self.io_harvest = disks::IOHarvest::default();
+ self.io_harvest = disks::IoHarvest::default();
self.io_labels_and_prev = Vec::default();
self.temp_harvest = Vec::default();
self.battery_harvest = Vec::default();
@@ -205,22 +205,15 @@ impl DataCollection {
}
fn eat_network(&mut self, network: network::NetworkHarvest, new_entry: &mut TimedData) {
- // trace!("Eating network.");
- // FIXME [NETWORKING; CONFIG]: The ability to config this?
- // FIXME [NETWORKING]: Support bits, support switching between decimal and binary units (move the log part to conversion and switch on the fly)
// RX
- new_entry.rx_data = if network.rx > 0 {
- (network.rx as f64).log2()
- } else {
- 0.0
- };
+ if network.rx > 0 {
+ new_entry.rx_data = network.rx as f64;
+ }
// TX
- new_entry.tx_data = if network.tx > 0 {
- (network.tx as f64).log2()
- } else {
- 0.0
- };
+ if network.tx > 0 {
+ new_entry.tx_data = network.tx as f64;
+ }
// In addition copy over latest data for easy reference
self.network_harvest = network;
@@ -250,7 +243,7 @@ impl DataCollection {
}
fn eat_disks(
- &mut self, disks: Vec<disks::DiskHarvest>, io: disks::IOHarvest, harvested_time: Instant,
+ &mut self, disks: Vec<disks::DiskHarvest>, io: disks::IoHarvest, harvested_time: Instant,
) {
// trace!("Eating disks.");
// TODO: [PO] To implement
@@ -300,8 +293,8 @@ impl DataCollection {
*io_prev = (io_r_pt, io_w_pt);
if let Some(io_labels) = self.io_labels.get_mut(itx) {
- let converted_read = get_simple_byte_values(r_rate, false);
- let converted_write = get_simple_byte_values(w_rate, false);
+ let converted_read = get_decimal_bytes(r_rate);
+ let converted_write = get_decimal_bytes(w_rate);
*io_labels = (
format!("{:.*}{}/s", 0, converted_read.0, converted_read.1),
format!("{:.*}{}/s", 0, converted_write.0, converted_write.1),
diff --git a/src/app/data_harvester.rs b/src/app/data_harvester.rs
index 3b7a0f63..207bb23a 100644
--- a/src/app/data_harvester.rs
+++ b/src/app/data_harvester.rs
@@ -36,7 +36,7 @@ pub struct Data {
pub network: Option<network::NetworkHarvest>,
pub list_of_processes: Option<Vec<processes::ProcessHarvest>>,
pub disks: Option<Vec<disks::DiskHarvest>>,
- pub io: Option<disks::IOHarvest>,
+ pub io: Option<disks::IoHarvest>,
pub list_of_batteries: Option<Vec<batteries::BatteryHarvest>>,
}
diff --git a/src/app/data_harvester/batteries.rs b/src/app/data_harvester/batteries.rs
index 66e3c76b..98cf6ae6 100644
--- a/src/app/data_harvester/batteries.rs
+++ b/src/app/data_harvester/batteries.rs
@@ -20,19 +20,11 @@ pub fn refresh_batteries(manager: &Manager, batteries: &mut [Battery]) -> Vec<Ba
Some(BatteryHarvest {
secs_until_full: {
let optional_time = battery.time_to_full();
- if let Some(time) = optional_time {
- Some(f64::from(time.get::<second>()) as i64)
- } else {
- None
- }
+ optional_time.map(|time| f64::from(time.get::<second>()) as i64)
},
secs_until_empty: {
let optional_time = battery.time_to_empty();
- if let Some(time) = optional_time {
- Some(f64::from(time.get::<second>()) as i64)
- } else {
- None
- }
+ optional_time.map(|time| f64::from(time.get::<second>()) as i64)
},
charge_percent: f64::from(battery.state_of_charge().get::<percent>()),
power_consumption_rate_watts: f64::from(battery.energy_rate().get::<watt>()),
diff --git a/src/app/data_harvester/disks.rs b/src/app/data_harvester/disks.rs
index 246f5b5d..ba1d2d49 100644
--- a/src/app/data_harvester/disks.rs
+++ b/src/app/data_harvester/disks.rs
@@ -10,21 +10,21 @@ pub struct DiskHarvest {
}
#[derive(Clone, Debug)]
-pub struct IOData {
+pub struct IoData {
pub read_bytes: u64,
pub write_bytes: u64,
}
-pub type IOHarvest = std::collections::HashMap<String, Option<IOData>>;
+pub type IoHarvest = std::collections::HashMap<String, Option<IoData>>;
-pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IOHarvest>> {
+pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Option<IoHarvest>> {
if !actually_get {
return Ok(None);
}
use futures::StreamExt;
- let mut io_hash: std::collections::HashMap<String, Option<IOData>> =
+ let mut io_hash: std::collections::HashMap<String, Option<IoData>> =
std::collections::HashMap::new();
let counter_stream = heim::disk::io_counters().await?;
@@ -37,7 +37,7 @@ pub async fn get_io_usage(actually_get: bool) -> crate::utils::error::Result<Opt
// FIXME: [MOUNT POINT] Add the filter here I guess?
io_hash.insert(
mount_point.to_string(),
- Some(IOData {
+ Some(IoData {
read_bytes: io.read_bytes().get::<heim::units::information::byte>(),
write_bytes: io.write_bytes().get::<heim::units::information::byte>(),
}),
diff --git a/src/app/data_harvester/network.rs b/src/app/data_harvester/network.rs
index 55d757f6..52dc8468 100644
--- a/src/app/data_harvester/network.rs
+++ b/src/app/data_harvester/network.rs
@@ -1,6 +1,7 @@
use std::time::Instant;
#[derive(Default, Clone, Debug)]
+/// All units in bits.
pub struct NetworkHarvest {
pub rx: u64,
pub tx: u64,
@@ -47,8 +48,8 @@ pub async fn get_network_data(
};
if to_keep {
- total_rx += network.get_total_received();
- total_tx += network.get_total_transmitted();
+ total_rx += network.get_total_received() * 8;
+ total_tx += network.get_total_transmitted() * 8;
}
}
@@ -106,8 +107,12 @@ pub async fn get_network_data(
};
if to_keep {
- total_rx += io.bytes_recv().get::<heim::units::information::byte>();
- total_tx += io.bytes_sent().get::<heim::units::information::byte>();
+ // TODO: Use bytes as the default instead, perhaps?
+ // Since you might have to do a double conversion (bytes -> bits -> bytes) in some cases;
+ // but if you stick to bytes, then in the bytes, case, you do no conversion, and in the bits case,
+ // you only do one conversion...
+ total_rx += io.bytes_recv().get::<heim::units::information::bit>();
+ total_tx += io.bytes_sent().get::<heim::units::information::bit>();
}
}
}
diff --git a/src/app/data_harvester/processes.rs b/src/app/data_harvester/processes.rs
index 4d7beda0..52e80c27 100644
--- a/src/app/data_harvester/processes.rs
+++ b/src/app/data_harvester/processes.rs
@@ -2,6 +2,9 @@ use crate::Pid;
use std::path::PathBuf;
use sysinfo::ProcessStatus;
+#[cfg(target_os = "linux")]
+use std::path::Path;
+
#[cfg(target_family = "unix")]
use crate::utils::error;
@@ -168,7 +171,7 @@ fn cpu_usage_calculation(
// SC in case that the parsing will fail due to length:
if val.len() <= 10 {
- return Err(error::BottomError::InvalidIO(format!(
+ return Err(error::BottomError::InvalidIo(format!(
"CPU parsing will fail due to too short of a return value; saw {} values, expected 10 values.",
val.len()
)));
@@ -222,8 +225,8 @@ fn get_linux_process_vsize_rss(stat: &[&str]) -> (u64, u64) {
#[cfg(target_os = "linux")]
/// Preferably use this only on small files.
-fn read_path_contents(path: &PathBuf) -> std::io::Result<String> {
- Ok(std::fs::read_to_string(path)?)
+fn read_path_contents(path: &Path) -> std::io::Result<String> {
+ std::fs::read_to_string(path)
}
#[cfg(target_os = "linux")]
@@ -272,9 +275,8 @@ fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMa
let output = std::process::Command::new("ps")
.args(&["-o", "pid=,pcpu=", "-p"])
.arg(
- pids.iter()
- .map(i32::to_string)
- .intersperse(",".to_string())
+ // Has to look like this since otherwise, it you hit a `unstable_name_collisions` warning.
+ Itertools::intersperse(pids.iter().map(i32::to_string), ",".to_string())
.collect::<String>(),
)
.output()?;
@@ -298,7 +300,7 @@ fn get_macos_cpu_usage(pids: &[i32]) -> std::io::Result<std::collections::HashMa
}
#[cfg(target_os = "linux")]
-fn get_uid_and_gid(path: &PathBuf) -> (Option<u32>, Option<u32>) {
+fn get_uid_and_gid(path: &Path) -> (Option<u32>, Option<u32>) {
// FIXME: [OPT] - can we merge our /stat and /status calls?
use std::io::prelude::*;
use std::io::BufReader;
@@ -470,15 +472,15 @@ fn read_proc(
Ok(ProcessHarvest {
pid,
parent_pid,
- name,
- command,
+ cpu_usage_percent,
mem_usage_percent,
mem_usage_bytes,
- cpu_usage_percent,
- total_read_bytes,
- total_write_bytes,
+ name,
+ command,
read_bytes_per_sec,
write_bytes_per_sec,
+ total_read_bytes,
+ total_write_bytes,
process_state,
process_state_char,
uid,
diff --git a/src/app/data_harvester/temperature.rs b/src/app/data_harvester/temperature.rs
index 1c818e31..3786adc7 100644
--- a/src/app/data_harvester/temperature.rs
+++ b/src/app/data_harvester/temperature.rs
@@ -95,11 +95,7 @@ pub async fn get_temperature_data(
while let Some(sensor) = sensor_data.next().await {
if let Ok(sensor) = sensor {
let component_name = Some(sensor.unit().to_string());
- let component_label = if let Some(label) = sensor.label() {
- Some(label.to_string())
- } else {
- None
- };
+ let component_label = sensor.label().map(|label| label.to_string());
let name = match (component_name, component_label) {
(Some(name), Some(label)) => format!("{}: {}", name, label),
diff --git a/src/app/query.rs b/src/app/query.rs
index 5a827aec..a783c658 100644
--- a/src/app/query.rs
+++ b/src/app/query.rs
@@ -188,11 +188,7 @@ impl ProcessQuery for ProcWidgetState {
let initial_or = Or {
lhs: And {
lhs: Prefix {
- or: if let Some(or) = list_of_ors.pop_front() {
- Some(Box::new(or))
- } else {
- None
- },
+ or: list_of_ors.pop_front().map(Box::new),
compare_prefix: None,
regex_prefix: None,
},
diff --git a/src/app/states.rs b/src/app/states.rs
index 39dd0222..c8af1737 100644
--- a/src/app/states.rs
+++ b/src/app/states.rs
@@ -42,18 +42,18 @@ pub struct AppScrollWidgetState {
#[derive(PartialEq)]
pub enum KillSignal {
- CANCEL,
- KILL(usize),
+ Cancel,
+ Kill(usize),
}
impl Default for KillSignal {
#[cfg(target_family = "unix")]
fn default() -> Self {
- KillSignal::KILL(15)
+ KillSignal::Kill(15)
}
#[cfg(target_os = "windows")]
fn default() -> Self {
- KillSignal::KILL(1)
+ KillSignal::Kill(1)
}
}
@@ -690,13 +690,29 @@ impl ProcState {
pub struct NetWidgetState {
pub current_display_time: u64,
pub autohide_timer: Option<Instant>,
+ // pub draw_max_range_cache: f64,
+ // pub draw_labels_cache: Vec<String>,
+ // pub draw_time_start_cache: f64,
+ // TODO: Re-enable these when we move net details state-side!
+ // pub unit_type: DataUnitTypes,
+ // pub scale_type: AxisScaling,
}
impl NetWidgetState {
- pub fn init(current_display_time: u64, autohide_timer: Option<Instant>) -> Self {
+ pub fn init(
+ current_display_time: u64,
+ autohide_timer: Option<Instant>,
+ // unit_type: DataUnitTypes,
+ // scale_type: AxisScaling,
+ ) -> Self {
NetWidgetState {
current_display_time,
autohide_timer,
+ // draw_max_range_cache: 0.0,
+ // draw_labels_cache: vec![],
+ // draw_time_start_cache: 0.0,
+ // unit_type,
+ // scale_type,
}
}
}
diff --git a/src/bin/main.rs b/src/bin/main.rs
index 70d02efe..e9854987 100644
--- a/src/bin/main.rs
+++ b/src/bin/main.rs
@@ -26,6 +26,10 @@ use crossterm::{
};
use tui::{backend::CrosstermBackend, Terminal};
+// TODO: Add a debugger tool:
+// Debugger binary. This isn't implemented yet; the idea for this is to make it easier to troubleshoot bug reports
+// by providing a built-in debugger to help gather relevant information to narrow down the problem.
+
fn main() -> Result<()> {
let matches = clap::get_matches();
// let is_debug = matches.is_present("debug");
@@ -178,6 +182,9 @@ fn main() -> Result<()> {
false,
app.app_config_fields.use_basic_mode
|| app.app_config_fields.use_old_network_legend,
+ &app.app_config_fields.network_scale_type,
+ &app.app_config_fields.network_unit_type,
+ app.app_config_fields.network_use_binary_prefix,
);
app.canvas_data.network_data_rx = network_data.rx;
app.canvas_data.network_data_tx = network_data.tx;
diff --git a/src/canvas.rs b/src/canvas.rs
index b904e217..1916f200 100644
--- a/src/canvas.rs
+++ b/src/canvas.rs
@@ -9,6 +9,8 @@ use tui::{
Frame, Terminal,
};
+// use ordered_float::OrderedFloat;
+
use canvas_colours::*;
use dialogs::*;
use screens::*;
@@ -54,7 +56,7 @@ pub struct DisplayableData {
pub mem_labels: Option<(String, String)>,
pub swap_labels: Option<(String, String)>,
- pub mem_data: Vec<Point>,
+ pub mem_data: Vec<Point>, // TODO: Switch this and all data points over to a better data structure...
pub swap_data: Vec<Point>,
pub load_avg_data: [f32; 3],
pub cpu_data: Vec<ConvertedCpuData>,
diff --git a/src/canvas/dialogs/dd_dialog.rs b/src/canvas/dialogs/dd_dialog.rs
index cd9029c8..0415aa2d 100644
--- a/src/canvas/dialogs/dd_dialog.rs
+++ b/src/canvas/dialogs/dd_dialog.rs
@@ -72,11 +72,11 @@ impl KillDialog for Painter {
) {
if cfg!(target_os = "windows") || !app_state.app_config_fields.is_advanced_kill {
let (yes_button, no_button) = match app_state.delete_dialog_state.selected_signal {
- KillSignal::KILL(_) => (
+ KillSignal::Kill(_) => (
Span::styled("Yes", self.colours.currently_selected_text_style),
Span::raw("No"),
),
- KillSignal::CANCEL => (
+ KillSignal::Cancel => (
Span::raw("Yes"),
Span::styled("No", self.colours.currently_selected_text_style),
),
@@ -249,8 +249,8 @@ impl KillDialog for Painter {
.split(*button_draw_loc)[1];
let mut selected = match app_state.delete_dialog_state.selected_signal {
- KillSignal::CANCEL => 0,
- KillSignal::KILL(signal) => signal,
+ KillSignal::Cancel => 0,
+ KillSignal::Kill(signal) => signal,
};
// 32+33 are skipped
if selected > 31 {
diff --git a/src/canvas/drawing_utils.rs b/src/canvas/drawing_utils.rs
index 222ca852..6aee1aa7 100644
--- a/src/canvas/drawing_utils.rs
+++ b/src/canvas/drawing_utils.rs
@@ -117,6 +117,12 @@ pub fn get_column_widths(
filtered_column_widths
}
+/// FIXME: [command move] This is a greedy method of determining column widths. This is reserved for columns where we are okay with
+/// shoving information as far right as required.
+// pub fn greedy_get_column_widths() -> Vec<u16> {
+// vec![]
+// }
+
pub fn get_search_start_position(
num_columns: usize, cursor_direction: &app::CursorDirection, cursor_bar: &mut usize,
current_cursor_position: usize, is_force_redraw: bool,
@@ -205,3 +211,14 @@ pub fn calculate_basic_use_bars(use_percentage: f64, num_bars_available: usize)
num_bars_available,
)
}
+
+/// Interpolates between two points. Mainly used to help fill in tui-rs blanks in certain situations.
+/// It is expected point_one is "further left" compared to point_two.
+/// A point is two floats, in (x, y) form. x is time, y is value.
+pub fn interpolate_points(point_one: &(f64, f64), point_two: &(f64, f64), time: f64) -> f64 {
+ let delta_x = point_two.0 - point_one.0;
+ let delta_y = point_two.1 - point_one.1;
+ let slope = delta_y / delta_x;
+
+ (point_one.1 + (time - point_one.0) * slope).max(0.0)
+}
diff --git a/src/canvas/widgets/cpu_graph.rs b/src/canvas/widgets/cpu_graph.rs
index 1b79482f..ff6838f2 100644
--- a/src/canvas/widgets/cpu_graph.rs
+++ b/src/canvas/widgets/cpu_graph.rs
@@ -4,7 +4,7 @@ use unicode_segmentation::UnicodeSegmentation;
use crate::{
app::{layout_manager::WidgetDirection, App},
canvas::{
- drawing_utils::{get_column_widths, get_start_position},
+ drawing_utils::{get_column_widths, get_start_position, interpolate_points},
Painter,
},
constants::*,
@@ -146,32 +146,34 @@ impl CpuGraphWidget for Painter {
];
let y_axis_labels = vec![
- Span::styled("0%", self.colours.graph_style),
+ Span::styled(" 0%", self.colours.graph_style),
Span::styled("100%", self.colours.graph_style),
];
+ let time_start = -(cpu_widget_state.current_display_time as f64);
+
let x_axis = if app_state.app_config_fields.hide_time