mirror of
https://github.com/ClementTsang/bottom.git
synced 2025-07-23 21:55:11 +02:00
other: fix humantime-related documentation, add tests, support numbers + strings in toml (#1220)
* update documentation and support either numerical times or human times for time_delta and default_time_value * update docs * give more human times on error
This commit is contained in:
parent
6f1a8f7e5b
commit
0b7f4c745d
@ -3,45 +3,45 @@
|
|||||||
The following flags can be provided to bottom in the command line to change the behaviour of the program. You can also
|
The following flags can be provided to bottom in the command line to change the behaviour of the program. You can also
|
||||||
see information on these flags by running `btm -h`, or run `btm --help` to display more detailed information on each flag:
|
see information on these flags by running `btm -h`, or run `btm --help` to display more detailed information on each flag:
|
||||||
|
|
||||||
| Flag | Behaviour |
|
| Flag | Behaviour |
|
||||||
| -------------------------------------------- | ------------------------------------------------------------------------------------ |
|
| ----------------------------------- | --------------------------------------------------------------- |
|
||||||
| `--autohide_time` | Temporarily shows the time scale in graphs. |
|
| --autohide_time | Temporarily shows the time scale in graphs. |
|
||||||
| `-b`, `--basic` | Hides graphs and uses a more basic look. |
|
| -b, --basic | Hides graphs and uses a more basic look. |
|
||||||
| `--battery` | Shows the battery widget. |
|
| --battery | Shows the battery widget. |
|
||||||
| `-S`, `--case_sensitive` | Enables case sensitivity by default. |
|
| -S, --case_sensitive | Enables case sensitivity by default. |
|
||||||
| `-c`, `--celsius` | Sets the temperature type to Celsius. |
|
| -c, --celsius | Sets the temperature type to Celsius. |
|
||||||
| `--color <COLOR SCHEME>` | Use a color scheme, use --help for supported values. |
|
| --color <COLOR SCHEME> | Use a color scheme, use --help for info. |
|
||||||
| `-C <CONFIG PATH>`, `--config <CONFIG PATH>` | Sets the location of the config file. |
|
| -C, --config <CONFIG PATH> | Sets the location of the config file. |
|
||||||
| `-u`, `--current_usage` | Sets process CPU% to be based on current CPU%. |
|
| -u, --current_usage | Sets process CPU% to be based on current CPU%. |
|
||||||
| `-t <MS>`, `--default_time_value <MS>` | Default time value for graphs in ms. |
|
| -t, --default_time_value <TIME> | Default time value for graphs. |
|
||||||
| `--default_widget_count <INT>` | Sets the n'th selected widget type as the default. |
|
| --default_widget_count <INT> | Sets the n'th selected widget type as the default. |
|
||||||
| `--default_widget_type <WIDGET TYPE>` | Sets the default widget type, use --help for more info. |
|
| --default_widget_type <WIDGET TYPE> | Sets the default widget type, use --help for info. |
|
||||||
| `--disable_advanced_kill` | Hides advanced options to stop a process on Unix-like systems. |
|
| --disable_advanced_kill | Hides advanced process killing. |
|
||||||
| `--disable_click` | Disables mouse clicks. |
|
| --disable_click | Disables mouse clicks. |
|
||||||
| `-m`, `--dot_marker` | Uses a dot marker for graphs. |
|
| -m, --dot_marker | Uses a dot marker for graphs. |
|
||||||
| `-f`, `--fahrenheit` | Sets the temperature type to Fahrenheit. |
|
| --enable_cache_memory | Enable collecting and displaying cache and buffer memory. |
|
||||||
| `-g`, `--group` | Groups processes with the same name by default. |
|
| --enable_gpu_memory | Enable collecting and displaying GPU memory usage. |
|
||||||
| `-h`, `--help` | Prints help information. Use --help for more info. |
|
| -e, --expanded | Expand the default widget upon starting the app. |
|
||||||
| `-a`, `--hide_avg_cpu` | Hides the average CPU usage. |
|
| -f, --fahrenheit | Sets the temperature type to Fahrenheit. |
|
||||||
| `--hide_table_gap` | Hides the spacing between table headers and entries. |
|
| -g, --group | Groups processes with the same name by default. |
|
||||||
| `--hide_time` | Hides the time scale. |
|
| -a, --hide_avg_cpu | Hides the average CPU usage. |
|
||||||
| `-k`, `--kelvin` | Sets the temperature type to Kelvin. |
|
| --hide_table_gap | Hides spacing between table headers and entries. |
|
||||||
| `-l`, `--left_legend` | Puts the CPU chart legend to the left side. |
|
| --hide_time | Hides the time scale. |
|
||||||
| `--mem_as_value` | Defaults to showing process memory usage by value. |
|
| -k, --kelvin | Sets the temperature type to Kelvin. |
|
||||||
| `--network_use_binary_prefix` | Displays the network widget with binary prefixes. |
|
| -l, --left_legend | Puts the CPU chart legend to the left side. |
|
||||||
| `--network_use_bytes` | Displays the network widget using bytes. |
|
| --mem_as_value | Defaults to showing process memory usage by value. |
|
||||||
| `--network_use_log` | Displays the network widget with a log scale. |
|
| --network_use_binary_prefix | Displays the network widget with binary prefixes. |
|
||||||
| `--process_command` | Show processes as their commands by default. |
|
| --network_use_bytes | Displays the network widget using bytes. |
|
||||||
| `-r`, `--rate <MS>` | Sets a refresh rate in ms. |
|
| --network_use_log | Displays the network widget with a log scale. |
|
||||||
| `-R`, `--regex` | Enables regex by default. |
|
| --process_command | Show processes as their commands by default. |
|
||||||
| `--show_table_scroll_position` | Shows the scroll position tracker in table widgets. |
|
| -r, --rate <MS> | Sets a refresh rate in ms. |
|
||||||
| `-d <MS>`, `--time_delta <MS>` | The amount in ms changed upon zooming. |
|
| -R, --regex | Enables regex by default. |
|
||||||
| `-T`, `--tree` | Defaults to showing the process widget in tree mode. |
|
| --retention <TIME> | The timespan of data kept. |
|
||||||
| `--use_old_network_legend` | DEPRECATED - uses the older network legend. |
|
| --show_table_scroll_position | Shows the scroll position tracker in table widgets. |
|
||||||
| `-V`, `--version` | Prints version information. |
|
| -d, --time_delta <TIME> | The amount of time changed upon zooming. |
|
||||||
| `-W`, `--whole_word` | Enables whole-word matching by default. |
|
| -T, --tree | Defaults the process widget be in tree mode. |
|
||||||
| `--enable_gpu_memory` | Enable collecting and displaying GPU memory usage. |
|
| -n, --unnormalized_cpu | Show process CPU% without normalizing over the number of cores. |
|
||||||
| `--enable_cache_memory` | Enable collecting and displaying cache and buffer memory (not available on Windows). |
|
| --use_old_network_legend | DEPRECATED - uses a separate network legend. |
|
||||||
| `--retention` | How much data is stored at once in terms of time. |
|
| -V, --version | Prints version information. |
|
||||||
| `-n`, `--unnormalized_cpu` | Show process CPU% without normalizing over the number of cores. |
|
| -W, --whole_word | Enables whole-word matching by default. |
|
||||||
| `-e`, `--expanded` | Expand the default widget upon starting the app. |
|
| -h, --help | Print help (see more with '--help') |
|
||||||
|
@ -8,7 +8,7 @@ Most of the [command line flags](../../command-line-flags) have config file equi
|
|||||||
each time:
|
each time:
|
||||||
|
|
||||||
| Field | Type | Functionality |
|
| Field | Type | Functionality |
|
||||||
|------------------------------|------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------|
|
| ---------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||||||
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
|
| `hide_avg_cpu` | Boolean | Hides the average CPU usage. |
|
||||||
| `dot_marker` | Boolean | Uses a dot marker for graphs. |
|
| `dot_marker` | Boolean | Uses a dot marker for graphs. |
|
||||||
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
|
| `left_legend` | Boolean | Puts the CPU chart legend to the left side. |
|
||||||
@ -21,8 +21,8 @@ each time:
|
|||||||
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
|
| `use_old_network_legend` | Boolean | DEPRECATED - uses the older network legend. |
|
||||||
| `battery` | Boolean | Shows the battery widget. |
|
| `battery` | Boolean | Shows the battery widget. |
|
||||||
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. |
|
| `rate` | Unsigned Int (represents milliseconds) | Sets a refresh rate in ms. |
|
||||||
| `default_time_value` | Unsigned Int (represents milliseconds) | Default time value for graphs in ms. |
|
| `default_time_value` | Unsigned Int (represents milliseconds) or String (represents human time) | Default time value for graphs in ms. |
|
||||||
| `time_delta` | Unsigned Int (represents milliseconds) | The amount in ms changed upon zooming. |
|
| `time_delta` | Unsigned Int (represents milliseconds) or String (represents human time) | The amount in ms changed upon zooming. |
|
||||||
| `hide_time` | Boolean | Hides the time scale. |
|
| `hide_time` | Boolean | Hides the time scale. |
|
||||||
| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. |
|
| `temperature_type` | String (one of ["k", "f", "c", "kelvin", "fahrenheit", "celsius"]) | Sets the temperature unit type. |
|
||||||
| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. |
|
| `default_widget_type` | String (one of ["cpu", "proc", "net", "temp", "mem", "disk"], same as layout options) | Sets the default widget type, use --help for more info. |
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
#temperature_type = "fahrenheit"
|
#temperature_type = "fahrenheit"
|
||||||
#temperature_type = "celsius"
|
#temperature_type = "celsius"
|
||||||
# The default time interval (in milliseconds).
|
# The default time interval (in milliseconds).
|
||||||
#default_time_value = 60000
|
#default_time_value = "60s"
|
||||||
# The time delta on each zoom in/out action (in milliseconds).
|
# The time delta on each zoom in/out action (in milliseconds).
|
||||||
#time_delta = 15000
|
#time_delta = 15000
|
||||||
# Hides the time scale.
|
# Hides the time scale.
|
||||||
@ -157,7 +157,6 @@
|
|||||||
# type="proc"
|
# type="proc"
|
||||||
# default=true
|
# default=true
|
||||||
|
|
||||||
|
|
||||||
# Filters - you can hide specific temperature sensors, network interfaces, and disks using filters. This is admittedly
|
# Filters - you can hide specific temperature sensors, network interfaces, and disks using filters. This is admittedly
|
||||||
# a bit hard to use as of now, and there is a planned in-app interface for managing this in the future:
|
# a bit hard to use as of now, and there is a planned in-app interface for managing this in the future:
|
||||||
#[disk_filter]
|
#[disk_filter]
|
||||||
|
20
src/args.rs
20
src/args.rs
@ -88,8 +88,6 @@ pub fn get_matches() -> clap::ArgMatches {
|
|||||||
build_app().get_matches()
|
build_app().get_matches()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Refactor this a bit, it's quite messy atm
|
|
||||||
// TODO: [DEBUG] Add a proper debugging solution.
|
|
||||||
pub fn build_app() -> Command {
|
pub fn build_app() -> Command {
|
||||||
// Temps
|
// Temps
|
||||||
let kelvin = Arg::new("kelvin")
|
let kelvin = Arg::new("kelvin")
|
||||||
@ -303,11 +301,13 @@ Defaults to \"default\".
|
|||||||
.short('t')
|
.short('t')
|
||||||
.long("default_time_value")
|
.long("default_time_value")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.value_name("MS")
|
.value_name("TIME")
|
||||||
.help("Default time value for graphs in ms.")
|
.help("Default time value for graphs.")
|
||||||
.long_help("Default time value for graphs in milliseconds. The minimum time is 30s (30000), and the default is 60s (60000).");
|
.long_help(
|
||||||
|
"Default time value for graphs. The minimum time is 30s, and the default is 60s.",
|
||||||
|
);
|
||||||
|
|
||||||
// TODO: Fix this, its broken in the manpage
|
// TODO: Charts are broken in the manpage
|
||||||
let default_widget_count = Arg::new("default_widget_count")
|
let default_widget_count = Arg::new("default_widget_count")
|
||||||
.long("default_widget_count")
|
.long("default_widget_count")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
@ -360,9 +360,9 @@ use CPU (3) as the default instead.
|
|||||||
.short('d')
|
.short('d')
|
||||||
.long("time_delta")
|
.long("time_delta")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.value_name("MS")
|
.value_name("TIME")
|
||||||
.help("The amount in ms changed upon zooming.")
|
.help("The amount of time changed upon zooming.")
|
||||||
.long_help("The amount of time in milliseconds changed when zooming in/out. The minimum is 1s (1000), and defaults to 15s (15000).");
|
.long_help("The amount of time changed when zooming in/out. The minimum is 1s, and defaults to 15s.");
|
||||||
|
|
||||||
let tree = Arg::new("tree")
|
let tree = Arg::new("tree")
|
||||||
.short('T')
|
.short('T')
|
||||||
@ -394,7 +394,7 @@ use CPU (3) as the default instead.
|
|||||||
let retention = Arg::new("retention")
|
let retention = Arg::new("retention")
|
||||||
.long("retention")
|
.long("retention")
|
||||||
.action(ArgAction::Set)
|
.action(ArgAction::Set)
|
||||||
.value_name("time")
|
.value_name("TIME")
|
||||||
.help("The timespan of data kept.")
|
.help("The timespan of data kept.")
|
||||||
.long_help("How much data is stored at once in terms of time. Takes in human-readable time spans (e.g. 10m, 1h), with a minimum of 1 minute. Note higher values will take up more memory. Defaults to 10 minutes.");
|
.long_help("How much data is stored at once in terms of time. Takes in human-readable time spans (e.g. 10m, 1h), with a minimum of 1 minute. Note higher values will take up more memory. Defaults to 10 minutes.");
|
||||||
|
|
||||||
|
@ -188,7 +188,6 @@ where
|
|||||||
|
|
||||||
let soft_limit = max(
|
let soft_limit = max(
|
||||||
if let Some(max_percentage) = max_percentage {
|
if let Some(max_percentage) = max_percentage {
|
||||||
// TODO: Rust doesn't have an `into()` or `try_into()` for floats to integers.
|
|
||||||
((*max_percentage * f32::from(total_width)).ceil()) as u16
|
((*max_percentage * f32::from(total_width)).ceil()) as u16
|
||||||
} else {
|
} else {
|
||||||
*desired
|
*desired
|
||||||
|
@ -543,7 +543,7 @@ pub const CONFIG_TEXT: &str = r##"# This is a default config file for bottom. A
|
|||||||
#temperature_type = "fahrenheit"
|
#temperature_type = "fahrenheit"
|
||||||
#temperature_type = "celsius"
|
#temperature_type = "celsius"
|
||||||
# The default time interval (in milliseconds).
|
# The default time interval (in milliseconds).
|
||||||
#default_time_value = 60000
|
#default_time_value = "60s"
|
||||||
# The time delta on each zoom in/out action (in milliseconds).
|
# The time delta on each zoom in/out action (in milliseconds).
|
||||||
#time_delta = 15000
|
#time_delta = 15000
|
||||||
# Hides the time scale.
|
# Hides the time scale.
|
||||||
|
@ -45,6 +45,25 @@ pub struct Config {
|
|||||||
pub processes: Option<ProcessConfig>,
|
pub processes: Option<ProcessConfig>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
enum StringOrNum {
|
||||||
|
String(String),
|
||||||
|
Num(u64),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for StringOrNum {
|
||||||
|
fn from(value: String) -> Self {
|
||||||
|
StringOrNum::String(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u64> for StringOrNum {
|
||||||
|
fn from(value: u64) -> Self {
|
||||||
|
StringOrNum::Num(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct ConfigFlags {
|
pub struct ConfigFlags {
|
||||||
pub hide_avg_cpu: Option<bool>,
|
pub hide_avg_cpu: Option<bool>,
|
||||||
@ -59,8 +78,8 @@ pub struct ConfigFlags {
|
|||||||
pub whole_word: Option<bool>,
|
pub whole_word: Option<bool>,
|
||||||
pub regex: Option<bool>,
|
pub regex: Option<bool>,
|
||||||
pub basic: Option<bool>,
|
pub basic: Option<bool>,
|
||||||
pub default_time_value: Option<String>,
|
default_time_value: Option<StringOrNum>,
|
||||||
pub time_delta: Option<String>,
|
time_delta: Option<StringOrNum>,
|
||||||
pub autohide_time: Option<bool>,
|
pub autohide_time: Option<bool>,
|
||||||
pub hide_time: Option<bool>,
|
pub hide_time: Option<bool>,
|
||||||
pub default_widget_type: Option<String>,
|
pub default_widget_type: Option<String>,
|
||||||
@ -615,7 +634,10 @@ fn get_default_time_value(
|
|||||||
try_parse_ms(default_time_value)?
|
try_parse_ms(default_time_value)?
|
||||||
} else if let Some(flags) = &config.flags {
|
} else if let Some(flags) = &config.flags {
|
||||||
if let Some(default_time_value) = &flags.default_time_value {
|
if let Some(default_time_value) = &flags.default_time_value {
|
||||||
try_parse_ms(default_time_value)?
|
match default_time_value {
|
||||||
|
StringOrNum::String(s) => try_parse_ms(s)?,
|
||||||
|
StringOrNum::Num(n) => *n,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_TIME_MILLISECONDS
|
DEFAULT_TIME_MILLISECONDS
|
||||||
}
|
}
|
||||||
@ -625,12 +647,12 @@ fn get_default_time_value(
|
|||||||
|
|
||||||
if default_time < 30000 {
|
if default_time < 30000 {
|
||||||
return Err(BottomError::ConfigError(
|
return Err(BottomError::ConfigError(
|
||||||
"set your default value to be at least 30000 milliseconds.".to_string(),
|
"set your default value to be at least 30s.".to_string(),
|
||||||
));
|
));
|
||||||
} else if default_time > retention_ms {
|
} else if default_time > retention_ms {
|
||||||
return Err(BottomError::ConfigError(format!(
|
return Err(BottomError::ConfigError(format!(
|
||||||
"set your default value to be at most {} milliseconds.",
|
"set your default value to be at most {}.",
|
||||||
retention_ms
|
humantime::Duration::from(Duration::from_millis(retention_ms))
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -644,7 +666,10 @@ fn get_time_interval(
|
|||||||
try_parse_ms(time_interval)?
|
try_parse_ms(time_interval)?
|
||||||
} else if let Some(flags) = &config.flags {
|
} else if let Some(flags) = &config.flags {
|
||||||
if let Some(time_interval) = &flags.time_delta {
|
if let Some(time_interval) = &flags.time_delta {
|
||||||
try_parse_ms(time_interval)?
|
match time_interval {
|
||||||
|
StringOrNum::String(s) => try_parse_ms(s)?,
|
||||||
|
StringOrNum::Num(n) => *n,
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
TIME_CHANGE_MILLISECONDS
|
TIME_CHANGE_MILLISECONDS
|
||||||
}
|
}
|
||||||
@ -654,12 +679,12 @@ fn get_time_interval(
|
|||||||
|
|
||||||
if time_interval < 1000 {
|
if time_interval < 1000 {
|
||||||
return Err(BottomError::ConfigError(
|
return Err(BottomError::ConfigError(
|
||||||
"set your time delta to be at least 1000 milliseconds.".to_string(),
|
"set your time delta to be at least 1s.".to_string(),
|
||||||
));
|
));
|
||||||
} else if time_interval > retention_ms {
|
} else if time_interval > retention_ms {
|
||||||
return Err(BottomError::ConfigError(format!(
|
return Err(BottomError::ConfigError(format!(
|
||||||
"set your time delta to be at most {} milliseconds.",
|
"set your time delta to be at most {}.",
|
||||||
retention_ms
|
humantime::Duration::from(Duration::from_millis(retention_ms))
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -972,8 +997,8 @@ mod test {
|
|||||||
|
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
let flags = ConfigFlags {
|
let flags = ConfigFlags {
|
||||||
time_delta: Some("2 min".to_string()),
|
time_delta: Some("2 min".to_string().into()),
|
||||||
default_time_value: Some("300s".to_string()),
|
default_time_value: Some("300s".to_string().into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -991,14 +1016,39 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn config_number_times() {
|
fn config_number_times_as_string() {
|
||||||
let app = crate::args::build_app();
|
let app = crate::args::build_app();
|
||||||
let matches = app.get_matches_from(["btm"]);
|
let matches = app.get_matches_from(["btm"]);
|
||||||
|
|
||||||
let mut config = Config::default();
|
let mut config = Config::default();
|
||||||
let flags = ConfigFlags {
|
let flags = ConfigFlags {
|
||||||
time_delta: Some("120000".to_string()),
|
time_delta: Some("120000".to_string().into()),
|
||||||
default_time_value: Some("300000".to_string()),
|
default_time_value: Some("300000".to_string().into()),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
config.flags = Some(flags);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_time_interval(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(2 * 60 * 1000)
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
get_default_time_value(&matches, &config, 60 * 60 * 1000),
|
||||||
|
Ok(5 * 60 * 1000)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn config_number_times_as_num() {
|
||||||
|
let app = crate::args::build_app();
|
||||||
|
let matches = app.get_matches_from(["btm"]);
|
||||||
|
|
||||||
|
let mut config = Config::default();
|
||||||
|
let flags = ConfigFlags {
|
||||||
|
time_delta: Some(120000.into()),
|
||||||
|
default_time_value: Some(300000.into()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user