Cleanup, improve error handling
This commit is contained in:
parent
50b8840c5b
commit
8467cf3fde
8 changed files with 215 additions and 586 deletions
223
Cargo.lock
generated
223
Cargo.lock
generated
|
@ -1,20 +1,5 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b6a2d3371669ab3ca9797670853d61402b03d0b4b9ebf33d677dfa720203072"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.3.8"
|
||||
|
@ -88,20 +73,6 @@ version = "1.0.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beef"
|
||||
version = "0.4.4"
|
||||
|
@ -156,16 +127,6 @@ dependencies = [
|
|||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "calloop"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59561a8b3968ba4bda0c46f42e0568507c5d26e94c3b6f2a0c730cbecd83ff3a"
|
||||
dependencies = [
|
||||
"log",
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.60"
|
||||
|
@ -253,76 +214,11 @@ version = "1.6.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "encoding"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b0d943856b990d12d3b55b359144ff341533e516d94098b1d3fc1ac666d36ec"
|
||||
dependencies = [
|
||||
"encoding-index-japanese",
|
||||
"encoding-index-korean",
|
||||
"encoding-index-simpchinese",
|
||||
"encoding-index-singlebyte",
|
||||
"encoding-index-tradchinese",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding-index-japanese"
|
||||
version = "1.20141219.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "04e8b2ff42e9a05335dbf8b5c6f7567e5591d0d916ccef4e0b1710d32a0d0c91"
|
||||
dependencies = [
|
||||
"encoding_index_tests",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding-index-korean"
|
||||
version = "1.20141219.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4dc33fb8e6bcba213fe2f14275f0963fd16f0a02c878e3095ecfdf5bee529d81"
|
||||
dependencies = [
|
||||
"encoding_index_tests",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding-index-simpchinese"
|
||||
version = "1.20141219.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d87a7194909b9118fc707194baa434a4e3b0fb6a5a757c73c3adb07aa25031f7"
|
||||
dependencies = [
|
||||
"encoding_index_tests",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding-index-singlebyte"
|
||||
version = "1.20141219.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3351d5acffb224af9ca265f435b859c7c01537c0849754d3db3fdf2bfe2ae84a"
|
||||
dependencies = [
|
||||
"encoding_index_tests",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding-index-tradchinese"
|
||||
version = "1.20141219.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd0e20d5688ce3cab59eb3ef3a2083a5c77bf496cb798dc6fcdb75f323890c18"
|
||||
dependencies = [
|
||||
"encoding_index_tests",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_index_tests"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a246d82be1c9d791c5dfde9a2bd045fc3cbba3fa2b11ad558f27d01712f00569"
|
||||
|
||||
[[package]]
|
||||
name = "eww"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"calloop",
|
||||
"crossbeam-channel",
|
||||
"derive_more",
|
||||
"extend",
|
||||
|
@ -331,7 +227,6 @@ dependencies = [
|
|||
"glib",
|
||||
"grass",
|
||||
"gtk",
|
||||
"hocon",
|
||||
"hotwatch",
|
||||
"ipc-channel",
|
||||
"itertools",
|
||||
|
@ -358,28 +253,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"failure_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.12"
|
||||
|
@ -604,12 +477,6 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aaf91faf136cb47367fa430cd46e37a788775e7fa104f8b4bcb3861dc389b724"
|
||||
|
||||
[[package]]
|
||||
name = "gio"
|
||||
version = "0.9.1"
|
||||
|
@ -800,20 +667,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hocon"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39554b1a6dc84511d3f8c0287ad63a78de60444b4032aec529d9e303ceaf0641"
|
||||
dependencies = [
|
||||
"failure",
|
||||
"java-properties",
|
||||
"memchr",
|
||||
"nom",
|
||||
"serde",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hotwatch"
|
||||
version = "0.4.3"
|
||||
|
@ -890,16 +743,6 @@ dependencies = [
|
|||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "java-properties"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "caf4418ade5bde22a283a7f2fb537ea397ec102718f259f2630714e7a5b389fa"
|
||||
dependencies = [
|
||||
"encoding",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
|
@ -964,16 +807,6 @@ version = "2.3.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c60c0dfe32c10b43a144bad8fc83538c52f58302c92300ea7ec7bf7b38d5a7b9"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.22"
|
||||
|
@ -1028,28 +861,6 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.18.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83450fe6a6142ddd95fb064b746083fc4ef1705fe81f64a64e1d4b39f54a1055"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"version_check 0.1.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.15"
|
||||
|
@ -1144,12 +955,6 @@ dependencies = [
|
|||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.4.1"
|
||||
|
@ -1314,7 +1119,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check 0.9.2",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1325,7 +1130,7 @@ checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check 0.9.2",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1451,12 +1256,6 @@ dependencies = [
|
|||
"xmlparser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -1569,18 +1368,6 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-deps"
|
||||
version = "1.3.2"
|
||||
|
@ -1719,12 +1506,6 @@ version = "0.0.10"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.2"
|
||||
|
|
|
@ -13,7 +13,6 @@ gio = { version = "", features = ["v2_44"] }
|
|||
glib = { version = "", features = ["v2_44"] }
|
||||
|
||||
regex = "1"
|
||||
hocon = { version = "0.3", default-features = false, features = [ "serde-support" ]}
|
||||
try_match = "0.2.2"
|
||||
anyhow = "1.0"
|
||||
derive_more = "0.99"
|
||||
|
@ -24,7 +23,6 @@ serde = {version = "1.0", features = ["derive"]}
|
|||
extend = "0.3.0"
|
||||
grass = "0.10"
|
||||
hotwatch = "0.4"
|
||||
calloop = "0.6"
|
||||
crossbeam-channel = "0.4"
|
||||
num = "0.3"
|
||||
stoppable_thread = "0.2"
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use super::*;
|
||||
|
||||
use crate::value::AttrValue;
|
||||
use hocon_ext::HoconExt;
|
||||
use crate::with_text_pos_context;
|
||||
use maplit::hashmap;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct WidgetDefinition {
|
||||
|
@ -15,6 +14,7 @@ pub struct WidgetDefinition {
|
|||
|
||||
impl WidgetDefinition {
|
||||
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
|
||||
with_text_pos_context! { xml =>
|
||||
if xml.tag_name() != "def" {
|
||||
bail!(
|
||||
"Illegal element: only <def> may be used in definition block, but found '{}'",
|
||||
|
@ -22,36 +22,17 @@ impl WidgetDefinition {
|
|||
);
|
||||
}
|
||||
|
||||
let size: Option<Result<_>> = xml
|
||||
.child("size")
|
||||
.ok()
|
||||
.map(|node| Ok((node.attr("x")?.parse()?, node.attr("y")?.parse()?)));
|
||||
let size: Option<_> = try {
|
||||
(xml.attr("width").ok()?, xml.attr("height").ok()?)
|
||||
};
|
||||
let size: Option<Result<_>> = size.map(|(x, y)| Ok((x.parse()?, y.parse()?)));
|
||||
|
||||
Ok(WidgetDefinition {
|
||||
WidgetDefinition {
|
||||
name: xml.attr("name")?.to_owned(),
|
||||
size: size.transpose()?,
|
||||
structure: WidgetUse::from_xml_node(xml.only_child()?)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_hocon(name: String, hocon: &Hocon) -> Result<Self> {
|
||||
let definition = hocon.as_hash()?;
|
||||
let structure = definition
|
||||
.get("structure")
|
||||
.cloned()
|
||||
.context("structure must be set in widget definition")
|
||||
.and_then(WidgetUse::parse_hocon)?;
|
||||
|
||||
Ok(WidgetDefinition {
|
||||
name,
|
||||
structure,
|
||||
size: try {
|
||||
(
|
||||
definition.get("size_x")?.as_i64()? as i32,
|
||||
definition.get("size_y")?.as_i64()? as i32,
|
||||
)
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,24 +43,6 @@ pub struct WidgetUse {
|
|||
pub attrs: HashMap<String, AttrValue>,
|
||||
}
|
||||
|
||||
impl WidgetUse {
|
||||
pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
|
||||
match xml {
|
||||
XmlNode::Text(text) => Ok(WidgetUse::simple_text(AttrValue::parse_string(text.text()))),
|
||||
XmlNode::Element(elem) => Ok(WidgetUse {
|
||||
name: elem.tag_name().to_string(),
|
||||
children: elem.children().map(WidgetUse::from_xml_node).collect::<Result<_>>()?,
|
||||
attrs: elem
|
||||
.attributes()
|
||||
.iter()
|
||||
.map(|attr| (attr.name().to_owned(), AttrValue::parse_string(attr.value().to_owned())))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
}),
|
||||
XmlNode::Ignored(_) => Err(anyhow!("Failed to parse node {:?} as widget use", xml)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WidgetUse {
|
||||
pub fn new(name: String, children: Vec<WidgetUse>) -> Self {
|
||||
WidgetUse {
|
||||
|
@ -88,49 +51,21 @@ impl WidgetUse {
|
|||
attrs: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_hocon(data: Hocon) -> Result<Self> {
|
||||
match data {
|
||||
Hocon::Hash(data) => {
|
||||
let (widget_name, widget_config) = data.into_iter().next().context("tried to parse empty hash as widget use")?;
|
||||
match widget_config {
|
||||
Hocon::Hash(widget_config) => WidgetUse::from_hash_definition(widget_name.clone(), widget_config),
|
||||
direct_childen => Ok(WidgetUse::new(
|
||||
widget_name.clone(),
|
||||
parse_widget_use_children(direct_childen)?,
|
||||
)),
|
||||
pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
|
||||
match xml {
|
||||
XmlNode::Text(text) => Ok(WidgetUse::simple_text(AttrValue::parse_string(text.text()))),
|
||||
XmlNode::Element(elem) => Ok(WidgetUse {
|
||||
name: elem.tag_name().to_string(),
|
||||
children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::<Result<_>>()?}?,
|
||||
attrs: elem
|
||||
.attributes()
|
||||
.iter()
|
||||
.map(|attr| (attr.name().to_owned(), AttrValue::parse_string(attr.value().to_owned())))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
}),
|
||||
XmlNode::Ignored(_) => Err(anyhow!("Failed to parse node {:?} as widget use", xml))?,
|
||||
}
|
||||
}
|
||||
primitive => Ok(WidgetUse::simple_text(AttrValue::try_from(&primitive)?)),
|
||||
}
|
||||
}
|
||||
|
||||
/// generate a WidgetUse from an array-style definition
|
||||
/// i.e.: { layout: [ "hi", "ho" ] }
|
||||
pub fn from_array_definition(widget_name: String, children: Vec<Hocon>) -> Result<Self> {
|
||||
let children = children.into_iter().map(WidgetUse::parse_hocon).collect::<Result<_>>()?;
|
||||
Ok(WidgetUse::new(widget_name, children))
|
||||
}
|
||||
|
||||
/// generate a WidgetUse from a hash-style definition
|
||||
/// i.e.: { layout: { orientation: "v", children: ["hi", "Ho"] } }
|
||||
pub fn from_hash_definition(widget_name: String, mut widget_config: HashMap<String, Hocon>) -> Result<Self> {
|
||||
let children = widget_config
|
||||
.remove("children")
|
||||
.map(parse_widget_use_children)
|
||||
.unwrap_or(Ok(Vec::new()))?;
|
||||
|
||||
let attrs = widget_config
|
||||
.into_iter()
|
||||
.filter_map(|(key, value)| Some((key.to_lowercase(), AttrValue::try_from(&value).ok()?)))
|
||||
.collect();
|
||||
|
||||
Ok(WidgetUse {
|
||||
name: widget_name.to_string(),
|
||||
children,
|
||||
attrs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn simple_text(text: AttrValue) -> Self {
|
||||
WidgetUse {
|
||||
|
@ -147,94 +82,79 @@ impl WidgetUse {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn parse_widget_use_children(children: Hocon) -> Result<Vec<WidgetUse>> {
|
||||
match children {
|
||||
Hocon::Hash(_) => bail!(
|
||||
"children of a widget must either be a list of widgets or a primitive value, but got hash: {:?}",
|
||||
children
|
||||
),
|
||||
Hocon::Array(widget_children) => widget_children
|
||||
.into_iter()
|
||||
.map(WidgetUse::parse_hocon)
|
||||
.collect::<Result<Vec<_>>>(),
|
||||
primitive => Ok(vec![WidgetUse::simple_text(AttrValue::try_from(&primitive)?)]),
|
||||
}
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use maplit::hashmap;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
#[test]
|
||||
fn test_simple_text() {
|
||||
let expected_attr_value = AttrValue::Concrete(PrimitiveValue::String("my text".to_owned()));
|
||||
let widget = WidgetUse::simple_text(expected_attr_value.clone());
|
||||
assert_eq!(
|
||||
widget,
|
||||
WidgetUse {
|
||||
name: "label".to_owned(),
|
||||
children: Vec::new(),
|
||||
attrs: hashmap! { "text".to_owned() => expected_attr_value},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
//#[cfg(test)]
|
||||
//mod test {
|
||||
//use super::*;
|
||||
//use maplit::hashmap;
|
||||
//use pretty_assertions::assert_eq;
|
||||
#[test]
|
||||
fn test_parse_widget_use() {
|
||||
let input = r#"
|
||||
<widget_name attr1="hi" attr2="12">
|
||||
<child_widget/>
|
||||
foo
|
||||
</widget_name>
|
||||
"#;
|
||||
let document = roxmltree::Document::parse(input).unwrap();
|
||||
let xml = XmlNode::from(document.root_element().clone());
|
||||
|
||||
//#[test]
|
||||
//fn test_parse_widget_use() {
|
||||
//let input_complex = r#"{
|
||||
//widget_name: {
|
||||
//value: "test"
|
||||
//children: [
|
||||
//{ child: {} }
|
||||
//{ child: { children: ["hi"] } }
|
||||
//]
|
||||
//}
|
||||
//}"#;
|
||||
//let expected = WidgetUse {
|
||||
//name: "widget_name".to_string(),
|
||||
//children: vec![
|
||||
//WidgetUse::new("child".to_string(), vec![]),
|
||||
//WidgetUse::new(
|
||||
//"child".to_string(),
|
||||
//vec![WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String(
|
||||
//"hi".to_string(),
|
||||
//)))],
|
||||
//),
|
||||
//],
|
||||
//attrs: hashmap! { "value".to_string() => AttrValue::Concrete(PrimitiveValue::String("test".to_string()))},
|
||||
//};
|
||||
//assert_eq!(
|
||||
//WidgetUse::parse_hocon(parse_hocon(input_complex).unwrap().clone()).unwrap(),
|
||||
//expected
|
||||
//);
|
||||
//}
|
||||
println!("{}", xml);
|
||||
assert_eq!(true, false);
|
||||
|
||||
//#[test]
|
||||
//fn test_parse_widget_definition() {
|
||||
//let input_complex = r#"{
|
||||
//structure: { foo: {} }
|
||||
//}"#;
|
||||
//let expected = WidgetDefinition {
|
||||
//name: "widget_name".to_string(),
|
||||
//structure: WidgetUse::new("foo".to_string(), vec![]),
|
||||
//size: None,
|
||||
//};
|
||||
//assert_eq!(
|
||||
//WidgetDefinition::parse_hocon("widget_name".to_string(), &parse_hocon(input_complex).unwrap()).unwrap(),
|
||||
//expected
|
||||
//);
|
||||
//}
|
||||
let expected = WidgetUse {
|
||||
name: "widget_name".to_owned(),
|
||||
attrs: hashmap! {
|
||||
"attr1".to_owned() => AttrValue::Concrete(PrimitiveValue::String("hi".to_owned())),
|
||||
"attr2".to_owned() => AttrValue::Concrete(PrimitiveValue::Number(12f64)),
|
||||
},
|
||||
children: vec![
|
||||
WidgetUse::new("child_widget".to_owned(), Vec::new()),
|
||||
WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String("foo".to_owned()))),
|
||||
],
|
||||
};
|
||||
assert_eq!(expected, WidgetUse::from_xml_node(xml).unwrap());
|
||||
}
|
||||
|
||||
//#[test]
|
||||
//fn test_parse_widget_use_xml() {
|
||||
//let input = r#"
|
||||
//<widget_name attr1="hi" attr2="12">
|
||||
//<child_widget/>
|
||||
//foo
|
||||
//</widget_name>
|
||||
//"#;
|
||||
//let document = roxmltree::Document::parse(input).unwrap();
|
||||
//let xml = document.root_element().clone();
|
||||
#[test]
|
||||
fn test_parse_widget_definition() {
|
||||
let input = r#"
|
||||
<def name="foo" width="12" height="20">
|
||||
<layout>test</layout>
|
||||
</def>
|
||||
"#;
|
||||
let document = roxmltree::Document::parse(input).unwrap();
|
||||
let xml = XmlNode::from(document.root_element().clone());
|
||||
|
||||
//let expected = WidgetUse {
|
||||
//name: "widget_name".to_owned(),
|
||||
//attrs: hashmap! {
|
||||
//"attr1".to_owned() => AttrValue::Concrete(PrimitiveValue::String("hi".to_owned())),
|
||||
//"attr2".to_owned() => AttrValue::Concrete(PrimitiveValue::Number(12f64)),
|
||||
//},
|
||||
//children: vec![
|
||||
//WidgetUse::new("child_widget".to_owned(), Vec::new()),
|
||||
//WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String("foo".to_owned()))),
|
||||
//],
|
||||
//};
|
||||
//assert_eq!(expected, WidgetUse::from_xml(xml).unwrap());
|
||||
//}
|
||||
//}
|
||||
let expected = WidgetDefinition {
|
||||
name: "foo".to_owned(),
|
||||
size: Some((12, 20)),
|
||||
structure: WidgetUse {
|
||||
name: "layout".to_owned(),
|
||||
children: vec![WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String(
|
||||
"test".to_owned(),
|
||||
)))],
|
||||
attrs: HashMap::new(),
|
||||
},
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
expected,
|
||||
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
use anyhow::*;
|
||||
use hocon::Hocon;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub trait HoconExt: Sized {
|
||||
fn as_hash(&self) -> Result<&HashMap<String, Self>>;
|
||||
fn as_array(&self) -> Result<&Vec<Self>>;
|
||||
}
|
||||
|
||||
impl HoconExt for Hocon {
|
||||
fn as_hash(&self) -> Result<&HashMap<String, Self>> {
|
||||
match self {
|
||||
Hocon::Hash(x) => Ok(x),
|
||||
_ => Err(anyhow!("as_hash called with {:?}", self)),
|
||||
}
|
||||
}
|
||||
fn as_array(&self) -> Result<&Vec<Self>> {
|
||||
match self {
|
||||
Hocon::Array(x) => Ok(x),
|
||||
_ => Err(anyhow!("as_array called with {:?}", self)),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +1,10 @@
|
|||
use crate::value::PrimitiveValue;
|
||||
use anyhow::*;
|
||||
use element::*;
|
||||
use hocon::*;
|
||||
use hocon_ext::HoconExt;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::TryFrom;
|
||||
use xml_ext::*;
|
||||
|
||||
pub mod element;
|
||||
pub mod hocon_ext;
|
||||
pub mod xml_ext;
|
||||
|
||||
#[allow(unused)]
|
||||
|
@ -80,40 +76,6 @@ impl EwwConfig {
|
|||
}))
|
||||
}
|
||||
|
||||
pub fn from_hocon(hocon: &Hocon) -> Result<Self> {
|
||||
let data = hocon.as_hash()?;
|
||||
|
||||
let widgets = data
|
||||
.get("widgets")
|
||||
.context("widgets field missing")?
|
||||
.as_hash()?
|
||||
.iter()
|
||||
.map(|(n, def)| Ok((n.clone(), WidgetDefinition::parse_hocon(n.clone(), def)?)))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let windows = data
|
||||
.get("windows")
|
||||
.context("windows field missing")?
|
||||
.as_hash()?
|
||||
.iter()
|
||||
.map(|(name, def)| Ok((name.clone(), EwwWindowDefinition::from_hocon(def)?)))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
let default_vars = data
|
||||
.get("default_vars")
|
||||
.unwrap_or(&Hocon::Hash(HashMap::new()))
|
||||
.as_hash()?
|
||||
.iter()
|
||||
.map(|(name, def)| Ok((name.clone(), PrimitiveValue::try_from(def)?)))
|
||||
.collect::<Result<_>>()?;
|
||||
|
||||
Ok(EwwConfig {
|
||||
widgets,
|
||||
windows,
|
||||
default_vars,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_widgets(&self) -> &HashMap<String, WidgetDefinition> {
|
||||
&self.widgets
|
||||
}
|
||||
|
@ -149,33 +111,4 @@ impl EwwWindowDefinition {
|
|||
let widget = WidgetUse::from_xml_node(xml.child("widget")?.only_child()?)?;
|
||||
Ok(EwwWindowDefinition { position, size, widget })
|
||||
}
|
||||
|
||||
pub fn from_hocon(hocon: &Hocon) -> Result<Self> {
|
||||
let data = hocon.as_hash().context("window config has to be a map structure")?;
|
||||
let position: Option<_> = try {
|
||||
(
|
||||
data.get("pos")?.as_hash().ok()?.get("x")?.as_i64()? as i32,
|
||||
data.get("pos")?.as_hash().ok()?.get("y")?.as_i64()? as i32,
|
||||
)
|
||||
};
|
||||
let size: Option<_> = try {
|
||||
(
|
||||
data.get("size")?.as_hash().ok()?.get("x")?.as_i64()? as i32,
|
||||
data.get("size")?.as_hash().ok()?.get("y")?.as_i64()? as i32,
|
||||
)
|
||||
};
|
||||
|
||||
let element = WidgetUse::parse_hocon(data.get("widget").context("no widget use given")?.clone())?;
|
||||
|
||||
Ok(EwwWindowDefinition {
|
||||
position: position.context("pos.x and pos.y need to be set")?,
|
||||
size: size.context("size.x and size.y need to be set")?,
|
||||
widget: element,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_hocon(s: &str) -> Result<Hocon> {
|
||||
let s = s.trim();
|
||||
Ok(HoconLoader::new().strict().load_str(s)?.hocon()?)
|
||||
}
|
||||
|
|
|
@ -1,24 +1,14 @@
|
|||
use crate::util::StringExt;
|
||||
use anyhow::*;
|
||||
use extend::ext;
|
||||
use itertools::Itertools;
|
||||
use std::fmt;
|
||||
|
||||
#[ext(pub)]
|
||||
impl<'a, 'b> roxmltree::Node<'a, 'b> {
|
||||
fn find_child_with_tag(&self, tag_name: &str) -> Result<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.children()
|
||||
.find(|child| child.tag_name().name() == tag_name)
|
||||
.with_context(|| anyhow!("node {} contained no child of type {}", self.tag_name().name(), tag_name,))
|
||||
}
|
||||
|
||||
fn try_attribute(&self, key: &str) -> Result<&str> {
|
||||
self.attribute(key)
|
||||
.with_context(|| anyhow!("attribute '{}' missing from '{}'", key, self.tag_name().name()))
|
||||
}
|
||||
#[macro_export]
|
||||
macro_rules! with_text_pos_context {
|
||||
($node:expr => $($code:tt)*) => {{
|
||||
let result: Result<_> = try { $($code)* };
|
||||
result.with_context(|| anyhow!("at: {}", $node.text_pos()))
|
||||
}};
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -37,30 +27,6 @@ impl<'a, 'b> fmt::Display for XmlNode<'a, 'b> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XmlElement<'a, 'b>(roxmltree::Node<'a, 'b>);
|
||||
|
||||
impl<'a, 'b> fmt::Display for XmlElement<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let children = self
|
||||
.children()
|
||||
.map(|child| format!("{}", child))
|
||||
.map(|x| x.lines().map(|line| format!(" {}", line)).join("\n"))
|
||||
.join("\n");
|
||||
|
||||
write!(f, "{}{}</{}>", self.as_tag_string(), children, self.tag_name())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XmlText<'a, 'b>(roxmltree::Node<'a, 'b>);
|
||||
|
||||
impl<'a, 'b> fmt::Display for XmlText<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Text({})", self.0.text().unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> XmlNode<'a, 'b> {
|
||||
pub fn as_text(self) -> Result<XmlText<'a, 'b>> {
|
||||
match self {
|
||||
|
@ -75,12 +41,60 @@ impl<'a, 'b> XmlNode<'a, 'b> {
|
|||
_ => Err(anyhow!("'{}' is not an element node", self)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_pos(&self) -> roxmltree::TextPos {
|
||||
let document = self.node().document();
|
||||
let range = self.node().range();
|
||||
document.text_pos_at(range.start)
|
||||
}
|
||||
|
||||
fn node(&self) -> roxmltree::Node<'a, 'b> {
|
||||
match self {
|
||||
XmlNode::Text(x) => x.0,
|
||||
XmlNode::Element(x) => x.0,
|
||||
XmlNode::Ignored(x) => x.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XmlText<'a, 'b>(roxmltree::Node<'a, 'b>);
|
||||
|
||||
impl<'a, 'b> fmt::Display for XmlText<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Text(\"{}\")", self.text())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> XmlText<'a, 'b> {
|
||||
pub fn text(&self) -> String {
|
||||
self.0.text().unwrap_or_default().trim_lines().trim_matches('\n').to_owned()
|
||||
}
|
||||
|
||||
pub fn text_pos(&self) -> roxmltree::TextPos {
|
||||
let document = self.0.document();
|
||||
let range = self.0.range();
|
||||
document.text_pos_at(range.start)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XmlElement<'a, 'b>(roxmltree::Node<'a, 'b>);
|
||||
|
||||
impl<'a, 'b> fmt::Display for XmlElement<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let children = self
|
||||
.children()
|
||||
.map(|child| format!("{}", child))
|
||||
.map(|x| x.lines().map(|line| format!(" {}", line)).join("\n"))
|
||||
.join("\n");
|
||||
|
||||
if children.len() == 0 {
|
||||
write!(f, "{}</{}>", self.as_tag_string(), self.tag_name())
|
||||
} else {
|
||||
write!(f, "{}\n{}\n</{}>", self.as_tag_string(), children, self.tag_name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'b> XmlElement<'a, 'b> {
|
||||
|
@ -98,9 +112,11 @@ impl<'a, 'b> XmlElement<'a, 'b> {
|
|||
}
|
||||
|
||||
pub fn child(&self, tagname: &str) -> Result<XmlElement> {
|
||||
with_text_pos_context! { self =>
|
||||
self.child_elements()
|
||||
.find(|child| child.tag_name() == tagname)
|
||||
.with_context(|| anyhow!("child element '{}' missing from {}", tagname, self.as_tag_string()))
|
||||
.with_context(|| anyhow!("child element '{}' missing from {}", tagname, self.as_tag_string()))?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn children(&self) -> impl Iterator<Item = XmlNode> {
|
||||
|
@ -118,24 +134,36 @@ impl<'a, 'b> XmlElement<'a, 'b> {
|
|||
}
|
||||
|
||||
pub fn attr(&self, key: &str) -> Result<&str> {
|
||||
with_text_pos_context! { self =>
|
||||
self.0
|
||||
.attribute(key)
|
||||
.with_context(|| anyhow!("'{}' missing attribute '{}'", self.as_tag_string(), key))
|
||||
.with_context(|| anyhow!("'{}' missing attribute '{}'", self.as_tag_string(), key))?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn only_child(&self) -> Result<XmlNode> {
|
||||
with_text_pos_context! { self =>
|
||||
let mut children_iter = self.children();
|
||||
let only_child = children_iter
|
||||
.next()
|
||||
.context(anyhow!("'{}' had no children", self.as_tag_string()))?;
|
||||
.with_context(|| anyhow!("'{}' had no children", self.as_tag_string()))?;
|
||||
if children_iter.next().is_some() {
|
||||
bail!("'{}' had more than one child", &self);
|
||||
}
|
||||
Ok(only_child)
|
||||
only_child
|
||||
}
|
||||
}
|
||||
|
||||
pub fn only_child_element(&self) -> Result<XmlElement> {
|
||||
Ok(self.only_child()?.as_element()?)
|
||||
with_text_pos_context! { self =>
|
||||
self.only_child()?.as_element()?
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text_pos(&self) -> roxmltree::TextPos {
|
||||
let document = self.0.document();
|
||||
let range = self.0.range();
|
||||
document.text_pos_at(range.start)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
50
src/value.rs
50
src/value.rs
|
@ -1,22 +1,37 @@
|
|||
use anyhow::*;
|
||||
use derive_more;
|
||||
use hocon::Hocon;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use try_match::try_match;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, derive_more::From)]
|
||||
#[derive(Clone, PartialEq, Deserialize, Serialize, derive_more::From)]
|
||||
pub enum PrimitiveValue {
|
||||
String(String),
|
||||
Number(f64),
|
||||
Boolean(bool),
|
||||
}
|
||||
|
||||
impl fmt::Display for PrimitiveValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
PrimitiveValue::String(s) => write!(f, "\"{}\"", s),
|
||||
PrimitiveValue::Number(n) => write!(f, "{}", n),
|
||||
PrimitiveValue::Boolean(b) => write!(f, "{}", b),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for PrimitiveValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::str::FromStr for PrimitiveValue {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
/// parses the value, trying to turn it into a number and a boolean first, before deciding that it is a string.
|
||||
fn from_str(s: &str) -> Result<PrimitiveValue> {
|
||||
fn from_str(s: &str) -> Result<Self> {
|
||||
Ok(PrimitiveValue::parse_string(s))
|
||||
}
|
||||
}
|
||||
|
@ -87,22 +102,6 @@ impl PrimitiveValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&Hocon> for PrimitiveValue {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(value: &Hocon) -> Result<Self> {
|
||||
Ok(match value {
|
||||
Hocon::String(s) if s.starts_with("$$") => {
|
||||
return Err(anyhow!("Tried to use variable reference {} as primitive value", s))
|
||||
}
|
||||
Hocon::String(s) => PrimitiveValue::String(s.to_string()),
|
||||
Hocon::Integer(n) => PrimitiveValue::Number(*n as f64),
|
||||
Hocon::Real(n) => PrimitiveValue::Number(*n as f64),
|
||||
Hocon::Boolean(b) => PrimitiveValue::Boolean(*b),
|
||||
_ => return Err(anyhow!("cannot convert {} to config::ConcreteValue")),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum AttrValue {
|
||||
Concrete(PrimitiveValue),
|
||||
|
@ -151,16 +150,3 @@ impl From<PrimitiveValue> for AttrValue {
|
|||
AttrValue::Concrete(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&Hocon> for AttrValue {
|
||||
type Error = anyhow::Error;
|
||||
fn try_from(value: &Hocon) -> Result<Self> {
|
||||
Ok(match value {
|
||||
Hocon::String(s) => AttrValue::parse_string(s.clone()),
|
||||
Hocon::Integer(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)),
|
||||
Hocon::Real(n) => AttrValue::Concrete(PrimitiveValue::Number(*n as f64)),
|
||||
Hocon::Boolean(b) => AttrValue::Concrete(PrimitiveValue::Boolean(*b)),
|
||||
_ => return Err(anyhow!("cannot convert {:?} to config::AttrValue", &value)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,8 +113,14 @@ fn build_gtk_label(bargs: &mut BuilderArgs) -> Result<gtk::Label> {
|
|||
Ok(gtk_widget)
|
||||
}
|
||||
|
||||
// TODO this is rather ugly,.....
|
||||
fn build_gtk_text(bargs: &mut BuilderArgs) -> Result<gtk::Label> {
|
||||
let text = bargs.widget.children.first().unwrap().get_attr("text")?;
|
||||
let text = bargs
|
||||
.widget
|
||||
.children
|
||||
.first()
|
||||
.context("text node must contain exactly one child")?
|
||||
.get_attr("text")?;
|
||||
let gtk_widget = gtk::Label::new(None);
|
||||
bargs.eww_state.resolve_str(
|
||||
bargs.local_env,
|
||||
|
|
Loading…
Add table
Reference in a new issue