Add docs for json values and make value related names shorter

This commit is contained in:
elkowar 2021-04-14 14:28:22 +02:00
parent ce4c22e2a6
commit aaac4c3b43
16 changed files with 223 additions and 221 deletions

View file

@ -32,4 +32,6 @@ The expression language supports:
- conditionals (`if condition then 'value' else 'other value'`)
- numbers, strings, booleans and variable references (`12`, `'hi'`, `true`, `some_variable`)
- strings can contain other expressions again: `'foo {{some_variable}} bar'`
- json access (`object.field`, `array[12]`, `object["field"]`)
- for this, the object/array value needs to refer to a variable that contains a valid json string.

View file

@ -3,7 +3,7 @@ use crate::{
config::{window_definition::WindowName, AnchorPoint, WindowStacking},
display_backend, eww_state,
script_var_handler::*,
value::{Coords, NumWithUnit, PrimitiveValue, VarName},
value::{Coords, NumWithUnit, PrimVal, VarName},
EwwPaths,
};
use anyhow::*;
@ -41,7 +41,7 @@ pub type DaemonResponseReceiver = tokio::sync::mpsc::UnboundedReceiver<DaemonRes
#[derive(Debug)]
pub enum DaemonCommand {
NoOp,
UpdateVars(Vec<(VarName, PrimitiveValue)>),
UpdateVars(Vec<(VarName, PrimVal)>),
ReloadConfigAndCss(DaemonResponseSender),
UpdateConfig(config::EwwConfig),
UpdateCss(String),
@ -193,7 +193,7 @@ impl App {
gtk::main_quit();
}
fn update_state(&mut self, fieldname: VarName, value: PrimitiveValue) {
fn update_state(&mut self, fieldname: VarName, value: PrimVal) {
self.eww_state.update_variable(fieldname, value)
}

View file

@ -4,7 +4,7 @@ use regex::Regex;
use std::ops::Range;
use crate::{
value::{AttrName, AttrValue},
value::{AttrName, AttrVal},
with_text_pos_context,
};
use maplit::hashmap;
@ -41,7 +41,7 @@ impl WidgetDefinition {
pub struct WidgetUse {
pub name: String,
pub children: Vec<WidgetUse>,
pub attrs: HashMap<AttrName, AttrValue>,
pub attrs: HashMap<AttrName, AttrVal>,
pub text_pos: Option<TextPos>,
}
@ -67,7 +67,7 @@ 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(AttrVal::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::<Result<_>>()?}?,
@ -77,7 +77,7 @@ impl WidgetUse {
.map(|attr| {
(
AttrName(attr.name().to_owned()),
AttrValue::parse_string(&xml_ext::resolve_escaped_symbols(&attr.value())),
AttrVal::parse_string(&xml_ext::resolve_escaped_symbols(&attr.value())),
)
})
.collect::<HashMap<_, _>>(),
@ -88,7 +88,7 @@ impl WidgetUse {
Ok(widget_use.at_pos(text_pos))
}
pub fn simple_text(text: AttrValue) -> Self {
pub fn simple_text(text: AttrVal) -> Self {
WidgetUse {
name: "label".to_owned(),
children: vec![],
@ -111,7 +111,7 @@ mod test {
#[test]
fn test_simple_text() {
let expected_attr_value = AttrValue::from_primitive("my text");
let expected_attr_value = AttrVal::from_primitive("my text");
let widget = WidgetUse::simple_text(expected_attr_value.clone());
assert_eq!(
widget,
@ -138,12 +138,12 @@ mod test {
let expected = WidgetUse {
name: "widget_name".to_owned(),
attrs: hashmap! {
AttrName("attr1".to_owned()) => AttrValue::from_primitive("hi"),
AttrName("attr2".to_owned()) => AttrValue::from_primitive("12"),
AttrName("attr1".to_owned()) => AttrVal::from_primitive("hi"),
AttrName("attr2".to_owned()) => AttrVal::from_primitive("12"),
},
children: vec![
WidgetUse::new("child_widget".to_owned(), Vec::new()),
WidgetUse::simple_text(AttrValue::from_primitive("foo".to_owned())),
WidgetUse::simple_text(AttrVal::from_primitive("foo".to_owned())),
],
..WidgetUse::default()
};
@ -165,7 +165,7 @@ mod test {
size: Some((12, 20)),
structure: WidgetUse {
name: "layout".to_owned(),
children: vec![WidgetUse::simple_text(AttrValue::from_primitive("test"))],
children: vec![WidgetUse::simple_text(AttrVal::from_primitive("test"))],
attrs: HashMap::new(),
..WidgetUse::default()
},

View file

@ -3,7 +3,7 @@ use std::collections::HashMap;
use crate::{
util,
value::{PrimitiveValue, VarName},
value::{PrimVal, VarName},
};
use super::{
@ -18,7 +18,7 @@ use std::path::PathBuf;
pub struct EwwConfig {
widgets: HashMap<String, WidgetDefinition>,
windows: HashMap<WindowName, EwwWindowDefinition>,
initial_variables: HashMap<VarName, PrimitiveValue>,
initial_variables: HashMap<VarName, PrimVal>,
script_vars: HashMap<VarName, ScriptVar>,
pub filepath: PathBuf,
}
@ -44,7 +44,7 @@ impl EwwConfig {
}
// TODO this is kinda ugly
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimitiveValue>> {
pub fn generate_initial_state(&self) -> Result<HashMap<VarName, PrimVal>> {
let mut vars =
self.script_vars.iter().map(|var| Ok((var.0.clone(), var.1.initial_value()?))).collect::<Result<HashMap<_, _>>>()?;
vars.extend(self.initial_variables.clone());
@ -73,7 +73,7 @@ impl EwwConfig {
pub struct RawEwwConfig {
widgets: HashMap<String, WidgetDefinition>,
windows: HashMap<WindowName, RawEwwWindowDefinition>,
initial_variables: HashMap<VarName, PrimitiveValue>,
initial_variables: HashMap<VarName, PrimVal>,
script_vars: HashMap<VarName, ScriptVar>,
pub filepath: PathBuf,
}
@ -181,14 +181,14 @@ impl RawEwwConfig {
}
}
fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimitiveValue>, HashMap<VarName, ScriptVar>)> {
fn parse_variables_block(xml: XmlElement) -> Result<(HashMap<VarName, PrimVal>, HashMap<VarName, ScriptVar>)> {
let mut normal_vars = HashMap::new();
let mut script_vars = HashMap::new();
for node in xml.child_elements() {
match node.tag_name() {
"var" => {
let value = node.only_child().map(|c| c.as_text_or_sourcecode()).unwrap_or_else(|_| String::new());
normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimitiveValue::from_string(value));
normal_vars.insert(VarName(node.attr("name")?.to_owned()), PrimVal::from_string(value));
}
"script-var" => {
let script_var = ScriptVar::from_xml_element(node)?;

View file

@ -1,6 +1,6 @@
use crate::{
util,
value::{PrimitiveValue, VarName},
value::{PrimVal, VarName},
};
use anyhow::*;

View file

@ -14,7 +14,7 @@ pub struct PollScriptVar {
}
impl PollScriptVar {
pub fn run_once(&self) -> Result<PrimitiveValue> {
pub fn run_once(&self) -> Result<PrimVal> {
run_command(&self.command)
}
}
@ -39,12 +39,12 @@ impl ScriptVar {
}
}
pub fn initial_value(&self) -> Result<PrimitiveValue> {
pub fn initial_value(&self) -> Result<PrimVal> {
match self {
ScriptVar::Poll(x) => {
run_command(&x.command).with_context(|| format!("Failed to compute initial value for {}", &self.name()))
}
ScriptVar::Tail(_) => Ok(PrimitiveValue::from_string(String::new())),
ScriptVar::Tail(_) => Ok(PrimVal::from_string(String::new())),
}
}
@ -63,9 +63,9 @@ impl ScriptVar {
}
/// Run a command and get the output
fn run_command(cmd: &str) -> Result<PrimitiveValue> {
fn run_command(cmd: &str) -> Result<PrimVal> {
log::debug!("Running command: {}", cmd);
let output = String::from_utf8(Command::new("/bin/sh").arg("-c").arg(cmd).output()?.stdout)?;
let output = output.trim_matches('\n');
Ok(PrimitiveValue::from(output))
Ok(PrimVal::from(output))
}

View file

@ -1,17 +1,17 @@
use crate::{
config::window_definition::WindowName,
value::{AttrName, AttrValueElement, VarName},
value::{AttrName, AttrValElement, VarName},
};
use anyhow::*;
use std::{collections::HashMap, sync::Arc};
use crate::value::{AttrValue, PrimitiveValue};
use crate::value::{AttrVal, PrimVal};
/// Handler that gets executed to apply the necessary parts of the eww state to
/// a gtk widget. These are created and initialized in EwwState::resolve.
pub struct StateChangeHandler {
func: Box<dyn Fn(HashMap<AttrName, PrimitiveValue>) -> Result<()> + 'static>,
unresolved_values: HashMap<AttrName, AttrValue>,
func: Box<dyn Fn(HashMap<AttrName, PrimVal>) -> Result<()> + 'static>,
unresolved_values: HashMap<AttrName, AttrVal>,
}
impl StateChangeHandler {
@ -21,7 +21,7 @@ impl StateChangeHandler {
/// Run the StateChangeHandler.
/// [`state`] should be the global [EwwState::state].
fn run_with_state(&self, state: &HashMap<VarName, PrimitiveValue>) {
fn run_with_state(&self, state: &HashMap<VarName, PrimVal>) {
let resolved_attrs = self
.unresolved_values
.clone()
@ -61,7 +61,7 @@ impl EwwWindowState {
#[derive(Default)]
pub struct EwwState {
windows: HashMap<WindowName, EwwWindowState>,
variables_state: HashMap<VarName, PrimitiveValue>,
variables_state: HashMap<VarName, PrimVal>,
}
impl std::fmt::Debug for EwwState {
@ -71,11 +71,11 @@ impl std::fmt::Debug for EwwState {
}
impl EwwState {
pub fn from_default_vars(defaults: HashMap<VarName, PrimitiveValue>) -> Self {
pub fn from_default_vars(defaults: HashMap<VarName, PrimVal>) -> Self {
EwwState { variables_state: defaults, ..EwwState::default() }
}
pub fn get_variables(&self) -> &HashMap<VarName, PrimitiveValue> {
pub fn get_variables(&self) -> &HashMap<VarName, PrimVal> {
&self.variables_state
}
@ -91,7 +91,7 @@ impl EwwState {
/// Update the value of a variable, running all registered
/// [StateChangeHandler]s.
pub fn update_variable(&mut self, key: VarName, value: PrimitiveValue) {
pub fn update_variable(&mut self, key: VarName, value: PrimVal) {
self.variables_state.insert(key.clone(), value);
// run all of the handlers
@ -103,27 +103,27 @@ impl EwwState {
}
/// Look up a single variable in the eww state, returning an `Err` when the value is not found.
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimitiveValue> {
pub fn lookup(&self, var_name: &VarName) -> Result<&PrimVal> {
self.variables_state.get(var_name).with_context(|| format!("Unknown variable '{}' referenced", var_name))
}
/// resolves a value if possible, using the current eww_state.
pub fn resolve_once<'a>(&'a self, value: &'a AttrValue) -> Result<PrimitiveValue> {
pub fn resolve_once<'a>(&'a self, value: &'a AttrVal) -> Result<PrimVal> {
value
.iter()
.map(|element| match element {
AttrValueElement::Primitive(primitive) => Ok(primitive.clone()),
AttrValueElement::Expr(expr) => expr.clone().eval(&self.variables_state),
AttrValElement::Primitive(primitive) => Ok(primitive.clone()),
AttrValElement::Expr(expr) => expr.clone().eval(&self.variables_state),
})
.collect()
}
/// Resolve takes a function that applies a set of fully resolved attribute
/// values to it's gtk widget.
pub fn resolve<F: Fn(HashMap<AttrName, PrimitiveValue>) -> Result<()> + 'static + Clone>(
pub fn resolve<F: Fn(HashMap<AttrName, PrimVal>) -> Result<()> + 'static + Clone>(
&mut self,
window_name: &WindowName,
required_attributes: HashMap<AttrName, AttrValue>,
required_attributes: HashMap<AttrName, AttrVal>,
set_value: F,
) {
let handler = StateChangeHandler { func: Box::new(set_value), unresolved_values: required_attributes };

View file

@ -5,7 +5,7 @@ use structopt::StructOpt;
use crate::{
app,
config::{AnchorPoint, WindowName},
value::{Coords, PrimitiveValue, VarName},
value::{Coords, PrimVal, VarName},
};
/// Struct that gets generated from `RawOpt`.
@ -61,7 +61,7 @@ pub enum ActionWithServer {
Update {
/// variable_name="new_value"-pairs that will be updated
#[structopt(parse(try_from_str = parse_var_update_arg))]
mappings: Vec<(VarName, PrimitiveValue)>,
mappings: Vec<(VarName, PrimVal)>,
},
/// open a window
@ -138,11 +138,11 @@ impl From<RawOpt> for Opt {
}
}
fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimitiveValue)> {
fn parse_var_update_arg(s: &str) -> Result<(VarName, PrimVal)> {
let (name, value) = s
.split_once('=')
.with_context(|| format!("arguments must be in the shape `variable_name=\"new_value\"`, but got: {}", s))?;
Ok((name.into(), PrimitiveValue::from_string(value.to_owned())))
Ok((name.into(), PrimVal::from_string(value.to_owned())))
}
impl ActionWithServer {

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use crate::{
app, config,
value::{PrimitiveValue, VarName},
value::{PrimVal, VarName},
};
use anyhow::*;
use app::DaemonCommand;
@ -197,7 +197,7 @@ impl TailVarHandler {
_ = handle.wait() => break,
_ = cancellation_token.cancelled() => break,
Ok(Some(line)) = stdout_lines.next_line() => {
let new_value = PrimitiveValue::from_string(line.to_owned());
let new_value = PrimVal::from_string(line.to_owned());
evt_send.send(DaemonCommand::UpdateVars(vec![(var.name.to_owned(), new_value)]))?;
}
else => break,

View file

@ -9,45 +9,45 @@ use super::super::*;
/// This can be a primitive String that contains any amount of variable
/// references, as would be generated by the string "foo {{var}} bar".
#[derive(Serialize, Deserialize, Clone, PartialEq, derive_more::Into, derive_more::From, Default)]
pub struct AttrValue(Vec<AttrValueElement>);
pub struct AttrVal(Vec<AttrValElement>);
impl fmt::Display for AttrValue {
impl fmt::Display for AttrVal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.iter().map(|x| format!("{}", x)).join(""))
}
}
impl fmt::Debug for AttrValue {
impl fmt::Debug for AttrVal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "AttrValue({:?})", self.0)
}
}
impl IntoIterator for AttrValue {
impl IntoIterator for AttrVal {
type IntoIter = std::vec::IntoIter<Self::Item>;
type Item = AttrValueElement;
type Item = AttrValElement;
fn into_iter(self) -> Self::IntoIter {
self.0.into_iter()
}
}
impl FromIterator<AttrValueElement> for AttrValue {
fn from_iter<T: IntoIterator<Item = AttrValueElement>>(iter: T) -> Self {
AttrValue(iter.into_iter().collect())
impl FromIterator<AttrValElement> for AttrVal {
fn from_iter<T: IntoIterator<Item = AttrValElement>>(iter: T) -> Self {
AttrVal(iter.into_iter().collect())
}
}
impl AttrValue {
pub fn from_primitive<T: Into<PrimitiveValue>>(v: T) -> Self {
AttrValue(vec![AttrValueElement::Primitive(v.into())])
impl AttrVal {
pub fn from_primitive<T: Into<PrimVal>>(v: T) -> Self {
AttrVal(vec![AttrValElement::Primitive(v.into())])
}
pub fn from_var_ref<T: Into<VarName>>(v: T) -> Self {
AttrValue(vec![AttrValueElement::Expr(AttrValueExpr::VarRef(v.into()))])
AttrVal(vec![AttrValElement::Expr(AttrValExpr::VarRef(v.into()))])
}
pub fn iter(&self) -> std::slice::Iter<AttrValueElement> {
pub fn iter(&self) -> std::slice::Iter<AttrValElement> {
self.0.iter()
}
@ -58,13 +58,13 @@ impl AttrValue {
/// resolve partially.
/// If a var-ref links to another var-ref, that other var-ref is used.
/// If a referenced variable is not found in the given hashmap, returns the var-ref unchanged.
pub fn resolve_one_level(self, variables: &HashMap<VarName, AttrValue>) -> AttrValue {
pub fn resolve_one_level(self, variables: &HashMap<VarName, AttrVal>) -> AttrVal {
self.into_iter()
.map(|entry| match entry {
AttrValueElement::Expr(expr) => AttrValueElement::Expr(expr.map_terminals_into(|child_expr| match child_expr {
AttrValueExpr::VarRef(var_name) => match variables.get(&var_name) {
Some(value) => AttrValueExpr::Literal(value.clone()),
None => AttrValueExpr::VarRef(var_name),
AttrValElement::Expr(expr) => AttrValElement::Expr(expr.map_terminals_into(|child_expr| match child_expr {
AttrValExpr::VarRef(var_name) => match variables.get(&var_name) {
Some(value) => AttrValExpr::Literal(value.clone()),
None => AttrValExpr::VarRef(var_name),
},
other => other,
})),
@ -77,17 +77,17 @@ impl AttrValue {
/// resolve fully.
/// As the variables here have to be primitive values,
/// this enforces that var-refs are not linking to other variables.
pub fn resolve_fully(self, variables: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
pub fn resolve_fully(self, variables: &HashMap<VarName, PrimVal>) -> Result<PrimVal> {
self.into_iter()
.map(|element| match element {
AttrValueElement::Primitive(x) => Ok(x),
AttrValueElement::Expr(expr) => expr.eval(variables),
AttrValElement::Primitive(x) => Ok(x),
AttrValElement::Expr(expr) => expr.eval(variables),
})
.collect()
}
// TODO this could be a fancy Iterator implementation, ig
pub fn parse_string(s: &str) -> AttrValue {
pub fn parse_string(s: &str) -> AttrVal {
let mut elements = Vec::new();
let mut cur_word = "".to_owned();
@ -98,7 +98,7 @@ impl AttrValue {
if c == '}' {
curly_count -= 1;
if curly_count == 0 {
elements.push(AttrValueElement::Expr(AttrValueExpr::parse(varref).unwrap()));
elements.push(AttrValElement::Expr(AttrValExpr::parse(varref).unwrap()));
cur_varref = None
}
} else {
@ -109,7 +109,7 @@ impl AttrValue {
curly_count += 1;
if curly_count == 2 {
if !cur_word.is_empty() {
elements.push(AttrValueElement::primitive(std::mem::take(&mut cur_word)));
elements.push(AttrValElement::primitive(std::mem::take(&mut cur_word)));
}
cur_varref = Some(String::new())
}
@ -122,52 +122,52 @@ impl AttrValue {
}
}
if let Some(unfinished_varref) = cur_varref.take() {
elements.push(AttrValueElement::primitive(unfinished_varref));
elements.push(AttrValElement::primitive(unfinished_varref));
} else if !cur_word.is_empty() {
elements.push(AttrValueElement::primitive(cur_word));
elements.push(AttrValElement::primitive(cur_word));
}
AttrValue(elements)
AttrVal(elements)
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum AttrValueElement {
Primitive(PrimitiveValue),
Expr(AttrValueExpr),
pub enum AttrValElement {
Primitive(PrimVal),
Expr(AttrValExpr),
}
impl fmt::Display for AttrValueElement {
impl fmt::Display for AttrValElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AttrValueElement::Primitive(x) => write!(f, "{}", x),
AttrValueElement::Expr(x) => write!(f, "{{{{{}}}}}", x),
AttrValElement::Primitive(x) => write!(f, "{}", x),
AttrValElement::Expr(x) => write!(f, "{{{{{}}}}}", x),
}
}
}
impl fmt::Debug for AttrValueElement {
impl fmt::Debug for AttrValElement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AttrValueElement::Primitive(x) => write!(f, "Primitive({:?})", x),
AttrValueElement::Expr(x) => write!(f, "Expr({:?})", x),
AttrValElement::Primitive(x) => write!(f, "Primitive({:?})", x),
AttrValElement::Expr(x) => write!(f, "Expr({:?})", x),
}
}
}
impl AttrValueElement {
impl AttrValElement {
pub fn primitive(s: String) -> Self {
AttrValueElement::Primitive(PrimitiveValue::from_string(s))
AttrValElement::Primitive(PrimVal::from_string(s))
}
pub fn as_expr(&self) -> Option<&AttrValueExpr> {
pub fn as_expr(&self) -> Option<&AttrValExpr> {
match self {
AttrValueElement::Expr(x) => Some(&x),
AttrValElement::Expr(x) => Some(&x),
_ => None,
}
}
pub fn as_primitive(&self) -> Option<&PrimitiveValue> {
pub fn as_primitive(&self) -> Option<&PrimVal> {
match self {
AttrValueElement::Primitive(x) => Some(&x),
AttrValElement::Primitive(x) => Some(&x),
_ => None,
}
}
@ -180,30 +180,30 @@ mod test {
#[test]
fn test_parse_string_or_var_ref_list() {
let input = "{{foo}}{{bar}}b{}azb{a}z{{bat}}{}quok{{test}}";
let output = AttrValue::parse_string(input);
let output = AttrVal::parse_string(input);
assert_eq!(
output,
AttrValue(vec![
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("foo".to_owned()))),
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bar".to_owned()))),
AttrValueElement::primitive("b{}azb{a}z".to_owned()),
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("bat".to_owned()))),
AttrValueElement::primitive("{}quok".to_owned()),
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("test".to_owned()))),
AttrVal(vec![
AttrValElement::Expr(AttrValExpr::VarRef(VarName("foo".to_owned()))),
AttrValElement::Expr(AttrValExpr::VarRef(VarName("bar".to_owned()))),
AttrValElement::primitive("b{}azb{a}z".to_owned()),
AttrValElement::Expr(AttrValExpr::VarRef(VarName("bat".to_owned()))),
AttrValElement::primitive("{}quok".to_owned()),
AttrValElement::Expr(AttrValExpr::VarRef(VarName("test".to_owned()))),
]),
)
}
#[test]
fn test_parse_string_with_var_refs_attr_value() {
assert_eq!(
AttrValue(
AttrVal(
vec![
AttrValueElement::Expr(AttrValueExpr::VarRef(VarName("var".to_owned()))),
AttrValueElement::primitive("something".to_owned())
AttrValElement::Expr(AttrValExpr::VarRef(VarName("var".to_owned()))),
AttrValElement::primitive("something".to_owned())
]
.into()
),
AttrValue::parse_string("{{var}}something")
AttrVal::parse_string("{{var}}something")
);
}
}

View file

@ -52,24 +52,24 @@ impl std::fmt::Display for UnaryOp {
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)]
pub enum AttrValueExpr {
Literal(AttrValue),
pub enum AttrValExpr {
Literal(AttrVal),
VarRef(VarName),
BinOp(Box<AttrValueExpr>, BinOp, Box<AttrValueExpr>),
UnaryOp(UnaryOp, Box<AttrValueExpr>),
IfElse(Box<AttrValueExpr>, Box<AttrValueExpr>, Box<AttrValueExpr>),
JsonAccessIndex(Box<AttrValueExpr>, Box<AttrValueExpr>),
BinOp(Box<AttrValExpr>, BinOp, Box<AttrValExpr>),
UnaryOp(UnaryOp, Box<AttrValExpr>),
IfElse(Box<AttrValExpr>, Box<AttrValExpr>, Box<AttrValExpr>),
JsonAccess(Box<AttrValExpr>, Box<AttrValExpr>),
}
impl std::fmt::Display for AttrValueExpr {
impl std::fmt::Display for AttrValExpr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AttrValueExpr::VarRef(x) => write!(f, "{}", x),
AttrValueExpr::Literal(x) => write!(f, "\"{}\"", x),
AttrValueExpr::BinOp(l, op, r) => write!(f, "({} {} {})", l, op, r),
AttrValueExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
AttrValueExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
AttrValueExpr::JsonAccessIndex(value, index) => write!(f, "{}[{}]", value, index),
AttrValExpr::VarRef(x) => write!(f, "{}", x),
AttrValExpr::Literal(x) => write!(f, "\"{}\"", x),
AttrValExpr::BinOp(l, op, r) => write!(f, "({} {} {})", l, op, r),
AttrValExpr::UnaryOp(op, x) => write!(f, "{}{}", op, x),
AttrValExpr::IfElse(a, b, c) => write!(f, "(if {} then {} else {})", a, b, c),
AttrValExpr::JsonAccess(value, index) => write!(f, "{}[{}]", value, index),
}
}
}
@ -79,9 +79,9 @@ impl std::fmt::Display for AttrValueExpr {
// write!(f, "{:?}", self)
//}
impl AttrValueExpr {
impl AttrValExpr {
pub fn map_terminals_into(self, f: impl Fn(Self) -> Self) -> Self {
use AttrValueExpr::*;
use AttrValExpr::*;
match self {
BinOp(box a, op, box b) => BinOp(box f(a), op, box f(b)),
IfElse(box a, box b, box c) => IfElse(box f(a), box f(b), box f(c)),
@ -90,12 +90,12 @@ impl AttrValueExpr {
}
/// resolve variable references in the expression. Fails if a variable cannot be resolved.
pub fn resolve_refs(self, variables: &HashMap<VarName, PrimitiveValue>) -> Result<Self> {
use AttrValueExpr::*;
pub fn resolve_refs(self, variables: &HashMap<VarName, PrimVal>) -> Result<Self> {
use AttrValExpr::*;
match self {
// Literal(x) => Ok(Literal(AttrValue::from_primitive(x.resolve_fully(&variables)?))),
Literal(x) => Ok(Literal(x)),
VarRef(ref name) => Ok(Literal(AttrValue::from_primitive(
VarRef(ref name) => Ok(Literal(AttrVal::from_primitive(
variables.get(name).with_context(|| format!("Unknown variable {} referenced in {:?}", &name, &self))?.clone(),
))),
BinOp(box a, op, box b) => Ok(BinOp(box a.resolve_refs(variables)?, op, box b.resolve_refs(variables)?)),
@ -103,12 +103,12 @@ impl AttrValueExpr {
IfElse(box a, box b, box c) => {
Ok(IfElse(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?, box c.resolve_refs(variables)?))
}
JsonAccessIndex(box a, box b) => Ok(JsonAccessIndex(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?)),
JsonAccess(box a, box b) => Ok(JsonAccess(box a.resolve_refs(variables)?, box b.resolve_refs(variables)?)),
}
}
pub fn var_refs(&self) -> Vec<&VarName> {
use AttrValueExpr::*;
use AttrValExpr::*;
match self {
Literal(s) => s.var_refs().collect(),
VarRef(name) => vec![name],
@ -124,7 +124,7 @@ impl AttrValueExpr {
refs.append(&mut c.var_refs());
refs
}
JsonAccessIndex(box a, box b) => {
JsonAccess(box a, box b) => {
let mut refs = a.var_refs();
refs.append(&mut b.var_refs());
refs
@ -132,60 +132,60 @@ impl AttrValueExpr {
}
}
pub fn eval(self, values: &HashMap<VarName, PrimitiveValue>) -> Result<PrimitiveValue> {
pub fn eval(self, values: &HashMap<VarName, PrimVal>) -> Result<PrimVal> {
match self {
AttrValueExpr::Literal(x) => x.resolve_fully(&values),
AttrValueExpr::VarRef(ref name) => values
AttrValExpr::Literal(x) => x.resolve_fully(&values),
AttrValExpr::VarRef(ref name) => values
.get(name)
.cloned()
.context(format!("Got unresolved variable {} while trying to evaluate expression {:?}", &name, &self)),
AttrValueExpr::BinOp(a, op, b) => {
AttrValExpr::BinOp(a, op, b) => {
let a = a.eval(values)?;
let b = b.eval(values)?;
Ok(match op {
BinOp::Equals => PrimitiveValue::from(a == b),
BinOp::NotEquals => PrimitiveValue::from(a != b),
BinOp::And => PrimitiveValue::from(a.as_bool()? && b.as_bool()?),
BinOp::Or => PrimitiveValue::from(a.as_bool()? || b.as_bool()?),
BinOp::Equals => PrimVal::from(a == b),
BinOp::NotEquals => PrimVal::from(a != b),
BinOp::And => PrimVal::from(a.as_bool()? && b.as_bool()?),
BinOp::Or => PrimVal::from(a.as_bool()? || b.as_bool()?),
BinOp::Plus => PrimitiveValue::from(a.as_f64()? + b.as_f64()?),
BinOp::Minus => PrimitiveValue::from(a.as_f64()? - b.as_f64()?),
BinOp::Times => PrimitiveValue::from(a.as_f64()? * b.as_f64()?),
BinOp::Div => PrimitiveValue::from(a.as_f64()? / b.as_f64()?),
BinOp::Mod => PrimitiveValue::from(a.as_f64()? % b.as_f64()?),
BinOp::GT => PrimitiveValue::from(a.as_f64()? > b.as_f64()?),
BinOp::LT => PrimitiveValue::from(a.as_f64()? < b.as_f64()?),
BinOp::Elvis => PrimitiveValue::from(if a.0.is_empty() { b } else { a }),
BinOp::Plus => PrimVal::from(a.as_f64()? + b.as_f64()?),
BinOp::Minus => PrimVal::from(a.as_f64()? - b.as_f64()?),
BinOp::Times => PrimVal::from(a.as_f64()? * b.as_f64()?),
BinOp::Div => PrimVal::from(a.as_f64()? / b.as_f64()?),
BinOp::Mod => PrimVal::from(a.as_f64()? % b.as_f64()?),
BinOp::GT => PrimVal::from(a.as_f64()? > b.as_f64()?),
BinOp::LT => PrimVal::from(a.as_f64()? < b.as_f64()?),
BinOp::Elvis => PrimVal::from(if a.0.is_empty() { b } else { a }),
})
}
AttrValueExpr::UnaryOp(op, a) => {
AttrValExpr::UnaryOp(op, a) => {
let a = a.eval(values)?;
Ok(match op {
UnaryOp::Not => PrimitiveValue::from(!a.as_bool()?),
UnaryOp::Not => PrimVal::from(!a.as_bool()?),
})
}
AttrValueExpr::IfElse(cond, yes, no) => {
AttrValExpr::IfElse(cond, yes, no) => {
if cond.eval(values)?.as_bool()? {
yes.eval(values)
} else {
no.eval(values)
}
}
AttrValueExpr::JsonAccessIndex(val, index) => {
AttrValExpr::JsonAccess(val, index) => {
let val = val.eval(values)?;
let index = index.eval(values)?;
match val.as_json_value()? {
serde_json::Value::Array(val) => {
let index = index.as_i32()?;
let indexed_value = val.get(index as usize).unwrap_or(&serde_json::Value::Null);
Ok(PrimitiveValue::from(indexed_value))
Ok(PrimVal::from(indexed_value))
}
serde_json::Value::Object(val) => {
let indexed_value = val
.get(&index.as_string()?)
.or_else(|| val.get(&format!("{}", index.as_i32().ok()?)))
.or_else(|| val.get(&index.as_i32().ok()?.to_string()))
.unwrap_or(&serde_json::Value::Null);
Ok(PrimitiveValue::from(indexed_value))
Ok(PrimVal::from(indexed_value))
}
_ => bail!("Unable to index into value {}", val),
}

View file

@ -53,34 +53,34 @@ fn parse_unary_op(i: &str) -> IResult<&str, UnaryOp, VerboseError<&str>> {
// actual tree //
/////////////////
fn parse_factor(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_factor(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, unary_op) = opt(parse_unary_op)(i)?;
let (i, factor) = alt((
context("expression", ws(delimited(tag("("), parse_expr, tag(")")))),
context("if-expression", ws(parse_ifelse)),
context("literal", map(ws(parse_literal), |x| AttrValueExpr::Literal(AttrValue::parse_string(x)))),
context("identifier", map(ws(parse_identifier), |x| AttrValueExpr::VarRef(VarName(x.to_string())))),
context("literal", map(ws(parse_literal), |x| AttrValExpr::Literal(AttrVal::parse_string(x)))),
context("identifier", map(ws(parse_identifier), |x| AttrValExpr::VarRef(VarName(x.to_string())))),
))(i)?;
Ok((
i,
match unary_op {
Some(op) => AttrValueExpr::UnaryOp(op, box factor),
Some(op) => AttrValExpr::UnaryOp(op, box factor),
None => factor,
},
))
}
fn parse_object_index(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_object_index(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, initial) = parse_factor(i)?;
let (i, remainder) = many0(alt((
delimited(tag("["), ws(parse_expr), tag("]")),
map(preceded(tag("."), parse_identifier), |x| AttrValueExpr::Literal(AttrValue::from_primitive(x))),
map(preceded(tag("."), parse_identifier), |x| AttrValExpr::Literal(AttrVal::from_primitive(x))),
)))(i)?;
let indexes = remainder.into_iter().fold(initial, |acc, index| AttrValueExpr::JsonAccessIndex(box acc, box index));
let indexes = remainder.into_iter().fold(initial, |acc, index| AttrValExpr::JsonAccess(box acc, box index));
Ok((i, indexes))
}
fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_term3(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, initial) = parse_object_index(i)?;
let (i, remainder) = many0(alt((
map(preceded(tag("*"), parse_object_index), |x| (BinOp::Times, x)),
@ -88,23 +88,23 @@ fn parse_term3(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("%"), parse_object_index), |x| (BinOp::Mod, x)),
)))(i)?;
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
Ok((i, exprs))
}
fn parse_term2(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_term2(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, initial) = parse_term3(i)?;
let (i, remainder) = many0(alt((
map(preceded(tag("+"), parse_term3), |x| (BinOp::Plus, x)),
map(preceded(tag("-"), parse_term3), |x| (BinOp::Minus, x)),
)))(i)?;
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
Ok((i, exprs))
}
fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_term1(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, initial) = parse_term2(i)?;
let (i, remainder) = many0(alt((
map(preceded(tag("=="), parse_term2), |x| (BinOp::Equals, x)),
@ -113,11 +113,11 @@ fn parse_term1(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("<"), parse_term2), |x| (BinOp::LT, x)),
)))(i)?;
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
Ok((i, exprs))
}
pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
pub fn parse_expr(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, initial) = parse_term1(i)?;
let (i, remainder) = many0(alt((
map(preceded(tag("&&"), parse_term1), |x| (BinOp::And, x)),
@ -125,22 +125,22 @@ pub fn parse_expr(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
map(preceded(tag("?:"), parse_term1), |x| (BinOp::Elvis, x)),
)))(i)?;
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValueExpr::BinOp(box acc, op, box expr));
let exprs = remainder.into_iter().fold(initial, |acc, (op, expr)| AttrValExpr::BinOp(box acc, op, box expr));
Ok((i, exprs))
}
fn parse_ifelse(i: &str) -> IResult<&str, AttrValueExpr, VerboseError<&str>> {
fn parse_ifelse(i: &str) -> IResult<&str, AttrValExpr, VerboseError<&str>> {
let (i, _) = tag("if")(i)?;
let (i, a) = context("condition", ws(parse_expr))(i)?;
let (i, _) = tag("then")(i)?;
let (i, b) = context("true-case", ws(parse_expr))(i)?;
let (i, _) = tag("else")(i)?;
let (i, c) = context("false-case", ws(parse_expr))(i)?;
Ok((i, AttrValueExpr::IfElse(box a, box b, box c)))
Ok((i, AttrValExpr::IfElse(box a, box b, box c)))
}
pub fn parse<'a>(i: &'a str) -> IResult<&'a str, AttrValueExpr, VerboseError<&'a str>> {
pub fn parse<'a>(i: &'a str) -> IResult<&'a str, AttrValExpr, VerboseError<&'a str>> {
complete(parse_expr)(i)
}
@ -150,64 +150,64 @@ mod test {
use pretty_assertions::assert_eq;
#[test]
fn test_parser() {
assert_eq!(AttrValueExpr::Literal(AttrValue::from_primitive("12")), AttrValueExpr::parse("12").unwrap());
assert_eq!(AttrValExpr::Literal(AttrVal::from_primitive("12")), AttrValExpr::parse("12").unwrap());
assert_eq!(
AttrValueExpr::UnaryOp(UnaryOp::Not, box AttrValueExpr::Literal(AttrValue::from_primitive("false"))),
AttrValueExpr::parse("!false").unwrap()
AttrValExpr::UnaryOp(UnaryOp::Not, box AttrValExpr::Literal(AttrVal::from_primitive("false"))),
AttrValExpr::parse("!false").unwrap()
);
assert_eq!(
AttrValueExpr::BinOp(
box AttrValueExpr::Literal(AttrValue::from_primitive("12")),
AttrValExpr::BinOp(
box AttrValExpr::Literal(AttrVal::from_primitive("12")),
BinOp::Plus,
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
),
AttrValueExpr::parse("12 + 2").unwrap()
AttrValExpr::parse("12 + 2").unwrap()
);
assert_eq!(
AttrValueExpr::UnaryOp(
AttrValExpr::UnaryOp(
UnaryOp::Not,
box AttrValueExpr::BinOp(
box AttrValueExpr::Literal(AttrValue::from_primitive("1")),
box AttrValExpr::BinOp(
box AttrValExpr::Literal(AttrVal::from_primitive("1")),
BinOp::Equals,
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
)
),
AttrValueExpr::parse("!(1 == 2)").unwrap()
AttrValExpr::parse("!(1 == 2)").unwrap()
);
assert_eq!(
AttrValueExpr::IfElse(
box AttrValueExpr::VarRef(VarName("a".to_string())),
box AttrValueExpr::VarRef(VarName("b".to_string())),
box AttrValueExpr::VarRef(VarName("c".to_string())),
AttrValExpr::IfElse(
box AttrValExpr::VarRef(VarName("a".to_string())),
box AttrValExpr::VarRef(VarName("b".to_string())),
box AttrValExpr::VarRef(VarName("c".to_string())),
),
AttrValueExpr::parse("if a then b else c").unwrap()
AttrValExpr::parse("if a then b else c").unwrap()
);
assert_eq!(
AttrValueExpr::JsonAccessIndex(
box AttrValueExpr::VarRef(VarName("array".to_string())),
box AttrValueExpr::BinOp(
box AttrValueExpr::Literal(AttrValue::from_primitive("1")),
AttrValExpr::JsonAccess(
box AttrValExpr::VarRef(VarName("array".to_string())),
box AttrValExpr::BinOp(
box AttrValExpr::Literal(AttrVal::from_primitive("1")),
BinOp::Plus,
box AttrValueExpr::Literal(AttrValue::from_primitive("2"))
box AttrValExpr::Literal(AttrVal::from_primitive("2"))
)
),
AttrValueExpr::parse(r#"(array)[1+2]"#).unwrap()
AttrValExpr::parse(r#"(array)[1+2]"#).unwrap()
);
assert_eq!(
AttrValueExpr::JsonAccessIndex(
box AttrValueExpr::JsonAccessIndex(
box AttrValueExpr::VarRef(VarName("object".to_string())),
box AttrValueExpr::Literal(AttrValue::from_primitive("field".to_string())),
AttrValExpr::JsonAccess(
box AttrValExpr::JsonAccess(
box AttrValExpr::VarRef(VarName("object".to_string())),
box AttrValExpr::Literal(AttrVal::from_primitive("field".to_string())),
),
box AttrValueExpr::Literal(AttrValue::from_primitive("field2".to_string())),
box AttrValExpr::Literal(AttrVal::from_primitive("field2".to_string())),
),
AttrValueExpr::parse(r#"object.field.field2"#).unwrap()
AttrValExpr::parse(r#"object.field.field2"#).unwrap()
);
}
#[test]
fn test_complex() {
let parsed =
AttrValueExpr::parse(r#"if hi > 12 + 2 * 2 && 12 == 15 then "foo" else if !true then 'hi' else "{{bruh}}""#).unwrap();
AttrValExpr::parse(r#"if hi > 12 + 2 * 2 && 12 == 15 then "foo" else if !true then 'hi' else "{{bruh}}""#).unwrap();
assert_eq!(
r#"(if ((hi > ("12" + ("2" * "2"))) && ("12" == "15")) then "foo" else (if !"true" then "hi" else "{{bruh}}"))"#,

View file

@ -6,21 +6,21 @@ use std::{convert::TryFrom, fmt, iter::FromIterator};
use crate::impl_try_from;
#[derive(Clone, Deserialize, Serialize, derive_more::From, Default)]
pub struct PrimitiveValue(pub String);
pub struct PrimVal(pub String);
impl fmt::Display for PrimitiveValue {
impl fmt::Display for PrimVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl fmt::Debug for PrimitiveValue {
impl fmt::Debug for PrimVal {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\"{}\"", self.0)
}
}
/// Manually implement equality, to allow for values in different formats (i.e. "1" and "1.0") to still be considered as equal.
impl std::cmp::PartialEq<Self> for PrimitiveValue {
impl std::cmp::PartialEq<Self> for PrimVal {
fn eq(&self, other: &Self) -> bool {
if let (Ok(a), Ok(b)) = (self.as_f64(), other.as_f64()) {
a == b
@ -30,56 +30,56 @@ impl std::cmp::PartialEq<Self> for PrimitiveValue {
}
}
impl FromIterator<PrimitiveValue> for PrimitiveValue {
fn from_iter<T: IntoIterator<Item = PrimitiveValue>>(iter: T) -> Self {
PrimitiveValue(iter.into_iter().join(""))
impl FromIterator<PrimVal> for PrimVal {
fn from_iter<T: IntoIterator<Item = PrimVal>>(iter: T) -> Self {
PrimVal(iter.into_iter().join(""))
}
}
impl std::str::FromStr for PrimitiveValue {
impl std::str::FromStr for PrimVal {
type Err = anyhow::Error;
/// parses the value, trying to turn it into a number and a boolean first,
/// before deciding that it is a string.
fn from_str(s: &str) -> Result<Self> {
Ok(PrimitiveValue::from_string(s.to_string()))
Ok(PrimVal::from_string(s.to_string()))
}
}
impl_try_from!(PrimitiveValue {
impl_try_from!(PrimVal {
for String => |x| x.as_string();
for f64 => |x| x.as_f64();
for bool => |x| x.as_bool();
for Vec<String> => |x| x.as_vec();
});
impl From<bool> for PrimitiveValue {
impl From<bool> for PrimVal {
fn from(x: bool) -> Self {
PrimitiveValue(x.to_string())
PrimVal(x.to_string())
}
}
impl From<i32> for PrimitiveValue {
impl From<i32> for PrimVal {
fn from(s: i32) -> Self {
PrimitiveValue(s.to_string())
PrimVal(s.to_string())
}
}
impl From<f64> for PrimitiveValue {
impl From<f64> for PrimVal {
fn from(s: f64) -> Self {
PrimitiveValue(s.to_string())
PrimVal(s.to_string())
}
}
impl From<&str> for PrimitiveValue {
impl From<&str> for PrimVal {
fn from(s: &str) -> Self {
PrimitiveValue(s.to_string())
PrimVal(s.to_string())
}
}
impl From<&serde_json::Value> for PrimitiveValue {
impl From<&serde_json::Value> for PrimVal {
fn from(v: &serde_json::Value) -> Self {
PrimitiveValue(
PrimVal(
v.as_str()
.map(|x| x.to_string())
.or_else(|| serde_json::to_string(v).ok())
@ -88,9 +88,9 @@ impl From<&serde_json::Value> for PrimitiveValue {
}
}
impl PrimitiveValue {
impl PrimVal {
pub fn from_string(s: String) -> Self {
PrimitiveValue(s)
PrimVal(s)
}
pub fn into_inner(self) -> String {

View file

@ -154,7 +154,7 @@ macro_rules! resolve_block {
};
(@get_value $args:ident, $name:expr, = $default:expr) => {
$args.widget.get_attr($name).cloned().unwrap_or(AttrValue::from_primitive($default))
$args.widget.get_attr($name).cloned().unwrap_or(AttrVal::from_primitive($default))
};
(@get_value $args:ident, $name:expr,) => {

View file

@ -1,5 +1,5 @@
use super::{run_command, BuilderArgs};
use crate::{config, eww_state, resolve_block, value::AttrValue, widgets::widget_node};
use crate::{config, eww_state, resolve_block, value::AttrVal, widgets::widget_node};
use anyhow::*;
use gtk::{prelude::*, ImageExt};
use std::{cell::RefCell, collections::HashMap, rc::Rc};
@ -377,7 +377,7 @@ fn build_gtk_image(bargs: &mut BuilderArgs) -> Result<gtk::Image> {
// @prop width - width of the image
// @prop height - height of the image
prop(path: as_string, width: as_i32 = 10000, height: as_i32 = 10000) {
if path.ends_with(".gif") {
if path.ends_with(".gif") {
let pixbuf_animation = gdk_pixbuf::PixbufAnimation::from_file(std::path::PathBuf::from(path))?;
gtk_widget.set_from_animation(&pixbuf_animation);
} else {

View file

@ -5,7 +5,7 @@ use crate::{
WindowName,
},
eww_state::EwwState,
value::{AttrName, AttrValue, VarName},
value::{AttrName, AttrVal, VarName},
};
use anyhow::*;
use dyn_clone;
@ -62,11 +62,11 @@ pub struct Generic {
pub name: String,
pub text_pos: Option<TextPos>,
pub children: Vec<Box<dyn WidgetNode>>,
pub attrs: HashMap<AttrName, AttrValue>,
pub attrs: HashMap<AttrName, AttrVal>,
}
impl Generic {
pub fn get_attr(&self, key: &str) -> Result<&AttrValue> {
pub fn get_attr(&self, key: &str) -> Result<&AttrVal> {
self.attrs.get(key).context(format!("attribute '{}' missing from use of '{}'", key, &self.name))
}
@ -98,7 +98,7 @@ impl WidgetNode for Generic {
pub fn generate_generic_widget_node(
defs: &HashMap<String, WidgetDefinition>,
local_env: &HashMap<VarName, AttrValue>,
local_env: &HashMap<VarName, AttrVal>,
w: WidgetUse,
) -> Result<Box<dyn WidgetNode>> {
if let Some(def) = defs.get(&w.name) {