mirror of
https://github.com/typst/typst
synced 2025-05-18 11:05:28 +08:00
Tidy up align function 🧺
This commit is contained in:
parent
fa3e2920c0
commit
93eaafb236
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user