diff options
Diffstat (limited to 'src/library/align.rs')
| -rw-r--r-- | src/library/align.rs | 193 |
1 files changed, 53 insertions, 140 deletions
diff --git a/src/library/align.rs b/src/library/align.rs index 530120e7..14e329e3 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -1,155 +1,68 @@ use crate::func::prelude::*; -/// 📐 `align`: Aligns content in different ways. -#[derive(Debug, PartialEq)] -pub struct Align { - body: Option<SyntaxTree>, - positional_1: Option<AlignSpecifier>, - positional_2: Option<AlignSpecifier>, - primary: Option<AlignSpecifier>, - secondary: Option<AlignSpecifier>, - horizontal: Option<AlignSpecifier>, - vertical: Option<AlignSpecifier>, -} - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -enum AlignSpecifier { - Origin, - Center, - End, - Left, - Right, - Top, - Bottom, -} - function! { - data: Align, + /// `align`: Aligns content along the layouting axes. + #[derive(Debug, PartialEq)] + pub struct Align { + body: Option<SyntaxTree>, + map: ArgMap<Key, AlignmentKey>, + } parse(args, body, ctx) { - let body = parse!(optional: body, ctx); - - let mut align = Align { - body, - positional_1: None, - positional_2: None, - primary: None, - secondary: None, - horizontal: None, - vertical: None, - }; - - if let Some(arg) = args.get_pos_opt::<ArgIdent>()? { - align.positional_1 = Some(parse_align_specifier(arg)?); + let mut map = ArgMap::new(); + map.put(Key::First, args.get_pos_opt::<ArgIdent>()?)?; + map.put(Key::Second, args.get_pos_opt::<ArgIdent>()?)?; + + for arg in args.keys() { + let key = match arg.val.0.val { + "horizontal" => Key::Axis(AxisKey::Horizontal), + "vertical" => Key::Axis(AxisKey::Vertical), + "primary" => Key::Axis(AxisKey::Primary), + "secondary" => Key::Axis(AxisKey::Secondary), + _ => pr!("unexpected argument"), + }; + + let value = AlignmentKey::parse(arg.val.1.val)?; + map.add(key, value); } - if let Some(arg) = args.get_pos_opt::<ArgIdent>()? { - align.positional_2 = Some(parse_align_specifier(arg)?); + Align { + body: parse!(optional: body, ctx), + map, } - - let mut parse_arg = |axis, target: &mut Option<AlignSpecifier>| { - Ok(if let Some(arg) = args.get_key_opt::<ArgIdent>(axis)? { - if target.is_none() { - *target = Some(parse_align_specifier(arg)?); - } else { - perr!("duplicate alignment specification for {} axis", axis); - } - }) - }; - - parse_arg("primary", &mut align.primary)?; - parse_arg("secondary", &mut align.secondary)?; - parse_arg("horizontal", &mut align.horizontal)?; - parse_arg("vertical", &mut align.vertical)?; - - args.done()?; - - Ok(align) } - layout(this, ctx) { - let mut axes = ctx.axes; - let primary_horizontal = axes.primary.is_horizontal(); - - let mut primary = false; - let mut secondary = false; - - let mut set_axis = |is_primary: bool, spec: Option<AlignSpecifier>| -> LayoutResult<()> { - if let Some(spec) = spec { - let (axis, was_set, name) = match is_primary { - true => (&mut axes.primary, &mut primary, "primary"), - false => (&mut axes.secondary, &mut secondary, "secondary"), - }; - - if *was_set { - panic!("duplicate alignment for {} axis", name); - } - - *was_set = true; - - let horizontal = axis.is_horizontal(); - let alignment = generic_alignment(spec, horizontal)?; - - if axis.alignment == Alignment::End && alignment == Alignment::Origin { - axis.expand = true; - } - - axis.alignment = alignment; - } - - Ok(()) - }; - - if let Some(spec) = this.positional_1 { - let positional = generic_alignment(spec, primary_horizontal).is_ok(); - set_axis(positional, this.positional_1)?; + layout(self, mut ctx) { + let axes = ctx.axes; + let basic = axes.primary.is_horizontal(); + + let map = self.map.dedup(|key, val| { + let axis = match key { + Key::First => val.axis(axes, GenericAxisKind::Primary), + Key::Second => val.axis(axes, GenericAxisKind::Secondary), + Key::Axis(AxisKey::Primary) => GenericAxisKind::Primary, + Key::Axis(AxisKey::Secondary) => GenericAxisKind::Secondary, + Key::Axis(AxisKey::Horizontal) => axes.horizontal(), + Key::Axis(AxisKey::Vertical) => axes.vertical(), + }; + + let alignment = val.generic(axes, axis)?; + Ok((key, alignment)) + })?; + + map.with(GenericAxisKind::Primary, |val| ctx.alignment.primary = val); + map.with(GenericAxisKind::Secondary, |val| ctx.alignment.secondary = val); + + match &self.body { + Some(body) => vec![AddMultiple(layout_tree(&body, ctx)?)], + None => vec![Command::SetAlignment(ctx.alignment)], } - - if let Some(spec) = this.positional_2 { - let positional = generic_alignment(spec, primary_horizontal).is_ok(); - set_axis(positional, this.positional_2)?; - } - - set_axis(true, this.primary)?; - set_axis(false, this.secondary)?; - set_axis(primary_horizontal, this.horizontal)?; - set_axis(!primary_horizontal, this.vertical)?; - - Ok(match &this.body { - Some(body) => vec![AddMultiple( - layout_tree(body, LayoutContext { - axes, - .. ctx.clone() - })? - )], - None => vec![Command::SetAxes(axes)] - }) } } -fn parse_align_specifier(arg: Spanned<&str>) -> ParseResult<AlignSpecifier> { - Ok(match arg.val { - "origin" => AlignSpecifier::Origin, - "center" => AlignSpecifier::Center, - "end" => AlignSpecifier::End, - "left" => AlignSpecifier::Left, - "right" => AlignSpecifier::Right, - "top" => AlignSpecifier::Top, - "bottom" => AlignSpecifier::Bottom, - s => perr!("invalid alignment specifier: {}", s), - }) -} - -fn generic_alignment(spec: AlignSpecifier, horizontal: bool) -> LayoutResult<Alignment> { - use AlignSpecifier::*; - Ok(match (spec, horizontal) { - (Origin, _) | (Left, true) | (Top, false) => Alignment::Origin, - (Center, _) => Alignment::Center, - (End, _) | (Right, true) | (Bottom, false) => Alignment::End, - _ => lerr!( - "invalid alignment specifier `{}` for {} axis", - format!("{:?}", spec).to_lowercase(), - if horizontal { "horizontal" } else { "vertical" }, - ), - }) +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +enum Key { + First, + Second, + Axis(AxisKey), } |
