use std::{collections::HashMap, fmt::Display, str::FromStr}; use simplexpr::{dynval::DynVal, SimplExpr}; use crate::{ error::{AstError, AstResult}, parser::{ ast::{Ast, Span}, ast_iterator::AstIterator, from_ast::{FromAst, FromAstElementContent}, }, value::{AttrName, NumWithUnit, VarName}, }; use super::{backend_window_options::BackendWindowOptions, widget_use::WidgetUse, window_geometry::WindowGeometry}; #[derive(Debug, Clone, serde::Serialize, PartialEq, Eq)] pub struct WindowDefinition { 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 WindowDefinition { 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.primitive_optional("monitor")?; let resizable = attrs.primitive_optional("resizable")?.unwrap_or(true); let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground); let geometry = attrs.ast_optional("geometry")?; let backend_options = BackendWindowOptions::from_attrs(&mut attrs)?; let widget = iter.expect_any()?; Ok(Self { name, monitor_number, resizable, widget, stacking, geometry, backend_options }) } } #[derive(Debug, thiserror::Error)] pub struct EnumParseError { pub input: String, pub expected: Vec<&'static str>, } impl Display for EnumParseError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "Failed to parse `{}`, must be one of {}", self.input, self.expected.join(", ")) } } /// 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: input, expected: vec![$($($s),*),*], }) } }; } #[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, smart_default::SmartDefault, serde::Serialize)] pub enum WindowStacking { #[default] Foreground, Background, Bottom, Overlay, } impl std::str::FromStr for WindowStacking { type Err = EnumParseError; 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, } } }