From 6febc0327304451bc956985b7cadb07a0b563c79 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Sat, 29 Aug 2020 11:32:32 +0200 Subject: [PATCH] =?UTF-8?q?Make=20align=20not=20behave=20box-like=20and=20?= =?UTF-8?q?smarter=20=F0=9F=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Doesn't layout contents into a box anymore, instead layouting inline in the parent context. Also makes axis inferring for center alignents smarter (just because I had fun doing it). It's unsure whether we want to keep it because it might be confusing. --- src/library/align.rs | 88 ++++++++++++++++++++++++++++++-------------- tests/coma.typ | 2 +- 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/library/align.rs b/src/library/align.rs index 14692ecaf..55e0f65e7 100644 --- a/src/library/align.rs +++ b/src/library/align.rs @@ -5,16 +5,19 @@ use super::*; /// # Positional arguments /// - At most two of `left`, `right`, `top`, `bottom`, `center`. /// +/// When `center` is used as a positional argument, it is automatically inferred +/// which axis it should apply to depending on further arguments, defaulting +/// to the axis, text is set along. +/// /// # Keyword arguments /// - `horizontal`: Any of `left`, `right` or `center`. /// - `vertical`: Any of `top`, `bottom` or `center`. /// /// There may not be two alignment specifications for the same axis. -pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> Pass { +pub async fn align(_: Span, mut args: TableValue, ctx: LayoutContext<'_>) -> Pass { let mut f = Feedback::new(); let content = args.take::(); - let h = args.take_key::>("horizontal", &mut f); let v = args.take_key::>("vertical", &mut f); let all = args @@ -23,40 +26,69 @@ pub async fn align(_: Span, mut args: TableValue, mut ctx: LayoutContext<'_>) -> .chain(h.into_iter().map(|align| (Some(Horizontal), align))) .chain(v.into_iter().map(|align| (Some(Vertical), align))); + let mut aligns = ctx.align; let mut had = [false; 2]; - for (axis, align) in all { - let axis = axis.unwrap_or_else(|| align.v.axis().unwrap_or_else(|| { - let primary = ctx.axes.primary.axis(); - if !had[primary as usize] { - primary - } else { - ctx.axes.secondary.axis() - } - })); + let mut deferred_center = false; - if align.v.axis().map(|a| a != axis).unwrap_or(false) { - error!( - @f, align.span, - "invalid alignment {} for {} axis", align.v, axis, - ); - } else if had[axis as usize] { - error!(@f, align.span, "duplicate alignment for {} axis", axis); + for (axis, align) in all { + // Check whether we know which axis this alignment belongs to. We don't + // 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 align.v.axis().map(|a| a != axis).unwrap_or(false) { + error!( + @f, align.span, + "invalid alignment {} for {} axis", align.v, axis, + ); + } else if had[axis as usize] { + error!(@f, align.span, "duplicate alignment for {} axis", axis); + } else { + let gen_align = align.v.to_generic(ctx.axes); + *aligns.get_mut(axis.to_generic(ctx.axes)) = gen_align; + had[axis as usize] = true; + } } else { + if had == [true, true] { + error!(@f, align.span, "duplicate alignment"); + } else if deferred_center { + // We have two unflushed centers, meaning we know that both axes + // are to be centered. + had = [true, true]; + aligns = LayoutAlign::new(Center, Center); + } else { + deferred_center = true; + } + } + + // Flush a deferred center alignment if we know have had at least one + // known alignment. + if deferred_center && had != [false, false] { + let axis = if !had[Horizontal as usize] { + Horizontal + } else { + Vertical + }; + + *aligns.get_mut(axis.to_generic(ctx.axes)) = Center; + had[axis as usize] = true; - let gen_axis = axis.to_generic(ctx.axes); - let gen_align = align.v.to_generic(ctx.axes); - *ctx.align.get_mut(gen_axis) = gen_align; + deferred_center = false; } } + // If center has not been flushed by known, it is the only argument and then + // we default to applying it to the primary axis. + if deferred_center { + aligns.primary = Center; + } + let commands = match content { - Some(tree) => { - ctx.base = ctx.spaces[0].size; - let layouted = layout(&tree, ctx).await; - f.extend(layouted.feedback); - vec![AddMultiple(layouted.output)] - } - None => vec![SetAlignment(ctx.align)], + Some(tree) => vec![ + SetAlignment(aligns), + LayoutSyntaxTree(tree), + SetAlignment(ctx.align), + ], + None => vec![SetAlignment(aligns)], }; args.unexpected(&mut f); diff --git a/tests/coma.typ b/tests/coma.typ index 404a81b30..3a886699c 100644 --- a/tests/coma.typ +++ b/tests/coma.typ @@ -7,7 +7,7 @@ Dr. Max Mustermann \ Ola Nordmann, John Doe ] -[align: right][ +[align: right >> box][ *WiSe 2019/2020* \ Woche 3 ]