Tidy up align function 🧺

This commit is contained in:
Laurenz 2020-10-05 16:06:25 +02:00
parent fa3e2920c0
commit 93eaafb236
2 changed files with 58 additions and 51 deletions

View File

@ -16,18 +16,21 @@ use crate::prelude::*;
/// There may not be two alignment specifications for the same axis. /// There may not be two alignment specifications for the same axis.
pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value { pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value {
let body = args.find::<SynTree>(); let body = args.find::<SynTree>();
let h = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal"); let first = args.get::<_, Spanned<SpecAlign>>(ctx, 0);
let v = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical"); let second = args.get::<_, Spanned<SpecAlign>>(ctx, 1);
let pos = args.find_all::<Spanned<SpecAlign>>(); let hor = args.get::<_, Spanned<SpecAlign>>(ctx, "horizontal");
let ver = args.get::<_, Spanned<SpecAlign>>(ctx, "vertical");
let iter = pos
.map(|align| (align.v.axis(), align))
.chain(h.into_iter().map(|align| (Some(SpecAxis::Horizontal), align)))
.chain(v.into_iter().map(|align| (Some(SpecAxis::Vertical), align)));
let aligns = parse_aligns(ctx, iter);
args.done(ctx); args.done(ctx);
let iter = first
.into_iter()
.chain(second.into_iter())
.map(|align| (align.v.axis(), align))
.chain(hor.into_iter().map(|align| (Some(SpecAxis::Horizontal), align)))
.chain(ver.into_iter().map(|align| (Some(SpecAxis::Vertical), align)));
let aligns = dedup_aligns(ctx, iter);
Value::Commands(match body { Value::Commands(match body {
Some(tree) => vec![ Some(tree) => vec![
SetAlignment(aligns), SetAlignment(aligns),
@ -39,63 +42,67 @@ pub async fn align(mut args: Args, ctx: &mut LayoutContext) -> Value {
} }
/// Deduplicate alignments and deduce to which axes they apply. /// Deduplicate alignments and deduce to which axes they apply.
fn parse_aligns( fn dedup_aligns(
ctx: &mut LayoutContext, ctx: &mut LayoutContext,
iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<SpecAlign>)>, iter: impl Iterator<Item = (Option<SpecAxis>, Spanned<SpecAlign>)>,
) -> LayoutAlign { ) -> LayoutAlign {
let mut aligns = ctx.state.align; let mut aligns = ctx.state.align;
let mut had = [false; 2]; let mut had = Gen2::new(false, false);
let mut deferred_center = false; let mut had_center = false;
for (axis, align) in iter { for (axis, Spanned { v: align, span }) in iter {
// Check whether we know which axis this alignment belongs to. We don't // Check whether we know which axis this alignment belongs to.
// if the alignment is `center` for a positional argument. Then we set
// `deferred_center` to true and handle the situation once we know more.
if let Some(axis) = axis { if let Some(axis) = axis {
if align.v.axis().map_or(false, |a| a != axis) { // We know the axis.
let gen_axis = axis.to_gen(ctx.state.sys);
let gen_align = align.to_gen(ctx.state.sys);
if align.axis().map_or(false, |a| a != axis) {
ctx.diag(error!( ctx.diag(error!(
align.span, span,
"invalid alignment {} for {} axis", align.v, axis, "invalid alignment `{}` for {} axis", align, axis,
)); ));
} else if had[axis as usize] { } else if had.get(gen_axis) {
ctx.diag(error!(align.span, "duplicate alignment for {} axis", axis)); ctx.diag(error!(span, "duplicate alignment for {} axis", axis));
} else { } else {
let gen_align = align.v.to_gen(ctx.state.sys); *aligns.get_mut(gen_axis) = gen_align;
*aligns.get_mut(axis.to_gen(ctx.state.sys)) = gen_align; *had.get_mut(gen_axis) = true;
had[axis as usize] = true;
} }
} else { } else {
if had == [true, true] { // We don't know the axis: This has to be a `center` alignment for a
ctx.diag(error!(align.span, "duplicate alignment")); // positional argument.
} else if deferred_center { debug_assert_eq!(align, SpecAlign::Center);
// We have two unflushed centers, meaning we know that both axes
// are to be centered. if had.primary && had.secondary {
had = [true, true]; 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.
aligns = LayoutAlign::new(GenAlign::Center, GenAlign::Center); aligns = LayoutAlign::new(GenAlign::Center, GenAlign::Center);
had.primary = true;
had.secondary = true;
} else { } else {
deferred_center = true; had_center = true;
} }
} }
// Flush a deferred center alignment if we know have had at least one // If we we know one alignment, we can handle the unspecified `center`
// known alignment. // alignment.
if deferred_center && had != [false, false] { if had_center && (had.primary || had.secondary) {
let axis = if !had[SpecAxis::Horizontal as usize] { if had.primary {
SpecAxis::Horizontal aligns.secondary = GenAlign::Center;
had.secondary = true;
} else { } else {
SpecAxis::Vertical aligns.primary = GenAlign::Center;
}; had.primary = true;
}
*aligns.get_mut(axis.to_gen(ctx.state.sys)) = GenAlign::Center; had_center = false;
had[axis as usize] = true;
deferred_center = false;
} }
} }
// If center has not been flushed by known, it is the only argument and then // If center has not been flushed by now, it is the only argument and then
// we default to applying it to the primary axis. // we default to applying it to the primary axis.
if deferred_center { if had_center {
aligns.primary = GenAlign::Center; aligns.primary = GenAlign::Center;
} }

View File

@ -51,7 +51,7 @@ use crate::prelude::*;
/// ``` /// ```
pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value { pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value {
let mut text = ctx.state.text.clone(); let mut text = ctx.state.text.clone();
let mut needs_flatten = false; let mut needs_flattening = false;
let body = args.find::<SynTree>(); let body = args.find::<SynTree>();
@ -67,7 +67,7 @@ pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value {
let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect(); let list: Vec<_> = args.find_all::<StringLike>().map(|s| s.to_lowercase()).collect();
if !list.is_empty() { if !list.is_empty() {
text.fallback.list = list; text.fallback.list = list;
needs_flatten = true; needs_flattening = true;
} }
if let Some(style) = args.get::<_, FontStyle>(ctx, "style") { if let Some(style) = args.get::<_, FontStyle>(ctx, "style") {
@ -89,12 +89,12 @@ pub async fn font(mut args: Args, ctx: &mut LayoutContext) -> Value {
.collect(); .collect();
text.fallback.update_class_list(class, fallback); text.fallback.update_class_list(class, fallback);
needs_flatten = true; needs_flattening = true;
} }
args.done(ctx); args.done(ctx);
if needs_flatten { if needs_flattening {
text.fallback.flatten(); text.fallback.flatten();
} }