diff --git a/docs/content/main/configuration.md b/docs/content/main/configuration.md
index 0907de1..943f33a 100644
--- a/docs/content/main/configuration.md
+++ b/docs/content/main/configuration.md
@@ -25,6 +25,10 @@ $HOME
Your config structure should look like this:
```xml
+
+
+
+
@@ -38,7 +42,9 @@ Your config structure should look like this:
```
-See [The `` block](#the-definitions-block),
+See
+[The `` block](#the-includes-block),
+[The `` block](#the-definitions-block),
[Variables](#variables) and the
[The `` block](#the-windows-block).
@@ -107,6 +113,15 @@ If you don't want a set interval and instead want it to tail (run the script whe
```
+### The `` block
+Here you can include other config files so that they are merged together at startup. Currently namespaced variables are not supported so be careful when reusing code.
+
+```xml
+
+
+
+
+```
### 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/config/eww_config.rs b/src/config/eww_config.rs
index 7f170b4..923e2ec 100644
--- a/src/config/eww_config.rs
+++ b/src/config/eww_config.rs
@@ -23,15 +23,40 @@ pub struct EwwConfig {
}
impl EwwConfig {
+ pub fn merge_includes(eww_config: EwwConfig, includes: Vec) -> Result {
+ let mut eww_config = eww_config.clone();
+ 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);
+ }
+ Ok(eww_config)
+ }
+
pub fn read_from_file>(path: P) -> Result {
- let content = util::replace_env_var_references(std::fs::read_to_string(path)?);
+ let content = util::replace_env_var_references(std::fs::read_to_string(path.as_ref())?);
let document = roxmltree::Document::parse(&content)?;
- let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?.clone());
+ let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?.clone(), path.as_ref());
result
}
- pub fn from_xml_element(xml: XmlElement) -> Result {
+ pub fn from_xml_element>(xml: XmlElement, path: P) -> Result {
+ let path = path.as_ref();
+ let includes = match xml.child("includes") {
+ Ok(tag) => tag
+ .child_elements()
+ .map(|child| {
+ let childpath = child.attr("path")?;
+ let basepath = path.parent().unwrap();
+ EwwConfig::read_from_file(basepath.join(childpath))
+ })
+ .collect::>>()
+ .context(format!("error handling include definitions: {}", path.display()))?,
+ Err(_) => Vec::new(),
+ };
+
let definitions = xml
.child("definitions")?
.child_elements()
@@ -40,7 +65,7 @@ impl EwwConfig {
Ok((def.name.clone(), def))
})
.collect::>>()
- .context("error parsing widget definitions")?;
+ .with_context(|| format!("error parsing widget definitions: {}", path.display()))?;
let windows = xml
.child("windows")?
@@ -50,7 +75,7 @@ impl EwwConfig {
Ok((def.name.to_owned(), def))
})
.collect::>>()
- .context("error parsing window definitions")?;
+ .with_context(|| format!("error parsing window definitions: {}", path.display()))?;
let variables_block = xml.child("variables").ok();
@@ -77,12 +102,13 @@ impl EwwConfig {
}
}
- Ok(EwwConfig {
+ let current_config = EwwConfig {
widgets: definitions,
windows,
initial_variables,
script_vars,
- })
+ };
+ EwwConfig::merge_includes(current_config, includes)
}
// TODO this is kinda ugly
@@ -122,3 +148,78 @@ impl EwwConfig {
self.script_vars.iter().find(|x| x.name() == name)
}
}
+
+#[cfg(test)]
+mod test {
+ use crate::config::{EwwConfig, XmlNode};
+ use std::collections::HashMap;
+
+ #[test]
+ fn test_merge_includes() {
+ let input1 = r#"
+
+
+
+
+ {{var1}}
+
+
+
+
+
+ var1
+
+
+
+
+
+
+
+
+
+
+
+ "#;
+ let input2 = r#"
+
+
+
+
+ {{var2}}
+
+
+
+
+ var2
+
+
+
+
+
+
+
+
+
+
+
+ "#;
+
+ let document1 = roxmltree::Document::parse(&input1).unwrap();
+ let document2 = roxmltree::Document::parse(input2).unwrap();
+ let config1 = EwwConfig::from_xml_element(XmlNode::from(document1.root_element()).as_element().unwrap().clone(), "");
+ let config2 = EwwConfig::from_xml_element(XmlNode::from(document2.root_element()).as_element().unwrap().clone(), "");
+ let base_config = EwwConfig {
+ widgets: HashMap::new(),
+ windows: HashMap::new(),
+ initial_variables: HashMap::new(),
+ script_vars: Vec::new(),
+ };
+
+ let merged_config = EwwConfig::merge_includes(base_config, vec![config1.unwrap(), config2.unwrap()]).unwrap();
+
+ assert_eq!(merged_config.widgets.len(), 2);
+ assert_eq!(merged_config.windows.len(), 2);
+ assert_eq!(merged_config.initial_variables.len(), 2);
+ assert_eq!(merged_config.script_vars.len(), 0);
+ }
+}
diff --git a/src/config/mod.rs b/src/config/mod.rs
index 757c9d2..7654c48 100644
--- a/src/config/mod.rs
+++ b/src/config/mod.rs
@@ -2,6 +2,7 @@ use crate::{
util,
value::{PrimitiveValue, VarName},
};
+
use anyhow::*;
use element::*;
diff --git a/src/script_var_handler.rs b/src/script_var_handler.rs
index f2da059..4412c8f 100644
--- a/src/script_var_handler.rs
+++ b/src/script_var_handler.rs
@@ -11,7 +11,6 @@ use crate::{
use anyhow::*;
use app::EwwCommand;
-use itertools::Itertools;
use dashmap::DashMap;
use std::io::BufRead;