typst/src/library/align.rs
Laurenz 9f6137d8a8 Remove tuples and objects in favor of tables 🛢
This refactores the parser tests to make them more concise and flexible with regards to spans.
2020-08-16 14:38:30 +02:00

77 lines
2.5 KiB
Rust

use super::*;
/// `align`: Align content along the layouting axes.
///
/// # Positional arguments
/// - At most two of `left`, `right`, `top`, `bottom`, `center`.
///
/// # 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 fn align(call: FuncCall, _: &ParseState) -> Pass<SyntaxNode> {
let mut f = Feedback::new();
let mut args = call.args;
let node = AlignNode {
content: args.take::<SyntaxTree>(),
aligns: args.take_all_num_vals::<Spanned<SpecAlign>>().collect(),
h: args.take_with_key::<_, Spanned<SpecAlign>>("horizontal", &mut f),
v: args.take_with_key::<_, Spanned<SpecAlign>>("vertical", &mut f),
};
args.unexpected(&mut f);
Pass::node(node, f)
}
#[derive(Debug, Clone, PartialEq)]
struct AlignNode {
content: Option<SyntaxTree>,
aligns: SpanVec<SpecAlign>,
h: Option<Spanned<SpecAlign>>,
v: Option<Spanned<SpecAlign>>,
}
#[async_trait(?Send)]
impl Layout for AlignNode {
async fn layout<'a>(&'a self, mut ctx: LayoutContext<'_>) -> Pass<Commands<'a>> {
let mut f = Feedback::new();
ctx.base = ctx.spaces[0].size;
let axes = ctx.axes;
let all = self.aligns.iter()
.map(|align| {
let spec = align.v.axis().unwrap_or(axes.primary.axis());
(spec, align)
})
.chain(self.h.iter().map(|align| (Horizontal, align)))
.chain(self.v.iter().map(|align| (Vertical, align)));
let mut had = [false; 2];
for (axis, align) in all {
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 {
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;
}
}
Pass::new(match &self.content {
Some(tree) => {
let layouted = layout(tree, ctx).await;
f.extend(layouted.feedback);
vec![AddMultiple(layouted.output)]
}
None => vec![SetAlignment(ctx.align)],
}, f)
}
}