Include numbering in PDF bookmark (#6622)

Co-authored-by: Laurenz <laurmaedje@gmail.com>
This commit is contained in:
Y.D.X. 2025-08-07 19:17:54 +08:00 committed by GitHub
parent c49b9640a6
commit 3455ac7dd2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 30 additions and 1 deletions

View File

@ -1,5 +1,6 @@
use std::num::NonZeroUsize; use std::num::NonZeroUsize;
use ecow::EcoString;
use typst_utils::NonZeroExt; use typst_utils::NonZeroExt;
use crate::diag::SourceResult; use crate::diag::SourceResult;
@ -103,6 +104,18 @@ pub struct HeadingElem {
/// ``` /// ```
pub numbering: Option<Numbering>, pub numbering: Option<Numbering>,
/// The resolved plain-text numbers.
///
/// This field is internal and only used for creating PDF bookmarks. We
/// don't currently have access to `World`, `Engine`, or `styles` in export,
/// which is needed to resolve the counter and numbering pattern into a
/// concrete string.
///
/// This remains unset if `numbering` is `None`.
#[internal]
#[synthesized]
pub numbers: EcoString,
/// A supplement for the heading. /// A supplement for the heading.
/// ///
/// For references to headings, this is added before the referenced number. /// For references to headings, this is added before the referenced number.
@ -202,6 +215,16 @@ impl Synthesize for Packed<HeadingElem> {
} }
}; };
if let Some((numbering, location)) =
self.numbering.get_ref(styles).as_ref().zip(self.location())
{
self.numbers = Some(
self.counter()
.display_at_loc(engine, location, styles, numbering)?
.plain_text(),
);
}
let elem = self.as_mut(); let elem = self.as_mut();
elem.level.set(Smart::Custom(elem.resolve_level(styles))); elem.level.set(Smart::Custom(elem.resolve_level(styles)));
elem.supplement elem.supplement

View File

@ -124,10 +124,16 @@ impl<'a> HeadingNode<'a> {
fn to_krilla(&self, gc: &GlobalContext) -> Option<OutlineNode> { fn to_krilla(&self, gc: &GlobalContext) -> Option<OutlineNode> {
let loc = self.element.location().unwrap(); let loc = self.element.location().unwrap();
let title = self.element.body.plain_text().to_string();
let pos = gc.document.introspector.position(loc); let pos = gc.document.introspector.position(loc);
let page_index = pos.page.get() - 1; let page_index = pos.page.get() - 1;
// Prepend the numbers to the title if they exist.
let text = self.element.body.plain_text();
let title = match &self.element.numbers {
Some(num) => format!("{num} {text}"),
None => text.to_string(),
};
if let Some(index) = gc.page_index_converter.pdf_page_index(page_index) { if let Some(index) = gc.page_index_converter.pdf_page_index(page_index) {
let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero()); let y = (pos.point.y - Abs::pt(10.0)).max(Abs::zero());
let dest = XyzDestination::new( let dest = XyzDestination::new(