diff options
Diffstat (limited to 'src/options/config.rs')
-rw-r--r-- | src/options/config.rs | 1148 |
1 files changed, 2 insertions, 1146 deletions
diff --git a/src/options/config.rs b/src/options/config.rs index 17c2241f..e76d867c 100644 --- a/src/options/config.rs +++ b/src/options/config.rs @@ -1,1147 +1,3 @@ -mod cpu; +pub mod cpu; pub mod layout; -mod process_columns; - -use std::{ - borrow::Cow, - convert::TryInto, - str::FromStr, - time::{Duration, Instant}, -}; - -use anyhow::{Context, Result}; -use clap::ArgMatches; -pub use cpu::{CpuConfig, CpuDefault}; -use hashbrown::{HashMap, HashSet}; -use indexmap::IndexSet; -use layout::*; -pub use process_columns::ProcessConfig; -use regex::Regex; -use serde::{Deserialize, Serialize}; -#[cfg(feature = "battery")] -use starship_battery::Manager; - -use crate::{ - app::{filter::Filter, layout_manager::*, *}, - canvas::{styling::CanvasStyling, ColourScheme}, - constants::*, - data_collection::temperature::TemperatureType, - utils::{ - data_units::DataUnit, - error::{self, BottomError}, - }, - widgets::*, -}; - -#[derive(Clone, Debug, Default, Deserialize)] -pub struct Config { - pub flags: Option<ConfigFlags>, - pub colors: Option<ConfigColours>, - pub row: Option<Vec<Row>>, - pub disk_filter: Option<IgnoreList>, - pub mount_filter: Option<IgnoreList>, - pub temp_filter: Option<IgnoreList>, - pub net_filter: Option<IgnoreList>, - pub processes: Option<ProcessConfig>, - pub cpu: Option<CpuConfig>, -} - -#[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)] -pub struct ConfigFlags { - 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>, - 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. - color: Option<String>, - mem_as_value: Option<bool>, - tree: Option<bool>, - show_table_scroll_position: 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: Option<bool>, - enable_cache_memory: Option<bool>, - retention: Option<StringOrNum>, -} - -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct ConfigColours { - pub table_header_color: Option<Cow<'static, str>>, - pub all_cpu_color: Option<Cow<'static, str>>, - pub avg_cpu_color: Option<Cow<'static, str>>, - pub cpu_core_colors: Option<Vec<Cow<'static, str>>>, - pub ram_color: Option<Cow<'static, str>>, - #[cfg(not(target_os = "windows"))] - pub cache_color: Option<Cow<'static, str>>, - pub swap_color: Option<Cow<'static, str>>, - pub arc_color: Option<Cow<'static, str>>, - pub gpu_core_colors: Option<Vec<Cow<'static, str>>>, - pub rx_color: Option<Cow<'static, str>>, - pub tx_color: Option<Cow<'static, str>>, - pub rx_total_color: Option<Cow<'static, str>>, // These only affect basic mode. - pub tx_total_color: Option<Cow<'static, str>>, // These only affect basic mode. - pub border_color: Option<Cow<'static, str>>, - pub highlighted_border_color: Option<Cow<'static, str>>, - pub disabled_text_color: Option<Cow<'static, str>>, - pub text_color: Option<Cow<'static, str>>, - pub selected_text_color: Option<Cow<'static, str>>, - pub selected_bg_color: Option<Cow<'static, str>>, - pub widget_title_color: Option<Cow<'static, str>>, - pub graph_color: Option<Cow<'static, str>>, - pub high_battery_color: Option<Cow<'static, str>>, - pub medium_battery_color: Option<Cow<'static, str>>, - pub low_battery_color: Option<Cow<'static, str>>, -} - -impl ConfigColours { - /// Returns `true` if there is a [`ConfigColours`] that is empty or there isn't one at all. - pub fn is_empty(&self) -> bool { - if let Ok(serialized_string) = toml_edit::ser::to_string(self) { - return serialized_string.is_empty(); - } - - true - } -} - -/// Workaround as per https://github.com/serde-rs/serde/issues/1030 -fn default_as_true() -> bool { - true -} - -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -pub struct IgnoreList { - #[serde(default = "default_as_true")] - // TODO: Deprecate and/or rename, current name sounds awful. - // Maybe to something like "deny_entries"? Currently it defaults to a denylist anyways, so maybe "allow_entries"? - pub is_list_ignored: bool, - pub list: Vec<String>, - #[serde(default = "bool::default")] - pub regex: bool, - #[serde(default = "bool::default")] - pub case_sensitive: bool, - #[serde(default = "bool::default")] - pub whole_word: bool, -} - -macro_rules! is_flag_enabled { - ($flag_name:ident, $matches:expr, $config:expr) => { - if $matches.get_flag(stringify!($flag_name)) { - true - } else if let Some(flags) = &$config.flags { - flags.$flag_name.unwrap_or(false) - } else { - false - } - }; - - ($cmd_flag:literal, $cfg_flag:ident, $matches:expr, $config:expr) => { - if $matches.get_flag($cmd_flag) { - true - } else if let Some(flags) = &$config.flags { - flags.$cfg_flag.unwrap_or(false) - } else { - false - } - }; -} - -pub fn init_app( - matches: ArgMatches, config: Config, widget_layout: &BottomLayout, default_widget_id: u64, - default_widget_type_option: &Option<BottomWidgetType>, styling: &CanvasStyling, -) -> Result<App> { - use BottomWidgetType::*; - - // Since everything takes a reference, but we want to take ownership here to drop matches/config later... - let matches = &matches; - let config = &config; - - let retention_ms = - get_retention(matches, 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 use_basic_mode = is_flag_enabled!(basic, matches, config); - let expanded_upon_startup = is_flag_enabled!(expanded_on_startup, matches, config); - - // 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 mut widget_map = HashMap::new(); - let mut cpu_state_map: HashMap<u64, CpuWidgetState> = HashMap::new(); - let mut mem_state_map: HashMap<u64, MemWidgetState> = HashMap::new(); - let mut net_state_map: HashMap<u64, NetWidgetState> = HashMap::new(); - let mut proc_state_map: HashMap<u64, ProcWidgetState> = HashMap::new(); - let mut temp_state_map: HashMap<u64, TempWidgetState> = HashMap::new(); - let mut disk_state_map: HashMap<u64, DiskTableWidget> = HashMap::new(); - let mut battery_state_map: HashMap<u64, BatteryWidgetState> = HashMap::new(); - - let autohide_timer = if autohide_time { - Some(Instant::now()) - } else { - None - }; - - let mut initial_widget_id: u64 = default_widget_id; - let mut initial_widget_type = Proc; - 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 proc_columns: Option<IndexSet<ProcWidgetColumn>> = { - let columns = config - .processes - .as_ref() - .and_then(|cfg| cfg.columns.clone()); - - match columns { - Some(columns) => { - if columns.is_empty() { - None - } else { - Some(IndexSet::from_iter(columns)) - } - } - None => None, - } - }; - - 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), - 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), - 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), - is_advanced_kill, - network_scale_type, - network_unit_type, - network_use_binary_prefix, - retention_ms, - }; - - let table_config = ProcTableConfig { - is_case_sensitive, - is_match_whole_word, - is_use_regex, - show_memory_as_values, - is_command: is_default_command, - }; - - for row in &widget_layout.rows { - for col in &row.children { - for col_row in &col.children { - for widget in &col_row.children { - widget_map.insert(widget.widget_id, widget.clone()); - if let Some(default_widget_type) = &default_widget_type_option { - if !is_custom_layout || use_basic_mode { - match widget.widget_type { - BasicCpu => { - if let Cpu = *default_widget_type { - initial_widget_id = widget.widget_id; - initial_widget_type = Cpu; - } - } - BasicMem => { - if let Mem = *default_widget_type { - initial_widget_id = widget.widget_id; - initial_widget_type = Cpu; - } - } - BasicNet => { - if let Net = *default_widget_type { - initial_widget_id = widget.widget_id; - initial_widget_type = Cpu; - } - } - _ => { - if *default_widget_type == widget.widget_type { - initial_widget_id = widget.widget_id; - initial_widget_type = widget.widget_type.clone(); - } - } - } - } - } - - used_widget_set.insert(widget.widget_type.clone()); - - match widget.widget_type { - Cpu => { - cpu_state_map.insert( - 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, - ), - ); - } - Mem => { - mem_state_map.insert( - widget.widget_id, - MemWidgetState::init(default_time_value, autohide_timer), - ); - } - Net => { - net_state_map.insert( - widget.widget_id, - NetWidgetState::init(default_time_value, autohide_timer), - ); - } - Proc => { - let mode = if is_grouped { - ProcWidgetMode::Grouped - } else if is_default_tree { - ProcWidgetMode::Tree { - collapsed_pids: Default::default(), - } - } else { - ProcWidgetMode::Normal - }; - - proc_state_map.insert( - widget.widget_id, - ProcWidgetState::new( - &app_config_fields, - mode, - table_config, - styling, - &proc_columns, - ), - ); - } - Disk => { - disk_state_map.insert( - widget.widget_id, - DiskTableWidget::new(&app_config_fields, styling), - ); - } - Temp => { - temp_state_map.insert( - widget.widget_id, - TempWidgetState::new(&app_config_fields, styling), - ); - } - Battery => { - battery_state_map - .insert(widget.widget_id, BatteryWidgetState::default()); - } - _ => {} - } - } - } - } - } - - let basic_table_widget_state = if use_basic_mode { - Some(match initial_widget_type { - Proc | Disk | Temp => BasicTableWidgetState { - currently_displayed_widget_type: initial_widget_type, - currently_displayed_widget_id: initial_widget_id, - widget_id: 100, - left_tlc: None, - left_brc: None, - right_tlc: None, - right_brc: None, - }, - _ => BasicTableWidgetState { - currently_displayed_widget_type: Proc, - currently_displayed_widget_id: DEFAULT_WIDGET_ID, - widget_id: 100, - left_tlc: None, - left_brc: None, - right_tlc: None, - right_brc: None, - }, - }) - } else { - None - }; - - let use_mem = used_widget_set.get(&Mem).is_some() || used_widget_set.get(&BasicMem).is_some(); - 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_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(), - use_temp: used_widget_set.get(&Temp).is_some(), - use_battery: used_widget_set.get(&Battery).is_some(), - }; - - let disk_filter = - get_ignore_list(&config.disk_filter).context("Update 'disk_filter' in your config file")?; - let mount_filter = get_ignore_list(&config.mount_filter) - .context("Update 'mount_filter' in your config file")?; - let temp_filter = - get_ignore_list(&config.temp_filter).context("Update 'temp_filter' in your config file")?; - let net_filter = - get_ignore_list(&config.net_filter).context("Update 'net_filter' in your config file")?; - - let states = AppWidgetStates { - cpu_state: CpuState::init(cpu_state_map), - mem_state: MemState::init(mem_state_map), - net_state: NetState::init(net_state_map), - proc_state: ProcState::init(proc_state_map), - temp_state: TempState::init(temp_state_map), - disk_state: DiskState::init(disk_state_map), - battery_state: BatteryState::init(battery_state_map), - basic_table_widget_state, - }; - - let current_widget = widget_map.get(&initial_widget_id).unwrap().clone(); - let filters = DataFilters { - disk_filter, - mount_filter, - temp_filter, - net_filter, - }; - let is_expanded = expanded_upon_startup && !use_basic_mode; - - Ok(App::new( - app_config_fields, - states, - widget_map, - current_widget, - used_widgets, - filters, - is_expanded, - )) -} - -pub fn get_widget_layout( - matches: &ArgMatches, config: &Config, -) -> error::Result<(BottomLayout, u64, Option<BottomWidgetType>)> { - let left_legend = is_flag_enabled!(left_legend, matches, config); - - let (default_widget_type, mut default_widget_count) = - get_default_widget_and_count(matches, config)?; - let mut default_widget_id = 1; - - let bottom_layout = if is_flag_enabled!(basic, matches, config) { - default_widget_id = DEFAULT_WIDGET_ID; - - BottomLayout::init_basic_default(get_use_battery(matches, 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) { - DEFAULT_BATTERY_LAYOUT - } else { - DEFAULT_LAYOUT - })? - .row - .unwrap(); - &ref_row - } - }; - - let mut iter_id = 0; // A lazy way of forcing unique IDs *shrugs* - let mut total_height_ratio = 0; - - let mut ret_bottom_layout = BottomLayout { - rows: rows - .iter() - .map(|row| { - row.convert_row_to_bottom_row( - &mut iter_id, - &mut total_height_ratio, - &mut default_widget_id, - &default_widget_type, - &mut default_widget_count, - left_legend, - ) - }) - .collect::<error::Result<Vec<_>>>()?, - total_row_height_ratio: total_height_ratio, - }; - - // Confirm that we have at least ONE widget left - if not, error out! - if iter_id > 0 { - ret_bottom_layout.get_movement_mappings(); - // debug!("Bottom layout: {ret_bottom_layout:#?}"); - - ret_bottom_layout - } else { - return Err(BottomError::ConfigError( - "please have at least one widget under the '[[row]]' section.".to_string(), - )); - } - }; - - 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 -} - -fn try_parse_ms(s: &str) -> error::Result<u64> { - if let Ok(val) = humantime::parse_duration(s) { - Ok(val.as_millis().try_into()?) - } else if let Ok(val) = s.parse::<u64>() { - Ok(val) - } else { - Err(BottomError::ConfigError( - "could not parse as a valid 64-bit unsigned integer or a human time".to_string(), - )) - } -} - -fn get_default_time_value( - matches: &ArgMatches, config: &Config, retention_ms: u64, -) -> 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 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)) - ))); - } - - Ok(default_time) -} - -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 - } - } else { - TIME_CHANGE_MILLISECONDS - }; - - if time_interval < 1000 { - return Err(BottomError::ConfigError( - "set your time delta to be at least 1s.".to_string(), - )); - } else if time_interval > retention_ms { - return Err(BottomError::ConfigError(format!( - "set your time delta to be at most {}.", - humantime::Duration::from(Duration::from_millis(retention_ms)) - ))); - } - - Ok(time_interval) -} - -fn get_default_widget_and_count( - matches: &ArgMatches, config: &Config, -) -> error::Result<(Option<BottomWidgetType>, u64)> { - let widget_type = if let Some(widget_type) = matches.get_one::<String>("default_widget_type") { - let parsed_widget = widget_type.parse::<BottomWidgetType>()?; - if let BottomWidgetType::Empty = parsed_widget { - None - } else { - Some(parsed_widget) - } - } else if let Some(flags) = &config.flags { - if let Some(widget_type) = &flags.default_widget_type { - let parsed_widget = widget_type.parse::<BottomWidgetType>()?; - if let BottomWidgetType::Empty = parsed_widget { - None - } else { - Some(parsed_widget) - } - } else { - None - } - } else { - None - }; - - let widget_count = if let Some(widget_count) = matches.get_one::<String>("default_widget_count") - { - Some(widget_count.parse::<u128>()?) - } else if let Some(flags) = &config.flags { - flags - .default_widget_count - .map(|widget_count| widget_count.into()) - } else { - None - }; - - match (widget_type, widget_count) { - (Some(widget_type), Some(widget_count)) => { - let widget_count = widget_count.try_into().map_err(|_| BottomError::ConfigError( - "set your widget count to be at most unsigned INT_MAX.".to_string() - ))?; - Ok((Some(widget_type), widget_count)) - } - (Some(widget_type), None) => Ok((Some(widget_type), 1)), - (None, Some(_widget_count)) => Err(BottomError::ConfigError( - "cannot set 'default_widget_count' by itself, it must be used with 'default_widget_type'.".to_string(), - )), - (None, None) => Ok((None, 1)) - } -} - -#[allow(unused_variables)] -fn get_use_battery(matches: &ArgMatches, config: &Config) -> bool { - #[cfg(feature = "battery")] - { - if matches.get_flag("battery") { - return true; - } else if let Some(flags) = &config.flags { - if let Some(battery) = flags.battery { - return battery; - } - } - - if let Ok(battery_manager) = Manager::new() { - if let Ok(batteries) = battery_manager.batteries() { - if batteries.count() == 0 { - return false; - } - } - } - } - - false -} - -#[allow(unused_variables)] -fn get_enable_gpu(matches: &ArgMatches, config: &Config) -> bool { - #[cfg(feature = "gpu")] - { - if matches.get_flag("enable_gpu") { - return true; - } else if let Some(flags) = &config.flags { - if let Some(enable_gpu) = flags.enable_gpu { - return enable_gpu; - } - } - } - - false -} - -#[allow(unused_variables)] -fn get_enable_cache_memory(matches: &ArgMatches, config: &Config) -> bool { - #[cfg(not(target_os = "windows"))] - { - if matches.get_flag("enable_cache_memory") { - return true; - } else if let Some(flags) = &config.flags { - if let Some(enable_cache_memory) = flags.enable_cache_memory { - return enable_cache_memory; - } - } - } - - false -} - -fn get_ignore_list(ignore_list: &Option<IgnoreList>) -> error::Result<Option<Filter>> { - if let Some(ignore_list) = ignore_list { - let list: Result<Vec<_>, _> = ignore_list - .list - .iter() - .map(|name| { - let escaped_string: String; - let res = format!( - "{}{}{}{}", - if ignore_list.whole_word { "^" } else { "" }, - if ignore_list.case_sensitive { - "" - } else { - "(?i)" - }, - if ignore_list.regex { - name - } else { - escaped_string = regex::escape(name); - &escaped_string - }, - if ignore_list.whole_word { "$" } else { "" }, - ); - - Regex::new(&res) - }) - .collect(); - - Ok(Some(Filter { - list: list?, - is_list_ignored: ignore_list.is_list_ignored, - })) - } else { - Ok(None) - } -} - -pub fn get_color_scheme(matches: &ArgMatches, config: &Config) -> error::Result<ColourScheme> { - if let Some(color) = matches.get_one::<String>("color") { - // Highest priority is always command line flags... - return ColourScheme::from_str(color); - } else if let Some(colors) = &config.colors { - if !colors.is_empty() { - // Then, give priority to custom colours... - return Ok(ColourScheme::Custom); - } else if let Some(flags) = &config.flags { - // Last priority is config file flags... - if let Some(color) = &flags.color { - return ColourScheme::from_str(color); - } - } - } else if let Some(flags) = &config.flags { - // Last priority is config file flags... - if let Some(color) = &flags.color { - return ColourScheme::from_str(color); - } - } - - // And lastly, the final case is just "default". - Ok(ColourScheme::Default) -} - -fn get_network_unit_type(matches: &ArgMatches, config: &Config) -> DataUnit { - if matches.get_flag("network_use_bytes") { - return DataUnit::Byte; - } else if let Some(flags) = &config.flags { - if let Some(network_use_bytes) = flags.network_use_bytes { - if network_use_bytes { - return DataUnit::Byte; - } - } - } - - DataUnit::Bit -} - -fn get_network_scale_type(matches: &ArgMatches, config: &Config) -> AxisScaling { - if matches.get_flag("network_use_log") { - return AxisScaling::Log; - } else if let Some(flags) = &config.flags { - if let Some(network_use_log) = flags.network_use_log { - if network_use_log { - return AxisScaling::Log; - } - } - } - - AxisScaling::Linear -} - -fn get_retention(matches: &ArgMatches, config: &Config) -> error::Result<u64> { - const DEFAULT_RETENTION_MS: u64 = 600 * 1000; // Keep 10 minutes of data. - - if let Some(retention) = matches.get_one::<String>("retention") { - try_parse_ms(retention) - } else if let Some(flags) = &config.flags { - if let Some(retention) = &flags.retention { - Ok(match retention { - StringOrNum::String(s) => try_parse_ms(s)?, - StringOrNum::Num(n) => *n, - }) - } else { - Ok(DEFAULT_RETENTION_MS) - } - } else { - Ok(DEFAULT_RETENTION_MS) - } -} - -#[cfg(test)] -mod test { - use clap::ArgMatches; - - use super::{get_color_scheme, get_time_interval, get_widget_layout, Config}; - use crate::{ - app::App, - canvas::styling::CanvasStyling, - options::config::{ - get_default_time_value, get_retention, get_update_rate, try_parse_ms, ConfigFlags, - }, - }; - - #[test] - fn verify_try_parse_ms() { - let a = "100s"; - let b = "100"; - let c = "1 min"; - let d = "1 hour 1 min"; - - assert_eq!(try_parse_ms(a), Ok(100 * 1000)); - assert_eq!(try_parse_ms(b), Ok(100)); - assert_eq!(try_parse_ms(c), Ok(60 * 1000)); - assert_eq!(try_parse_ms(d), Ok(3660 * 1000)); - - let a_bad = "1 test"; - let b_bad = "-100"; - - assert!(try_parse_ms(a_bad).is_err()); - assert!(try_parse_ms(b_bad).is_err()); - } - - #[test] - fn matches_human_times() { - let config = Config::default(); - let app = crate::args::build_app(); - - { - let app = app.clone(); - let delta_args = vec!["btm", "--time_delta", "2 min"]; - let matches = app.get_matches_from(delta_args); - - assert_eq!( - get_time_interval(&matches, &config, 60 * 60 * 1000), - Ok(2 * 60 * 1000) - ); - } - - { - let default_time_args = vec!["btm", "--default_time_value", "300s"]; - let matches = app.get_matches_from(default_time_args); - - assert_eq!( - get_default_time_value(&matches, &config, 60 * 60 * 1000), - Ok(5 * 60 * 1000) - ); - } - } - - #[test] - fn matches_number_times() { - let config = Config::default(); - let app = crate::args::build_app(); - - { - let app = app.clone(); - let delta_args = vec!["btm", "--time_delta", "120000"]; - let matches = app.get_matches_from(delta_ |