diff --git a/docs/content/main/configuration.md b/docs/content/main/configuration.md index a9ad2fe..aefced7 100644 --- a/docs/content/main/configuration.md +++ b/docs/content/main/configuration.md @@ -118,11 +118,13 @@ Here you can include other config files so that they are merged together at star ```xml - - + + ``` +If you define a variable/widget/window, in a config file, when it's defined somewhere else, you can see a warning in the eww logs (`eww logs`) + ### The `` block In here you whole widget will be made, and you can also create your own widgets. Check [Widget Documentation](@/main/widgets.md) for pre-defined widgets. diff --git a/src/app.rs b/src/app.rs index 4c930ba..7a0d8e5 100644 --- a/src/app.rs +++ b/src/app.rs @@ -265,7 +265,7 @@ impl App { // TODO somehow make this less shit for newly_used_var in self .variables_only_used_in(&window_name) - .filter_map(|var| self.eww_config.get_script_var(&var)) + .filter_map(|var| self.eww_config.get_script_var(&var).ok()) { self.script_var_handler.add(newly_used_var.clone()); } diff --git a/src/config/eww_config.rs b/src/config/eww_config.rs index f11008e..ff0f0c2 100644 --- a/src/config/eww_config.rs +++ b/src/config/eww_config.rs @@ -14,24 +14,41 @@ use super::{ use std::path::PathBuf; #[derive(Debug, Clone)] +/// Structure to hold the eww config pub struct EwwConfig { widgets: HashMap, windows: HashMap, initial_variables: HashMap, - - // TODO make this a hashmap - script_vars: Vec, + script_vars: HashMap, pub filepath: PathBuf, } impl EwwConfig { pub fn merge_includes(mut eww_config: EwwConfig, includes: Vec) -> Result { - // TODO issue warnings on conflict - for config in includes { - eww_config.widgets.extend(config.widgets); - eww_config.windows.extend(config.windows); - eww_config.script_vars.extend(config.script_vars); - eww_config.initial_variables.extend(config.initial_variables); + let config_path = eww_config.filepath.clone(); + let log_conflict = |what: &str, conflict: &str, included_path: &std::path::PathBuf| { + eprintln!( + "{} '{}' defined twice (defined in {} and in {})", + what, + conflict, + config_path.display(), + included_path.display() + ); + }; + + for included_config in includes { + for conflict in extend_safe(&mut eww_config.widgets, included_config.widgets) { + log_conflict("widget", &conflict, &included_config.filepath) + } + for conflict in extend_safe(&mut eww_config.windows, included_config.windows) { + log_conflict("window", &conflict.to_string(), &included_config.filepath) + } + for conflict in extend_safe(&mut eww_config.script_vars, included_config.script_vars) { + log_conflict("script-var", &conflict.to_string(), &included_config.filepath) + } + for conflict in extend_safe(&mut eww_config.initial_variables, included_config.initial_variables) { + log_conflict("var", &conflict.to_string(), &included_config.filepath) + } } Ok(eww_config) } @@ -118,7 +135,7 @@ impl EwwConfig { let mut vars = self .script_vars .iter() - .map(|var| Ok((var.name().clone(), var.initial_value()?))) + .map(|var| Ok((var.0.clone(), var.1.initial_value()?))) .collect::>>()?; vars.extend(self.get_default_vars().clone()); Ok(vars) @@ -142,18 +159,20 @@ impl EwwConfig { &self.initial_variables } - pub fn get_script_vars(&self) -> &Vec { - &self.script_vars + pub fn get_script_vars(&self) -> Vec { + self.script_vars.values().cloned().collect() } - pub fn get_script_var(&self, name: &VarName) -> Option<&ScriptVar> { - self.script_vars.iter().find(|x| x.name() == name) + pub fn get_script_var(&self, name: &VarName) -> Result<&ScriptVar> { + self.script_vars + .get(name) + .with_context(|| format!("No script var named '{}' exists", name)) } } -fn parse_variables_block(xml: XmlElement) -> Result<(HashMap, Vec)> { +fn parse_variables_block(xml: XmlElement) -> Result<(HashMap, HashMap)> { let mut normal_vars = HashMap::new(); - let mut script_vars = Vec::new(); + let mut script_vars = HashMap::new(); for node in xml.child_elements() { match node.tag_name() { "var" => { @@ -165,7 +184,8 @@ fn parse_variables_block(xml: XmlElement) -> Result<(HashMap { - script_vars.push(ScriptVar::from_xml_element(node)?); + let script_var = ScriptVar::from_xml_element(node)?; + script_vars.insert(script_var.name().clone(), script_var); } _ => bail!("Illegal element in variables block: {}", node.as_tag_string()), } @@ -187,6 +207,16 @@ fn join_path_pretty, P2: AsRef>(a: P, } } +/// extends a hashmap, returning a list of keys that already where present in the hashmap. +fn extend_safe>( + a: &mut HashMap, + b: T, +) -> Vec { + b.into_iter() + .filter_map(|(k, v)| a.insert(k.clone(), v).map(|_| k.clone())) + .collect() +} + #[cfg(test)] mod test { use crate::config::{EwwConfig, XmlNode}; @@ -254,7 +284,7 @@ mod test { widgets: HashMap::new(), windows: HashMap::new(), initial_variables: HashMap::new(), - script_vars: Vec::new(), + script_vars: HashMap::new(), filepath: "test_path".into(), }; diff --git a/src/main.rs b/src/main.rs index 9d4fa46..51fbb95 100644 --- a/src/main.rs +++ b/src/main.rs @@ -90,7 +90,7 @@ fn main() { } else { log::info!("Initializing Eww server."); let _ = std::fs::remove_file(&*crate::IPC_SOCKET_PATH); - println!("Run `eww logs` to see any errors, warnings or informatiion while editing your configuration."); + println!("Run `eww logs` to see any errors, warnings or information while editing your configuration."); server::initialize_server()?; } }