diff options
author | ClementTsang <34804052+ClementTsang@users.noreply.github.com> | 2024-01-29 03:52:34 -0500 |
---|---|---|
committer | ClementTsang <34804052+ClementTsang@users.noreply.github.com> | 2024-02-19 20:08:54 -0500 |
commit | 0c5a1d1ae02934f0b54665ab049f68cf6b4d9f64 (patch) | |
tree | 25a125518a40d6f25ed989b47d2aaaf77a82c2eb | |
parent | c1119e794232d12283900ada494edb1f6f9c0b39 (diff) |
first big migration hurdle done
28 files changed, 461 insertions, 680 deletions
diff --git a/.github/workflows/validate_schema.yml b/.github/workflows/validate_schema.yml index d14d7f66..544b3aad 100644 --- a/.github/workflows/validate_schema.yml +++ b/.github/workflows/validate_schema.yml @@ -25,7 +25,7 @@ jobs: uses: fkirc/skip-duplicate-actions@f75f66ce1886f00957d99748a42c724f4330bdcf # v5.3.1 with: skip_after_successful_duplicate: "true" - paths: '["schema/**", ".github/workflows/validate_schema.yml"]' + paths: '["schema/**", ".github/workflows/validate_schema.yml", "sample_configs/**", "scripts/schema/**"]' do_not_skip: '["workflow_dispatch"]' test-build-documentation: diff --git a/docs/content/troubleshooting.md b/docs/content/troubleshooting.md index db5b2c24..67ecbd47 100644 --- a/docs/content/troubleshooting.md +++ b/docs/content/troubleshooting.md @@ -109,10 +109,10 @@ If your configuration files aren't working, here are a few things to try: It may be handy to refer to the automatically generated config files or the [sample configuration files](https://github.com/ClementTsang/bottom/tree/main/sample_configs). The config files also follow the [TOML](https://toml.io/en/) format. -Also make sure your config options are under the right table - for example, to set your temperature type, you must set it under the `[flags]` table: +Also make sure your config options are under the right table - for example, to set your temperature type, you must set it under the `[temperature]` table: ```toml -[flags] +[temperature] temperature_type = "f" ``` diff --git a/docs/content/usage/basic-mode.md b/docs/content/usage/basic-mode.md index ff631d12..340d9eec 100644 --- a/docs/content/usage/basic-mode.md +++ b/docs/content/usage/basic-mode.md @@ -19,7 +19,7 @@ btm --basic or through the config: ```toml -[flags] +[general] basic = true ``` diff --git a/rustfmt.toml b/rustfmt.toml index c4a8b584..03c3542d 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -11,3 +11,4 @@ max_width = 100 # group_imports = "StdExternalCrate" # wrap_comments = true # format_code_in_doc_comments = true +# format_macro_matchers = true diff --git a/sample_configs/default_config.toml b/sample_configs/default_config.toml index 8524ea43..578c33ca 100644 --- a/sample_configs/default_config.toml +++ b/sample_configs/default_config.toml @@ -1,192 +1,2 @@ -# This is a default config file for bottom. All of the settings are commented -# out by default; if you wish to change them uncomment and modify as you see -# fit. -# This group of options represents a command-line option. Flags explicitly -# added when running (ie: btm -a) will override this config file if an option -# is also set here. - -[flags] -# Whether to hide the average cpu entry. -#hide_avg_cpu = false -# Whether to use dot markers rather than braille. -#dot_marker = false -# The update rate of the application. -#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. -#current_usage = false -# Whether to set CPU% on a process to be based on the total CPU or per-core CPU% (not divided by the number of cpus). -#unnormalized_cpu = false -# Whether to group processes with the same name together by default. -#group_processes = false -# Whether to make process searching case sensitive by default. -#case_sensitive = false -# Whether to make process searching look for matching the entire word by default. -#whole_word = false -# Whether to make process searching use regex by default. -#regex = false -# Defaults to Celsius. Temperature is one of: -#temperature_type = "k" -#temperature_type = "f" -#temperature_type = "c" -#temperature_type = "kelvin" -#temperature_type = "fahrenheit" -#temperature_type = "celsius" -# The default time interval (in milliseconds). -#default_time_value = "60s" -# The time delta on each zoom in/out action (in milliseconds). -#time_delta = 15000 -# Hides the time scale. -#hide_time = false -# Override layout default widget -#default_widget_type = "proc" -#default_widget_count = 1 -# Expand selected widget upon starting the app -#expanded_on_startup = true -# Use basic mode -#basic = false -# Use the old network legend style -#use_old_network_legend = false -# Remove space in tables -#hide_table_gap = false -# Show the battery widgets -#battery = false -# Disable mouse clicks -#disable_click = false -# Built-in themes. Valid values are "default", "default-light", "gruvbox", "gruvbox-light", "nord", "nord-light" -#color = "default" -# Show memory values in the processes widget as values by default -#mem_as_value = false -# Show tree mode by default in the processes widget. -#tree = false -# Shows an indicator in table widgets tracking where in the list you are. -#show_table_scroll_position = false -# Show processes as their commands by default in the process widget. -#process_command = false -# Displays the network widget with binary prefixes. -#network_use_binary_prefix = false -# Displays the network widget using bytes. -#network_use_bytes = false -# Displays the network widget with a log scale. -#network_use_log = false -# Hides advanced options to stop a process on Unix-like systems. -#disable_advanced_kill = false -# Shows GPU(s) memory -#enable_gpu = false -# Shows cache and buffer memory -#enable_cache_memory = false -# How much data is stored at once in terms of time. -#retention = "10m" - -# These are flags around the process widget. - -#[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. - -#[colors] # Uncomment if you want to use custom colors -# Represents the colour of table headers (processes, CPU, disks, temperature). -#table_header_color="LightBlue" -# Represents the colour of the label each widget has. -#widget_title_color="Gray" -# Represents the average CPU color. -#avg_cpu_color="Red" -# Represents the colour the core will use in the CPU legend and graph. -#cpu_core_colors=["LightMagenta", "LightYellow", "LightCyan", "LightGreen", "LightBlue", "LightRed", "Cyan", "Green", "Blue", "Red"] -# Represents the colour RAM will use in the memory legend and graph. -#ram_color="LightMagenta" -# Represents the colour SWAP will use in the memory legend and graph. -#swap_color="LightYellow" -# Represents the colour ARC will use in the memory legend and graph. -#arc_color="LightCyan" -# Represents the colour the GPU will use in the legend and graph. -#gpu_core_colors=["LightGreen", "LightBlue", "LightRed", "Cyan", "Green", "Blue", "Red"] -# Represents the colour rx will use in the network legend and graph. -#rx_color="LightCyan" -# Represents the colour tx will use in the network legend and graph. -#tx_color="LightGreen" -# Represents the colour of the border of unselected widgets. -#border_color="Gray" -# Represents the colour of the border of selected widgets. -#highlighted_border_color="LightBlue" -# Represents the colour of most text. -#text_color="Gray" -# Represents the colour of text that is selected. -#selected_text_color="Black" -# Represents the background colour of text that is selected. -#selected_bg_color="LightBlue" -# Represents the colour of the lines and text of the graph. -#graph_color="Gray" -# Represents the colours of the battery based on charge -#high_battery_color="green" -#medium_battery_color="yellow" -#low_battery_color="red" - -# Layout - layouts follow a pattern like this: -# [[row]] represents a row in the application. -# [[row.child]] represents either a widget or a column. -# [[row.child.child]] represents a widget. -# -# All widgets must have the type value set to one of ["cpu", "mem", "proc", "net", "temp", "disk", "empty"]. -# All layout components have a ratio value - if this is not set, then it defaults to 1. -# The default widget layout: -#[[row]] -# ratio=30 -# [[row.child]] -# type="cpu" -#[[row]] -# ratio=40 -# [[row.child]] -# ratio=4 -# type="mem" -# [[row.child]] -# ratio=3 -# [[row.child.child]] -# type="temp" -# [[row.child.child]] -# type="disk" -#[[row]] -# ratio=30 -# [[row.child]] -# type="net" -# [[row.child]] -# type="proc" -# default=true - -# 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: -#[disk_filter] -#is_list_ignored = true -#list = ["/dev/sda\\d+", "/dev/nvme0n1p2"] -#regex = true -#case_sensitive = false -#whole_word = false - -#[mount_filter] -#is_list_ignored = true -#list = ["/mnt/.*", "/boot"] -#regex = true -#case_sensitive = false -#whole_word = false - -#[temp_filter] -#is_list_ignored = true -#list = ["cpu", "wifi"] -#regex = false -#case_sensitive = false -#whole_word = false - -#[net_filter] -#is_list_ignored = true -#list = ["virbr0.*"] -#regex = true -#case_sensitive = false -#whole_word = false +# TODO: FIX THIS diff --git a/sample_configs/demo_config.toml b/sample_configs/demo_config.toml index e6c5cf71..f5841577 100644 --- a/sample_configs/demo_config.toml +++ b/sample_configs/demo_config.toml @@ -1,15 +1,19 @@ -[flags] +[general] +rate = 1000 +default_widget_type = "cpu" +default_widget_count = 1 + +[cpu] avg_cpu = true +left_legend = false +[temperature] # Temperature is one of: temperature_type = "c" -rate = 1000 -left_legend = false +[process] current_usage = false group_processes = false case_sensitive = false whole_word = false regex = true -default_widget_type = "cpu" -default_widget_count = 1 @@ -58,7 +58,6 @@ pub struct AppConfigFields { pub use_old_network_legend: bool, pub table_gap: u16, pub disable_click: bool, - pub enable_gpu: bool, pub enable_cache_memory: bool, pub show_table_scroll_position: bool, pub is_advanced_kill: bool, diff --git a/src/canvas/styling.rs b/src/canvas/styling.rs index 24e87edf..fe0ea9f9 100644 --- a/src/canvas/styling.rs +++ b/src/canvas/styling.rs @@ -6,7 +6,7 @@ use tui::style::{Color, Style}; use super::ColourScheme; use crate::{ - options::config::{colours::ColourConfig, palettes::*, NewConfig}, + options::config::{colours::ColourConfig, palettes::*, ConfigV2}, utils::error, }; @@ -16,7 +16,6 @@ pub struct CanvasStyling { pub currently_selected_text_style: Style, pub table_header_style: Style, pub ram_style: Style, - #[cfg(not(target_os = "windows"))] pub cache_style: Style, pub swap_style: Style, pub arc_style: Style, @@ -54,7 +53,6 @@ impl Default for CanvasStyling { .bg(currently_selected_bg_colour), table_header_style: Style::default().fg(HIGHLIGHT_COLOUR), ram_style: Style::default().fg(FIRST_COLOUR), - #[cfg(not(target_os = "windows"))] cache_style: Style::default().fg(FIFTH_COLOUR), swap_style: Style::default().fg(SECOND_COLOUR), arc_style: Style::default().fg(THIRD_COLOUR), @@ -126,7 +124,7 @@ macro_rules! try_set_colour_list { } impl CanvasStyling { - pub fn new(colour_scheme: ColourScheme, config: &NewConfig) -> anyhow::Result<Self> { + pub fn new(colour_scheme: ColourScheme, config: &ConfigV2) -> anyhow::Result<Self> { let mut canvas_colours = Self::default(); match colour_scheme { @@ -237,9 +235,8 @@ impl CanvasStyling { mod test { use tui::style::{Color, Style}; - use crate::options::config::NewConfig; - use super::{CanvasStyling, ColourScheme}; + use crate::options::config::ConfigV2; #[test] fn default_selected_colour_works() { @@ -285,7 +282,7 @@ mod test { #[test] fn built_in_colour_schemes_work() { - let config = NewConfig::default(); + let config = ConfigV2::default(); CanvasStyling::new(ColourScheme::Default, &config).unwrap(); CanvasStyling::new(ColourScheme::DefaultLight, &config).unwrap(); CanvasStyling::new(ColourScheme::Gruvbox, &config).unwrap(); diff --git a/src/canvas/styling/colour_utils.rs b/src/canvas/styling/colour_utils.rs index 1c1def3e..d3f570ff 100644 --- a/src/canvas/styling/colour_utils.rs +++ b/src/canvas/styling/colour_utils.rs @@ -9,7 +9,6 @@ pub const FIRST_COLOUR: Color = Color::LightMagenta; pub const SECOND_COLOUR: Color = Color::LightYellow; pub const THIRD_COLOUR: Color = Color::LightCyan; pub const FOURTH_COLOUR: Color = Color::LightGreen; -#[cfg(not(target_os = "windows"))] pub const FIFTH_COLOUR: Color = Color::LightRed; pub const HIGHLIGHT_COLOUR: Color = Color::LightBlue; pub const AVG_COLOUR: Color = Color::Red; diff --git a/src/constants.rs b/src/constants.rs index 2c8742d9..76c0fd37 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -261,6 +261,7 @@ pub const DEFAULT_BATTERY_LAYOUT: &str = r#" pub const DEFAULT_CONFIG_FILE_PATH: &str = "bottom/bottom.toml"; // TODO: Eventually deprecate this, or grab from a file. +// TODO: FIX THIS! pub const CONFIG_TEXT: &str = r#"# This is a default config file for bottom. All of the settings are commented # out by default; if you wish to change them uncomment and modify as you see # fit. diff --git a/src/options.rs b/src/options.rs index 47389a9c..4844de6e 100644 --- a/src/options.rs +++ b/src/options.rs @@ -5,21 +5,19 @@ pub mod args; pub mod config; -use std::{ - convert::TryInto, - str::FromStr, - time::{Duration, Instant}, -}; +use std::{convert::TryInto, str::FromStr, time::Instant}; use anyhow::{Context, Result}; -use clap::ArgMatches; use hashbrown::{HashMap, HashSet}; use indexmap::IndexSet; use regex::Regex; #[cfg(feature = "battery")] use starship_battery::Manager; -use self::config::{layout::Row, IgnoreList, NewConfig}; +use self::{ + args::StringOrNum, + config::{layout::Row, ConfigV2, IgnoreList}, +}; use crate::{ app::{filter::Filter, layout_manager::*, *}, canvas::{styling::CanvasStyling, ColourScheme}, @@ -33,24 +31,27 @@ use crate::{ }; pub fn init_app( - config: NewConfig, widget_layout: &BottomLayout, default_widget_id: u64, + config: ConfigV2, widget_layout: &BottomLayout, default_widget_id: u64, default_widget_type_option: &Option<BottomWidgetType>, styling: &CanvasStyling, ) -> Result<App> { use BottomWidgetType::*; let retention_ms = get_retention(&config).context("Update `retention` in your config file.")?; - let autohide_time = is_flag_enabled!(autohide_time, matches, config); - let default_time_value = get_default_time_value(matches, config, retention_ms) - .context("Update 'default_time_value' in your config file.")?; + let autohide_time = config.general.args.autohide_time.unwrap_or(false); + let default_time_value = get_default_time_value(&config, retention_ms)?; - let use_basic_mode = is_flag_enabled!(basic, matches, config); - let expanded_upon_startup = is_flag_enabled!(expanded_on_startup, matches, config); + let use_basic_mode = config.general.args.basic.unwrap_or(false); + let expanded_upon_startup = config.general.args.expanded.unwrap_or(false); // For processes - let is_grouped = is_flag_enabled!(group_processes, matches, config); - let is_case_sensitive = is_flag_enabled!(case_sensitive, matches, config); - let is_match_whole_word = is_flag_enabled!(whole_word, matches, config); - let is_use_regex = is_flag_enabled!(regex, matches, config); + let is_grouped = config.process.args.group_processes.unwrap_or(false); + let is_case_sensitive = config.process.args.case_sensitive.unwrap_or(false); + let is_match_whole_word = config.process.args.whole_word.unwrap_or(false); + let is_use_regex = config.process.args.regex.unwrap_or(false); + let show_memory_as_values = config.process.args.mem_as_value.unwrap_or(false); + let is_default_tree = config.process.args.tree.unwrap_or(false); + let is_default_command = config.process.args.process_command.unwrap_or(false); + let is_advanced_kill = !(config.process.args.disable_advanced_kill.unwrap_or(false)); let mut widget_map = HashMap::new(); let mut cpu_state_map: HashMap<u64, CpuWidgetState> = HashMap::new(); @@ -72,17 +73,24 @@ pub fn init_app( let is_custom_layout = config.row.is_some(); let mut used_widget_set = HashSet::new(); - let show_memory_as_values = is_flag_enabled!(mem_as_value, matches, config); - let is_default_tree = is_flag_enabled!(tree, matches, config); - let is_default_command = is_flag_enabled!(process_command, matches, config); - let is_advanced_kill = !(is_flag_enabled!(disable_advanced_kill, matches, config)); - - let network_unit_type = get_network_unit_type(matches, config); - let network_scale_type = get_network_scale_type(matches, config); - let network_use_binary_prefix = is_flag_enabled!(network_use_binary_prefix, matches, config); + let network_unit_type = if config.network.args.network_use_bytes.unwrap_or(false) { + DataUnit::Byte + } else { + DataUnit::Bit + }; + let network_scale_type = if config.network.args.network_use_log.unwrap_or(false) { + AxisScaling::Log + } else { + AxisScaling::Linear + }; + let network_use_binary_prefix = config + .network + .args + .network_use_binary_prefix + .unwrap_or(false); let proc_columns: Option<IndexSet<ProcWidgetColumn>> = { - let columns = config.processes.columns.as_ref(); + let columns = config.process.columns.as_ref(); match columns { Some(columns) => { @@ -98,27 +106,27 @@ pub fn init_app( // TODO: Can probably just reuse the options struct. let app_config_fields = AppConfigFields { - 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.")?, - show_average_cpu: get_show_average_cpu(matches, config), - use_dot: is_flag_enabled!(dot_marker, matches, config), - left_legend: is_flag_enabled!(left_legend, matches, config), - use_current_cpu_total: is_flag_enabled!(current_usage, matches, config), - unnormalized_cpu: is_flag_enabled!(unnormalized_cpu, matches, config), + update_rate: get_update_rate(&config)?, + temperature_type: get_temperature(&config)?, + show_average_cpu: !config.cpu.args.hide_avg_cpu.unwrap_or(false), + use_dot: config.general.args.dot_marker.unwrap_or(false), + left_legend: config.cpu.args.left_legend.unwrap_or(false), + use_current_cpu_total: config.process.args.current_usage.unwrap_or(false), + unnormalized_cpu: config.process.args.unnormalized_cpu.unwrap_or(false), use_basic_mode, default_time_value, - time_interval: get_time_interval(matches, config, retention_ms) - .context("Update 'time_delta' in your config file.")?, - hide_time: is_flag_enabled!(hide_time, matches, config), + time_interval: get_time_interval(&config, retention_ms)?, + hide_time: config.general.args.hide_time.unwrap_or(false), autohide_time, - use_old_network_legend: is_flag_enabled!(use_old_network_legend, matches, config), - table_gap: u16::from(!(is_flag_enabled!(hide_table_gap, matches, config))), - disable_click: is_flag_enabled!(disable_click, matches, config), - enable_gpu: get_enable_gpu(matches, config), - enable_cache_memory: get_enable_cache_memory(matches, config), - show_table_scroll_position: is_flag_enabled!(show_table_scroll_position, matches, config), + use_old_network_legend: config.network.args.use_old_network_legend.unwrap_or(false), + table_gap: u16::from(!(config.general.args.hide_table_gap.unwrap_or(false))), + disable_click: config.general.args.disable_click.unwrap_or(false), + enable_cache_memory: get_enable_cache_memory(&config), + show_table_scroll_position: config + .general + .args + .show_table_scroll_position + .unwrap_or(false), is_advanced_kill, network_scale_type, network_unit_type, @@ -271,8 +279,17 @@ pub fn init_app( let used_widgets = UsedWidgets { use_cpu: used_widget_set.get(&Cpu).is_some() || used_widget_set.get(&BasicCpu).is_some(), use_mem, - use_cache: use_mem && get_enable_cache_memory(matches, config), - use_gpu: get_enable_gpu(matches, config), + use_cache: use_mem && get_enable_cache_memory(&config), + use_gpu: { + #[cfg(feature = "gpu")] + { + config.gpu.enabled() + } + #[cfg(not(feature = "gpu"))] + { + false + } + }, use_net: used_widget_set.get(&Net).is_some() || used_widget_set.get(&BasicNet).is_some(), use_proc: used_widget_set.get(&Proc).is_some(), use_disk: used_widget_set.get(&Disk).is_some(), @@ -321,25 +338,24 @@ pub fn init_app( } pub fn get_widget_layout( - config: &NewConfig, + config: &ConfigV2, ) -> error::Result<(BottomLayout, u64, Option<BottomWidgetType>)> { - let left_legend = config.cpu.args.left_legend; + let left_legend = config.cpu.args.left_legend.unwrap_or(false); - let (default_widget_type, mut default_widget_count) = - get_default_widget_and_count(matches, config)?; + let (default_widget_type, mut default_widget_count) = get_default_widget_and_count(config)?; let mut default_widget_id = 1; - let bottom_layout = if is_flag_enabled!(basic, matches, config) { + let bottom_layout = if config.general.args.basic.unwrap_or(false) { default_widget_id = DEFAULT_WIDGET_ID; - BottomLayout::init_basic_default(get_use_battery(matches, config)) + BottomLayout::init_basic_default(get_use_battery(config)) } else { let ref_row: Vec<Row>; // Required to handle reference let rows = match &config.row { Some(r) => r, None => { // This cannot (like it really shouldn't) fail! - ref_row = toml_edit::de::from_str::<Config>(if get_use_battery(matches, config) { + ref_row = toml_edit::de::from_str::<ConfigV2>(if get_use_battery(config) { DEFAULT_BATTERY_LAYOUT } else { DEFAULT_LAYOUT @@ -384,67 +400,7 @@ pub fn get_widget_layout( Ok((bottom_layout, default_widget_id, default_widget_type)) } -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 { - match rate { - StringOrNum::String(s) => try_parse_ms(s)?, - StringOrNum::Num(n) => *n, - } - } else { - DEFAULT_REFRESH_RATE_IN_MILLISECONDS - } - } else { - DEFAULT_REFRESH_RATE_IN_MILLISECONDS - }; - - if update_rate < 250 { - return Err(BottomError::ConfigError( - "set your update rate to be at least 250 ms.".to_string(), - )); - } - - Ok(update_rate) -} - -fn get_temperature(matches: &ArgMatches, config: &Config) -> error::Result<TemperatureType> { - if matches.get_flag("fahrenheit") { - return Ok(TemperatureType::Fahrenheit); - } else if matches.get_flag("kelvin") { - return Ok(TemperatureType::Kelvin); - } else if matches.get_flag("celsius") { - return Ok(TemperatureType::Celsius); - } else if let Some(flags) = &config.flags { - if let Some(temp_type) = &flags.temperature_type { - // Give lowest priority to config. - return match temp_type.as_str() { - "fahrenheit" | "f" => Ok(TemperatureType::Fahrenheit), - "kelvin" | "k" => Ok(TemperatureType::Kelvin), - "celsius" | "c" => Ok(TemperatureType::Celsius), - _ => Err(BottomError::ConfigError(format!( - "\"{temp_type}\" is an invalid temperature type, use \"<kelvin|k|celsius|c|fahrenheit|f>\"." - ))), - }; - } - } - Ok(TemperatureType::Celsius) -} - -/// Yes, this function gets whether to show average CPU (true) or not (false) -fn get_show_average_cpu(matches: &ArgMatches, config: &Config) -> bool { - if matches.get_flag("hide_avg_cpu") { - return false; - } else if let Some(flags) = &config.flags { - if let Some(avg_cpu) = flags.hide_avg_cpu { - return !avg_cpu; - } - } - - true -} - +#[inline] fn try_parse_ms(s: &str) -> error::Result<u64> { if let Ok(val) = humantime::parse_duration(s) { Ok(val.as_millis().try_into()?) @@ -457,124 +413,120 @@ fn try_parse_ms(s: &str) -> error::Result<u64> { } } -fn get_default_time_value( - matches: &ArgMatches, config: &Config, retention_ms: u64, +#[inline] +fn get_duration( + value: &Option<StringOrNum>, min: u64, max: Option<u64>, default: u64, + what_to_fix: &'static str, ) -> error::Result<u64> { - let default_time = - if let Some(default_time_value) = matches.get_one::<String>("default_time_value") { - try_parse_ms(default_time_value)? - } else if let Some(flags) = &config.flags { - if let Some(default_time_value) = &flags.default_time_value { - match default_time_value { - StringOrNum::String(s) => try_parse_ms(s)?, - StringOrNum::Num(n) => *n, - } - } else { - DEFAULT_TIME_MILLISECONDS - } - } else { - DEFAULT_TIME_MILLISECONDS + if let Some(value) = value { + let value = match value { + StringOrNum::String(s) => try_parse_ms(s)?, + StringOrNum::Num(n) => *n, }; - if default_time < 30000 { - return Err(BottomError::ConfigError( - "set your default value to be at least 30s.".to_string(), - )); - } else if default_time > retention_ms { - return Err(BottomError::ConfigError(format!( - "set your default value to be at most {}.", - humantime::Duration::from(Duration::from_millis(retention_ms)) - ))); + if value < min { + return Err(BottomError::ConfigError(format!( + "set your {what_to_fix} to be at least {min} ms." + ))); + } + + if let Some(max) = max { + if value > max { + return Err(BottomError::ConfigError(format!( + "set your {what_to_fix} to be less than {max} ms." + ))); + } + } + + Ok(value) + } else { + Ok(default) } +} - Ok(default_time) +#[inline] +fn get_update_rate(config: &ConfigV2) -> error::Result<u64> { + get_duration( + &config.general.args.rate, + 250, + None, + DEFAULT_REFRESH_RATE_IN_MILLISECONDS, + "update rate", + ) } -fn get_time_interval( - matches: &ArgMatches, config: &Config, retention_ms: u64, -) -> error::Result<u64> { - let time_interval = if let Some(time_interval) = matches.get_one::<String>("time_delta") { - try_parse_ms(time_interval)? - } else if let Some(flags) = &config.flags { - if let Some(time_interval) = &flags.time_delta { - match time_interval { - StringOrNum::String(s) => try_parse_ms(s)?, - StringOrNum::Num(n) => *n, - } - } else { - TIME_CHANGE_MILLISECONDS +fn get_temperature(con |