feat(config): Add optional widget arguments prefixed with ?
This commit is contained in:
parent
7aa8d8a404
commit
c380313ba7
4 changed files with 39 additions and 9 deletions
|
@ -2,7 +2,7 @@ use crate::eww_state::EwwState;
|
||||||
use anyhow::*;
|
use anyhow::*;
|
||||||
use dyn_clone;
|
use dyn_clone;
|
||||||
use eww_shared_util::{AttrName, Span, Spanned, VarName};
|
use eww_shared_util::{AttrName, Span, Spanned, VarName};
|
||||||
use simplexpr::SimplExpr;
|
use simplexpr::{dynval::DynVal, SimplExpr};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use yuck::{
|
use yuck::{
|
||||||
config::{validate::ValidationError, widget_definition::WidgetDefinition, widget_use::WidgetUse},
|
config::{validate::ValidationError, widget_definition::WidgetDefinition, widget_use::WidgetUse},
|
||||||
|
@ -116,13 +116,20 @@ pub fn generate_generic_widget_node(
|
||||||
Err(AstError::TooManyNodes(w.children_span(), 0).note("User-defined widgets cannot be given children."))?
|
Err(AstError::TooManyNodes(w.children_span(), 0).note("User-defined widgets cannot be given children."))?
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_local_env = w
|
let mut new_local_env = w
|
||||||
.attrs
|
.attrs
|
||||||
.attrs
|
.attrs
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, value)| Ok((VarName(name.0), value.value.as_simplexpr()?.resolve_one_level(local_env))))
|
.map(|(name, value)| Ok((VarName(name.0), value.value.as_simplexpr()?.resolve_one_level(local_env))))
|
||||||
.collect::<AstResult<HashMap<VarName, _>>>()?;
|
.collect::<AstResult<HashMap<VarName, _>>>()?;
|
||||||
|
|
||||||
|
for expected in def.expected_args.iter().filter(|x| x.optional) {
|
||||||
|
let var_name = VarName(expected.name.clone().0);
|
||||||
|
if !new_local_env.contains_key(&var_name) {
|
||||||
|
new_local_env.insert(var_name, SimplExpr::Literal(DynVal::from(String::new())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let content = generate_generic_widget_node(defs, &new_local_env, def.widget.clone())?;
|
let content = generate_generic_widget_node(defs, &new_local_env, def.widget.clone())?;
|
||||||
Ok(Box::new(UserDefined { name: w.name, span: w.span, content }))
|
Ok(Box::new(UserDefined { name: w.name, span: w.span, content }))
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -59,7 +59,7 @@ pub fn validate_widget_definition(
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
let mut variables_in_scope = globals.clone();
|
let mut variables_in_scope = globals.clone();
|
||||||
for arg in def.expected_args.iter() {
|
for arg in def.expected_args.iter() {
|
||||||
variables_in_scope.insert(VarName(arg.0.to_string()));
|
variables_in_scope.insert(VarName(arg.name.to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
validate_variables_in_widget_use(other_defs, &variables_in_scope, &def.widget, true)
|
validate_variables_in_widget_use(other_defs, &variables_in_scope, &def.widget, true)
|
||||||
|
@ -73,11 +73,14 @@ pub fn validate_variables_in_widget_use(
|
||||||
) -> Result<(), ValidationError> {
|
) -> Result<(), ValidationError> {
|
||||||
let matching_definition = defs.get(&widget.name);
|
let matching_definition = defs.get(&widget.name);
|
||||||
if let Some(matching_def) = matching_definition {
|
if let Some(matching_def) = matching_definition {
|
||||||
let missing_arg = matching_def.expected_args.iter().find(|expected| !widget.attrs.attrs.contains_key(*expected));
|
let missing_arg = matching_def
|
||||||
|
.expected_args
|
||||||
|
.iter()
|
||||||
|
.find(|expected| !expected.optional && !widget.attrs.attrs.contains_key(&expected.name));
|
||||||
if let Some(missing_arg) = missing_arg {
|
if let Some(missing_arg) = missing_arg {
|
||||||
return Err(ValidationError::MissingAttr {
|
return Err(ValidationError::MissingAttr {
|
||||||
widget_name: widget.name.clone(),
|
widget_name: widget.name.clone(),
|
||||||
arg_name: missing_arg.clone(),
|
arg_name: missing_arg.name.clone(),
|
||||||
arg_list_span: Some(matching_def.args_span),
|
arg_list_span: Some(matching_def.args_span),
|
||||||
use_span: widget.attrs.span,
|
use_span: widget.attrs.span,
|
||||||
});
|
});
|
||||||
|
|
|
@ -13,10 +13,27 @@ use crate::{
|
||||||
use eww_shared_util::{AttrName, Span, Spanned, VarName};
|
use eww_shared_util::{AttrName, Span, Spanned, VarName};
|
||||||
|
|
||||||
use super::widget_use::WidgetUse;
|
use super::widget_use::WidgetUse;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)]
|
||||||
|
pub struct AttrSpec {
|
||||||
|
pub name: AttrName,
|
||||||
|
pub optional: bool,
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromAst for AttrSpec {
|
||||||
|
fn from_ast(e: Ast) -> AstResult<Self> {
|
||||||
|
let span = e.span();
|
||||||
|
let symbol = e.as_symbol()?;
|
||||||
|
let (name, optional) = if let Some(name) = symbol.strip_prefix('?') { (name.to_string(), true) } else { (symbol, false) };
|
||||||
|
Ok(Self { name: AttrName(name), optional, span })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)]
|
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize)]
|
||||||
pub struct WidgetDefinition {
|
pub struct WidgetDefinition {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub expected_args: Vec<AttrName>,
|
pub expected_args: Vec<AttrSpec>,
|
||||||
pub widget: WidgetUse,
|
pub widget: WidgetUse,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
pub args_span: Span,
|
pub args_span: Span,
|
||||||
|
@ -31,7 +48,7 @@ impl FromAstElementContent for WidgetDefinition {
|
||||||
.expect_array()
|
.expect_array()
|
||||||
.wrong_expr_type_to(|_, _| Some(FormFormatError::WidgetDefArglistMissing(name_span.point_span_at_end())))
|
.wrong_expr_type_to(|_, _| Some(FormFormatError::WidgetDefArglistMissing(name_span.point_span_at_end())))
|
||||||
.note(EXPECTED_WIDGET_DEF_FORMAT)?;
|
.note(EXPECTED_WIDGET_DEF_FORMAT)?;
|
||||||
let expected_args = expected_args.into_iter().map(|x| x.as_symbol().map(AttrName)).collect::<AstResult<_>>()?;
|
let expected_args = expected_args.into_iter().map(AttrSpec::from_ast).collect::<AstResult<_>>()?;
|
||||||
let widget = iter.expect_any().note(EXPECTED_WIDGET_DEF_FORMAT).and_then(WidgetUse::from_ast)?;
|
let widget = iter.expect_any().note(EXPECTED_WIDGET_DEF_FORMAT).and_then(WidgetUse::from_ast)?;
|
||||||
iter.expect_done().map_err(|e| FormFormatError::WidgetDefMultipleChildren(e.span()))?;
|
iter.expect_done().map_err(|e| FormFormatError::WidgetDefMultipleChildren(e.span()))?;
|
||||||
Ok(Self { name, expected_args, widget, span, args_span })
|
Ok(Self { name, expected_args, widget, span, args_span })
|
||||||
|
|
|
@ -89,7 +89,7 @@ Depending on if you are using X11 or wayland, some additional properties exist:
|
||||||
While our bar is already looking great, it's a bit boring. Thus, let's add some actual content!
|
While our bar is already looking great, it's a bit boring. Thus, let's add some actual content!
|
||||||
|
|
||||||
```lisp
|
```lisp
|
||||||
(defwidget greeter [text name]
|
(defwidget greeter [?text name]
|
||||||
(box :orientation "horizontal"
|
(box :orientation "horizontal"
|
||||||
:halign "center"
|
:halign "center"
|
||||||
text
|
text
|
||||||
|
@ -108,7 +108,10 @@ To show this, let's replace the text in our window definition with a call to thi
|
||||||
|
|
||||||
There is a lot going on here, so let's step through this.
|
There is a lot going on here, so let's step through this.
|
||||||
|
|
||||||
We are creating a widget named `greeter`. This widget takes two attributes, called `text` and `name`, which must be set when the widget is used.
|
We are creating a widget named `greeter`. This widget takes two attributes, called `text` and `name`.
|
||||||
|
The declaration `?text` specifies that the `text`-attribute is optional, and can thus be left out. In that case,
|
||||||
|
it's value will be the empty string `""`.
|
||||||
|
The `name` attribute _must_ be provided.
|
||||||
|
|
||||||
Now, we declare the body of our widget. We make use of a `box`, which we set a couple attributes of.
|
Now, we declare the body of our widget. We make use of a `box`, which we set a couple attributes of.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue