continue implementing window definition
This commit is contained in:
parent
49bd2c6678
commit
dd5078b4be
9 changed files with 223 additions and 63 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -222,6 +222,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simplexpr",
|
"simplexpr",
|
||||||
"smart-default",
|
"smart-default",
|
||||||
|
"strum",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ serde = {version = "1.0", features = ["derive"]}
|
||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
lazy_static = "1.4"
|
lazy_static = "1.4"
|
||||||
pretty_assertions = "0.7"
|
pretty_assertions = "0.7"
|
||||||
smart-default = "0.6"
|
|
||||||
|
|
||||||
|
strum = { version = "0.21", features = ["derive"] }
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,14 @@ use std::{
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
};
|
};
|
||||||
|
|
||||||
use simplexpr::{dynval::DynVal, eval::EvalError, SimplExpr};
|
use simplexpr::{
|
||||||
|
dynval::{DynVal, FromDynVal},
|
||||||
|
eval::EvalError,
|
||||||
|
SimplExpr,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
error::AstError,
|
||||||
parser::{
|
parser::{
|
||||||
ast::{Ast, Span},
|
ast::{Ast, Span},
|
||||||
from_ast::FromAst,
|
from_ast::FromAst,
|
||||||
|
@ -44,11 +49,11 @@ pub struct UnusedAttrs {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize)]
|
||||||
pub struct AttrEntry {
|
pub struct AttrEntry {
|
||||||
pub key_span: Span,
|
pub key_span: Span,
|
||||||
pub value: SimplExpr,
|
pub value: Ast,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AttrEntry {
|
impl AttrEntry {
|
||||||
pub fn new(key_span: Span, value: SimplExpr) -> AttrEntry {
|
pub fn new(key_span: Span, value: Ast) -> AttrEntry {
|
||||||
AttrEntry { key_span, value }
|
AttrEntry { key_span, value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -64,51 +69,42 @@ impl Attributes {
|
||||||
Attributes { span, attrs }
|
Attributes { span, attrs }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_required<T: TryFrom<DynVal>>(&mut self, key: &str) -> Result<T, AttrError> {
|
pub fn ast_required<T: FromAst>(&mut self, key: &str) -> Result<T, AstError> {
|
||||||
let key = AttrName(key.to_string());
|
let key = AttrName(key.to_string());
|
||||||
match self.attrs.remove(&key) {
|
match self.attrs.remove(&key) {
|
||||||
Some(AttrEntry { key_span, value }) => {
|
Some(AttrEntry { key_span, value }) => T::from_ast(value),
|
||||||
let value_span = value.span();
|
None => Err(AttrError::MissingRequiredAttr(self.span, key.clone()).into()),
|
||||||
let dynval = value.eval_no_vars().map_err(|err| AttrError::EvaluationError(value_span.into(), err))?;
|
|
||||||
T::try_from(dynval).map_err(|_| AttrError::AttrTypeError(value_span.into(), key.clone()))
|
|
||||||
}
|
|
||||||
None => Err(AttrError::MissingRequiredAttr(self.span, key.clone())),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_optional<T: TryFrom<DynVal>>(&mut self, key: &str) -> Result<Option<T>, AttrError> {
|
pub fn ast_optional<T: FromAst>(&mut self, key: &str) -> Result<Option<T>, AstError> {
|
||||||
let key = AttrName(key.to_string());
|
match self.attrs.remove(&AttrName(key.to_string())) {
|
||||||
match self.attrs.remove(&key) {
|
Some(AttrEntry { key_span, value }) => T::from_ast(value).map(Some),
|
||||||
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),
|
None => Ok(None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn parse_required<T: TryFrom<SimplExpr>>(&mut self, key: &str) -> Result<T, AttrError> {
|
pub fn primitive_required<T: FromDynVal>(&mut self, key: &str) -> Result<T, AstError> {
|
||||||
// let key = AttrName(key.to_string());
|
let ast: SimplExpr = self.ast_required(&key)?;
|
||||||
// match self.attrs.remove(&key) {
|
Ok(ast
|
||||||
// Some(value) => match value.value.try_into() {
|
.eval_no_vars()
|
||||||
// Ok(value) => Ok(value),
|
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))?
|
||||||
// Err(_) => Err(AttrError::AttrTypeError(value.value.span().into(), key.clone())),
|
.read_as()
|
||||||
// },
|
.map_err(|_| AttrError::AttrTypeError(ast.span().into(), AttrName(key.to_string())))?)
|
||||||
// None => Err(AttrError::MissingRequiredAttr(self.span, key.clone())),
|
}
|
||||||
// }
|
|
||||||
// }
|
pub fn primitive_optional<T: FromDynVal>(&mut self, key: &str) -> Result<Option<T>, AstError> {
|
||||||
//
|
let ast: SimplExpr = match self.ast_optional(key)? {
|
||||||
// pub fn parse_optional<T: TryFrom<SimplExpr>>(&mut self, key: &str) -> Result<Option<T>, AttrError> {
|
Some(ast) => ast,
|
||||||
// let key = AttrName(key.to_string());
|
None => return Ok(None),
|
||||||
// match self.attrs.remove(&key) {
|
};
|
||||||
// Some(value) => match value.value.try_into() {
|
Ok(Some(
|
||||||
// Ok(value) => Ok(Some(value)),
|
ast.eval_no_vars()
|
||||||
// Err(_) => Err(AttrError::AttrTypeError(value.value.span().into(), key.clone())),
|
.map_err(|err| AttrError::EvaluationError(ast.span().into(), err))?
|
||||||
// },
|
.read_as()
|
||||||
// None => Ok(None),
|
.map_err(|_| AttrError::AttrTypeError(ast.span().into(), AttrName(key.to_string())))?,
|
||||||
// }
|
))
|
||||||
// }
|
}
|
||||||
|
|
||||||
/// Consumes the attributes to return a list of unused attributes which may be used to emit a warning.
|
/// Consumes the attributes to return a list of unused attributes which may be used to emit a warning.
|
||||||
/// TODO actually use this and implement warnings,... lol
|
/// TODO actually use this and implement warnings,... lol
|
||||||
|
|
|
@ -9,3 +9,4 @@ pub mod var_definition;
|
||||||
pub mod widget_definition;
|
pub mod widget_definition;
|
||||||
pub mod widget_use;
|
pub mod widget_use;
|
||||||
pub mod window_definition;
|
pub mod window_definition;
|
||||||
|
pub mod window_geometry;
|
||||||
|
|
|
@ -49,7 +49,7 @@ impl FromAstElementContent for PollScriptVar {
|
||||||
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
let (_, name) = iter.expect_symbol()?;
|
let (_, name) = iter.expect_symbol()?;
|
||||||
let mut attrs = iter.expect_key_values()?;
|
let mut attrs = iter.expect_key_values()?;
|
||||||
let interval: String = attrs.eval_required("interval")?;
|
let interval: String = attrs.primitive_required("interval")?;
|
||||||
let interval = crate::util::parse_duration(&interval).map_err(|e| AstError::Other(Some(span), e.into()))?;
|
let interval = crate::util::parse_duration(&interval).map_err(|e| AstError::Other(Some(span), e.into()))?;
|
||||||
let (_, script) = iter.expect_literal()?;
|
let (_, script) = iter.expect_literal()?;
|
||||||
Ok(Self { name: VarName(name), command: VarSource::Shell(script.to_string()), interval })
|
Ok(Self { name: VarName(name), command: VarSource::Shell(script.to_string()), interval })
|
||||||
|
|
|
@ -35,7 +35,7 @@ impl FromAst for WidgetUse {
|
||||||
maplit::hashmap! {
|
maplit::hashmap! {
|
||||||
AttrName("text".to_string()) => AttrEntry::new(
|
AttrName("text".to_string()) => AttrEntry::new(
|
||||||
span.into(),
|
span.into(),
|
||||||
SimplExpr::Literal(span.into(), text.clone())
|
Ast::Literal(span.into(), text.clone())
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashMap;
|
use std::{collections::HashMap, fmt::Display, str::FromStr};
|
||||||
|
|
||||||
use simplexpr::{dynval::DynVal, SimplExpr};
|
use simplexpr::{dynval::DynVal, SimplExpr};
|
||||||
|
|
||||||
|
@ -9,15 +9,15 @@ use crate::{
|
||||||
from_ast::{FromAst, FromAstElementContent},
|
from_ast::{FromAst, FromAstElementContent},
|
||||||
},
|
},
|
||||||
spanned,
|
spanned,
|
||||||
value::{AttrName, VarName},
|
value::{AttrName, NumWithUnit, VarName},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::widget_use::WidgetUse;
|
use super::{widget_use::WidgetUse, window_geometry::WindowGeometry};
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Serialize)]
|
#[derive(Debug, Clone, serde::Serialize)]
|
||||||
pub struct EwwWindowDefinition {
|
pub struct EwwWindowDefinition {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub geometry: Option<EwwWindowGeometry>,
|
pub geometry: Option<WindowGeometry>,
|
||||||
pub stacking: WindowStacking,
|
pub stacking: WindowStacking,
|
||||||
pub monitor_number: Option<i32>,
|
pub monitor_number: Option<i32>,
|
||||||
pub widget: WidgetUse,
|
pub widget: WidgetUse,
|
||||||
|
@ -33,17 +33,24 @@ impl FromAstElementContent for EwwWindowDefinition {
|
||||||
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
let (_, name) = iter.expect_symbol()?;
|
let (_, name) = iter.expect_symbol()?;
|
||||||
let mut attrs = iter.expect_key_values()?;
|
let mut attrs = iter.expect_key_values()?;
|
||||||
let monitor_number = attrs.eval_optional("monitor")?;
|
let monitor_number = attrs.primitive_optional("monitor")?;
|
||||||
let resizable = attrs.eval_optional("resizable")?.unwrap_or(true);
|
let resizable = attrs.primitive_optional("resizable")?.unwrap_or(true);
|
||||||
let stacking = attrs.eval_optional("stacking")?.unwrap_or(WindowStacking::Foreground);
|
let stacking = attrs.primitive_optional("stacking")?.unwrap_or(WindowStacking::Foreground);
|
||||||
|
let geometry = attrs.ast_optional("geometry")?;
|
||||||
let widget = iter.expect_any()?;
|
let widget = iter.expect_any()?;
|
||||||
Ok(Self { name, monitor_number, resizable, widget, stacking })
|
Ok(Self { name, monitor_number, resizable, widget, stacking, geometry })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub struct EnumParseError {
|
pub struct EnumParseError {
|
||||||
input: String,
|
pub input: String,
|
||||||
expected: Vec<&'static str>,
|
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,
|
/// Parse a string with a concrete set of options into some data-structure,
|
||||||
|
@ -62,14 +69,14 @@ macro_rules! enum_parse {
|
||||||
match input.as_str() {
|
match input.as_str() {
|
||||||
$( $( $s )|* => Ok($val) ),*,
|
$( $( $s )|* => Ok($val) ),*,
|
||||||
_ => Err(EnumParseError {
|
_ => Err(EnumParseError {
|
||||||
input: $name,
|
input: input,
|
||||||
expected: vec![$($($s),*),*],
|
expected: vec![$($($s),*),*],
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, SmartDefault)]
|
#[derive(Debug, Clone, PartialEq, Eq, smart_default::SmartDefault)]
|
||||||
pub enum EwwWindowType {
|
pub enum EwwWindowType {
|
||||||
#[default]
|
#[default]
|
||||||
Dock,
|
Dock,
|
||||||
|
@ -102,9 +109,9 @@ pub enum Side {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for Side {
|
impl std::str::FromStr for Side {
|
||||||
type Err = anyhow::Error;
|
type Err = EnumParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Side> {
|
fn from_str(s: &str) -> Result<Side, Self::Err> {
|
||||||
enum_parse! { "side", s,
|
enum_parse! { "side", s,
|
||||||
"l" | "left" => Side::Left,
|
"l" | "left" => Side::Left,
|
||||||
"r" | "right" => Side::Right,
|
"r" | "right" => Side::Right,
|
||||||
|
@ -121,13 +128,18 @@ pub struct StrutDefinition {
|
||||||
pub dist: NumWithUnit,
|
pub dist: NumWithUnit,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StrutDefinition {
|
impl FromAstElementContent for StrutDefinition {
|
||||||
pub fn from_xml_element(xml: XmlElement) -> Result<Self> {
|
fn get_element_name() -> &'static str {
|
||||||
Ok(StrutDefinition { side: xml.attr("side")?.parse()?, dist: xml.attr("distance")?.parse()? })
|
"struts"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
|
let mut attrs = iter.expect_key_values()?;
|
||||||
|
Ok(StrutDefinition { side: attrs.primitive_required("side")?, dist: attrs.primitive_required("distance")? })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, SmartDefault)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display, smart_default::SmartDefault, serde::Serialize)]
|
||||||
pub enum WindowStacking {
|
pub enum WindowStacking {
|
||||||
#[default]
|
#[default]
|
||||||
Foreground,
|
Foreground,
|
||||||
|
@ -137,9 +149,9 @@ pub enum WindowStacking {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::str::FromStr for WindowStacking {
|
impl std::str::FromStr for WindowStacking {
|
||||||
type Err = anyhow::Error;
|
type Err = EnumParseError;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
enum_parse! { "WindowStacking", s,
|
enum_parse! { "WindowStacking", s,
|
||||||
"foreground" | "fg" => WindowStacking::Foreground,
|
"foreground" | "fg" => WindowStacking::Foreground,
|
||||||
"background" | "bg" => WindowStacking::Background,
|
"background" | "bg" => WindowStacking::Background,
|
||||||
|
|
150
src/config/window_geometry.rs
Normal file
150
src/config/window_geometry.rs
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use simplexpr::{dynval::DynVal, SimplExpr};
|
||||||
|
|
||||||
|
use crate::{enum_parse, error::{AstError, AstResult}, parser::{
|
||||||
|
ast::{Ast, AstIterator, Span},
|
||||||
|
from_ast::{FromAst, FromAstElementContent},
|
||||||
|
}, spanned, value::{AttrName, Coords, VarName}};
|
||||||
|
|
||||||
|
use super::{widget_use::WidgetUse, window_definition::EnumParseError};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, smart_default::SmartDefault, Serialize, Deserialize, strum::Display)]
|
||||||
|
pub enum AnchorAlignment {
|
||||||
|
#[strum(serialize = "start")]
|
||||||
|
#[default]
|
||||||
|
START,
|
||||||
|
#[strum(serialize = "center")]
|
||||||
|
CENTER,
|
||||||
|
#[strum(serialize = "end")]
|
||||||
|
END,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnchorAlignment {
|
||||||
|
pub fn from_x_alignment(s: &str) -> Result<AnchorAlignment, EnumParseError> {
|
||||||
|
enum_parse! { "x-alignment", s,
|
||||||
|
"l" | "left" => AnchorAlignment::START,
|
||||||
|
"c" | "center" => AnchorAlignment::CENTER,
|
||||||
|
"r" | "right" => AnchorAlignment::END,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_y_alignment(s: &str) -> Result<AnchorAlignment, EnumParseError> {
|
||||||
|
enum_parse! { "y-alignment", s,
|
||||||
|
"t" | "top" => AnchorAlignment::START,
|
||||||
|
"c" | "center" => AnchorAlignment::CENTER,
|
||||||
|
"b" | "bottom" => AnchorAlignment::END,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn alignment_to_coordinate(&self, size_inner: i32, size_container: i32) -> i32 {
|
||||||
|
match self {
|
||||||
|
AnchorAlignment::START => 0,
|
||||||
|
AnchorAlignment::CENTER => (size_container / 2) - (size_inner / 2),
|
||||||
|
AnchorAlignment::END => size_container - size_inner,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default, Serialize, Deserialize)]
|
||||||
|
pub struct AnchorPoint {
|
||||||
|
pub x: AnchorAlignment,
|
||||||
|
pub y: AnchorAlignment,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for AnchorPoint {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
use AnchorAlignment::*;
|
||||||
|
match (self.x, self.y) {
|
||||||
|
(CENTER, CENTER) => write!(f, "center"),
|
||||||
|
(x, y) => write!(
|
||||||
|
f,
|
||||||
|
"{} {}",
|
||||||
|
match x {
|
||||||
|
START => "left",
|
||||||
|
CENTER => "center",
|
||||||
|
END => "right",
|
||||||
|
},
|
||||||
|
match y {
|
||||||
|
START => "top",
|
||||||
|
CENTER => "center",
|
||||||
|
END => "bottom",
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum AnchorPointParseError {
|
||||||
|
#[error("Could not parse anchor: Must either be \"center\" or be formatted like \"top left\"")]
|
||||||
|
WrongFormat(String),
|
||||||
|
#[error(transparent)]
|
||||||
|
EnumParseError(#[from] EnumParseError),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl std::str::FromStr for AnchorPoint {
|
||||||
|
type Err = AnchorPointParseError;
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
if s == "center" {
|
||||||
|
Ok(AnchorPoint { x: AnchorAlignment::CENTER, y: AnchorAlignment::CENTER })
|
||||||
|
} else {
|
||||||
|
let (first, second) = s
|
||||||
|
.split_once(' ')
|
||||||
|
.ok_or_else(|| AnchorPointParseError::WrongFormat(s.to_string()))?;
|
||||||
|
let x_y_result: Result<_, EnumParseError> = try {
|
||||||
|
AnchorPoint { x: AnchorAlignment::from_x_alignment(first)?, y: AnchorAlignment::from_y_alignment(second)? }
|
||||||
|
};
|
||||||
|
x_y_result.or_else(|_| {
|
||||||
|
Ok(AnchorPoint { x: AnchorAlignment::from_x_alignment(second)?, y: AnchorAlignment::from_y_alignment(first)? })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Serialize)]
|
||||||
|
pub struct WindowGeometry {
|
||||||
|
pub anchor_point: AnchorPoint,
|
||||||
|
pub offset: Coords,
|
||||||
|
pub size: Coords,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromAstElementContent for WindowGeometry {
|
||||||
|
fn get_element_name() -> &'static str {
|
||||||
|
"geometry"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_tail<I: Iterator<Item = Ast>>(span: Span, mut iter: AstIterator<I>) -> AstResult<Self> {
|
||||||
|
let mut attrs = iter.expect_key_values()?;
|
||||||
|
Ok(WindowGeometry {
|
||||||
|
anchor_point: attrs.primitive_optional("anchor")?.unwrap_or_default(),
|
||||||
|
size: Coords {
|
||||||
|
x: attrs.primitive_optional("width")?.unwrap_or_default(),
|
||||||
|
y: attrs.primitive_optional("height")?.unwrap_or_default(),
|
||||||
|
},
|
||||||
|
offset: Coords {
|
||||||
|
x: attrs.primitive_optional("x")?.unwrap_or_default(),
|
||||||
|
y: attrs.primitive_optional("y")?.unwrap_or_default(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowGeometry {
|
||||||
|
pub fn override_if_given(&self, anchor_point: Option<AnchorPoint>, offset: Option<Coords>, size: Option<Coords>) -> Self {
|
||||||
|
WindowGeometry {
|
||||||
|
anchor_point: anchor_point.unwrap_or(self.anchor_point),
|
||||||
|
offset: offset.unwrap_or(self.offset),
|
||||||
|
size: size.unwrap_or(self.size),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for WindowGeometry {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}-{} ({})", self.offset, self.size, self.anchor_point)
|
||||||
|
}
|
||||||
|
}
|
|
@ -252,7 +252,7 @@ fn parse_key_values(iter: &mut AstIterator<impl Iterator<Item = Ast>>) -> AstRes
|
||||||
Some(Ast::Keyword(key_span, kw)) => match iter.next() {
|
Some(Ast::Keyword(key_span, kw)) => match iter.next() {
|
||||||
Some(value) => {
|
Some(value) => {
|
||||||
attrs_span.1 = iter.remaining_span.0;
|
attrs_span.1 = iter.remaining_span.0;
|
||||||
let attr_value = AttrEntry { key_span, value: value.as_simplexpr()? };
|
let attr_value = AttrEntry { key_span, value };
|
||||||
data.insert(AttrName(kw), attr_value);
|
data.insert(AttrName(kw), attr_value);
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue