diff --git a/CHANGELOG.md b/CHANGELOG.md index 86841312..67f0c462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1216](https://github.com/ClementTsang/bottom/pull/1216): Fix arguments not being sorted alphabetically. - [#1219](https://github.com/ClementTsang/bottom/pull/1219): Fix overflow/underflow in graph timespan zoom. +## Features + +- [#1221](https://github.com/ClementTsang/bottom/pull/1221): Support human times for `rate`. + ## [0.9.2] - 2023-06-11 ## Bug Fixes diff --git a/src/app.rs b/src/app.rs index 5418f615..03782a56 100644 --- a/src/app.rs +++ b/src/app.rs @@ -45,7 +45,7 @@ pub enum AxisScaling { /// by config files or launch options. #[derive(Debug, Default, Eq, PartialEq)] pub struct AppConfigFields { - pub update_rate_in_milliseconds: u64, + pub update_rate: u64, pub temperature_type: temperature::TemperatureType, pub use_dot: bool, pub left_legend: bool, diff --git a/src/args.rs b/src/args.rs index 87035a6a..b384acc0 100644 --- a/src/args.rs +++ b/src/args.rs @@ -353,8 +353,8 @@ use CPU (3) as the default instead. .long("rate") .action(ArgAction::Set) .value_name("MS") - .help("Sets a refresh rate in ms.") - .long_help("Sets a refresh rate in milliseconds. The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources."); + .help("Sets the data refresh rate.") + .long_help("Sets the data refresh rate. The minimum is 250ms, and defaults to 1000ms. Smaller values may take more computer resources."); let time_delta = Arg::new("time_delta") .short('d') diff --git a/src/constants.rs b/src/constants.rs index a76c8609..9a0cd04a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -520,7 +520,7 @@ pub const CONFIG_TEXT: &str = r##"# This is a default config file for bottom. A # Whether to use dot markers rather than braille. #dot_marker = false # The update rate of the application. -#rate = 1000 +#rate = "1s" # Whether to put the CPU legend to the left. #left_legend = false # Whether to set CPU% on a process to be based on the total CPU or just current usage. diff --git a/src/lib.rs b/src/lib.rs index 6424c286..86d36cb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -484,7 +484,7 @@ pub fn create_collection_thread( let use_current_cpu_total = app_config_fields.use_current_cpu_total; let unnormalized_cpu = app_config_fields.unnormalized_cpu; let show_average_cpu = app_config_fields.show_average_cpu; - let update_time = app_config_fields.update_rate_in_milliseconds; + let update_time = app_config_fields.update_rate; thread::spawn(move || { let mut data_state = data_harvester::DataCollector::new(filters); diff --git a/src/options.rs b/src/options.rs index 4a4d15f5..412748a6 100644 --- a/src/options.rs +++ b/src/options.rs @@ -66,45 +66,45 @@ impl From for StringOrNum { #[derive(Clone, Debug, Default, Deserialize, Serialize)] pub struct ConfigFlags { - pub hide_avg_cpu: Option, - pub dot_marker: Option, - pub temperature_type: Option, - pub rate: Option, - pub left_legend: Option, - pub current_usage: Option, - pub unnormalized_cpu: Option, - pub group_processes: Option, - pub case_sensitive: Option, - pub whole_word: Option, - pub regex: Option, - pub basic: Option, + hide_avg_cpu: Option, + dot_marker: Option, + temperature_type: Option, + rate: Option, + left_legend: Option, + current_usage: Option, + unnormalized_cpu: Option, + group_processes: Option, + case_sensitive: Option, + whole_word: Option, + regex: Option, + basic: Option, default_time_value: Option, time_delta: Option, - pub autohide_time: Option, - pub hide_time: Option, - pub default_widget_type: Option, - pub default_widget_count: Option, - pub expanded_on_startup: Option, - pub use_old_network_legend: Option, - pub hide_table_gap: Option, - pub battery: Option, - pub disable_click: Option, - pub no_write: Option, + autohide_time: Option, + hide_time: Option, + default_widget_type: Option, + default_widget_count: Option, + expanded_on_startup: Option, + use_old_network_legend: Option, + hide_table_gap: Option, + battery: Option, + disable_click: Option, + no_write: Option, /// For built-in colour palettes. - pub color: Option, - pub mem_as_value: Option, - pub tree: Option, + color: Option, + mem_as_value: Option, + tree: Option, show_table_scroll_position: Option, - pub process_command: Option, - pub disable_advanced_kill: Option, - pub network_use_bytes: Option, - pub network_use_log: Option, - pub network_use_binary_prefix: Option, - pub enable_gpu_memory: Option, - pub enable_cache_memory: Option, + process_command: Option, + disable_advanced_kill: Option, + network_use_bytes: Option, + network_use_log: Option, + network_use_binary_prefix: Option, + enable_gpu_memory: Option, + enable_cache_memory: Option, #[serde(with = "humantime_serde")] #[serde(default)] - pub retention: Option, + retention: Option, } #[derive(Clone, Debug, Default, Deserialize, Serialize)] @@ -262,7 +262,7 @@ pub fn build_app( }; let app_config_fields = AppConfigFields { - update_rate_in_milliseconds: get_update_rate_in_milliseconds(matches, config) + update_rate: get_update_rate(matches, config) .context("Update 'rate' in your config file.")?, temperature_type: get_temperature(matches, config) .context("Update 'temperature_type' in your config file.")?, @@ -549,16 +549,15 @@ pub fn get_widget_layout( Ok((bottom_layout, default_widget_id, default_widget_type)) } -fn get_update_rate_in_milliseconds(matches: &ArgMatches, config: &Config) -> error::Result { - let update_rate_in_milliseconds = if let Some(update_rate) = matches.get_one::("rate") { - update_rate.parse::().map_err(|_| { - BottomError::ConfigError( - "could not parse as a valid 64-bit unsigned integer".to_string(), - ) - })? +fn get_update_rate(matches: &ArgMatches, config: &Config) -> error::Result { + let update_rate = if let Some(update_rate) = matches.get_one::("rate") { + try_parse_ms(update_rate)? } else if let Some(flags) = &config.flags { - if let Some(rate) = flags.rate { - rate + if let Some(rate) = &flags.rate { + match rate { + StringOrNum::String(s) => try_parse_ms(s)?, + StringOrNum::Num(n) => *n, + } } else { DEFAULT_REFRESH_RATE_IN_MILLISECONDS } @@ -566,13 +565,13 @@ fn get_update_rate_in_milliseconds(matches: &ArgMatches, config: &Config) -> err DEFAULT_REFRESH_RATE_IN_MILLISECONDS }; - if update_rate_in_milliseconds < 250 { + if update_rate < 250 { return Err(BottomError::ConfigError( - "set your update rate to be at least 250 milliseconds.".to_string(), + "set your update rate to be at least 250 ms.".to_string(), )); } - Ok(update_rate_in_milliseconds) + Ok(update_rate) } fn get_temperature( @@ -914,7 +913,7 @@ mod test { use crate::{ app::App, canvas::canvas_styling::CanvasStyling, - options::{get_default_time_value, try_parse_ms, ConfigFlags}, + options::{get_default_time_value, get_update_rate, try_parse_ms, ConfigFlags}, }; #[test] @@ -999,6 +998,7 @@ mod test { let flags = ConfigFlags { time_delta: Some("2 min".to_string().into()), default_time_value: Some("300s".to_string().into()), + rate: Some("1s".to_string().into()), ..Default::default() }; @@ -1013,6 +1013,8 @@ mod test { get_default_time_value(&matches, &config, 60 * 60 * 1000), Ok(5 * 60 * 1000) ); + + assert_eq!(get_update_rate(&matches, &config), Ok(1000)); } #[test] @@ -1024,6 +1026,7 @@ mod test { let flags = ConfigFlags { time_delta: Some("120000".to_string().into()), default_time_value: Some("300000".to_string().into()), + rate: Some("1000".to_string().into()), ..Default::default() }; @@ -1038,6 +1041,8 @@ mod test { get_default_time_value(&matches, &config, 60 * 60 * 1000), Ok(5 * 60 * 1000) ); + + assert_eq!(get_update_rate(&matches, &config), Ok(1000)); } #[test] @@ -1049,6 +1054,7 @@ mod test { let flags = ConfigFlags { time_delta: Some(120000.into()), default_time_value: Some(300000.into()), + rate: Some(1000.into()), ..Default::default() }; @@ -1063,6 +1069,8 @@ mod test { get_default_time_value(&matches, &config, 60 * 60 * 1000), Ok(5 * 60 * 1000) ); + + assert_eq!(get_update_rate(&matches, &config), Ok(1000)); } fn create_app(config: Config, matches: ArgMatches) -> App { diff --git a/tests/arg_tests.rs b/tests/arg_tests.rs index 0bbddce8..c233c14e 100644 --- a/tests/arg_tests.rs +++ b/tests/arg_tests.rs @@ -15,7 +15,7 @@ fn test_small_rate() { .assert() .failure() .stderr(predicate::str::contains( - "set your update rate to be at least 250 milliseconds.", + "set your update rate to be at least 250 ms.", )); }