diff --git a/src/util.rs b/src/util.rs index 08a6a4c..31c89c7 100644 --- a/src/util.rs +++ b/src/util.rs @@ -50,6 +50,48 @@ macro_rules! loop_select { } } +/// Parse a string with a concrete set of options into some data-structure, +/// and return a nicely formatted error message on invalid values. I.e.: +/// ```rs +/// let input = "up"; +/// enum_parse { "direction", input, +/// "up" => Direction::Up, +/// "down" => Direction::Down, +/// } +/// ``` +#[macro_export] +macro_rules! enum_parse { + ($name:literal, $input:expr, $($($s:literal)|* => $val:expr),* $(,)?) => { + let input = $input; + match input { + $( $( $s )|* => Ok($val) ),*, + _ => Err(anyhow!(concat!("Couldn't parse ", $name, ": '{}'. Possible values are ", $($($s),*),*), input)) + } + }; +} + +/// Compute the difference of two lists, returning a tuple of +/// ( +/// elements that where in a but not in b, +/// elements that where in b but not in a +/// ). +pub fn list_difference<'a, 'b, T: PartialEq>(a: &'a [T], b: &'b [T]) -> (Vec<&'a T>, Vec<&'b T>) { + let mut missing = Vec::new(); + for elem in a { + if !b.contains(elem) { + missing.push(elem); + } + } + + let mut new = Vec::new(); + for elem in b { + if !a.contains(elem) { + new.push(elem); + } + } + (missing, new) +} + /// Joins two paths while keeping it somewhat pretty. /// If the second path is absolute, this will just return the second path. /// If it is relative, it will return the second path joined onto the first path, removing any `./` if present. @@ -112,7 +154,6 @@ pub fn parse_duration(s: &str) -> Result { } } - pub trait IterAverage { fn avg(self) -> f32; } diff --git a/src/widgets/widget_definitions.rs b/src/widgets/widget_definitions.rs index 701f58c..a2bce03 100644 --- a/src/widgets/widget_definitions.rs +++ b/src/widgets/widget_definitions.rs @@ -1,6 +1,11 @@ #![allow(clippy::option_map_unit_fn)] use super::{run_command, BuilderArgs}; -use crate::{config, eww_state, resolve_block, value::AttrVal, widgets::widget_node, util::parse_duration}; +use crate::{ + config, enum_parse, eww_state, resolve_block, + util::{list_difference, parse_duration}, + value::AttrVal, + widgets::widget_node, +}; use anyhow::*; use gdk::WindowExt; use glib; @@ -275,11 +280,11 @@ fn build_gtk_revealer(bargs: &mut BuilderArgs) -> Result { let gtk_widget = gtk::Revealer::new(); resolve_block!(bargs, gtk_widget, { // @prop transition - the name of the transition. Possible values: $transition - prop(transition: as_string) { gtk_widget.set_transition_type(parse_transition(&transition)?); }, + prop(transition: as_string = "crossfade") { gtk_widget.set_transition_type(parse_transition(&transition)?); }, // @prop reveal - sets if the child is revealed or not prop(reveal: as_bool) { gtk_widget.set_reveal_child(reveal); }, // @prop duration - the duration of the reveal transition - prop(duration: as_string) { gtk_widget.set_transition_duration(parse_duration(&duration)?.as_millis() as u32); }, + prop(duration: as_string = "500ms") { gtk_widget.set_transition_duration(parse_duration(&duration)?.as_millis() as u32); }, }); Ok(gtk_widget) } @@ -568,36 +573,33 @@ fn build_gtk_calendar(bargs: &mut BuilderArgs) -> Result { /// @var orientation - "vertical", "v", "horizontal", "h" fn parse_orientation(o: &str) -> Result { - Ok(match o { + enum_parse! { "orientation", o, "vertical" | "v" => gtk::Orientation::Vertical, "horizontal" | "h" => gtk::Orientation::Horizontal, - _ => bail!(r#"Couldn't parse orientation: '{}'. Possible values are "vertical", "v", "horizontal", "h""#, o), - }) + } } /// @var transition - "slideright", "slideleft", "slideup", "slidedown", "crossfade", "none" fn parse_transition(t: &str) -> Result { - Ok(match t { + enum_parse! { "transition", t, "slideright" => gtk::RevealerTransitionType::SlideRight, "slideleft" => gtk::RevealerTransitionType::SlideLeft, "slideup" => gtk::RevealerTransitionType::SlideUp, "slidedown" => gtk::RevealerTransitionType::SlideDown, - "crossfade" => gtk::RevealerTransitionType::Crossfade, + "fade" | "crossfade" => gtk::RevealerTransitionType::Crossfade, "none" => gtk::RevealerTransitionType::None, - _ => bail!(r#"Couldn't parse transition: '{}'. Possible values are "slideright", "slideleft", "slideup", "slidedown", "crossfade" and "none" "#, t), - }) + } } /// @var alignment - "fill", "baseline", "center", "start", "end" fn parse_align(o: &str) -> Result { - Ok(match o { + enum_parse! { "alignment", o, "fill" => gtk::Align::Fill, "baseline" => gtk::Align::Baseline, "center" => gtk::Align::Center, "start" => gtk::Align::Start, "end" => gtk::Align::End, - _ => bail!(r#"Couldn't parse alignment: '{}'. Possible values are "fill", "baseline", "center", "start", "end""#, o), - }) + } } fn connect_first_map, F: Fn(&W) + 'static>(widget: &W, func: F) { @@ -610,25 +612,3 @@ fn connect_first_map, F: Fn(&W) + 'static>(widget: &W, func: } }); } - -/// Compute the difference of two lists, returning a tuple of -/// ( -/// elements that where in a but not in b, -/// elements that where in b but not in a -/// ). -fn list_difference<'a, 'b, T: PartialEq>(a: &'a [T], b: &'b [T]) -> (Vec<&'a T>, Vec<&'b T>) { - let mut missing = Vec::new(); - for elem in a { - if !b.contains(elem) { - missing.push(elem); - } - } - - let mut new = Vec::new(); - for elem in b { - if !a.contains(elem) { - new.push(elem); - } - } - (missing, new) -}