diff --git a/library/src/text/raw.rs b/library/src/text/raw.rs index 4a9a925c0..4cc26fa67 100644 --- a/library/src/text/raw.rs +++ b/library/src/text/raw.rs @@ -102,6 +102,27 @@ pub struct RawElem { /// ``` /// ```` pub lang: Option, + + /// The horizontal alignment that each line in a raw block should have. + /// This option is ignored if this is not a raw block (if specified + /// `block: false` or single backticks were used in markup mode). + /// + /// By default, this is set to `{start}`, meaning that raw text is + /// aligned towards the start of the text direction inside the block + /// by default, regardless of the current context's alignment (allowing + /// you to center the raw block itself without centering the text inside + /// it, for example). + /// + /// ````example + /// #set raw(align: center) + /// + /// ```typc + /// let f(x) = x + /// code = "centered" + /// ``` + /// ```` + #[default(HorizontalAlign(GenAlign::Start))] + pub align: HorizontalAlign, } impl RawElem { @@ -180,6 +201,8 @@ impl Show for RawElem { }; if self.block(styles) { + // Align the text before inserting it into the block. + realized = realized.aligned(Axes::with_x(Some(self.align(styles).into()))); realized = BlockElem::new().with_body(Some(realized)).pack(); } diff --git a/src/geom/align.rs b/src/geom/align.rs index 69f32bee9..a15ec4e60 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -106,6 +106,18 @@ impl From for GenAlign { } } +impl From for GenAlign { + fn from(align: HorizontalAlign) -> Self { + align.0 + } +} + +impl From for GenAlign { + fn from(align: VerticalAlign) -> Self { + align.0 + } +} + impl Debug for GenAlign { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { @@ -184,7 +196,45 @@ impl Fold for GenAlign { } } -#[derive(Copy, Clone, Eq, PartialEq, Debug)] +/// Utility struct to restrict a passed alignment value to the horizontal axis +/// on cast. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct HorizontalAlign(pub GenAlign); + +cast_from_value! { + HorizontalAlign, + align: GenAlign => { + if align.axis() != Axis::X { + Err("alignment must be horizontal")?; + } + Self(align) + }, +} + +cast_to_value! { + v: HorizontalAlign => v.0.into() +} + +/// Utility struct to restrict a passed alignment value to the vertical axis on +/// cast. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct VerticalAlign(pub GenAlign); + +cast_from_value! { + VerticalAlign, + align: GenAlign => { + if align.axis() != Axis::Y { + Err("alignment must be vertical")?; + } + Self(align) + }, +} + +cast_to_value! { + v: VerticalAlign => v.0.into() +} + +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum LeftRightAlternator { Left, Right, diff --git a/tests/ref/text/raw-align.png b/tests/ref/text/raw-align.png new file mode 100644 index 000000000..734008e1a Binary files /dev/null and b/tests/ref/text/raw-align.png differ diff --git a/tests/typ/text/raw-align.typ b/tests/typ/text/raw-align.typ new file mode 100644 index 000000000..2e124ea98 --- /dev/null +++ b/tests/typ/text/raw-align.typ @@ -0,0 +1,37 @@ +// Test the alignment of text inside of raw blocks. + +--- +// Text inside raw block should be unaffected by outer alignment by default. +#set align(center) +#set page(width: 180pt) +#set text(6pt) + +#lorem(20) + +```py +def something(x): + return x + +a = 342395823859823958329 +b = 324923 +``` + +#lorem(20) + +--- +// Text inside raw block should follow the specified alignment. +#set page(width: 180pt) +#set text(6pt) + +#lorem(20) +#align(center, raw( + lang: "typ", + block: true, + align: right, + "#let f(x) = x\n#align(center, line(length: 1em))", +)) +#lorem(20) + +--- +// Error: 17-20 alignment must be horizontal +#set raw(align: top)