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.
This commit is contained in:
parent
7eff79395d
commit
57e87d88d0
|
@ -113,6 +113,7 @@ script:
|
||||||
cargo test --verbose --target $TARGET
|
cargo test --verbose --target $TARGET
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# FIXME: [TRAVIS] Probably want to update this with the new build targets and all.
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- |
|
- |
|
||||||
echo "Test whether installing works. This is mostly just a sanity check.";
|
echo "Test whether installing works. This is mostly just a sanity check.";
|
||||||
|
|
|
@ -43,7 +43,6 @@ sysinfo = "0.15.1"
|
||||||
thiserror = "1.0.20"
|
thiserror = "1.0.20"
|
||||||
toml = "0.5.6"
|
toml = "0.5.6"
|
||||||
tui = {version = "0.12.0", features = ["crossterm"], default-features = false }
|
tui = {version = "0.12.0", features = ["crossterm"], default-features = false }
|
||||||
# tui = {version = "0.11.0", features = ["crossterm"], default-features = false, path="../tui-rs" }
|
|
||||||
typed-builder = "0.7.0"
|
typed-builder = "0.7.0"
|
||||||
unicode-segmentation = "1.6.0"
|
unicode-segmentation = "1.6.0"
|
||||||
unicode-width = "0.1"
|
unicode-width = "0.1"
|
||||||
|
|
141
src/app.rs
141
src/app.rs
|
@ -13,6 +13,8 @@ pub use states::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
canvas, constants,
|
canvas, constants,
|
||||||
options::Config,
|
options::Config,
|
||||||
|
options::ConfigFlags,
|
||||||
|
options::WidgetIdEnabled,
|
||||||
utils::error::{BottomError, Result},
|
utils::error::{BottomError, Result},
|
||||||
Pid,
|
Pid,
|
||||||
};
|
};
|
||||||
|
@ -105,6 +107,9 @@ pub struct App {
|
||||||
#[builder(default = false, setter(skip))]
|
#[builder(default = false, setter(skip))]
|
||||||
pub is_config_open: bool,
|
pub is_config_open: bool,
|
||||||
|
|
||||||
|
#[builder(default = false, setter(skip))]
|
||||||
|
pub did_config_fail_to_save: bool,
|
||||||
|
|
||||||
pub cpu_state: CpuState,
|
pub cpu_state: CpuState,
|
||||||
pub mem_state: MemState,
|
pub mem_state: MemState,
|
||||||
pub net_state: NetState,
|
pub net_state: NetState,
|
||||||
|
@ -179,7 +184,7 @@ impl App {
|
||||||
|
|
||||||
self.is_force_redraw = true;
|
self.is_force_redraw = true;
|
||||||
} else if self.is_config_open {
|
} else if self.is_config_open {
|
||||||
self.close_config();
|
self.close_config_screen();
|
||||||
} else {
|
} else {
|
||||||
match self.current_widget.widget_type {
|
match self.current_widget.widget_type {
|
||||||
BottomWidgetType::Proc => {
|
BottomWidgetType::Proc => {
|
||||||
|
@ -454,6 +459,7 @@ impl App {
|
||||||
|
|
||||||
pub fn toggle_ignore_case(&mut self) {
|
pub fn toggle_ignore_case(&mut self) {
|
||||||
let is_in_search_widget = self.is_in_search_widget();
|
let is_in_search_widget = self.is_in_search_widget();
|
||||||
|
let mut is_case_sensitive: Option<bool> = None;
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.widget_states
|
||||||
|
@ -466,13 +472,49 @@ impl App {
|
||||||
proc_widget_state.update_query();
|
proc_widget_state.update_query();
|
||||||
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
||||||
|
|
||||||
// Also toggle it in the config file.
|
// Remember, it's the opposite (ignoring case is case "in"sensitive)
|
||||||
|
is_case_sensitive = Some(!proc_widget_state.process_search_state.is_ignoring_case);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also toggle it in the config file if we actually changed it.
|
||||||
|
if let Some(is_ignoring_case) = is_case_sensitive {
|
||||||
|
if let Some(flags) = &mut self.config.flags {
|
||||||
|
if let Some(map) = &mut flags.search_case_enabled_widgets_map {
|
||||||
|
// Just update the map.
|
||||||
|
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
|
||||||
|
*mapping = is_ignoring_case;
|
||||||
|
|
||||||
|
flags.search_case_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
} else {
|
||||||
|
// Map doesn't exist yet... initialize ourselves.
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_ignoring_case);
|
||||||
|
flags.search_case_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
flags.search_case_enabled_widgets_map = Some(map);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Must initialize it ourselves...
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_ignoring_case);
|
||||||
|
|
||||||
|
self.config.flags = Some(
|
||||||
|
ConfigFlags::builder()
|
||||||
|
.search_case_enabled_widgets(WidgetIdEnabled::create_from_hashmap(&map))
|
||||||
|
.search_case_enabled_widgets_map(map)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.did_config_fail_to_save = self.update_config_file().is_err();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_search_whole_word(&mut self) {
|
pub fn toggle_search_whole_word(&mut self) {
|
||||||
let is_in_search_widget = self.is_in_search_widget();
|
let is_in_search_widget = self.is_in_search_widget();
|
||||||
|
let mut is_searching_whole_word: Option<bool> = None;
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.widget_states
|
||||||
|
@ -484,12 +526,55 @@ impl App {
|
||||||
.search_toggle_whole_word();
|
.search_toggle_whole_word();
|
||||||
proc_widget_state.update_query();
|
proc_widget_state.update_query();
|
||||||
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
||||||
|
|
||||||
|
is_searching_whole_word = Some(
|
||||||
|
proc_widget_state
|
||||||
|
.process_search_state
|
||||||
|
.is_searching_whole_word,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also toggle it in the config file if we actually changed it.
|
||||||
|
if let Some(is_searching_whole_word) = is_searching_whole_word {
|
||||||
|
if let Some(flags) = &mut self.config.flags {
|
||||||
|
if let Some(map) = &mut flags.search_whole_word_enabled_widgets_map {
|
||||||
|
// Just update the map.
|
||||||
|
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
|
||||||
|
*mapping = is_searching_whole_word;
|
||||||
|
|
||||||
|
flags.search_whole_word_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
} else {
|
||||||
|
// Map doesn't exist yet... initialize ourselves.
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
|
||||||
|
flags.search_whole_word_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
flags.search_whole_word_enabled_widgets_map = Some(map);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Must initialize it ourselves...
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
|
||||||
|
|
||||||
|
self.config.flags = Some(
|
||||||
|
ConfigFlags::builder()
|
||||||
|
.search_whole_word_enabled_widgets(WidgetIdEnabled::create_from_hashmap(
|
||||||
|
&map,
|
||||||
|
))
|
||||||
|
.search_whole_word_enabled_widgets_map(map)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.did_config_fail_to_save = self.update_config_file().is_err();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_search_regex(&mut self) {
|
pub fn toggle_search_regex(&mut self) {
|
||||||
let is_in_search_widget = self.is_in_search_widget();
|
let is_in_search_widget = self.is_in_search_widget();
|
||||||
|
let mut is_searching_with_regex: Option<bool> = None;
|
||||||
if let Some(proc_widget_state) = self
|
if let Some(proc_widget_state) = self
|
||||||
.proc_state
|
.proc_state
|
||||||
.widget_states
|
.widget_states
|
||||||
|
@ -499,8 +584,48 @@ impl App {
|
||||||
proc_widget_state.process_search_state.search_toggle_regex();
|
proc_widget_state.process_search_state.search_toggle_regex();
|
||||||
proc_widget_state.update_query();
|
proc_widget_state.update_query();
|
||||||
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
self.proc_state.force_update = Some(self.current_widget.widget_id - 1);
|
||||||
|
|
||||||
|
is_searching_with_regex = Some(
|
||||||
|
proc_widget_state
|
||||||
|
.process_search_state
|
||||||
|
.is_searching_with_regex,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also toggle it in the config file if we actually changed it.
|
||||||
|
if let Some(is_searching_whole_word) = is_searching_with_regex {
|
||||||
|
if let Some(flags) = &mut self.config.flags {
|
||||||
|
if let Some(map) = &mut flags.search_regex_enabled_widgets_map {
|
||||||
|
// Just update the map.
|
||||||
|
let mapping = map.entry(self.current_widget.widget_id - 1).or_default();
|
||||||
|
*mapping = is_searching_whole_word;
|
||||||
|
|
||||||
|
flags.search_regex_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
} else {
|
||||||
|
// Map doesn't exist yet... initialize ourselves.
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
|
||||||
|
flags.search_regex_enabled_widgets =
|
||||||
|
Some(WidgetIdEnabled::create_from_hashmap(&map));
|
||||||
|
flags.search_regex_enabled_widgets_map = Some(map);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Must initialize it ourselves...
|
||||||
|
let mut map = HashMap::default();
|
||||||
|
map.insert(self.current_widget.widget_id - 1, is_searching_whole_word);
|
||||||
|
|
||||||
|
self.config.flags = Some(
|
||||||
|
ConfigFlags::builder()
|
||||||
|
.search_regex_enabled_widgets(WidgetIdEnabled::create_from_hashmap(&map))
|
||||||
|
.search_regex_enabled_widgets_map(map)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.did_config_fail_to_save = self.update_config_file().is_err();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toggle_tree_mode(&mut self) {
|
pub fn toggle_tree_mode(&mut self) {
|
||||||
|
@ -1265,28 +1390,28 @@ impl App {
|
||||||
|
|
||||||
pub fn on_space(&mut self) {}
|
pub fn on_space(&mut self) {}
|
||||||
|
|
||||||
pub fn open_config(&mut self) {
|
pub fn open_config_screen(&mut self) {
|
||||||
self.is_config_open = true;
|
self.is_config_open = true;
|
||||||
self.is_force_redraw = true;
|
self.is_force_redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_config(&mut self) {
|
pub fn close_config_screen(&mut self) {
|
||||||
self.is_config_open = false;
|
self.is_config_open = false;
|
||||||
self.is_force_redraw = true;
|
self.is_force_redraw = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call this whenever the config value is updated!
|
/// Call this whenever the config value is updated!
|
||||||
#[allow(dead_code)] //FIXME: Remove this
|
|
||||||
fn update_config_file(&mut self) -> anyhow::Result<()> {
|
fn update_config_file(&mut self) -> anyhow::Result<()> {
|
||||||
if self.app_config_fields.no_write {
|
if self.app_config_fields.no_write {
|
||||||
|
debug!("No write enabled. Config will not be written.");
|
||||||
// Don't write!
|
// Don't write!
|
||||||
// FIXME: [CONFIG] This should be made VERY clear to the user... make a thing saying "it will not write due to no_write option"
|
// FIXME: [CONFIG] This should be made VERY clear to the user... make a thing saying "it will not write due to no_write option"
|
||||||
Ok(())
|
Ok(())
|
||||||
} else if let Some(config_path) = &self.config_path {
|
} else if let Some(config_path) = &self.config_path {
|
||||||
// Update
|
// Update
|
||||||
std::fs::File::open(config_path)?
|
// debug!("Updating config file - writing to: {:?}", config_path);
|
||||||
.write_all(toml::to_string(&self.config)?.as_bytes())?;
|
std::fs::File::create(config_path)?
|
||||||
|
.write_all(self.config.get_config_as_bytes()?.as_ref())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
// FIXME: [CONFIG] Put an actual error message?
|
// FIXME: [CONFIG] Put an actual error message?
|
||||||
|
|
|
@ -34,7 +34,7 @@ fn main() -> Result<()> {
|
||||||
|
|
||||||
let config_path = read_config(matches.value_of("config_location"))
|
let config_path = read_config(matches.value_of("config_location"))
|
||||||
.context("Unable to access the given config file location.")?;
|
.context("Unable to access the given config file location.")?;
|
||||||
let config: Config = create_or_get_config(&config_path)
|
let mut config: Config = create_or_get_config(&config_path)
|
||||||
.context("Unable to properly parse or create the config file.")?;
|
.context("Unable to properly parse or create the config file.")?;
|
||||||
|
|
||||||
// Get widget layout separately
|
// Get widget layout separately
|
||||||
|
@ -45,7 +45,7 @@ fn main() -> Result<()> {
|
||||||
// Create "app" struct, which will control most of the program and store settings/state
|
// Create "app" struct, which will control most of the program and store settings/state
|
||||||
let mut app = build_app(
|
let mut app = build_app(
|
||||||
&matches,
|
&matches,
|
||||||
&config,
|
&mut config,
|
||||||
&widget_layout,
|
&widget_layout,
|
||||||
default_widget_id,
|
default_widget_id,
|
||||||
&default_widget_type_option,
|
&default_widget_type_option,
|
||||||
|
|
|
@ -246,7 +246,8 @@ pub const DEFAULT_BATTERY_LAYOUT: &str = r##"
|
||||||
pub const DEFAULT_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
|
pub const DEFAULT_CONFIG_FILE_PATH: &str = "bottom/bottom.toml";
|
||||||
|
|
||||||
pub const CONFIG_TOP_HEAD: &str = r##"# This is bottom's config file. Values in this config file will change when changed in the
|
pub const CONFIG_TOP_HEAD: &str = r##"# This is bottom's config file. Values in this config file will change when changed in the
|
||||||
# interface. You can also manually change these values.
|
# interface. You can also manually change these values. Be aware that contents of this file will be overwritten if something is
|
||||||
|
# changed in the application; you can disable writing via the --no_write flag or no_write config option.
|
||||||
|
|
||||||
"##;
|
"##;
|
||||||
|
|
||||||
|
@ -272,6 +273,6 @@ pub const CONFIG_LAYOUT_HEAD: &str = r##"
|
||||||
# All layout components have a ratio value - if this is not set, then it defaults to 1.
|
# All layout components have a ratio value - if this is not set, then it defaults to 1.
|
||||||
"##;
|
"##;
|
||||||
|
|
||||||
pub const CONFIG_DIVIDER: &str = r##"
|
pub const CONFIG_FILTER_HEAD: &str = r##"
|
||||||
#########################################################################
|
# These options represent disabled entries for the temperature and disk widgets.
|
||||||
"##;
|
"##;
|
||||||
|
|
150
src/options.rs
150
src/options.rs
|
@ -1,6 +1,6 @@
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Instant;
|
use std::{borrow::Cow, time::Instant};
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -12,6 +12,8 @@ use crate::{
|
||||||
utils::error::{self, BottomError},
|
utils::error::{self, BottomError},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use typed_builder::*;
|
||||||
|
|
||||||
use layout_options::*;
|
use layout_options::*;
|
||||||
|
|
||||||
pub mod layout_options;
|
pub mod layout_options;
|
||||||
|
@ -27,31 +29,129 @@ pub struct Config {
|
||||||
pub temp_filter: Option<IgnoreList>,
|
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 {
|
pub struct ConfigFlags {
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub hide_avg_cpu: Option<bool>,
|
pub hide_avg_cpu: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub dot_marker: Option<bool>,
|
pub dot_marker: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub temperature_type: Option<String>,
|
pub temperature_type: Option<String>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub rate: Option<u64>,
|
pub rate: Option<u64>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub left_legend: Option<bool>,
|
pub left_legend: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub current_usage: Option<bool>,
|
pub current_usage: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub group_processes: Option<bool>,
|
pub group_processes: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub case_sensitive: Option<bool>,
|
pub case_sensitive: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub whole_word: Option<bool>,
|
pub whole_word: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub regex: Option<bool>,
|
pub regex: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub default_widget: Option<String>,
|
pub default_widget: Option<String>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub basic: Option<bool>,
|
pub basic: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub default_time_value: Option<u64>,
|
pub default_time_value: Option<u64>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub time_delta: Option<u64>,
|
pub time_delta: Option<u64>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub autohide_time: Option<bool>,
|
pub autohide_time: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub hide_time: Option<bool>,
|
pub hide_time: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub default_widget_type: Option<String>,
|
pub default_widget_type: Option<String>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub default_widget_count: Option<u64>,
|
pub default_widget_count: Option<u64>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub use_old_network_legend: Option<bool>,
|
pub use_old_network_legend: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub hide_table_gap: Option<bool>,
|
pub hide_table_gap: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub battery: Option<bool>,
|
pub battery: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub disable_click: Option<bool>,
|
pub disable_click: Option<bool>,
|
||||||
|
|
||||||
|
#[builder(default, setter(strip_option))]
|
||||||
pub no_write: Option<bool>,
|
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)]
|
#[derive(Clone, Default, Deserialize, Serialize)]
|
||||||
|
@ -85,7 +185,7 @@ pub struct IgnoreList {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_app(
|
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>,
|
default_widget_id: u64, default_widget_type_option: &Option<BottomWidgetType>,
|
||||||
config_path: Option<PathBuf>,
|
config_path: Option<PathBuf>,
|
||||||
) -> Result<App> {
|
) -> Result<App> {
|
||||||
|
@ -271,6 +371,48 @@ pub fn build_app(
|
||||||
let temp_filter =
|
let temp_filter =
|
||||||
get_ignore_list(&config.temp_filter).context("Update 'temp_filter' in your config file")?;
|
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()
|
Ok(App::builder()
|
||||||
.app_config_fields(app_config_fields)
|
.app_config_fields(app_config_fields)
|
||||||
.cpu_state(CpuState::init(cpu_state_map))
|
.cpu_state(CpuState::init(cpu_state_map))
|
||||||
|
@ -281,7 +423,7 @@ pub fn build_app(
|
||||||
.temp_state(TempState::init(temp_state_map))
|
.temp_state(TempState::init(temp_state_map))
|
||||||
.battery_state(BatteryState::init(battery_state_map))
|
.battery_state(BatteryState::init(battery_state_map))
|
||||||
.basic_table_widget_state(basic_table_widget_state)
|
.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)
|
.widget_map(widget_map)
|
||||||
.used_widgets(used_widgets)
|
.used_widgets(used_widgets)
|
||||||
.filters(DataFilters {
|
.filters(DataFilters {
|
||||||
|
|
Loading…
Reference in New Issue