diff options
| author | HaeNoe <57222371+haenoe@users.noreply.github.com> | 2024-05-06 17:21:35 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-05-06 15:21:35 +0000 |
| commit | 6d0c159e97a9274fedcdd269b886385e987da6e0 (patch) | |
| tree | 4898488f27ef3387e8c0e433ba2d862889ff36e3 /crates | |
| parent | 102e6717e85bbc6a707d16df24f5f3cf660f735d (diff) | |
Indent configuration for multiline headings (#3459)
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/typst/src/model/heading.rs | 52 |
1 files changed, 45 insertions, 7 deletions
diff --git a/crates/typst/src/model/heading.rs b/crates/typst/src/model/heading.rs index d3976948..0744687e 100644 --- a/crates/typst/src/model/heading.rs +++ b/crates/typst/src/model/heading.rs @@ -3,12 +3,14 @@ use std::num::NonZeroUsize; use crate::diag::SourceResult; use crate::engine::Engine; use crate::foundations::{ - elem, Content, NativeElement, Packed, Show, ShowSet, Smart, StyleChain, Styles, - Synthesize, + elem, Content, NativeElement, Packed, Resolve, Show, ShowSet, Smart, StyleChain, + Styles, Synthesize, }; use crate::introspection::{Count, Counter, CounterUpdate, Locatable}; -use crate::layout::{BlockElem, Em, HElem, VElem}; -use crate::model::{Numbering, Outlinable, Refable, Supplement}; +use crate::layout::{ + Abs, Axes, BlockElem, Em, HElem, LayoutMultiple, Length, Regions, VElem, +}; +use crate::model::{Numbering, Outlinable, ParElem, Refable, Supplement}; use crate::text::{FontWeight, LocalName, SpaceElem, TextElem, TextSize}; use crate::util::NonZeroExt; @@ -163,6 +165,18 @@ pub struct HeadingElem { #[default(Smart::Auto)] pub bookmarked: Smart<bool>, + /// The indent all but the first line of a heading should have. + /// + /// The default value of `{auto}` indicates that the subsequent heading + /// lines will be indented based on the width of the numbering. + /// + /// ```example + /// #set heading(numbering: "1.") + /// #heading[A very, very, very, very, very, very long heading] + /// ``` + #[default(Smart::Auto)] + pub hanging_indent: Smart<Length>, + /// The heading's title. #[required] pub body: Content, @@ -201,15 +215,39 @@ impl Synthesize for Packed<HeadingElem> { impl Show for Packed<HeadingElem> { #[typst_macros::time(name = "heading", span = self.span())] fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> { + const SPACING_TO_NUMBERING: Em = Em::new(0.3); + let span = self.span(); let mut realized = self.body().clone(); + + let hanging_indent = self.hanging_indent(styles); + + let mut indent = match hanging_indent { + Smart::Custom(length) => length.resolve(styles), + Smart::Auto => Abs::zero(), + }; + if let Some(numbering) = (**self).numbering(styles).as_ref() { - realized = Counter::of(HeadingElem::elem()) + let numbering = Counter::of(HeadingElem::elem()) .display_at_loc(engine, self.location().unwrap(), styles, numbering)? - .spanned(span) - + HElem::new(Em::new(0.3).into()).with_weak(true).pack() + .spanned(span); + + if hanging_indent.is_auto() { + let pod = Regions::one(Axes::splat(Abs::inf()), Axes::splat(false)); + let size = numbering.measure(engine, styles, pod)?.into_frame().size(); + + indent = size.x + SPACING_TO_NUMBERING.resolve(styles); + } + + realized = numbering + + HElem::new(SPACING_TO_NUMBERING.into()).with_weak(true).pack() + realized; } + + if indent != Abs::zero() { + realized = realized.styled(ParElem::set_hanging_indent(indent.into())); + } + Ok(BlockElem::new().with_body(Some(realized)).pack().spanned(span)) } } |
