summaryrefslogtreecommitdiff
path: root/src/library/align.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-03-25 21:32:33 +0100
committerLaurenz <laurmaedje@gmail.com>2021-03-25 21:32:33 +0100
commit76fc4cca62f5b955200b2c62cc85b69eea491ece (patch)
tree5b8492268c996cf23b13e26c7a4356fbd156286d /src/library/align.rs
parente8057a53856dc09594c9e5861f1cd328531616e0 (diff)
Refactor alignments & directions 📐
- Adds lang function - Refactors execution context - Adds StackChild and ParChild enums
Diffstat (limited to 'src/library/align.rs')
-rw-r--r--src/library/align.rs144
1 files changed, 46 insertions, 98 deletions
diff --git a/src/library/align.rs b/src/library/align.rs
index 765ed988..d5811bf4 100644
--- a/src/library/align.rs
+++ b/src/library/align.rs
@@ -6,11 +6,6 @@ use super::*;
/// - Alignments: variadic, of type `alignment`.
/// - Body: optional, of type `template`.
///
-/// Which axis an alignment should apply to (main or cross) is inferred from
-/// either the argument itself (for anything other than `center`) or from the
-/// second argument if present, defaulting to the cross axis for a single
-/// `center` alignment.
-///
/// # Named parameters
/// - Horizontal alignment: `horizontal`, of type `alignment`.
/// - Vertical alignment: `vertical`, of type `alignment`.
@@ -21,32 +16,44 @@ use super::*;
///
/// # Relevant types and constants
/// - Type `alignment`
+/// - `start`
+/// - `center`
+/// - `end`
/// - `left`
/// - `right`
/// - `top`
/// - `bottom`
-/// - `center`
pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
- let first = args.find(ctx);
- let second = args.find(ctx);
- let hor = args.get(ctx, "horizontal");
- let ver = args.get(ctx, "vertical");
+ let first = args.find::<AlignValue>(ctx);
+ let second = args.find::<AlignValue>(ctx);
+ let mut horizontal = args.get::<AlignValue>(ctx, "horizontal");
+ let mut vertical = args.get::<AlignValue>(ctx, "vertical");
let body = args.find::<TemplateValue>(ctx);
+ for value in first.into_iter().chain(second) {
+ match value.axis() {
+ Some(SpecAxis::Horizontal) | None if horizontal.is_none() => {
+ horizontal = Some(value);
+ }
+ Some(SpecAxis::Vertical) | None if vertical.is_none() => {
+ vertical = Some(value);
+ }
+ _ => {}
+ }
+ }
+
Value::template("align", move |ctx| {
let snapshot = ctx.state.clone();
- let values = first
- .into_iter()
- .chain(second.into_iter())
- .map(|arg: Spanned<AlignValue>| (arg.v.axis(), arg))
- .chain(hor.into_iter().map(|arg| (Some(SpecAxis::Horizontal), arg)))
- .chain(ver.into_iter().map(|arg| (Some(SpecAxis::Vertical), arg)));
-
- apply(ctx, values);
+ if let Some(horizontal) = horizontal {
+ ctx.state.aligns.cross = horizontal.to_align(ctx.state.lang.dir);
+ }
- if ctx.state.aligns.main != snapshot.aligns.main {
- ctx.push_linebreak();
+ if let Some(vertical) = vertical {
+ ctx.state.aligns.main = vertical.to_align(Dir::TTB);
+ if ctx.state.aligns.main != snapshot.aligns.main {
+ ctx.push_linebreak();
+ }
}
if let Some(body) = &body {
@@ -56,109 +63,48 @@ pub fn align(ctx: &mut EvalContext, args: &mut FuncArgs) -> Value {
})
}
-/// Deduplicate and apply the alignments.
-fn apply(
- ctx: &mut ExecContext,
- values: impl Iterator<Item = (Option<SpecAxis>, Spanned<AlignValue>)>,
-) {
- let mut had = Gen::uniform(false);
- let mut had_center = false;
-
- for (axis, Spanned { v: arg, span }) in values {
- // Check whether we know which axis this alignment belongs to.
- if let Some(axis) = axis {
- // We know the axis.
- let gen_axis = axis.switch(ctx.state.dirs);
- let gen_align = arg.switch(ctx.state.dirs);
-
- if arg.axis().map_or(false, |a| a != axis) {
- ctx.diag(error!(span, "invalid alignment for {} axis", axis));
- } else if had.get(gen_axis) {
- ctx.diag(error!(span, "duplicate alignment for {} axis", axis));
- } else {
- *ctx.state.aligns.get_mut(gen_axis) = gen_align;
- *had.get_mut(gen_axis) = true;
- }
- } else {
- // We don't know the axis: This has to be a `center` alignment for a
- // positional argument.
- debug_assert_eq!(arg, AlignValue::Center);
-
- if had.main && had.cross {
- ctx.diag(error!(span, "duplicate alignment"));
- } else if had_center {
- // Both this and the previous one are unspecified `center`
- // alignments. Both axes should be centered.
- ctx.state.aligns.main = Align::Center;
- ctx.state.aligns.cross = Align::Center;
- had = Gen::uniform(true);
- } else {
- had_center = true;
- }
- }
-
- // If we we know the other alignment, we can handle the unspecified
- // `center` alignment.
- if had_center && (had.main || had.cross) {
- if had.main {
- ctx.state.aligns.cross = Align::Center;
- } else {
- ctx.state.aligns.main = Align::Center;
- }
- had = Gen::uniform(true);
- had_center = false;
- }
- }
-
- // If `had_center` wasn't flushed by now, it's the only argument and
- // then we default to applying it to the cross axis.
- if had_center {
- ctx.state.aligns.cross = Align::Center;
- }
-}
-
-/// An alignment value.
+/// An alignment specifier passed to `align`.
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub(super) enum AlignValue {
- Left,
+ Start,
Center,
+ End,
+ Left,
Right,
Top,
Bottom,
}
impl AlignValue {
- /// The specific axis this alignment refers to.
fn axis(self) -> Option<SpecAxis> {
match self {
+ Self::Start => None,
+ Self::Center => None,
+ Self::End => None,
Self::Left => Some(SpecAxis::Horizontal),
Self::Right => Some(SpecAxis::Horizontal),
Self::Top => Some(SpecAxis::Vertical),
Self::Bottom => Some(SpecAxis::Vertical),
- Self::Center => None,
}
}
-}
-
-impl Switch for AlignValue {
- type Other = Align;
- fn switch(self, dirs: LayoutDirs) -> Self::Other {
- let get = |dir: Dir, at_positive_start| {
- if dir.is_positive() == at_positive_start {
+ fn to_align(self, dir: Dir) -> Align {
+ let side = |is_at_positive_start| {
+ if dir.is_positive() == is_at_positive_start {
Align::Start
} else {
Align::End
}
};
- let dirs = dirs.switch(dirs);
match self {
- Self::Left => get(dirs.horizontal, true),
- Self::Right => get(dirs.horizontal, false),
- Self::Top => get(dirs.vertical, true),
- Self::Bottom => get(dirs.vertical, false),
+ Self::Start => Align::Start,
Self::Center => Align::Center,
+ Self::End => Align::End,
+ Self::Left => side(true),
+ Self::Right => side(false),
+ Self::Top => side(true),
+ Self::Bottom => side(false),
}
}
}
@@ -166,8 +112,10 @@ impl Switch for AlignValue {
impl Display for AlignValue {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
f.pad(match self {
- Self::Left => "left",
+ Self::Start => "start",
Self::Center => "center",
+ Self::End => "end",
+ Self::Left => "left",
Self::Right => "right",
Self::Top => "top",
Self::Bottom => "bottom",