From 3d5509b5701a1120a77a7502480221386bf0acf8 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Sun, 11 Oct 2020 17:53:45 +0200 Subject: [PATCH] Add inline xml support for vars --- src/config/element.rs | 2 +- src/config/mod.rs | 4 +-- src/config/xml_ext.rs | 41 ++++++++++++++++++++++++++----- src/widgets/widget_definitions.rs | 24 +++++++++--------- 4 files changed, 51 insertions(+), 20 deletions(-) diff --git a/src/config/element.rs b/src/config/element.rs index 33aefdb..fe49dcd 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -286,7 +286,7 @@ mod test { assert_eq!( expected, - WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap() + WidgetDefinition::from_xml_element(xml.as_element().unwrap().to_owned()).unwrap() ); } diff --git a/src/config/mod.rs b/src/config/mod.rs index 3db88b4..c5c3042 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -57,7 +57,7 @@ impl EwwConfig { let content = std::fs::read_to_string(path)?; let document = roxmltree::Document::parse(&content)?; - let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?); + let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?.clone()); result } @@ -97,7 +97,7 @@ impl EwwConfig { PrimitiveValue::parse_string( &node .only_child() - .and_then(|c| Ok(c.as_text()?.text())) + .map(|c| c.as_text_or_sourcecode()) .unwrap_or_else(|_| String::new()), ), ); diff --git a/src/config/xml_ext.rs b/src/config/xml_ext.rs index 9ee5a36..fc715a4 100644 --- a/src/config/xml_ext.rs +++ b/src/config/xml_ext.rs @@ -11,7 +11,7 @@ macro_rules! with_text_pos_context { }}; } -#[derive(Debug)] +#[derive(Debug, Clone)] pub enum XmlNode<'a, 'b> { Element(XmlElement<'a, 'b>), Text(XmlText<'a, 'b>), @@ -28,15 +28,44 @@ impl<'a, 'b> fmt::Display for XmlNode<'a, 'b> { } } +/// Get the part of a string that is selected by the start and end TextPos. +/// Will panic if the range is out of bounds in any way. +fn get_text_from_text_range(s: &str, (start_pos, end_pos): (roxmltree::TextPos, roxmltree::TextPos)) -> String { + let mut code_text = s + .lines() + .dropping(start_pos.row as usize - 1) + .take(end_pos.row as usize - (start_pos.row as usize - 1)) + .collect_vec(); + if let Some(first_line) = code_text.first_mut() { + *first_line = first_line.split_at(start_pos.col as usize - 1).1; + } + if let Some(last_line) = code_text.last_mut() { + *last_line = last_line.split_at(end_pos.col as usize - 1).0; + } + code_text.join("\n") +} + impl<'a, 'b> XmlNode<'a, 'b> { - pub fn as_text(self) -> Result> { + pub fn get_sourcecode(&self) -> String { + let input_text = self.node().document().input_text(); + let range = self.node().range(); + let start_pos = self.node().document().text_pos_at(range.start); + let end_pos = self.node().document().text_pos_at(range.end); + get_text_from_text_range(input_text, (start_pos, end_pos)) + } + + pub fn as_text_or_sourcecode(&self) -> String { + self.as_text().map(|c| c.text()).unwrap_or_else(|_| self.get_sourcecode()) + } + + pub fn as_text(&self) -> Result<&XmlText<'a, 'b>> { match self { XmlNode::Text(text) => Ok(text), _ => Err(anyhow!("'{}' is not a text node", self)), } } - pub fn as_element(self) -> Result> { + pub fn as_element(&self) -> Result<&XmlElement<'a, 'b>> { match self { XmlNode::Element(element) => Ok(element), _ => Err(anyhow!("'{}' is not an element node", self)), @@ -62,7 +91,7 @@ impl<'a, 'b> XmlNode<'a, 'b> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct XmlText<'a, 'b>(roxmltree::Node<'a, 'b>); impl<'a, 'b> fmt::Display for XmlText<'a, 'b> { @@ -83,7 +112,7 @@ impl<'a, 'b> XmlText<'a, 'b> { } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct XmlElement<'a, 'b>(roxmltree::Node<'a, 'b>); impl<'a, 'b> fmt::Display for XmlElement<'a, 'b> { @@ -161,7 +190,7 @@ impl<'a, 'b> XmlElement<'a, 'b> { pub fn only_child_element(&self) -> Result { with_text_pos_context! { self => - self.only_child()?.as_element()? + self.only_child()?.as_element()?.clone() } } diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index 62c203f..df69db3 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -146,18 +146,20 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result { let widget_definitions = bargs.widget_definitions.clone(); resolve_block!(bargs, gtk_widget, { prop(content: as_string) { - let document = roxmltree::Document::parse(&content)?; - let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?; - let child_widget = super::widget_use_to_gtk_widget( - &widget_definitions, - &mut eww_state::EwwState::default(), - &window_name, - &std::collections::HashMap::new(), - &content_widget_use, - )?; gtk_widget.get_children().iter().for_each(|w| gtk_widget.remove(w)); - gtk_widget.add(&child_widget); - child_widget.show(); + if !content.is_empty() { + let document = roxmltree::Document::parse(&content)?; + let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?; + let child_widget = super::widget_use_to_gtk_widget( + &widget_definitions, + &mut eww_state::EwwState::default(), + &window_name, + &std::collections::HashMap::new(), + &content_widget_use, + )?; + gtk_widget.add(&child_widget); + child_widget.show(); + } } }); Ok(gtk_widget)