diff --git a/src/config/element.rs b/src/config/element.rs index cbce72f..c8e3614 100644 --- a/src/config/element.rs +++ b/src/config/element.rs @@ -75,19 +75,14 @@ impl WidgetUse { }; let text_pos = xml.text_pos(); let widget_use = match xml { - XmlNode::Text(text) => WidgetUse::simple_text(AttrValue::parse_string(text.text())), + XmlNode::Text(text) => WidgetUse::simple_text(AttrValue::parse_string(&text.text())), XmlNode::Element(elem) => WidgetUse { name: elem.tag_name().to_owned(), children: with_text_pos_context! { elem => elem.children().map(WidgetUse::from_xml_node).collect::>()?}?, attrs: elem .attributes() .iter() - .map(|attr| { - ( - AttrName(attr.name().to_owned()), - AttrValue::parse_string(attr.value().to_owned()), - ) - }) + .map(|attr| (AttrName(attr.name().to_owned()), AttrValue::parse_string(attr.value()))) .collect::>(), ..WidgetUse::default() }, @@ -125,7 +120,7 @@ mod test { #[test] fn test_simple_text() { - let expected_attr_value = AttrValue::Concrete(PrimitiveValue::from_string("my text".to_owned())); + let expected_attr_value = AttrValue::from_primitive("my text"); let widget = WidgetUse::simple_text(expected_attr_value.clone()); assert_eq!( widget, @@ -135,7 +130,7 @@ mod test { attrs: hashmap! { AttrName("text".to_owned()) => expected_attr_value}, ..WidgetUse::default() }, - ) + ); } #[test] @@ -152,12 +147,12 @@ mod test { let expected = WidgetUse { name: "widget_name".to_owned(), attrs: hashmap! { - AttrName("attr1".to_owned()) => AttrValue::Concrete(PrimitiveValue::from_string("hi".to_owned())), - AttrName("attr2".to_owned()) => AttrValue::Concrete(PrimitiveValue::from_string("12".to_owned())), + AttrName("attr1".to_owned()) => AttrValue::from_primitive("hi"), + AttrName("attr2".to_owned()) => AttrValue::from_primitive("12"), }, children: vec![ WidgetUse::new("child_widget".to_owned(), Vec::new()), - WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::from_string("foo".to_owned()))), + WidgetUse::simple_text(AttrValue::from_primitive("foo".to_owned())), ], ..WidgetUse::default() }; @@ -179,9 +174,7 @@ mod test { size: Some((12, 20)), structure: WidgetUse { name: "layout".to_owned(), - children: vec![WidgetUse::simple_text(AttrValue::Concrete(PrimitiveValue::from_string( - "test".to_owned(), - )))], + children: vec![WidgetUse::simple_text(AttrValue::from_primitive("test"))], attrs: HashMap::new(), ..WidgetUse::default() }, diff --git a/src/eww_state.rs b/src/eww_state.rs index 6c91323..37eb32b 100644 --- a/src/eww_state.rs +++ b/src/eww_state.rs @@ -1,9 +1,9 @@ use crate::{ config::WindowName, - value::{self, AttrName, VarName}, + util, + value::{AttrName, StringOrVarRef, VarName}, }; use anyhow::*; -use itertools::Itertools; use std::{collections::HashMap, process::Command, sync::Arc}; use crate::value::{AttrValue, PrimitiveValue}; @@ -12,33 +12,33 @@ use crate::value::{AttrValue, PrimitiveValue}; /// a gtk widget. These are created and initialized in EwwState::resolve. pub struct StateChangeHandler { func: Box) -> Result<()> + 'static>, - constant_values: HashMap, - unresolved_attrs: HashMap, - string_with_varrefs_resolvers: HashMap) -> PrimitiveValue>>, + unresolved_values: Vec<(AttrName, AttrValue)>, } impl StateChangeHandler { + fn used_variables(&self) -> impl Iterator { + self.unresolved_values.iter().flat_map(|(_, value)| value.var_refs()) + } + /// Run the StateChangeHandler. /// [`state`] should be the global [EwwState::state]. - fn run_with_state(&self, state: &HashMap) -> Result<()> { - let mut all_resolved_attrs = self.constant_values.clone(); - for (attr_name, var_ref) in self.unresolved_attrs.iter() { - let resolved = state - .get(var_ref) - // TODO provide context here, including line numbers - .with_context(|| format!("Unknown variable '{}' was referenced", var_ref))?; - all_resolved_attrs.insert(attr_name.to_owned(), resolved.clone()); - } - for (attr_name, resolver) in self.string_with_varrefs_resolvers.iter() { - all_resolved_attrs.insert(attr_name.to_owned(), resolver(state)); - } + fn run_with_state(&self, state: &HashMap) { + let resolved_attrs = self + .unresolved_values + .iter() + .cloned() + .map(|(attr_name, value)| Ok((attr_name, value.resolve_fully(state)?))) + .collect::>(); - let result: Result<_> = (self.func)(all_resolved_attrs); - if let Err(err) = result { - eprintln!("WARN: Error while resolving attributes: {}", err); + match resolved_attrs { + Ok(resolved_attrs) => { + let result: Result<_> = (self.func)(resolved_attrs); + util::print_result_err("while updating UI based after state change", &result); + } + Err(err) => { + eprintln!("Error whiel resolving attributes {:?}", err); + } } - - Ok(()) } } @@ -54,10 +54,11 @@ impl EwwWindowState { /// register a new [StateChangeHandler] fn put_handler(&mut self, handler: StateChangeHandler) { let handler = Arc::new(handler); - for var_name in handler.unresolved_attrs.values() { - let entry: &mut Vec> = - self.state_change_handlers.entry(var_name.clone()).or_insert_with(Vec::new); - entry.push(handler.clone()); + for var_name in handler.used_variables() { + self.state_change_handlers + .entry(var_name.clone()) + .or_insert_with(Vec::new) + .push(handler.clone()); } } } @@ -110,9 +111,7 @@ impl EwwState { .flatten(); for handler in handlers { - handler - .run_with_state(&self.variables_state) - .with_context(|| format!("When updating value of {}", &key))?; + handler.run_with_state(&self.variables_state) } Ok(()) } @@ -126,35 +125,18 @@ impl EwwState { local_env: &'a HashMap, value: &'a AttrValue, ) -> Result { - match value { - AttrValue::Concrete(primitive) => Ok(primitive.clone()), - AttrValue::VarRef(var_name) => match local_env.get(var_name) { - // look up if variables are found in the local env, and resolve as far as possible - Some(AttrValue::Concrete(primitive)) => Ok(primitive.clone()), - Some(AttrValue::VarRef(var_name)) => self + value + .iter() + .map(|element| match element { + StringOrVarRef::Primitive(primitive) => Ok(primitive.clone()), + StringOrVarRef::VarRef(var_name) => self .variables_state .get(var_name) .cloned() - .ok_or_else(|| anyhow!("Unknown variable '{}' referenced", var_name)), - Some(AttrValue::StringWithVarRefs(content)) => content - .iter() - .map(|x| x.clone().to_attr_value()) - .map(|value| self.resolve_once(local_env, &value)) - .fold_results(String::new(), |acc, cur| format!("{}{}", acc, cur)) - .map(PrimitiveValue::from_string), - None => self - .variables_state - .get(var_name) - .cloned() - .ok_or_else(|| anyhow!("Unknown variable '{}' referenced", var_name)), - }, - AttrValue::StringWithVarRefs(content) => content - .iter() - .map(|x| x.clone().to_attr_value()) - .map(|value| self.resolve_once(local_env, &value)) - .fold_results(String::new(), |acc, cur| format!("{}{}", acc, cur)) - .map(PrimitiveValue::from_string), - } + .or_else(|| local_env.get(var_name).and_then(|x| self.resolve_once(local_env, x).ok())) + .with_context(|| format!("Unknown variable '{}' referenced", var_name)), + }) + .collect() } /// Resolve takes a function that applies a set of fully resolved attribute @@ -166,99 +148,26 @@ impl EwwState { &mut self, window_name: &WindowName, local_env: &HashMap, - mut needed_attributes: HashMap, + mut attributes: HashMap, set_value: F, ) { - // Resolve first collects all variable references and creates a set of - // unresolved attribute -> VarName pairs. additionally, all constant values are - // looked up and collected, including the values from the local environment - // These are then used to generate a StateChangeHandler, which is then executed - // and registered in the windows state. + let window_state = self + .windows + .entry(window_name.clone()) + .or_insert_with(EwwWindowState::default); - let result: Result<_> = try { - let window_state = self - .windows - .entry(window_name.clone()) - .or_insert_with(EwwWindowState::default); + let resolved_attributes: Vec<(AttrName, AttrValue)> = attributes + .drain() + .map(|(attr_name, attr_value)| (attr_name, attr_value.resolve_one_level(local_env))) + .collect(); - let mut string_with_varrefs_resolvers: HashMap<_, Box) -> PrimitiveValue>> = - HashMap::new(); - - let mut resolved_attrs = HashMap::new(); - let mut unresolved_attrs: HashMap = HashMap::new(); - needed_attributes - .drain() - .for_each(|(attr_name, attr_value)| match attr_value { - // directly resolve primitive values - AttrValue::Concrete(primitive) => { - resolved_attrs.insert(attr_name, primitive); - } - AttrValue::StringWithVarRefs(content) => { - let content = content.resolve_one_level(local_env); - let resolver = generate_string_with_var_refs_resolver(content); - string_with_varrefs_resolvers.insert(attr_name, Box::new(resolver)); - } - - AttrValue::VarRef(var_name) => match local_env.get(&var_name) { - Some(AttrValue::StringWithVarRefs(content)) => { - let content = content.clone().resolve_one_level(local_env); - let resolver = generate_string_with_var_refs_resolver(content); - string_with_varrefs_resolvers.insert(attr_name, Box::new(resolver)); - } - - // look up if variables are found in the local env, and resolve as far as possible - Some(AttrValue::Concrete(concrete_from_local)) => { - resolved_attrs.insert(attr_name, concrete_from_local.clone()); - } - Some(AttrValue::VarRef(var_ref_from_local)) => { - unresolved_attrs.insert(attr_name, var_ref_from_local.clone()); - } - None => { - // if it's not in the local env, it must reference the global state, - // and should thus directly be inserted into the unresolved attrs. - unresolved_attrs.insert(attr_name, var_name); - } - }, - }); - - if unresolved_attrs.is_empty() && string_with_varrefs_resolvers.is_empty() { - // if there are no unresolved variables, we can set the value directly - set_value(resolved_attrs)?; - } else { - // otherwise register and execute the handler - let handler = StateChangeHandler { - string_with_varrefs_resolvers, - func: Box::new(set_value.clone()), - constant_values: resolved_attrs, - unresolved_attrs, - }; - handler.run_with_state(&self.variables_state)?; - window_state.put_handler(handler); - } + let handler = StateChangeHandler { + func: Box::new(set_value), + unresolved_values: resolved_attributes, }; - if let Err(e) = result { - eprintln!("Error resolving values: {:?}", e); - } - } -} -pub fn generate_string_with_var_refs_resolver( - string_with_varrefs: value::StringWithVarRefs, -) -> impl Fn(&HashMap) -> PrimitiveValue { - move |variables: &HashMap| { - PrimitiveValue::from_string( - string_with_varrefs - .iter() - .map(|entry| match entry { - value::StringOrVarRef::VarRef(var_name) => variables - .get(var_name) - .expect(&format!("Impossible state: unknown variable {}.\n{:?}", var_name, variables)) - .clone() - .into_inner(), - value::StringOrVarRef::Primitive(s) => s.to_string(), - }) - .join(""), - ) + handler.run_with_state(&self.variables_state); + window_state.put_handler(handler); } } diff --git a/src/main.rs b/src/main.rs index f4c0963..e119169 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,5 @@ #![feature(trace_macros)] +#![feature(slice_concat_trait)] #![feature(result_cloned)] #![feature(iterator_fold_self)] #![feature(try_blocks)] @@ -88,10 +89,10 @@ pub enum OptAction { OpenWindow { window_name: config::WindowName, - #[structopt(short, long, help="The position of the window, where it should open.")] + #[structopt(short, long, help = "The position of the window, where it should open.")] pos: Option, - #[structopt(short, long, help="The size of the window to open")] + #[structopt(short, long, help = "The size of the window to open")] size: Option, }, diff --git a/src/value/attr_value.rs b/src/value/attr_value.rs index 889c941..42965ec 100644 --- a/src/value/attr_value.rs +++ b/src/value/attr_value.rs @@ -1,108 +1,163 @@ use anyhow::*; -use lazy_static::lazy_static; -use regex::Regex; +use std::{collections::HashMap, iter::FromIterator}; use super::*; -#[derive(Clone, Debug, PartialEq)] -pub enum AttrValue { - Concrete(PrimitiveValue), - StringWithVarRefs(StringWithVarRefs), - VarRef(VarName), +#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From)] +pub struct AttrValue(Vec); + +impl IntoIterator for AttrValue { + type IntoIter = std::vec::IntoIter; + type Item = StringOrVarRef; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl FromIterator for AttrValue { + fn from_iter>(iter: T) -> Self { + let mut result = AttrValue(Vec::new()); + result.0.extend(iter); + result + } } impl AttrValue { - pub fn as_string(&self) -> Result { - match self { - AttrValue::Concrete(x) => x.as_string(), - _ => Err(anyhow!("{:?} is not a string", self)), - } + pub fn from_primitive>(v: T) -> Self { + AttrValue(vec![StringOrVarRef::Primitive(v.into())]) } - pub fn as_f64(&self) -> Result { - match self { - AttrValue::Concrete(x) => x.as_f64(), - _ => Err(anyhow!("{:?} is not an f64", self)), - } + pub fn iter(&self) -> std::slice::Iter { + self.0.iter() } - pub fn as_i32(&self) -> Result { - match self { - AttrValue::Concrete(x) => x.as_i32(), - _ => Err(anyhow!("{:?} is not an i32", self)), - } + pub fn var_refs(&self) -> impl Iterator { + self.0.iter().filter_map(|x| x.as_var_ref()) } - pub fn as_bool(&self) -> Result { - match self { - AttrValue::Concrete(x) => x.as_bool(), - _ => Err(anyhow!("{:?} is not a bool", self)), - } + pub fn resolve_one_level(self, variables: &HashMap) -> AttrValue { + self.into_iter() + .flat_map(|entry| match entry { + StringOrVarRef::VarRef(var_name) => match variables.get(&var_name) { + Some(value) => value.0.clone(), + _ => vec![StringOrVarRef::VarRef(var_name)], + }, + _ => vec![entry], + }) + .collect() } - pub fn as_var_ref(&self) -> Result<&VarName> { - match self { - AttrValue::VarRef(x) => Ok(x), - _ => Err(anyhow!("{:?} is not a variable reference", self)), - } + pub fn resolve_fully(self, variables: &HashMap) -> Result { + self.into_iter() + .map(|element| match element { + StringOrVarRef::Primitive(x) => Ok(x), + StringOrVarRef::VarRef(var_name) => variables + .get(&var_name) + .cloned() + .with_context(|| format!("Unknown variable '{}' referenced", var_name)), + }) + .collect() } - /// parses the value, trying to turn it into VarRef, - /// a number and a boolean first, before deciding that it is a string. - pub fn parse_string(s: String) -> Self { - lazy_static! { - static ref VAR_REF_PATTERN: Regex = Regex::new("\\{\\{(.*?)\\}\\}").unwrap(); - }; + // TODO this could be a fancy Iterator implementation, ig + pub fn parse_string(s: &str) -> AttrValue { + let mut elements = Vec::new(); - let pattern: &Regex = &*VAR_REF_PATTERN; - if let Some(match_range) = pattern.find(&s) { - if match_range.start() == 0 && match_range.end() == s.len() { - // we can unwrap here, as we just verified that there is a valid match already - let ref_name = VAR_REF_PATTERN.captures(&s).and_then(|cap| cap.get(1)).unwrap().as_str(); - AttrValue::VarRef(VarName(ref_name.to_owned())) + let mut cur_word = "".to_owned(); + let mut cur_varref: Option = 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(VarName(std::mem::take(varref)))); + cur_varref = None + } + } else { + curly_count = 2; + varref.push(c); + } } else { - AttrValue::StringWithVarRefs(StringWithVarRefs::parse_string(&s)) + if c == '{' { + curly_count += 1; + if curly_count == 2 { + if !cur_word.is_empty() { + elements.push(StringOrVarRef::primitive(std::mem::take(&mut cur_word))); + } + cur_varref = Some(String::new()) + } + } else { + cur_word.push(c); + } } - } else { - AttrValue::Concrete(PrimitiveValue::from_string(s)) } - } -} -impl From for AttrValue { - fn from(value: PrimitiveValue) -> Self { - AttrValue::Concrete(value) + if let Some(unfinished_varref) = cur_varref.take() { + elements.push(StringOrVarRef::primitive(unfinished_varref)); + } else if !cur_word.is_empty() { + elements.push(StringOrVarRef::primitive(cur_word.to_owned())); + } + AttrValue(elements) } } -#[cfg(test)] +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub enum StringOrVarRef { + Primitive(PrimitiveValue), + VarRef(VarName), +} + +impl StringOrVarRef { + pub fn primitive(s: String) -> Self { + StringOrVarRef::Primitive(PrimitiveValue::from_string(s)) + } + + pub fn as_var_ref(&self) -> Option<&VarName> { + match self { + StringOrVarRef::VarRef(x) => Some(&x), + _ => None, + } + } + + pub fn as_primitive(&self) -> Option<&PrimitiveValue> { + match self { + StringOrVarRef::Primitive(x) => Some(&x), + _ => None, + } + } +} + +#[cfg(Test)] mod test { - use super::*; use pretty_assertions::assert_eq; #[test] - fn test_parse_concrete_attr_value() { + 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!( - AttrValue::Concrete(PrimitiveValue::from_string("foo".to_owned())), - AttrValue::parse_string("foo".to_owned()) - ); - } - #[test] - fn test_parse_var_ref_attr_value() { - assert_eq!( - AttrValue::VarRef(VarName("foo".to_owned())), - AttrValue::parse_string("{{foo}}".to_owned()) - ); + 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()), + ], + ) } #[test] fn test_parse_string_with_var_refs_attr_value() { assert_eq!( - AttrValue::StringWithVarRefs( + AttrValue( vec![ StringOrVarRef::VarRef(VarName("var".to_owned())), StringOrVarRef::primitive("something".to_owned()) ] .into() ), - AttrValue::parse_string("{{var}}something".to_owned()) + AttrValue::parse_string("{{var}}something") ); } } diff --git a/src/value/primitive.rs b/src/value/primitive.rs index 9c05f8a..e367821 100644 --- a/src/value/primitive.rs +++ b/src/value/primitive.rs @@ -1,11 +1,12 @@ use anyhow::*; use derive_more; +use itertools::Itertools; use serde::{Deserialize, Serialize}; -use std::{convert::TryFrom, fmt}; +use std::{convert::TryFrom, fmt, iter::FromIterator}; use crate::impl_try_from; -#[derive(Clone, PartialEq, Deserialize, Serialize, derive_more::From)] +#[derive(Clone, PartialEq, Deserialize, Serialize, derive_more::From, Default)] pub struct PrimitiveValue(String); impl fmt::Display for PrimitiveValue { @@ -19,6 +20,12 @@ impl fmt::Debug for PrimitiveValue { } } +impl FromIterator for PrimitiveValue { + fn from_iter>(iter: T) -> Self { + PrimitiveValue(iter.into_iter().join("")) + } +} + impl std::str::FromStr for PrimitiveValue { type Err = anyhow::Error; diff --git a/src/value/string_with_varrefs.rs b/src/value/string_with_varrefs.rs deleted file mode 100644 index 3a6beaa..0000000 --- a/src/value/string_with_varrefs.rs +++ /dev/null @@ -1,135 +0,0 @@ -use std::{collections::HashMap, iter::FromIterator}; - -use serde::{Deserialize, Serialize}; -use IntoIterator; - -use super::{AttrValue, PrimitiveValue, VarName}; - -#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From)] -pub struct StringWithVarRefs(Vec); - -impl IntoIterator for StringWithVarRefs { - type IntoIter = std::vec::IntoIter; - type Item = StringOrVarRef; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl FromIterator for StringWithVarRefs { - fn from_iter>(iter: T) -> Self { - let mut result = StringWithVarRefs(Vec::new()); - result.0.extend(iter); - result - } -} - -impl StringWithVarRefs { - pub fn iter(&self) -> std::slice::Iter { - self.0.iter() - } - - pub fn var_refs(&self) -> impl Iterator { - self.0.iter().filter_map(|x| x.as_var_ref()) - } - - pub fn resolve_one_level(self, variables: &HashMap) -> StringWithVarRefs { - self.into_iter() - .map(|entry| match entry { - StringOrVarRef::VarRef(var_name) => match variables.get(&var_name).clone() { - Some(AttrValue::Concrete(primitive)) => StringOrVarRef::Primitive(primitive.clone()), - _ => StringOrVarRef::VarRef(var_name), - }, - _ => entry, - }) - .collect() - } - - // TODO this could be a fancy Iterator implementation, ig - pub fn parse_string(s: &str) -> StringWithVarRefs { - let mut elements = Vec::new(); - - let mut cur_word = "".to_owned(); - let mut cur_varref: Option = 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(VarName(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::primitive(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::primitive(unfinished_varref)); - } else if !cur_word.is_empty() { - elements.push(StringOrVarRef::primitive(cur_word.to_owned())); - } - StringWithVarRefs(elements) - } -} - -#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum StringOrVarRef { - Primitive(PrimitiveValue), - VarRef(VarName), -} - -impl StringOrVarRef { - pub fn primitive(s: String) -> Self { - StringOrVarRef::Primitive(PrimitiveValue::from_string(s)) - } - - pub fn to_attr_value(self) -> AttrValue { - match self { - StringOrVarRef::Primitive(x) => AttrValue::Concrete(x), - StringOrVarRef::VarRef(x) => AttrValue::VarRef(x), - } - } - - pub fn as_var_ref(&self) -> Option<&VarName> { - match self { - StringOrVarRef::VarRef(x) => Some(&x), - _ => None, - } - } -} - -#[cfg(Test)] -mod test { - #[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()), - ], - ) - } -} diff --git a/src/widgets/mod.rs b/src/widgets/mod.rs index 532fb26..e41fc13 100644 --- a/src/widgets/mod.rs +++ b/src/widgets/mod.rs @@ -71,20 +71,7 @@ pub fn widget_use_to_gtk_widget( .attrs .clone() .into_iter() - .map(|(attr_name, attr_value)| { - ( - VarName(attr_name.0), - match attr_value { - AttrValue::VarRef(var_ref) => { - local_env.get(&var_ref).cloned().unwrap_or_else(|| AttrValue::VarRef(var_ref)) - } - AttrValue::StringWithVarRefs(content) => { - AttrValue::StringWithVarRefs(content.resolve_one_level(local_env)) - } - AttrValue::Concrete(value) => AttrValue::Concrete(value), - }, - ) - }) + .map(|(attr_name, attr_value)| (VarName(attr_name.0), attr_value.resolve_one_level(local_env))) .collect(); let custom_widget = widget_use_to_gtk_widget( @@ -215,7 +202,7 @@ macro_rules! resolve_block { }; (@get_value $args:ident, $name:expr, = $default:expr) => { - $args.widget.get_attr($name).cloned().unwrap_or(AttrValue::Concrete(PrimitiveValue::from($default))) + $args.widget.get_attr($name).cloned().unwrap_or(AttrValue::from_primitive($default)) }; (@get_value $args:ident, $name:expr,) => { diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index ef7c85a..6ba577f 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -1,8 +1,5 @@ use super::{run_command, BuilderArgs}; -use crate::{ - config, eww_state, resolve_block, - value::{AttrValue, PrimitiveValue}, -}; +use crate::{config, eww_state, resolve_block, value::AttrValue}; use anyhow::*; use gtk::{prelude::*, ImageExt}; use std::{cell::RefCell, rc::Rc};