From 7c05cda33acb32b1a8ea701dfcb76cb0567a9ea8 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sun, 4 Oct 2020 23:28:58 +0200 Subject: [PATCH] Add linenumber information to more errors --- src/config/element.rs | 45 +++++++++++++++++++++++++++++++++++-------- src/config/mod.rs | 7 ++++++- src/config/xml_ext.rs | 4 ++++ src/widgets/mod.rs | 16 ++++++++++++--- 4 files changed, 60 insertions(+), 12 deletions(-) diff --git a/src/config/element.rs b/src/config/element.rs index 547910f..7fd98a6 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -1,6 +1,7 @@ use super::*; use lazy_static::lazy_static; use regex::Regex; +use std::ops::Range; use crate::value::AttrValue; use crate::with_text_pos_context; @@ -38,11 +39,23 @@ impl WidgetDefinition { } } -#[derive(Debug, Clone, PartialEq, Default)] +#[derive(Debug, Clone, Default)] pub struct WidgetUse { pub name: String, pub children: Vec, pub attrs: HashMap, + pub text_pos: Option, +} + +#[derive(Debug, Clone)] +pub struct PositionData { + pub range: Range, +} + +impl PartialEq for WidgetUse { + fn eq(&self, other: &WidgetUse) -> bool { + self.name == other.name && self.children == other.children && self.attrs == other.attrs + } } impl WidgetUse { @@ -51,18 +64,21 @@ impl WidgetUse { name, children, attrs: HashMap::new(), + ..WidgetUse::default() } } + pub fn from_xml_node(xml: XmlNode) -> Result { lazy_static! { static ref PATTERN: Regex = Regex::new("\\{\\{(.*)\\}\\}").unwrap(); }; - match xml { + let text_pos = xml.text_pos(); + let widget_use = match xml { // TODO the matching here is stupid. This currently uses the inefficient function to parse simple single varrefs, // TODO and does the regex match twice in the from_text_with_var_refs part - XmlNode::Text(text) if PATTERN.is_match(&text.text()) => Ok(WidgetUse::from_text_with_var_refs(&text.text())), - XmlNode::Text(text) => Ok(WidgetUse::simple_text(AttrValue::parse_string(text.text()))), - XmlNode::Element(elem) => Ok(WidgetUse { + XmlNode::Text(text) if PATTERN.is_match(&text.text()) => WidgetUse::from_text_with_var_refs(&text.text()), + XmlNode::Text(text) => WidgetUse::simple_text(AttrValue::parse_string(text.text())), + XmlNode::Element(elem) => WidgetUse { name: elem.tag_name().to_string(), children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::>()?}?, attrs: elem @@ -70,9 +86,11 @@ impl WidgetUse { .iter() .map(|attr| (attr.name().to_owned(), AttrValue::parse_string(attr.value().to_owned()))) .collect::>(), - }), + ..WidgetUse::default() + }, XmlNode::Ignored(_) => Err(anyhow!("Failed to parse node {:?} as widget use", xml))?, - } + }; + Ok(widget_use.at_pos(text_pos)) } pub fn simple_text(text: AttrValue) -> Self { @@ -80,6 +98,7 @@ impl WidgetUse { name: "label".to_owned(), children: vec![], attrs: hashmap! { "text".to_string() => text }, // TODO this hardcoded "text" is dumdum + ..WidgetUse::default() } } @@ -95,9 +114,15 @@ impl WidgetUse { .map(StringOrVarRef::to_attr_value) .map(WidgetUse::simple_text) .collect(), + ..WidgetUse::default() } } + pub fn at_pos(mut self, text_pos: roxmltree::TextPos) -> Self { + self.text_pos = Some(text_pos); + self + } + pub fn get_attr(&self, key: &str) -> Result<&AttrValue> { self.attrs .get(key) @@ -181,6 +206,7 @@ mod test { name: "label".to_owned(), children: Vec::new(), attrs: hashmap! { "text".to_owned() => expected_attr_value}, + ..WidgetUse::default() }, ) } @@ -198,7 +224,8 @@ mod test { children: vec![ WidgetUse::simple_text(expected_attr_value1), WidgetUse::simple_text(expected_attr_value2), - ] + ], + ..WidgetUse::default() } ) } @@ -227,6 +254,7 @@ mod test { WidgetUse::new("child_widget".to_owned(), Vec::new()), WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::String("foo".to_owned()))), ], + ..WidgetUse::default() }; assert_eq!(expected, WidgetUse::from_xml_node(xml).unwrap()); } @@ -250,6 +278,7 @@ mod test { "test".to_owned(), )))], attrs: HashMap::new(), + ..WidgetUse::default() }, }; diff --git a/src/config/mod.rs b/src/config/mod.rs index b0abdac..c8ee0fb 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -65,7 +65,12 @@ impl EwwConfig { pub fn read_from_file>(path: P) -> Result { let content = std::fs::read_to_string(path)?; let document = roxmltree::Document::parse(&content)?; - EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?) + + let start = std::time::Instant::now(); + let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?); + let end = std::time::Instant::now(); + dbg!(end - start); + result } pub fn from_xml_element(xml: XmlElement) -> Result { diff --git a/src/config/xml_ext.rs b/src/config/xml_ext.rs index f2da5f6..ab3acf5 100644 --- a/src/config/xml_ext.rs +++ b/src/config/xml_ext.rs @@ -42,6 +42,10 @@ impl<'a, 'b> XmlNode<'a, 'b> { } } + pub fn text_range(&self) -> std::ops::Range { + self.node().range() + } + pub fn text_pos(&self) -> roxmltree::TextPos { let document = self.node().document(); let range = self.node().range(); diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 33a89f8..3931252 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -61,7 +61,15 @@ pub fn build_gtk_widget( }; let gtk_widget = match widget_to_gtk_widget(&mut bargs) { Ok(Some(gtk_widget)) => gtk_widget, - result => return result, + result => { + return result.with_context(|| { + anyhow!( + "{}Error building widget {}", + bargs.widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), + bargs.widget.name, + ) + }) + } }; if let Some(gtk_widget) = gtk_widget.dynamic_cast_ref::() { @@ -70,7 +78,8 @@ pub fn build_gtk_widget( let child_widget = element_to_gtk_thing(widget_definitions, bargs.eww_state, local_env, child); let child_widget = child_widget.with_context(|| { format!( - "error while building child '{:#?}' of '{}'", + "{}error while building child '{:#?}' of '{}'", + widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), &child, >k_widget.get_widget_name() ) @@ -86,7 +95,8 @@ pub fn build_gtk_widget( if !bargs.unhandled_attrs.is_empty() { eprintln!( - "WARN: Unknown attribute used in {}: {}", + "{}WARN: Unknown attribute used in {}: {}", + widget.text_pos.map(|x| format!("{} |", x)).unwrap_or_default(), widget.name, bargs.unhandled_attrs.join(", ") )