Support Multi-file configuration (#45)
* install pango in CI * <includes> xml support and EwwConfig merging * Moved EwwConfig changes after merge * Implemented relative paths * Implemented paths in error messages * Corrected include's error context message * Written merge_includes test, fixed a simple bug * Added "includes" label error check * cargo format * install pango in CI * <includes> xml support and EwwConfig merging * Moved EwwConfig changes after merge * Implemented relative paths * Implemented paths in error messages * Corrected include's error context message * Written merge_includes test, fixed a simple bug * Added "includes" label error check * cargo format * Removed outdated comments and unused imports * Fix dependency error * Updated docs to add the <includes> block * Removed unnecessary comment Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Removed duplicated test block Should'nt be there in the first place. My bad. Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Better error context handling in eww_config.rs Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Better error context handling in eww_config.rs (again) Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> * Removed unnecessary error check Co-authored-by: ElKowar <5300871+elkowar@users.noreply.github.com> Co-authored-by: elkowar <5300871+elkowar@users.noreply.github.com> Co-authored-by: druskus20@gmail.com <druskus20>
This commit is contained in:
parent
ac8bc7d8b5
commit
bc555900d3
4 changed files with 125 additions and 9 deletions
|
@ -25,6 +25,10 @@ $HOME
|
||||||
Your config structure should look like this:
|
Your config structure should look like this:
|
||||||
```xml
|
```xml
|
||||||
<eww>
|
<eww>
|
||||||
|
<definitions>
|
||||||
|
<!-- Put your <file>'s in here -->
|
||||||
|
</definitions>
|
||||||
|
|
||||||
<definitions>
|
<definitions>
|
||||||
<!-- Put your <def>'s in here -->
|
<!-- Put your <def>'s in here -->
|
||||||
</definitions>
|
</definitions>
|
||||||
|
@ -38,7 +42,9 @@ Your config structure should look like this:
|
||||||
</windows>
|
</windows>
|
||||||
</eww>
|
</eww>
|
||||||
```
|
```
|
||||||
See [The `<definitons>` block](#the-definitions-block),
|
See
|
||||||
|
[The `<includes>` block](#the-includes-block),
|
||||||
|
[The `<definitons>` block](#the-definitions-block),
|
||||||
[Variables](#variables) and the
|
[Variables](#variables) and the
|
||||||
[The `<windows>` block](#the-windows-block).
|
[The `<windows>` 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
|
||||||
</script-var>
|
</script-var>
|
||||||
</variables>
|
</variables>
|
||||||
```
|
```
|
||||||
|
### The `<includes>` 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
|
||||||
|
<includes>
|
||||||
|
<file path="./something.xml"/>
|
||||||
|
<file path="./somethingelse.xml"/>
|
||||||
|
</includes>
|
||||||
|
```
|
||||||
|
|
||||||
### The `<definitions>` block
|
### The `<definitions>` 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.
|
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.
|
||||||
|
|
|
@ -23,15 +23,40 @@ pub struct EwwConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EwwConfig {
|
impl EwwConfig {
|
||||||
|
pub fn merge_includes(eww_config: EwwConfig, includes: Vec<EwwConfig>) -> Result<EwwConfig> {
|
||||||
|
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<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
|
pub fn read_from_file<P: AsRef<std::path::Path>>(path: P) -> Result<Self> {
|
||||||
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 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
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
|
pub fn from_xml_element<P: AsRef<std::path::Path>>(xml: XmlElement, path: P) -> Result<Self> {
|
||||||
|
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::<Result<Vec<_>>>()
|
||||||
|
.context(format!("error handling include definitions: {}", path.display()))?,
|
||||||
|
Err(_) => Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
let definitions = xml
|
let definitions = xml
|
||||||
.child("definitions")?
|
.child("definitions")?
|
||||||
.child_elements()
|
.child_elements()
|
||||||
|
@ -40,7 +65,7 @@ impl EwwConfig {
|
||||||
Ok((def.name.clone(), def))
|
Ok((def.name.clone(), def))
|
||||||
})
|
})
|
||||||
.collect::<Result<HashMap<_, _>>>()
|
.collect::<Result<HashMap<_, _>>>()
|
||||||
.context("error parsing widget definitions")?;
|
.with_context(|| format!("error parsing widget definitions: {}", path.display()))?;
|
||||||
|
|
||||||
let windows = xml
|
let windows = xml
|
||||||
.child("windows")?
|
.child("windows")?
|
||||||
|
@ -50,7 +75,7 @@ impl EwwConfig {
|
||||||
Ok((def.name.to_owned(), def))
|
Ok((def.name.to_owned(), def))
|
||||||
})
|
})
|
||||||
.collect::<Result<HashMap<_, _>>>()
|
.collect::<Result<HashMap<_, _>>>()
|
||||||
.context("error parsing window definitions")?;
|
.with_context(|| format!("error parsing window definitions: {}", path.display()))?;
|
||||||
|
|
||||||
let variables_block = xml.child("variables").ok();
|
let variables_block = xml.child("variables").ok();
|
||||||
|
|
||||||
|
@ -77,12 +102,13 @@ impl EwwConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(EwwConfig {
|
let current_config = EwwConfig {
|
||||||
widgets: definitions,
|
widgets: definitions,
|
||||||
windows,
|
windows,
|
||||||
initial_variables,
|
initial_variables,
|
||||||
script_vars,
|
script_vars,
|
||||||
})
|
};
|
||||||
|
EwwConfig::merge_includes(current_config, includes)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this is kinda ugly
|
// TODO this is kinda ugly
|
||||||
|
@ -122,3 +148,78 @@ impl EwwConfig {
|
||||||
self.script_vars.iter().find(|x| x.name() == name)
|
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#"
|
||||||
|
<eww>
|
||||||
|
<definitions>
|
||||||
|
<def name="test1">
|
||||||
|
<box orientation="v">
|
||||||
|
{{var1}}
|
||||||
|
</box>
|
||||||
|
</def>
|
||||||
|
</definitions>
|
||||||
|
|
||||||
|
<variables>
|
||||||
|
<var name="var1">var1</var>
|
||||||
|
</variables>
|
||||||
|
<windows>
|
||||||
|
<window name="window1">
|
||||||
|
<size x="100" y="200" />
|
||||||
|
<pos x="100" y="200" />
|
||||||
|
<widget>
|
||||||
|
<test1 name="test2" />
|
||||||
|
</widget>
|
||||||
|
</window>
|
||||||
|
</windows>
|
||||||
|
</eww>
|
||||||
|
"#;
|
||||||
|
let input2 = r#"
|
||||||
|
<eww>
|
||||||
|
<definitions>
|
||||||
|
<def name="test2">
|
||||||
|
<box orientation="v">
|
||||||
|
{{var2}}
|
||||||
|
</box>
|
||||||
|
</def>
|
||||||
|
</definitions>
|
||||||
|
<variables>
|
||||||
|
<var name="var2">var2</var>
|
||||||
|
</variables>
|
||||||
|
<windows>
|
||||||
|
<window name="window2">
|
||||||
|
<size x="100" y="200" />
|
||||||
|
<pos x="100" y="200" />
|
||||||
|
<widget>
|
||||||
|
<test2 name="test2" />
|
||||||
|
</widget>
|
||||||
|
</window>
|
||||||
|
</windows>
|
||||||
|
</eww>
|
||||||
|
"#;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
||||||
util,
|
util,
|
||||||
value::{PrimitiveValue, VarName},
|
value::{PrimitiveValue, VarName},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
|
|
||||||
use element::*;
|
use element::*;
|
||||||
|
|
|
@ -11,7 +11,6 @@ use crate::{
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use app::EwwCommand;
|
use app::EwwCommand;
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use std::io::BufRead;
|
use std::io::BufRead;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue