mirror of
https://github.com/ClementTsang/bottom
synced 2024-11-24 21:23:08 +00:00
feature: support human times for rate (#1221)
This commit is contained in:
parent
0b7f4c745d
commit
cc3833289f
7 changed files with 65 additions and 53 deletions
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
102
src/options.rs
102
src/options.rs
|
@ -66,45 +66,45 @@ impl From<u64> for StringOrNum {
|
|||
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct ConfigFlags {
|
||||
pub hide_avg_cpu: Option<bool>,
|
||||
pub dot_marker: Option<bool>,
|
||||
pub temperature_type: Option<String>,
|
||||
pub rate: Option<u64>,
|
||||
pub left_legend: Option<bool>,
|
||||
pub current_usage: Option<bool>,
|
||||
pub unnormalized_cpu: Option<bool>,
|
||||
pub group_processes: Option<bool>,
|
||||
pub case_sensitive: Option<bool>,
|
||||
pub whole_word: Option<bool>,
|
||||
pub regex: Option<bool>,
|
||||
pub basic: Option<bool>,
|
||||
hide_avg_cpu: Option<bool>,
|
||||
dot_marker: Option<bool>,
|
||||
temperature_type: Option<String>,
|
||||
rate: Option<StringOrNum>,
|
||||
left_legend: Option<bool>,
|
||||
current_usage: Option<bool>,
|
||||
unnormalized_cpu: Option<bool>,
|
||||
group_processes: Option<bool>,
|
||||
case_sensitive: Option<bool>,
|
||||
whole_word: Option<bool>,
|
||||
regex: Option<bool>,
|
||||
basic: Option<bool>,
|
||||
default_time_value: Option<StringOrNum>,
|
||||
time_delta: Option<StringOrNum>,
|
||||
pub autohide_time: Option<bool>,
|
||||
pub hide_time: Option<bool>,
|
||||
pub default_widget_type: Option<String>,
|
||||
pub default_widget_count: Option<u64>,
|
||||
pub expanded_on_startup: Option<bool>,
|
||||
pub use_old_network_legend: Option<bool>,
|
||||
pub hide_table_gap: Option<bool>,
|
||||
pub battery: Option<bool>,
|
||||
pub disable_click: Option<bool>,
|
||||
pub no_write: Option<bool>,
|
||||
autohide_time: Option<bool>,
|
||||
hide_time: Option<bool>,
|
||||
default_widget_type: Option<String>,
|
||||
default_widget_count: Option<u64>,
|
||||
expanded_on_startup: Option<bool>,
|
||||
use_old_network_legend: Option<bool>,
|
||||
hide_table_gap: Option<bool>,
|
||||
battery: Option<bool>,
|
||||
disable_click: Option<bool>,
|
||||
no_write: Option<bool>,
|
||||
/// For built-in colour palettes.
|
||||
pub color: Option<String>,
|
||||
pub mem_as_value: Option<bool>,
|
||||
pub tree: Option<bool>,
|
||||
color: Option<String>,
|
||||
mem_as_value: Option<bool>,
|
||||
tree: Option<bool>,
|
||||
show_table_scroll_position: Option<bool>,
|
||||
pub process_command: Option<bool>,
|
||||
pub disable_advanced_kill: Option<bool>,
|
||||
pub network_use_bytes: Option<bool>,
|
||||
pub network_use_log: Option<bool>,
|
||||
pub network_use_binary_prefix: Option<bool>,
|
||||
pub enable_gpu_memory: Option<bool>,
|
||||
pub enable_cache_memory: Option<bool>,
|
||||
process_command: Option<bool>,
|
||||
disable_advanced_kill: Option<bool>,
|
||||
network_use_bytes: Option<bool>,
|
||||
network_use_log: Option<bool>,
|
||||
network_use_binary_prefix: Option<bool>,
|
||||
enable_gpu_memory: Option<bool>,
|
||||
enable_cache_memory: Option<bool>,
|
||||
#[serde(with = "humantime_serde")]
|
||||
#[serde(default)]
|
||||
pub retention: Option<Duration>,
|
||||
retention: Option<Duration>,
|
||||
}
|
||||
|
||||
#[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<u64> {
|
||||
let update_rate_in_milliseconds = if let Some(update_rate) = matches.get_one::<String>("rate") {
|
||||
update_rate.parse::<u64>().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<u64> {
|
||||
let update_rate = if let Some(update_rate) = matches.get_one::<String>("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 {
|
||||
|
|
|
@ -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.",
|
||||
));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue