Implement inline var-refs
This commit is contained in:
parent
bb60ab69c3
commit
f92f8bfb66
5 changed files with 104 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -310,6 +310,7 @@ dependencies = [
|
||||||
"hotwatch",
|
"hotwatch",
|
||||||
"ipc-channel",
|
"ipc-channel",
|
||||||
"itertools",
|
"itertools",
|
||||||
|
"lazy_static",
|
||||||
"log 0.4.11",
|
"log 0.4.11",
|
||||||
"maplit",
|
"maplit",
|
||||||
"notify",
|
"notify",
|
||||||
|
|
|
@ -33,6 +33,7 @@ scheduled-executor = "0.4"
|
||||||
debug_stub_derive = "0.3"
|
debug_stub_derive = "0.3"
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
pretty_env_logger = "0.4"
|
pretty_env_logger = "0.4"
|
||||||
|
lazy_static = "1.4.0"
|
||||||
|
|
||||||
#thiserror = "1.0"
|
#thiserror = "1.0"
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
use crate::value::AttrValue;
|
use crate::value::AttrValue;
|
||||||
use crate::with_text_pos_context;
|
use crate::with_text_pos_context;
|
||||||
|
@ -52,7 +54,13 @@ impl WidgetUse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
|
pub fn from_xml_node(xml: XmlNode) -> Result<Self> {
|
||||||
|
lazy_static! {
|
||||||
|
static ref PATTERN: Regex = Regex::new("\\{\\{(.*)\\}\\}").unwrap();
|
||||||
|
};
|
||||||
match xml {
|
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::Text(text) => Ok(WidgetUse::simple_text(AttrValue::parse_string(text.text()))),
|
||||||
XmlNode::Element(elem) => Ok(WidgetUse {
|
XmlNode::Element(elem) => Ok(WidgetUse {
|
||||||
name: elem.tag_name().to_string(),
|
name: elem.tag_name().to_string(),
|
||||||
|
@ -75,24 +83,19 @@ impl WidgetUse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Even just thinking of this gives me horrible nightmares.....
|
pub fn from_text_with_var_refs(text: &str) -> Self {
|
||||||
//pub fn from_text(text: String) -> Self {
|
WidgetUse {
|
||||||
//WidgetUse::text_with_var_refs(
|
|
||||||
//text.split(" ")
|
|
||||||
//.map(|word| AttrValue::parse_string(word.to_owned()))
|
|
||||||
//.collect_vec(),
|
|
||||||
//)
|
|
||||||
//}
|
|
||||||
|
|
||||||
pub fn text_with_var_refs(elements: Vec<AttrValue>) -> Self {
|
|
||||||
dbg!(WidgetUse {
|
|
||||||
name: "layout".to_owned(),
|
name: "layout".to_owned(),
|
||||||
attrs: hashmap! {
|
attrs: hashmap! {
|
||||||
"halign".to_owned() => AttrValue::Concrete(PrimitiveValue::String("center".to_owned())),
|
"halign".to_owned() => AttrValue::Concrete(PrimitiveValue::String("center".to_owned())),
|
||||||
"space-evenly".to_owned() => AttrValue::Concrete(PrimitiveValue::String("false".to_owned())),
|
"space-evenly".to_owned() => AttrValue::Concrete(PrimitiveValue::String("false".to_owned())),
|
||||||
},
|
},
|
||||||
children: elements.into_iter().map(WidgetUse::simple_text).collect(),
|
children: parse_string_with_var_refs(text)
|
||||||
})
|
.into_iter()
|
||||||
|
.map(StringOrVarRef::to_attr_value)
|
||||||
|
.map(WidgetUse::simple_text)
|
||||||
|
.collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
|
||||||
|
@ -102,6 +105,62 @@ impl WidgetUse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
enum StringOrVarRef {
|
||||||
|
String(String),
|
||||||
|
VarRef(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StringOrVarRef {
|
||||||
|
fn to_attr_value(self) -> AttrValue {
|
||||||
|
match self {
|
||||||
|
StringOrVarRef::String(x) => AttrValue::Concrete(PrimitiveValue::parse_string(&x)),
|
||||||
|
StringOrVarRef::VarRef(x) => AttrValue::VarRef(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this could be a fancy Iterator implementation, ig
|
||||||
|
fn parse_string_with_var_refs(s: &str) -> Vec<StringOrVarRef> {
|
||||||
|
let mut elements = Vec::new();
|
||||||
|
|
||||||
|
let mut cur_word = "".to_owned();
|
||||||
|
let mut cur_varref: Option<String> = None;
|
||||||
|
let mut curly_count = 0;
|
||||||
|
for c in s.chars() {
|
||||||
|
if let Some(ref mut varref) = cur_varref {
|
||||||
|
if c == '}' {
|
||||||
|
curly_count -= 1;
|
||||||
|
if curly_count == 0 {
|
||||||
|
elements.push(StringOrVarRef::VarRef(std::mem::take(varref)));
|
||||||
|
cur_varref = None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
curly_count = 2;
|
||||||
|
varref.push(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if c == '{' {
|
||||||
|
curly_count += 1;
|
||||||
|
if curly_count == 2 {
|
||||||
|
if !cur_word.is_empty() {
|
||||||
|
elements.push(StringOrVarRef::String(std::mem::take(&mut cur_word)));
|
||||||
|
}
|
||||||
|
cur_varref = Some(String::new())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cur_word.push(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(unfinished_varref) = cur_varref.take() {
|
||||||
|
elements.push(StringOrVarRef::String(unfinished_varref));
|
||||||
|
} else if !cur_word.is_empty() {
|
||||||
|
elements.push(StringOrVarRef::String(cur_word.to_owned()));
|
||||||
|
}
|
||||||
|
elements
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -130,7 +189,7 @@ mod test {
|
||||||
fn test_text_with_var_refs() {
|
fn test_text_with_var_refs() {
|
||||||
let expected_attr_value1 = mk_attr_str("my text");
|
let expected_attr_value1 = mk_attr_str("my text");
|
||||||
let expected_attr_value2 = AttrValue::VarRef("var".to_owned());
|
let expected_attr_value2 = AttrValue::VarRef("var".to_owned());
|
||||||
let widget = WidgetUse::text_with_var_refs(vec![expected_attr_value1.clone(), expected_attr_value2.clone()]);
|
let widget = WidgetUse::from_text_with_var_refs("my text{{var}}");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
widget,
|
widget,
|
||||||
WidgetUse {
|
WidgetUse {
|
||||||
|
@ -199,4 +258,21 @@ mod test {
|
||||||
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap()
|
WidgetDefinition::from_xml_element(xml.as_element().unwrap()).unwrap()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_string_or_var_ref_list() {
|
||||||
|
let input = "{{foo}}{{bar}}baz{{bat}}quok{{test}}";
|
||||||
|
let output = parse_string_with_var_refs(input);
|
||||||
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
vec![
|
||||||
|
StringOrVarRef::VarRef("foo".to_owned()),
|
||||||
|
StringOrVarRef::VarRef("bar".to_owned()),
|
||||||
|
StringOrVarRef::String("baz".to_owned()),
|
||||||
|
StringOrVarRef::VarRef("bat".to_owned()),
|
||||||
|
StringOrVarRef::String("quok".to_owned()),
|
||||||
|
StringOrVarRef::VarRef("test".to_owned()),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
19
src/value.rs
19
src/value.rs
|
@ -1,7 +1,8 @@
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use derive_more;
|
use derive_more;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use regex::Regex;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
@ -127,20 +128,18 @@ impl AttrValue {
|
||||||
_ => Err(anyhow!("{:?} is not a bool", self)),
|
_ => Err(anyhow!("{:?} is not a bool", self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn as_var_ref(&self) -> Result<&String> {
|
|
||||||
match self {
|
|
||||||
AttrValue::VarRef(x) => Ok(x),
|
|
||||||
_ => Err(anyhow!("{:?} is not a VarRef", self)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// parses the value, trying to turn it into VarRef,
|
/// parses the value, trying to turn it into VarRef,
|
||||||
/// a number and a boolean first, before deciding that it is a string.
|
/// a number and a boolean first, before deciding that it is a string.
|
||||||
pub fn parse_string(s: String) -> Self {
|
pub fn parse_string(s: String) -> Self {
|
||||||
if s.starts_with("$$") {
|
lazy_static! {
|
||||||
AttrValue::VarRef(s.trim_start_matches("$$").to_string())
|
static ref PATTERN: Regex = Regex::new("^\\{\\{(.*)\\}\\}$").unwrap();
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(ref_name) = PATTERN.captures(&s).and_then(|cap| cap.get(1)).map(|x| x.as_str()) {
|
||||||
|
AttrValue::VarRef(ref_name.to_owned())
|
||||||
} else {
|
} else {
|
||||||
AttrValue::Concrete(PrimitiveValue::parse_string(&s))
|
AttrValue::Concrete(PrimitiveValue::String(s))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,7 +70,7 @@ pub fn build_gtk_widget(
|
||||||
let child_widget = element_to_gtk_thing(widget_definitions, bargs.eww_state, local_env, child);
|
let child_widget = element_to_gtk_thing(widget_definitions, bargs.eww_state, local_env, child);
|
||||||
let child_widget = child_widget.with_context(|| {
|
let child_widget = child_widget.with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"error while building child '{:?}' of '{}'",
|
"error while building child '{:#?}' of '{}'",
|
||||||
&child,
|
&child,
|
||||||
>k_widget.get_widget_name()
|
>k_widget.get_widget_name()
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Reference in a new issue