From 49bd2c667895c9b44e86d302ba32fafd8a0d67f1 Mon Sep 17 00:00:00 2001 From: elkowar <5300871+elkowar@users.noreply.github.com> Date: Tue, 20 Jul 2021 17:06:05 +0200 Subject: [PATCH] Start implementing window definition --- Cargo.toml | 1 + src/config/attributes.rs | 12 +++ src/config/mod.rs | 1 + src/config/window_definition.rs | 150 ++++++++++++++++++++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 src/config/window_definition.rs diff --git a/Cargo.toml b/Cargo.toml index 8b35304..81ee6d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ serde = {version = "1.0", features = ["derive"]} serde_json = "1.0" lazy_static = "1.4" pretty_assertions = "0.7" +smart-default = "0.6" anyhow = "1" diff --git a/src/config/attributes.rs b/src/config/attributes.rs index 8a4154a..132e292 100644 --- a/src/config/attributes.rs +++ b/src/config/attributes.rs @@ -76,6 +76,18 @@ impl Attributes { } } + pub fn eval_optional>(&mut self, key: &str) -> Result, AttrError> { + let key = AttrName(key.to_string()); + match self.attrs.remove(&key) { + Some(AttrEntry { key_span, value }) => { + let value_span = value.span(); + let dynval = value.eval_no_vars().map_err(|err| AttrError::EvaluationError(value_span.into(), err))?; + T::try_from(dynval).map(Some).map_err(|_| AttrError::AttrTypeError(value_span.into(), key.clone())) + } + None => Ok(None), + } + } + // pub fn parse_required>(&mut self, key: &str) -> Result { // let key = AttrName(key.to_string()); // match self.attrs.remove(&key) { diff --git a/src/config/mod.rs b/src/config/mod.rs index 3c51d23..91325de 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -8,3 +8,4 @@ pub mod validate; pub mod var_definition; pub mod widget_definition; pub mod widget_use; +pub mod window_definition; diff --git a/src/config/window_definition.rs b/src/config/window_definition.rs new file mode 100644 index 0000000..75dbbcb --- /dev/null +++ b/src/config/window_definition.rs @@ -0,0 +1,150 @@ +use std::collections::HashMap; + +use simplexpr::{dynval::DynVal, SimplExpr}; + +use crate::{ + error::{AstError, AstResult}, + parser::{ + ast::{Ast, AstIterator, Span}, + from_ast::{FromAst, FromAstElementContent}, + }, + spanned, + value::{AttrName, VarName}, +}; + +use super::widget_use::WidgetUse; + +#[derive(Debug, Clone, serde::Serialize)] +pub struct EwwWindowDefinition { + pub name: String, + pub geometry: Option, + pub stacking: WindowStacking, + pub monitor_number: Option, + pub widget: WidgetUse, + pub resizable: bool, + // pub backend_options: BackendWindowOptions, +} + +impl FromAstElementContent for EwwWindowDefinition { + fn get_element_name() -> &'static str { + "defwindow" + } + + fn from_tail>(span: Span, mut iter: AstIterator) -> AstResult { + let (_, name) = iter.expect_symbol()?; + let mut attrs = iter.expect_key_values()?; + let monitor_number = attrs.eval_optional("monitor")?; + let resizable = attrs.eval_optional("resizable")?.unwrap_or(true); + let stacking = attrs.eval_optional("stacking")?.unwrap_or(WindowStacking::Foreground); + let widget = iter.expect_any()?; + Ok(Self { name, monitor_number, resizable, widget, stacking }) + } +} + +pub struct EnumParseError { + input: String, + expected: Vec<&'static str>, +} + +/// Parse a string with a concrete set of options into some data-structure, +/// and return an [EnumParseError] +/// ```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.to_lowercase(); + match input.as_str() { + $( $( $s )|* => Ok($val) ),*, + _ => Err(EnumParseError { + input: $name, + expected: vec![$($($s),*),*], + }) + } + }; +} + +#[derive(Debug, Clone, PartialEq, Eq, SmartDefault)] +pub enum EwwWindowType { + #[default] + Dock, + Dialog, + Toolbar, + Normal, + Utility, +} +impl FromStr for EwwWindowType { + type Err = EnumParseError; + + fn from_str(s: &str) -> Result { + enum_parse! { "window type", s, + "dock" => Self::Dock, + "toolbar" => Self::Toolbar, + "dialog" => Self::Dialog, + "normal" => Self::Normal, + "utility" => Self::Utility, + } + } +} + +#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault)] +pub enum Side { + #[default] + Top, + Left, + Right, + Bottom, +} + +impl std::str::FromStr for Side { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + enum_parse! { "side", s, + "l" | "left" => Side::Left, + "r" | "right" => Side::Right, + "t" | "top" => Side::Top, + "b" | "bottom" => Side::Bottom, + } + } +} + +// Surface definition if the backend for X11 is enable +#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)] +pub struct StrutDefinition { + pub side: Side, + pub dist: NumWithUnit, +} + +impl StrutDefinition { + pub fn from_xml_element(xml: XmlElement) -> Result { + Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? }) + } +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, SmartDefault)] +pub enum WindowStacking { + #[default] + Foreground, + Background, + Bottom, + Overlay, +} + +impl std::str::FromStr for WindowStacking { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + enum_parse! { "WindowStacking", s, + "foreground" | "fg" => WindowStacking::Foreground, + "background" | "bg" => WindowStacking::Background, + "bottom" | "bt" => WindowStacking::Bottom, + "overlay" | "ov" => WindowStacking::Overlay, + } + } +}