From b6f92c2f3d4773870a6cde224fb2844d291989d2 Mon Sep 17 00:00:00 2001 From: Clement Tsang <34804052+ClementTsang@users.noreply.github.com> Date: Sun, 10 Dec 2023 15:21:35 -0500 Subject: [PATCH] feature: support default selection of average CPU graph (#1353) * feature: support default selection of average CPU graph * test --- .cargo/config.toml | 12 --- docs/content/configuration/config-file/cpu.md | 11 +++ sample_configs/default_config.toml | 4 + src/app.rs | 22 +++--- src/components/data_table.rs | 16 +++- src/components/data_table/draw.rs | 9 ++- src/components/data_table/sortable.rs | 1 + src/constants.rs | 4 + src/options.rs | 13 ++- src/options/cpu.rs | 79 +++++++++++++++++++ src/widgets/cpu_graph.rs | 15 +++- 11 files changed, 152 insertions(+), 34 deletions(-) create mode 100644 docs/content/configuration/config-file/cpu.md create mode 100644 src/options/cpu.rs diff --git a/.cargo/config.toml b/.cargo/config.toml index 4d45f24b..7e766c36 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -3,15 +3,3 @@ rustflags = ["-C", "target-feature=+crt-static"] [target.i686-pc-windows-msvc] rustflags = ["-C", "target-feature=+crt-static"] - -# [target.arm-unknown-linux-gnueabihf] -# linker = "arm-linux-gnueabihf-gcc" - -# [target.armv7-unknown-linux-gnueabihf] -# linker = "arm-linux-gnueabihf-gcc" - -# [target.aarch64-unknown-linux-gnu] -# linker = "aarch64-linux-gnu-gcc" - -# [target.aarch64-unknown-linux-musl] -# linker = "aarch64-linux-musl-gcc" \ No newline at end of file diff --git a/docs/content/configuration/config-file/cpu.md b/docs/content/configuration/config-file/cpu.md new file mode 100644 index 00000000..77d8fe30 --- /dev/null +++ b/docs/content/configuration/config-file/cpu.md @@ -0,0 +1,11 @@ +# CPU + +## Default CPU Graph Selection + +You can configure which CPU graph is shown by default when starting up bottom by setting `cpu.default`. + +```toml +[cpu] +# One of "all" (default), "average"/"avg" +default = "average" +``` diff --git a/sample_configs/default_config.toml b/sample_configs/default_config.toml index 7d6a9f28..a7731dd6 100644 --- a/sample_configs/default_config.toml +++ b/sample_configs/default_config.toml @@ -85,6 +85,10 @@ #[processes] #columns = ["PID", "Name", "CPU%", "Mem%", "R/s", "W/s", "T.Read", "T.Write", "User", "State", "GMEM%", "GPU%"] +# [cpu] +# One of "all" (default), "average"/"avg" +# default = "average" + # These are all the components that support custom theming. Note that colour support # will depend on terminal support. diff --git a/src/app.rs b/src/app.rs index 32f0af06..005a743b 100644 --- a/src/app.rs +++ b/src/app.rs @@ -49,7 +49,7 @@ pub struct AppConfigFields { pub temperature_type: temperature::TemperatureType, pub use_dot: bool, pub left_legend: bool, - pub show_average_cpu: bool, + pub show_average_cpu: bool, // TODO: Unify this in CPU options pub use_current_cpu_total: bool, pub unnormalized_cpu: bool, pub use_basic_mode: bool, @@ -1910,7 +1910,7 @@ impl App { .proc_state .get_mut_widget_state(self.current_widget.widget_id) { - proc_widget_state.table.set_first(); + proc_widget_state.table.to_first(); } } BottomWidgetType::ProcSort => { @@ -1919,7 +1919,7 @@ impl App { .proc_state .get_mut_widget_state(self.current_widget.widget_id - 2) { - proc_widget_state.sort_table.set_first(); + proc_widget_state.sort_table.to_first(); } } BottomWidgetType::Temp => { @@ -1928,7 +1928,7 @@ impl App { .temp_state .get_mut_widget_state(self.current_widget.widget_id) { - temp_widget_state.table.set_first(); + temp_widget_state.table.to_first(); } } BottomWidgetType::Disk => { @@ -1937,7 +1937,7 @@ impl App { .disk_state .get_mut_widget_state(self.current_widget.widget_id) { - disk_widget_state.table.set_first(); + disk_widget_state.table.to_first(); } } BottomWidgetType::CpuLegend => { @@ -1946,7 +1946,7 @@ impl App { .cpu_state .get_mut_widget_state(self.current_widget.widget_id - 1) { - cpu_widget_state.table.set_first(); + cpu_widget_state.table.to_first(); } } @@ -1969,7 +1969,7 @@ impl App { .proc_state .get_mut_widget_state(self.current_widget.widget_id) { - proc_widget_state.table.set_last(); + proc_widget_state.table.to_last(); } } BottomWidgetType::ProcSort => { @@ -1978,7 +1978,7 @@ impl App { .proc_state .get_mut_widget_state(self.current_widget.widget_id - 2) { - proc_widget_state.sort_table.set_last(); + proc_widget_state.sort_table.to_last(); } } BottomWidgetType::Temp => { @@ -1987,7 +1987,7 @@ impl App { .temp_state .get_mut_widget_state(self.current_widget.widget_id) { - temp_widget_state.table.set_last(); + temp_widget_state.table.to_last(); } } BottomWidgetType::Disk => { @@ -1997,7 +1997,7 @@ impl App { .get_mut_widget_state(self.current_widget.widget_id) { if !self.converted_data.disk_data.is_empty() { - disk_widget_state.table.set_last(); + disk_widget_state.table.to_last(); } } } @@ -2007,7 +2007,7 @@ impl App { .cpu_state .get_mut_widget_state(self.current_widget.widget_id - 1) { - cpu_widget_state.table.set_last(); + cpu_widget_state.table.to_last(); } } _ => {} diff --git a/src/components/data_table.rs b/src/components/data_table.rs index ed79961a..4ae23d1d 100644 --- a/src/components/data_table.rs +++ b/src/components/data_table.rs @@ -40,6 +40,7 @@ pub struct DataTable> { data: Vec, sort_type: S, first_draw: bool, + first_index: Option, _pd: PhantomData<(DataType, S, Header)>, } @@ -55,6 +56,7 @@ impl, H: ColumnHeader> DataTable, H: ColumnHeader> DataTable, H: ColumnHeader, S: SortType, C: DataTableColumn> DataTable { + /// Sets the default value selected on first initialization, if possible. + pub fn first_draw_index(mut self, first_index: usize) -> Self { + self.first_index = Some(first_index); + self + } + /// Sets the scroll position to the first value. - pub fn set_first(&mut self) { + pub fn to_first(&mut self) { self.state.current_index = 0; self.state.scroll_direction = ScrollDirection::Up; } /// Sets the scroll position to the last value. - pub fn set_last(&mut self) { + pub fn to_last(&mut self) { self.state.current_index = self.data.len().saturating_sub(1); self.state.scroll_direction = ScrollDirection::Down; } @@ -189,11 +197,11 @@ mod test { let mut table = DataTable::new(columns, props, styling); table.set_data((0..=4).map(|index| TestType { index }).collect::>()); - table.set_last(); + table.to_last(); assert_eq!(table.current_index(), 4); assert_eq!(table.state.scroll_direction, ScrollDirection::Down); - table.set_first(); + table.to_first(); assert_eq!(table.current_index(), 0); assert_eq!(table.state.scroll_direction, ScrollDirection::Up); diff --git a/src/components/data_table/draw.rs b/src/components/data_table/draw.rs index 3903f381..91fef6ba 100644 --- a/src/components/data_table/draw.rs +++ b/src/components/data_table/draw.rs @@ -200,10 +200,15 @@ where self.props.table_gap }; - let columns = &self.columns; if !self.data.is_empty() || !self.first_draw { - self.first_draw = false; // TODO: Doing it this way is fine, but it could be done better (e.g. showing custom no results/entries message) + if self.first_draw { + self.first_draw = false; // TODO: Doing it this way is fine, but it could be done better (e.g. showing custom no results/entries message) + if let Some(first_index) = self.first_index { + self.set_position(first_index); + } + } + let columns = &self.columns; let rows = { let num_rows = usize::from(inner_height.saturating_sub(table_gap + header_height)); diff --git a/src/components/data_table/sortable.rs b/src/components/data_table/sortable.rs index b44906a4..3a3de1fc 100644 --- a/src/components/data_table/sortable.rs +++ b/src/components/data_table/sortable.rs @@ -260,6 +260,7 @@ where order: props.order, }, first_draw: true, + first_index: None, data: vec![], _pd: PhantomData, } diff --git a/src/constants.rs b/src/constants.rs index f511313e..3ad60f82 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -598,6 +598,10 @@ pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. Al # PID, Name, CPU%, Mem%, R/s, W/s, T.Read, T.Write, User, State, Time, GMem%, GPU% #columns = ["PID", "Name", "CPU%", "Mem%", "R/s", "W/s", "T.Read", "T.Write", "User", "State", "GMEM%", "GPU%"] +# [cpu] +# One of "all" (default), "average"/"avg" +# default = "average" + # These are all the components that support custom theming. Note that colour support # will depend on terminal support. #[colors] # Uncomment if you want to use custom colors diff --git a/src/options.rs b/src/options.rs index 152db131..08c96e34 100644 --- a/src/options.rs +++ b/src/options.rs @@ -28,8 +28,11 @@ use crate::{ pub mod layout_options; -pub mod process_columns; -use self::process_columns::ProcessConfig; +mod process_columns; +pub use process_columns::ProcessConfig; + +mod cpu; +pub use cpu::{CpuConfig, CpuDefault}; use anyhow::{Context, Result}; @@ -43,6 +46,7 @@ pub struct Config { pub temp_filter: Option, pub net_filter: Option, pub processes: Option, + pub cpu: Option, } #[derive(Clone, Debug, Deserialize, Serialize)] @@ -340,6 +344,11 @@ pub fn build_app( widget.widget_id, CpuWidgetState::new( &app_config_fields, + config + .cpu + .as_ref() + .map(|cfg| cfg.default) + .unwrap_or_default(), default_time_value, autohide_timer, styling, diff --git a/src/options/cpu.rs b/src/options/cpu.rs new file mode 100644 index 00000000..ce027305 --- /dev/null +++ b/src/options/cpu.rs @@ -0,0 +1,79 @@ +use serde::Deserialize; + +/// The default selection of the CPU widget. If the given selection is invalid, we will fall back to all. +#[derive(Clone, Copy, Debug, Default, Deserialize)] +#[serde(rename_all = "lowercase")] +pub enum CpuDefault { + #[default] + All, + #[serde(alias = "avg")] + Average, +} + +/// Process column settings. +#[derive(Clone, Debug, Default, Deserialize)] +pub struct CpuConfig { + #[serde(default)] + pub default: CpuDefault, +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn default_cpu_default() { + let config = ""; + let generated: CpuConfig = toml_edit::de::from_str(config).unwrap(); + match generated.default { + CpuDefault::All => {} + CpuDefault::Average => { + panic!("the default should be all") + } + } + } + + #[test] + fn all_cpu_default() { + let config = r#" + default = "all" + "#; + let generated: CpuConfig = toml_edit::de::from_str(config).unwrap(); + match generated.default { + CpuDefault::All => {} + CpuDefault::Average => { + panic!("the default should be all") + } + } + } + + #[test] + fn avg_cpu_default() { + let config = r#" + default = "avg" + "#; + + let generated: CpuConfig = toml_edit::de::from_str(config).unwrap(); + match generated.default { + CpuDefault::All => { + panic!("the avg should be set") + } + CpuDefault::Average => {} + } + } + + #[test] + fn average_cpu_default() { + let config = r#" + default = "average" + "#; + + let generated: CpuConfig = toml_edit::de::from_str(config).unwrap(); + match generated.default { + CpuDefault::All => { + panic!("the avg should be set") + } + CpuDefault::Average => {} + } + } +} diff --git a/src/widgets/cpu_graph.rs b/src/widgets/cpu_graph.rs index 2b555c10..3d3e6df1 100644 --- a/src/widgets/cpu_graph.rs +++ b/src/widgets/cpu_graph.rs @@ -11,6 +11,7 @@ use crate::{ DataToCell, }, data_conversion::CpuWidgetData, + options::CpuDefault, utils::gen_util::truncate_to_text, }; @@ -165,8 +166,8 @@ pub struct CpuWidgetState { impl CpuWidgetState { pub fn new( - config: &AppConfigFields, current_display_time: u64, autohide_timer: Option, - colours: &CanvasStyling, + config: &AppConfigFields, default_selection: CpuDefault, current_display_time: u64, + autohide_timer: Option, colours: &CanvasStyling, ) -> Self { const COLUMNS: [Column; 2] = [ Column::soft(CpuWidgetColumn::CPU, Some(0.5)), @@ -183,13 +184,21 @@ impl CpuWidgetState { }; let styling = DataTableStyling::from_colours(colours); + let mut table = DataTable::new(COLUMNS, props, styling); + match default_selection { + CpuDefault::All => {} + CpuDefault::Average if !config.show_average_cpu => {} + CpuDefault::Average => { + table = table.first_draw_index(1); + } + } CpuWidgetState { current_display_time, is_legend_hidden: false, show_avg: config.show_average_cpu, autohide_timer, - table: DataTable::new(COLUMNS, props, styling), + table, styling: CpuWidgetStyling::from_colours(colours), } }