summaryrefslogtreecommitdiffstats
path: root/src/options.rs
diff options
context:
space:
mode:
authorClement Tsang <34804052+ClementTsang@users.noreply.github.com>2020-09-28 19:50:21 -0400
committerGitHub <noreply@github.com>2020-09-28 19:50:21 -0400
commit57e87d88d09e6282770a2315977fe43ef52958b4 (patch)
tree12af86e5aebad78d067caf9a93d5e15efc4f5dc9 /src/options.rs
parent7eff79395db3efe9914d3e5ddcd6df7a1fdc649d (diff)
feature: Add persistent search settings (#257)
Adds persistent search settings across runs, by saving to the config file. Each process widget keeps track of it's *own* behaviour. The previous flags/options are now for *global* behaviour. The following new behaviour is: - Relevant flags: `--case_sensitive`, `--whole_word`, and `--regex`, will *override* the current widget's default behaviour. - Relevant options: `case_sensitive`, `whole_word`, and `regex`, will also *override* the current widget's default behaviour. As per before, if you set, say, `--case_sensitive`and `case_sensitive=true`, the flag always overrides. Documentation updates will be done in #248.
Diffstat (limited to 'src/options.rs')
-rw-r--r--src/options.rs150
1 files changed, 146 insertions, 4 deletions
diff --git a/src/options.rs b/src/options.rs
index 1efd10c9..0f85a611 100644
--- a/src/options.rs
+++ b/src/options.rs
@@ -1,6 +1,6 @@
use regex::Regex;
use serde::{Deserialize, Serialize};
-use std::time::Instant;
+use std::{borrow::Cow, time::Instant};
use std::{
collections::{HashMap, HashSet},
path::PathBuf,
@@ -12,6 +12,8 @@ use crate::{
utils::error::{self, BottomError},
};
+use typed_builder::*;
+
use layout_options::*;
pub mod layout_options;
@@ -27,31 +29,129 @@ pub struct Config {
pub temp_filter: Option<IgnoreList>,
}
-#[derive(Clone, Default, Deserialize, Serialize)]
+impl Config {
+ pub fn get_config_as_bytes(&self) -> anyhow::Result<Vec<u8>> {
+ let mut config_string: Vec<Cow<'_, str>> = Vec::default();
+
+ // Top level
+ config_string.push(CONFIG_TOP_HEAD.into());
+ config_string.push(toml::to_string_pretty(self)?.into());
+
+ Ok(config_string.concat().as_bytes().to_vec())
+ }
+}
+
+#[derive(Clone, Debug, Default, Deserialize, Serialize, TypedBuilder)]
pub struct ConfigFlags {
+ #[builder(default, setter(strip_option))]
pub hide_avg_cpu: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub dot_marker: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub temperature_type: Option<String>,
+
+ #[builder(default, setter(strip_option))]
pub rate: Option<u64>,
+
+ #[builder(default, setter(strip_option))]
pub left_legend: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub current_usage: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub group_processes: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub case_sensitive: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub whole_word: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub regex: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub default_widget: Option<String>,
+
+ #[builder(default, setter(strip_option))]
pub basic: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub default_time_value: Option<u64>,
+
+ #[builder(default, setter(strip_option))]
pub time_delta: Option<u64>,
+
+ #[builder(default, setter(strip_option))]
pub autohide_time: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub hide_time: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub default_widget_type: Option<String>,
+
+ #[builder(default, setter(strip_option))]
pub default_widget_count: Option<u64>,
+
+ #[builder(default, setter(strip_option))]
pub use_old_network_legend: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub hide_table_gap: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub battery: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub disable_click: Option<bool>,
+
+ #[builder(default, setter(strip_option))]
pub no_write: Option<bool>,
+
+ // This is a huge hack to enable hashmap functionality WITHOUT being able to serializing the field.
+ // Basically, keep a hashmap in the struct, and convert to a vector every time.
+ #[builder(default, setter(strip_option))]
+ #[serde(skip)]
+ pub search_case_enabled_widgets_map: Option<HashMap<u64, bool>>,
+
+ #[builder(default, setter(strip_option))]
+ pub search_case_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
+
+ #[builder(default, setter(strip_option))]
+ #[serde(skip)]
+ pub search_whole_word_enabled_widgets_map: Option<HashMap<u64, bool>>,
+
+ #[builder(default, setter(strip_option))]
+ pub search_whole_word_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
+
+ #[builder(default, setter(strip_option))]
+ #[serde(skip)]
+ pub search_regex_enabled_widgets_map: Option<HashMap<u64, bool>>,
+
+ #[builder(default, setter(strip_option))]
+ pub search_regex_enabled_widgets: Option<Vec<WidgetIdEnabled>>,
+}
+
+#[derive(Clone, Default, Debug, Deserialize, Serialize)]
+pub struct WidgetIdEnabled {
+ id: u64,
+ enabled: bool,
+}
+
+impl WidgetIdEnabled {
+ pub fn create_from_hashmap(hashmap: &HashMap<u64, bool>) -> Vec<WidgetIdEnabled> {
+ hashmap
+ .iter()
+ .map(|(id, enabled)| WidgetIdEnabled {
+ id: *id,
+ enabled: *enabled,
+ })
+ .collect()
+ }
}
#[derive(Clone, Default, Deserialize, Serialize)]
@@ -85,7 +185,7 @@ pub struct IgnoreList {
}
pub fn build_app(
- matches: &clap::ArgMatches<'static>, config: &Config, widget_layout: &BottomLayout,
+ matches: &clap::ArgMatches<'static>, config: &mut Config, widget_layout: &BottomLayout,
default_widget_id: u64, default_widget_type_option: &Option<BottomWidgetType>,
config_path: Option<PathBuf>,
) -> Result<App> {
@@ -271,6 +371,48 @@ pub fn build_app(
let temp_filter =
get_ignore_list(&config.temp_filter).context("Update 'temp_filter' in your config file")?;
+ // One more thing - we have to update the search settings of our proc_state_map, and create the hashmaps if needed!
+ // Note that if you change your layout, this might not actually match properly... not sure if/where we should deal with that...
+ if let Some(flags) = &mut config.flags {
+ if flags.case_sensitive.is_none() && !matches.is_present("case_sensitive") {
+ if let Some(search_case_enabled_widgets) = &flags.search_case_enabled_widgets {
+ let mapping = HashMap::new();
+ for widget in search_case_enabled_widgets {
+ if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
+ proc_widget.process_search_state.is_ignoring_case = !widget.enabled;
+ }
+ }
+ flags.search_case_enabled_widgets_map = Some(mapping);
+ }
+ }
+
+ if flags.whole_word.is_none() && !matches.is_present("whole_word") {
+ if let Some(search_whole_word_enabled_widgets) =
+ &flags.search_whole_word_enabled_widgets
+ {
+ let mapping = HashMap::new();
+ for widget in search_whole_word_enabled_widgets {
+ if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
+ proc_widget.process_search_state.is_searching_whole_word = widget.enabled;
+ }
+ }
+ flags.search_whole_word_enabled_widgets_map = Some(mapping);
+ }
+ }
+
+ if flags.regex.is_none() && !matches.is_present("regex") {
+ if let Some(search_regex_enabled_widgets) = &flags.search_regex_enabled_widgets {
+ let mapping = HashMap::new();
+ for widget in search_regex_enabled_widgets {
+ if let Some(proc_widget) = proc_state_map.get_mut(&widget.id) {
+ proc_widget.process_search_state.is_searching_with_regex = widget.enabled;
+ }
+ }
+ flags.search_regex_enabled_widgets_map = Some(mapping);
+ }
+ }
+ }
+
Ok(App::builder()
.app_config_fields(app_config_fields)
.cpu_state(CpuState::init(cpu_state_map))
@@ -281,7 +423,7 @@ pub fn build_app(
.temp_state(TempState::init(temp_state_map))
.battery_state(BatteryState::init(battery_state_map))
.basic_table_widget_state(basic_table_widget_state)
- .current_widget(widget_map.get(&initial_widget_id).unwrap().clone()) // FIXME: [UNWRAP] - many of the unwraps are fine (like this one) but do a once-over and/or switch to expect?
+ .current_widget(widget_map.get(&initial_widget_id).unwrap().clone()) // TODO: [UNWRAP] - many of the unwraps are fine (like this one) but do a once-over and/or switch to expect?
.widget_map(widget_map)
.used_widgets(used_widgets)
.filters(DataFilters {