mirror of
https://github.com/typst/typst
synced 2025-05-13 20:46:23 +08:00
Align set rule
This commit is contained in:
parent
495b525694
commit
cd089b6194
@ -1,62 +1,22 @@
|
||||
use super::{HorizontalAlign, ParNode};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Align content along the layouting axes.
|
||||
/// Just an empty shell to scope styles.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct AlignNode {
|
||||
/// How to align the content horizontally and vertically.
|
||||
pub aligns: Axes<Option<GenAlign>>,
|
||||
/// The content to be aligned.
|
||||
pub body: Content,
|
||||
}
|
||||
pub enum AlignNode {}
|
||||
|
||||
#[node(Layout)]
|
||||
#[node]
|
||||
impl AlignNode {
|
||||
/// The alignment.
|
||||
#[property(fold, skip)]
|
||||
pub const ALIGNS: Axes<Option<GenAlign>> =
|
||||
Axes::new(GenAlign::Start, GenAlign::Specific(Align::Top));
|
||||
|
||||
fn construct(_: &Vm, args: &mut Args) -> SourceResult<Content> {
|
||||
args.expect("body")
|
||||
}
|
||||
|
||||
fn set(...) {
|
||||
let aligns: Axes<Option<GenAlign>> = args.find()?.unwrap_or_default();
|
||||
let body: Content = args.expect("body")?;
|
||||
|
||||
if let Axes { x: Some(x), y: None } = aligns {
|
||||
if !body.has::<dyn Layout>() || body.has::<dyn Inline>() {
|
||||
return Ok(body.styled(ParNode::ALIGN, HorizontalAlign(x)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { aligns, body }.pack())
|
||||
}
|
||||
}
|
||||
|
||||
impl Layout for AlignNode {
|
||||
fn layout(
|
||||
&self,
|
||||
vt: &mut Vt,
|
||||
styles: StyleChain,
|
||||
regions: Regions,
|
||||
) -> SourceResult<Fragment> {
|
||||
// The child only needs to expand along an axis if there's no alignment.
|
||||
let mut pod = regions.clone();
|
||||
pod.expand &= self.aligns.as_ref().map(Option::is_none);
|
||||
|
||||
// Align paragraphs inside the child.
|
||||
let mut map = StyleMap::new();
|
||||
if let Some(align) = self.aligns.x {
|
||||
map.set(ParNode::ALIGN, HorizontalAlign(align));
|
||||
}
|
||||
|
||||
// Layout the child.
|
||||
let mut fragment = self.body.layout(vt, styles.chain(&map), pod)?;
|
||||
for (region, frame) in regions.iter().zip(&mut fragment) {
|
||||
// Align in the target size. The target size depends on whether we
|
||||
// should expand.
|
||||
let target = regions.expand.select(region, frame.size());
|
||||
let aligns = self
|
||||
.aligns
|
||||
.map(|align| align.resolve(styles))
|
||||
.unwrap_or(Axes::new(Align::Left, Align::Top));
|
||||
|
||||
frame.resize(target, aligns);
|
||||
}
|
||||
|
||||
Ok(fragment)
|
||||
styles.set(Self::ALIGNS, aligns);
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
par: &ParNode,
|
||||
styles: StyleChain,
|
||||
) -> SourceResult<()> {
|
||||
let aligns = Axes::new(styles.get(ParNode::ALIGN), Align::Top);
|
||||
let aligns = styles.get(AlignNode::ALIGNS).resolve(styles);
|
||||
let leading = styles.get(ParNode::LEADING);
|
||||
let consecutive = self.last_was_par;
|
||||
let fragment = par.layout(
|
||||
@ -172,17 +172,7 @@ impl<'a> FlowLayouter<'a> {
|
||||
}
|
||||
|
||||
// How to align the block.
|
||||
let aligns = Axes::new(
|
||||
// For non-expanding paragraphs it is crucial that we align the
|
||||
// whole paragraph as it is itself aligned.
|
||||
styles.get(ParNode::ALIGN),
|
||||
// Vertical align node alignment is respected by the flow.
|
||||
block
|
||||
.to::<AlignNode>()
|
||||
.and_then(|aligned| aligned.aligns.y)
|
||||
.map(|align| align.resolve(styles))
|
||||
.unwrap_or(Align::Top),
|
||||
);
|
||||
let aligns = styles.get(AlignNode::ALIGNS).resolve(styles);
|
||||
|
||||
// Layout the block itself.
|
||||
let sticky = styles.get(BlockNode::STICKY);
|
||||
|
@ -412,7 +412,9 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
bail!(span, "not allowed here");
|
||||
}
|
||||
self.interrupt_page(styles)?;
|
||||
} else if map.interruption::<ParNode>().is_some() {
|
||||
} else if map.interruption::<ParNode>().is_some()
|
||||
|| map.interruption::<AlignNode>().is_some()
|
||||
{
|
||||
self.interrupt_par()?;
|
||||
} else if map.interruption::<ListNode>().is_some()
|
||||
|| map.interruption::<EnumNode>().is_some()
|
||||
|
@ -5,6 +5,7 @@ use xi_unicode::LineBreakIterator;
|
||||
use typst::model::Key;
|
||||
|
||||
use super::{HNode, RepeatNode, Spacing};
|
||||
use crate::layout::AlignNode;
|
||||
use crate::prelude::*;
|
||||
use crate::text::{
|
||||
shape, LinebreakNode, Quoter, Quotes, ShapedText, SmartQuoteNode, SpaceNode, TextNode,
|
||||
@ -22,9 +23,6 @@ impl ParNode {
|
||||
/// The spacing between lines.
|
||||
#[property(resolve)]
|
||||
pub const LEADING: Length = Em::new(0.65).into();
|
||||
/// How to align text and inline objects in their line.
|
||||
#[property(resolve)]
|
||||
pub const ALIGN: HorizontalAlign = HorizontalAlign(GenAlign::Start);
|
||||
/// Whether to justify text in its line.
|
||||
pub const JUSTIFY: bool = false;
|
||||
/// How to determine line breaks.
|
||||
@ -554,7 +552,7 @@ fn prepare<'a>(
|
||||
styles,
|
||||
hyphenate: shared_get(styles, &par.0, TextNode::HYPHENATE),
|
||||
lang: shared_get(styles, &par.0, TextNode::LANG),
|
||||
align: styles.get(ParNode::ALIGN),
|
||||
align: styles.get(AlignNode::ALIGNS).x.resolve(styles),
|
||||
justify: styles.get(ParNode::JUSTIFY),
|
||||
})
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
use super::AlignNode;
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Place content at an absolute position.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct PlaceNode(pub Content);
|
||||
pub struct PlaceNode(pub Content, bool);
|
||||
|
||||
#[node(Layout, Behave)]
|
||||
impl PlaceNode {
|
||||
@ -12,7 +11,8 @@ impl PlaceNode {
|
||||
let dx = args.named("dx")?.unwrap_or_default();
|
||||
let dy = args.named("dy")?.unwrap_or_default();
|
||||
let body = args.expect::<Content>("body")?;
|
||||
Ok(Self(body.moved(Axes::new(dx, dy)).aligned(aligns)).pack())
|
||||
let out_of_flow = aligns.y.is_some();
|
||||
Ok(Self(body.moved(Axes::new(dx, dy)).aligned(aligns), out_of_flow).pack())
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ impl PlaceNode {
|
||||
/// origin. Instead of relative to the parent's current flow/cursor
|
||||
/// position.
|
||||
pub fn out_of_flow(&self) -> bool {
|
||||
self.0.to::<AlignNode>().map_or(false, |node| node.aligns.y.is_some())
|
||||
self.1
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use typst::model::StyledNode;
|
||||
|
||||
use super::{AlignNode, ParNode, Spacing};
|
||||
use super::{AlignNode, Spacing};
|
||||
use crate::prelude::*;
|
||||
|
||||
/// Arrange content and spacing along an axis.
|
||||
@ -180,21 +180,13 @@ impl<'a> StackLayouter<'a> {
|
||||
|
||||
// Block-axis alignment of the `AlignNode` is respected
|
||||
// by the stack node.
|
||||
let align = block
|
||||
.to::<AlignNode>()
|
||||
.and_then(|node| node.aligns.get(self.axis))
|
||||
.map(|align| align.resolve(styles))
|
||||
.unwrap_or_else(|| {
|
||||
if let Some(styled) = block.to::<StyledNode>() {
|
||||
let map = &styled.map;
|
||||
if map.contains(ParNode::ALIGN) {
|
||||
return StyleChain::new(map).get(ParNode::ALIGN);
|
||||
}
|
||||
}
|
||||
|
||||
self.dir.start().into()
|
||||
});
|
||||
let aligns = if let Some(styled) = block.to::<StyledNode>() {
|
||||
styles.chain(&styled.map).get(AlignNode::ALIGNS)
|
||||
} else {
|
||||
styles.get(AlignNode::ALIGNS)
|
||||
};
|
||||
|
||||
let align = aligns.get(self.axis).resolve(styles);
|
||||
let fragment = block.layout(vt, styles, self.regions)?;
|
||||
let len = fragment.len();
|
||||
for (i, frame) in fragment.into_iter().enumerate() {
|
||||
|
@ -208,6 +208,6 @@ fn items() -> LangItems {
|
||||
math_atom: |atom| math::AtomNode(atom).pack(),
|
||||
math_script: |base, sub, sup| math::ScriptNode { base, sub, sup }.pack(),
|
||||
math_frac: |num, denom| math::FracNode { num, denom }.pack(),
|
||||
math_align: |count| math::AlignNode(count).pack(),
|
||||
math_align_point: |count| math::AlignPointNode(count).pack(),
|
||||
}
|
||||
}
|
||||
|
@ -442,14 +442,14 @@ impl Texify for ScriptNode {
|
||||
}
|
||||
}
|
||||
|
||||
/// A math alignment indicator: `&`, `&&`.
|
||||
/// A math alignment point: `&`, `&&`.
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct AlignNode(pub usize);
|
||||
pub struct AlignPointNode(pub usize);
|
||||
|
||||
#[node(Texify)]
|
||||
impl AlignNode {}
|
||||
impl AlignPointNode {}
|
||||
|
||||
impl Texify for AlignNode {
|
||||
impl Texify for AlignPointNode {
|
||||
fn texify(&self, _: &mut Texifier) -> SourceResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ impl ContentExt for Content {
|
||||
}
|
||||
|
||||
fn aligned(self, aligns: Axes<Option<GenAlign>>) -> Self {
|
||||
crate::layout::AlignNode { aligns, body: self }.pack()
|
||||
self.styled(crate::layout::AlignNode::ALIGNS, aligns)
|
||||
}
|
||||
|
||||
fn padded(self, padding: Sides<Rel<Length>>) -> Self {
|
||||
|
@ -45,16 +45,13 @@ impl<T> Corners<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Zip two instances into an instance.
|
||||
pub fn zip<F, V, W>(self, other: Corners<V>, mut f: F) -> Corners<W>
|
||||
where
|
||||
F: FnMut(T, V) -> W,
|
||||
{
|
||||
/// Zip two instances into one.
|
||||
pub fn zip<U>(self, other: Corners<U>) -> Corners<(T, U)> {
|
||||
Corners {
|
||||
top_left: f(self.top_left, other.top_left),
|
||||
top_right: f(self.top_right, other.top_right),
|
||||
bottom_right: f(self.bottom_right, other.bottom_right),
|
||||
bottom_left: f(self.bottom_left, other.bottom_left),
|
||||
top_left: (self.top_left, other.top_left),
|
||||
top_right: (self.top_right, other.top_right),
|
||||
bottom_right: (self.bottom_right, other.bottom_right),
|
||||
bottom_left: (self.bottom_left, other.bottom_left),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,16 +45,13 @@ impl<T> Sides<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Zip two instances into an instance.
|
||||
pub fn zip<F, V, W>(self, other: Sides<V>, mut f: F) -> Sides<W>
|
||||
where
|
||||
F: FnMut(T, V) -> W,
|
||||
{
|
||||
/// Zip two instances into one.
|
||||
pub fn zip<U>(self, other: Sides<U>) -> Sides<(T, U)> {
|
||||
Sides {
|
||||
left: f(self.left, other.left),
|
||||
top: f(self.top, other.top),
|
||||
right: f(self.right, other.right),
|
||||
bottom: f(self.bottom, other.bottom),
|
||||
left: (self.left, other.left),
|
||||
top: (self.top, other.top),
|
||||
right: (self.right, other.right),
|
||||
bottom: (self.bottom, other.bottom),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +429,7 @@ impl Eval for ast::MathNode {
|
||||
Self::Symbol(v) => (vm.items.symbol)(v.get().clone() + ":op".into()),
|
||||
Self::Script(v) => v.eval(vm)?,
|
||||
Self::Frac(v) => v.eval(vm)?,
|
||||
Self::Align(v) => v.eval(vm)?,
|
||||
Self::AlignPoint(v) => v.eval(vm)?,
|
||||
Self::Group(v) => v.eval(vm)?,
|
||||
Self::Expr(v) => {
|
||||
if let ast::Expr::Ident(ident) = v {
|
||||
@ -480,11 +480,11 @@ impl Eval for ast::Frac {
|
||||
}
|
||||
}
|
||||
|
||||
impl Eval for ast::Align {
|
||||
impl Eval for ast::AlignPoint {
|
||||
type Output = Content;
|
||||
|
||||
fn eval(&self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
Ok((vm.items.math_align)(self.count()))
|
||||
Ok((vm.items.math_align_point)(self.count()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,8 +74,8 @@ pub struct LangItems {
|
||||
fn(base: Content, sub: Option<Content>, sup: Option<Content>) -> Content,
|
||||
/// A fraction in a formula: `x/2`.
|
||||
pub math_frac: fn(num: Content, denom: Content) -> Content,
|
||||
/// An alignment indicator in a formula: `&`, `&&`.
|
||||
pub math_align: fn(count: usize) -> Content,
|
||||
/// An alignment point in a formula: `&`, `&&`.
|
||||
pub math_align_point: fn(count: usize) -> Content,
|
||||
}
|
||||
|
||||
impl Debug for LangItems {
|
||||
@ -107,7 +107,7 @@ impl Hash for LangItems {
|
||||
self.math_atom.hash(state);
|
||||
self.math_script.hash(state);
|
||||
self.math_frac.hash(state);
|
||||
self.math_align.hash(state);
|
||||
self.math_align_point.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -913,6 +913,14 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl Fold for Axes<Option<GenAlign>> {
|
||||
type Output = Axes<GenAlign>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer).map(|(inner, outer)| inner.unwrap_or(outer))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Fold for Sides<T>
|
||||
where
|
||||
T: Fold,
|
||||
@ -920,7 +928,7 @@ where
|
||||
type Output = Sides<T::Output>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer, |inner, outer| inner.fold(outer))
|
||||
self.zip(outer).map(|(inner, outer)| inner.fold(outer))
|
||||
}
|
||||
}
|
||||
|
||||
@ -928,7 +936,7 @@ impl Fold for Sides<Option<Rel<Abs>>> {
|
||||
type Output = Sides<Rel<Abs>>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer, |inner, outer| inner.unwrap_or(outer))
|
||||
self.zip(outer).map(|(inner, outer)| inner.unwrap_or(outer))
|
||||
}
|
||||
}
|
||||
|
||||
@ -936,7 +944,7 @@ impl Fold for Sides<Option<Smart<Rel<Length>>>> {
|
||||
type Output = Sides<Smart<Rel<Length>>>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer, |inner, outer| inner.unwrap_or(outer))
|
||||
self.zip(outer).map(|(inner, outer)| inner.unwrap_or(outer))
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,7 +955,7 @@ where
|
||||
type Output = Corners<T::Output>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer, |inner, outer| inner.fold(outer))
|
||||
self.zip(outer).map(|(inner, outer)| inner.fold(outer))
|
||||
}
|
||||
}
|
||||
|
||||
@ -955,7 +963,7 @@ impl Fold for Corners<Option<Rel<Abs>>> {
|
||||
type Output = Corners<Rel<Abs>>;
|
||||
|
||||
fn fold(self, outer: Self::Output) -> Self::Output {
|
||||
self.zip(outer, |inner, outer| inner.unwrap_or(outer))
|
||||
self.zip(outer).map(|(inner, outer)| inner.unwrap_or(outer))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -453,8 +453,8 @@ pub enum MathNode {
|
||||
Script(Script),
|
||||
/// A fraction: `x/2`.
|
||||
Frac(Frac),
|
||||
/// An alignment indicator: `&`, `&&`.
|
||||
Align(Align),
|
||||
/// An alignment point: `&`, `&&`.
|
||||
AlignPoint(AlignPoint),
|
||||
/// Grouped mathematical material.
|
||||
Group(Math),
|
||||
/// An expression.
|
||||
@ -472,7 +472,7 @@ impl AstNode for MathNode {
|
||||
SyntaxKind::Symbol(_) => node.cast().map(Self::Symbol),
|
||||
SyntaxKind::Script => node.cast().map(Self::Script),
|
||||
SyntaxKind::Frac => node.cast().map(Self::Frac),
|
||||
SyntaxKind::Align => node.cast().map(Self::Align),
|
||||
SyntaxKind::AlignPoint => node.cast().map(Self::AlignPoint),
|
||||
SyntaxKind::Math => node.cast().map(Self::Group),
|
||||
_ => node.cast().map(Self::Expr),
|
||||
}
|
||||
@ -488,7 +488,7 @@ impl AstNode for MathNode {
|
||||
Self::Symbol(v) => v.as_untyped(),
|
||||
Self::Script(v) => v.as_untyped(),
|
||||
Self::Frac(v) => v.as_untyped(),
|
||||
Self::Align(v) => v.as_untyped(),
|
||||
Self::AlignPoint(v) => v.as_untyped(),
|
||||
Self::Group(v) => v.as_untyped(),
|
||||
Self::Expr(v) => v.as_untyped(),
|
||||
}
|
||||
@ -558,11 +558,11 @@ impl Frac {
|
||||
}
|
||||
|
||||
node! {
|
||||
/// An alignment indicator in a formula: `&`, `&&`.
|
||||
Align
|
||||
/// An alignment point in a formula: `&`, `&&`.
|
||||
AlignPoint
|
||||
}
|
||||
|
||||
impl Align {
|
||||
impl AlignPoint {
|
||||
/// The number of ampersands.
|
||||
pub fn count(&self) -> usize {
|
||||
self.0.children().filter(|n| n.kind() == &SyntaxKind::Amp).count()
|
||||
|
@ -302,7 +302,7 @@ impl Category {
|
||||
SyntaxKind::Atom(_) => None,
|
||||
SyntaxKind::Script => None,
|
||||
SyntaxKind::Frac => None,
|
||||
SyntaxKind::Align => None,
|
||||
SyntaxKind::AlignPoint => None,
|
||||
|
||||
SyntaxKind::Ident(_) => match parent.kind() {
|
||||
SyntaxKind::Markup { .. }
|
||||
|
@ -179,8 +179,8 @@ pub enum SyntaxKind {
|
||||
Script,
|
||||
/// A fraction in a formula: `x/2`.
|
||||
Frac,
|
||||
/// An alignment indicator in a formula: `&`, `&&`.
|
||||
Align,
|
||||
/// An alignment point in a formula: `&`, `&&`.
|
||||
AlignPoint,
|
||||
|
||||
/// An identifier: `it`.
|
||||
Ident(EcoString),
|
||||
@ -408,7 +408,7 @@ impl SyntaxKind {
|
||||
Self::Atom(_) => "math atom",
|
||||
Self::Script => "script",
|
||||
Self::Frac => "fraction",
|
||||
Self::Align => "alignment indicator",
|
||||
Self::AlignPoint => "alignment point",
|
||||
Self::Ident(_) => "identifier",
|
||||
Self::Bool(_) => "boolean",
|
||||
Self::Int(_) => "integer",
|
||||
@ -528,7 +528,7 @@ impl Hash for SyntaxKind {
|
||||
Self::Atom(c) => c.hash(state),
|
||||
Self::Script => {}
|
||||
Self::Frac => {}
|
||||
Self::Align => {}
|
||||
Self::AlignPoint => {}
|
||||
Self::Ident(v) => v.hash(state),
|
||||
Self::Bool(v) => v.hash(state),
|
||||
Self::Int(v) => v.hash(state),
|
||||
|
@ -499,7 +499,7 @@ fn math_group(p: &mut Parser, group: Group) {
|
||||
}
|
||||
|
||||
fn math_align(p: &mut Parser) {
|
||||
p.perform(SyntaxKind::Align, |p| {
|
||||
p.perform(SyntaxKind::AlignPoint, |p| {
|
||||
p.assert(SyntaxKind::Amp);
|
||||
while p.eat_if(SyntaxKind::Amp) {}
|
||||
})
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
@ -10,9 +10,9 @@
|
||||
// Ensure that constructor styles win, but not over outer styles.
|
||||
// The outer paragraph should be right-aligned,
|
||||
// but the B should be center-aligned.
|
||||
#set par(align: center)
|
||||
#par(align: right)[
|
||||
A #rect(width: 2cm, fill: conifer, inset: 4pt)[B]
|
||||
#set list(label: [>])
|
||||
#list(label: [--])[
|
||||
#rect(width: 2cm, fill: conifer, inset: 4pt, list[A])
|
||||
]
|
||||
|
||||
---
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
// Test ragged-left.
|
||||
#set par(align: right)
|
||||
#set align(right)
|
||||
To the right! Where the sunlight peeks behind the mountain.
|
||||
|
||||
---
|
||||
@ -35,11 +35,3 @@ fn main() {}
|
||||
- List
|
||||
|
||||
Paragraph
|
||||
|
||||
---
|
||||
// Error: 17-20 must be horizontal
|
||||
#set par(align: top)
|
||||
|
||||
---
|
||||
// Error: 17-33 expected alignment, found 2d alignment
|
||||
#set par(align: horizon + center)
|
||||
|
@ -32,7 +32,7 @@ A#repeat(rect(width: 2.5em, height: 1em))B
|
||||
// Test single repeat in both directions.
|
||||
A#repeat(rect(width: 6em, height: 0.7em))B
|
||||
|
||||
#set par(align: center)
|
||||
#set align(center)
|
||||
A#repeat(rect(width: 6em, height: 0.7em))B
|
||||
|
||||
#set text(dir: rtl)
|
||||
|
@ -19,7 +19,7 @@ Add #h(10pt) #h(10pt) up
|
||||
|
||||
---
|
||||
// Test spacing collapsing before spacing.
|
||||
#set par(align: right)
|
||||
#set align(right)
|
||||
A #h(0pt) B #h(0pt) \
|
||||
A B \
|
||||
A #h(-1fr) B
|
||||
|
@ -11,5 +11,5 @@
|
||||
}
|
||||
|
||||
#set page(width: auto)
|
||||
#set par(align: center)
|
||||
#set align(center)
|
||||
#table(columns: 1 + modifiers.len(), ..cells)
|
||||
|
@ -18,6 +18,6 @@
|
||||
---
|
||||
// Test that lone punctuation doesn't overhang into the margin.
|
||||
#set page(margin: 0pt)
|
||||
#set par(align: end)
|
||||
#set align(end)
|
||||
#set text(dir: rtl)
|
||||
:
|
||||
|
@ -22,7 +22,7 @@
|
||||
#let star(width, ..args) = box(width: width, height: width)[
|
||||
#set text(spacing: 0%)
|
||||
#set line(..args)
|
||||
#set par(align: left)
|
||||
#set align(left)
|
||||
#line(length: +30%, origin: (09.0%, 02%))
|
||||
#line(length: +30%, origin: (38.7%, 02%), angle: -72deg)
|
||||
#line(length: +30%, origin: (57.5%, 02%), angle: 252deg)
|
||||
|
Loading…
x
Reference in New Issue
Block a user