Skip to content

Commit

Permalink
Support actions in def_widget macro
Browse files Browse the repository at this point in the history
  • Loading branch information
elkowar committed Apr 26, 2022
1 parent f36ed31 commit 4f7a756
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 25 deletions.
36 changes: 26 additions & 10 deletions crates/eww/src/widgets/def_widget_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ macro_rules! def_widget {
// If an attribute is explicitly marked as optional (? appended to type)
// the attribute will still show up here, as a `None` value. Otherwise, all values in this map
// will be `Some`.
let attr_map: Result<HashMap<eww_shared_util::AttrName, Option<simplexpr::SimplExpr>>> = try {
let attr_map: Result<HashMap<eww_shared_util::AttrName, Option<yuck::config::action::AttrValue>>> = try {
::maplit::hashmap! {
$(
eww_shared_util::AttrName(::std::stringify!($attr_name).to_owned()) =>
Expand All @@ -32,7 +32,7 @@ macro_rules! def_widget {
// Get all the variables that are referred to in any of the attributes expressions
let required_vars: Vec<eww_shared_util::VarName> = attr_map
.values()
.flat_map(|expr| expr.as_ref().map(|x| x.collect_var_refs()).unwrap_or_default())
.flat_map(|expr| expr.as_ref().and_then(|x| x.try_into_simplexpr()).map(|x| x.collect_var_refs()).unwrap_or_default())
.collect();

$args.scope_graph.register_listener(
Expand All @@ -53,13 +53,13 @@ macro_rules! def_widget {
let $attr_name = attr_map.get(::std::stringify!($attr_name))
.context("Missing attribute, this should never happen")?;

// if the value is Some, evaluate and typecast it as expected
let $attr_name = if let Some(x) = $attr_name {
Some(x.eval(&values)?.$typecast_func()?)
} else {
None
};
// If the attribute is optional, keep it as Option<T>, otherwise unwrap


// If the value is some, evaluate and typecast it.
// This now uses a new macro, to match on the type cast function:
// if we're casting into an action, we wanna do a different thing than if we where casting into an expr
let $attr_name = def_widget!(@value_depending_on_type values, $attr_name : $typecast_func $(? $(@ $optional @)?)? $(= $default)?); // If the attribute is optional, keep it as Option<T>, otherwise unwrap

// because we _know_ the value in the attr_map is Some if the attribute is not optional.
def_widget!(@unwrap_if_required $attr_name $(? $($optional)?)?);
)*
Expand All @@ -76,6 +76,20 @@ macro_rules! def_widget {
})+
};

(@value_depending_on_type $values:expr, $attr_name:ident : as_action $(? $(@ $optional:tt @)?)? $(= $default:expr)?) => {
match $attr_name {
Some(yuck::config::action::AttrValue::Action(action)) => Some(action.eval_exprs(&$values)?),
_ => None,
}
};

(@value_depending_on_type $values:expr, $attr_name:ident : $typecast_func:ident $(? $(@ $optional:tt @)?)? $(= $default:expr)?) => {
match $attr_name {
Some(yuck::config::action::AttrValue::SimplExpr(expr)) => Some(expr.eval(&$values)?.$typecast_func()?),
_ => None,
}
};

(@unwrap_if_required $value:ident ?) => { };
(@unwrap_if_required $value:ident) => {
let $value = $value.unwrap();
Expand All @@ -88,7 +102,9 @@ macro_rules! def_widget {

// The attribute has a default value
(@get_value $args:ident, $name:expr, = $default:expr) => {
Some($args.widget_use.attrs.ast_optional::<yuck::config::action::AttrValue>($name)?.clone().unwrap_or_else(|| simplexpr::SimplExpr::synth_literal($default)))
Some($args.widget_use.attrs.ast_optional::<yuck::config::action::AttrValue>($name)?
.clone()
.unwrap_or_else(|| yuck::config::action::AttrValue::SimplExpr(simplexpr::SimplExpr::synth_literal($default))))
};

// The attribute is required - the prop will only be ran if this attribute is actually provided.
Expand Down
2 changes: 1 addition & 1 deletion crates/eww/src/widgets/widget_definitions.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#![allow(clippy::option_map_unit_fn)]
use super::{build_widget::BuilderArgs, circular_progressbar::*, transform::*, run_command};
use super::{build_widget::BuilderArgs, circular_progressbar::*, run_command, transform::*};
use crate::{
def_widget, enum_parse,
error::DiagError,
Expand Down
35 changes: 28 additions & 7 deletions crates/yuck/src/config/action.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use std::collections::HashMap;

use eww_shared_util::VarName;
use simplexpr::SimplExpr;
use simplexpr::{dynval::DynVal, eval::EvalError, SimplExpr};

pub static ACTION_NAMES: &[&str] = &["update"];

Expand All @@ -10,13 +12,32 @@ pub enum AttrValue {
SimplExpr(SimplExpr),
}

#[derive(Debug, Clone)]
impl AttrValue {
pub fn try_into_simplexpr(&self) -> Option<&SimplExpr> {
match self {
Self::SimplExpr(x) => Some(x),
_ => None,
}
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Action {
Update(Update),
Update(VarName, SimplExpr),
Noop,
}

#[derive(Debug, Clone)]
pub struct Update {
pub varname: VarName,
pub value: SimplExpr,
impl Action {
pub fn eval_exprs(&self, values: &HashMap<VarName, DynVal>) -> Result<ResolvedAction, EvalError> {
Ok(match self {
Self::Update(varname, expr) => ResolvedAction::Update(varname.clone(), expr.eval(values)?),
Self::Noop => ResolvedAction::Noop,
})
}
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub enum ResolvedAction {
Update(VarName, DynVal),
Noop,
}
13 changes: 6 additions & 7 deletions crates/yuck/src/parser/from_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ use super::{
ast::{Ast, AstType},
ast_iterator::AstIterator,
};
use crate::{
config::action::{AttrValue, Update},
error::*,
parser,
};
use crate::{config::action::AttrValue, error::*, parser};
use eww_shared_util::{AttrName, Span, VarName};
use itertools::Itertools;
use simplexpr::{ast::SimplExpr, dynval::DynVal};
Expand Down Expand Up @@ -71,14 +67,17 @@ impl FromAst for Action {
let (varname_span, varname) = iter.expect_symbol()?;
let (value_span, value) = iter.expect_simplexpr()?;
iter.expect_done()?;
Ok(Action::Update(Update { varname: VarName(varname), value }))
Ok(Action::Update(VarName(varname), value))
}
_ => Err(AstError::UnknownAction(span, action)),
}
}
}
impl FromAst for AttrValue {
fn from_ast(e: Ast) -> AstResult<Self> {
todo!()
match &e {
Ast::List(..) => Ok(AttrValue::Action(Action::from_ast(e)?)),
_ => Ok(AttrValue::SimplExpr(SimplExpr::from_ast(e)?)),
}
}
}

0 comments on commit 4f7a756

Please sign in to comment.