Add inline xml support for vars

This commit is contained in:
elkowar 2020-10-11 17:53:45 +02:00
parent 42ae0e6d04
commit 3d5509b570
4 changed files with 51 additions and 20 deletions

View file

@ -286,7 +286,7 @@ mod test {
assert_eq!( assert_eq!(
expected, expected,
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap() WidgetDefinition::from_xml_element(xml.as_element().unwrap().to_owned()).unwrap()
); );
} }

View file

@ -57,7 +57,7 @@ impl EwwConfig {
let content = std::fs::read_to_string(path)?; let content = std::fs::read_to_string(path)?;
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()?); let result = EwwConfig::from_xml_element(XmlNode::from(document.root_element()).as_element()?.clone());
result result
} }
@ -97,7 +97,7 @@ impl EwwConfig {
PrimitiveValue::parse_string( PrimitiveValue::parse_string(
&node &node
.only_child() .only_child()
.and_then(|c| Ok(c.as_text()?.text())) .map(|c| c.as_text_or_sourcecode())
.unwrap_or_else(|_| String::new()), .unwrap_or_else(|_| String::new()),
), ),
); );

View file

@ -11,7 +11,7 @@ macro_rules! with_text_pos_context {
}}; }};
} }
#[derive(Debug)] #[derive(Debug, Clone)]
pub enum XmlNode<'a, 'b> { pub enum XmlNode<'a, 'b> {
Element(XmlElement<'a, 'b>), Element(XmlElement<'a, 'b>),
Text(XmlText<'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> { impl<'a, 'b> XmlNode<'a, 'b> {
pub fn as_text(self) -> Result<XmlText<'a, 'b>> { 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 { match self {
XmlNode::Text(text) => Ok(text), XmlNode::Text(text) => Ok(text),
_ => Err(anyhow!("'{}' is not a text node", self)), _ => Err(anyhow!("'{}' is not a text node", self)),
} }
} }
pub fn as_element(self) -> Result<XmlElement<'a, 'b>> { pub fn as_element(&self) -> Result<&XmlElement<'a, 'b>> {
match self { match self {
XmlNode::Element(element) => Ok(element), XmlNode::Element(element) => Ok(element),
_ => Err(anyhow!("'{}' is not an element node", self)), _ => 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>); pub struct XmlText<'a, 'b>(roxmltree::Node<'a, 'b>);
impl<'a, 'b> fmt::Display for XmlText<'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>); pub struct XmlElement<'a, 'b>(roxmltree::Node<'a, 'b>);
impl<'a, 'b> fmt::Display for XmlElement<'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<XmlElement> { pub fn only_child_element(&self) -> Result<XmlElement> {
with_text_pos_context! { self => with_text_pos_context! { self =>
self.only_child()?.as_element()? self.only_child()?.as_element()?.clone()
} }
} }

View file

@ -146,6 +146,8 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Frame> {
let widget_definitions = bargs.widget_definitions.clone(); let widget_definitions = bargs.widget_definitions.clone();
resolve_block!(bargs, gtk_widget, { resolve_block!(bargs, gtk_widget, {
prop(content: as_string) { prop(content: as_string) {
gtk_widget.get_children().iter().for_each(|w| gtk_widget.remove(w));
if !content.is_empty() {
let document = roxmltree::Document::parse(&content)?; let document = roxmltree::Document::parse(&content)?;
let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?; let content_widget_use = config::element::WidgetUse::from_xml_node(document.root_element().into())?;
let child_widget = super::widget_use_to_gtk_widget( let child_widget = super::widget_use_to_gtk_widget(
@ -155,10 +157,10 @@ fn build_gtk_literal(bargs: &mut BuilderArgs) -> Result<gtk::Frame> {
&std::collections::HashMap::new(), &std::collections::HashMap::new(),
&content_widget_use, &content_widget_use,
)?; )?;
gtk_widget.get_children().iter().for_each(|w| gtk_widget.remove(w));
gtk_widget.add(&child_widget); gtk_widget.add(&child_widget);
child_widget.show(); child_widget.show();
} }
}
}); });
Ok(gtk_widget) Ok(gtk_widget)
} }