diff options
Diffstat (limited to 'crates/typst-library/src/meta/reference.rs')
| -rw-r--r-- | crates/typst-library/src/meta/reference.rs | 283 |
1 files changed, 0 insertions, 283 deletions
diff --git a/crates/typst-library/src/meta/reference.rs b/crates/typst-library/src/meta/reference.rs deleted file mode 100644 index 3a463c80..00000000 --- a/crates/typst-library/src/meta/reference.rs +++ /dev/null @@ -1,283 +0,0 @@ -use super::{BibliographyElem, CiteElem, Counter, Figurable, Numbering}; -use crate::math::EquationElem; -use crate::meta::FootnoteElem; -use crate::prelude::*; -use crate::text::TextElem; - -/// A reference to a label or bibliography. -/// -/// Produces a textual reference to a label. For example, a reference to a -/// heading will yield an appropriate string such as "Section 1" for a reference -/// to the first heading. The references are also links to the respective -/// element. Reference syntax can also be used to [cite]($cite) from a -/// bibliography. -/// -/// Referenceable elements include [headings]($heading), [figures]($figure), -/// [equations]($math.equation), and [footnotes]($footnote). To create a custom -/// referenceable element like a theorem, you can create a figure of a custom -/// [`kind`]($figure.kind) and write a show rule for it. In the future, there -/// might be a more direct way to define a custom referenceable element. -/// -/// If you just want to link to a labelled element and not get an automatic -/// textual reference, consider using the [`link`]($link) function instead. -/// -/// # Example -/// ```example -/// #set heading(numbering: "1.") -/// #set math.equation(numbering: "(1)") -/// -/// = Introduction <intro> -/// Recent developments in -/// typesetting software have -/// rekindled hope in previously -/// frustrated researchers. @distress -/// As shown in @results, we ... -/// -/// = Results <results> -/// We discuss our approach in -/// comparison with others. -/// -/// == Performance <perf> -/// @slow demonstrates what slow -/// software looks like. -/// $ O(n) = 2^n $ <slow> -/// -/// #bibliography("works.bib") -/// ``` -/// -/// # Syntax -/// This function also has dedicated syntax: A reference to a label can be -/// created by typing an `@` followed by the name of the label (e.g. -/// `[= Introduction <intro>]` can be referenced by typing `[@intro]`). -/// -/// To customize the supplement, add content in square brackets after the -/// reference: `[@intro[Chapter]]`. -/// -/// # Customization -/// If you write a show rule for references, you can access the referenced -/// element through the `element` field of the reference. The `element` may -/// be `{none}` even if it exists if Typst hasn't discovered it yet, so you -/// always need to handle that case in your code. -/// -/// ```example -/// #set heading(numbering: "1.") -/// #set math.equation(numbering: "(1)") -/// -/// #show ref: it => { -/// let eq = math.equation -/// let el = it.element -/// if el != none and el.func() == eq { -/// // Override equation references. -/// numbering( -/// el.numbering, -/// ..counter(eq).at(el.location()) -/// ) -/// } else { -/// // Other references as usual. -/// it -/// } -/// } -/// -/// = Beginnings <beginning> -/// In @beginning we prove @pythagoras. -/// $ a^2 + b^2 = c^2 $ <pythagoras> -/// ``` -#[elem(title = "Reference", Synthesize, Locatable, Show)] -pub struct RefElem { - /// The target label that should be referenced. - /// - /// Can be a label that is defined in the document or an entry from the - /// [`bibliography`]($bibliography). - #[required] - pub target: Label, - - /// A supplement for the reference. - /// - /// For references to headings or figures, this is added before the - /// referenced number. For citations, this can be used to add a page number. - /// - /// If a function is specified, it is passed the referenced element and - /// should return content. - /// - /// ```example - /// #set heading(numbering: "1.") - /// #set ref(supplement: it => { - /// if it.func() == heading { - /// "Chapter" - /// } else { - /// "Thing" - /// } - /// }) - /// - /// = Introduction <intro> - /// In @intro, we see how to turn - /// Sections into Chapters. And - /// in @intro[Part], it is done - /// manually. - /// ``` - #[borrowed] - pub supplement: Smart<Option<Supplement>>, - - /// A synthesized citation. - #[synthesized] - pub citation: Option<CiteElem>, - - /// The referenced element. - #[synthesized] - pub element: Option<Content>, -} - -impl Synthesize for RefElem { - fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { - let citation = self.to_citation(vt, styles)?; - self.push_citation(Some(citation)); - self.push_element(None); - - let target = *self.target(); - if !BibliographyElem::has(vt, target) { - if let Ok(elem) = vt.introspector.query_label(target) { - self.push_element(Some(elem.into_inner())); - return Ok(()); - } - } - - Ok(()) - } -} - -impl Show for RefElem { - #[tracing::instrument(name = "RefElem::show", skip_all)] - fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - Ok(vt.delayed(|vt| { - let target = *self.target(); - let elem = vt.introspector.query_label(target); - let span = self.span(); - - if BibliographyElem::has(vt, target) { - if elem.is_ok() { - bail!(span, "label occurs in the document and its bibliography"); - } - - return Ok(self.to_citation(vt, styles)?.spanned(span).pack()); - } - - let elem = elem.at(span)?; - - if elem.func() == FootnoteElem::elem() { - return Ok(FootnoteElem::with_label(target).spanned(span).pack()); - } - - let refable = elem - .with::<dyn Refable>() - .ok_or_else(|| { - if elem.can::<dyn Figurable>() { - eco_format!( - "cannot reference {} directly, try putting it into a figure", - elem.func().name() - ) - } else { - eco_format!("cannot reference {}", elem.func().name()) - } - }) - .at(span)?; - - let numbering = refable - .numbering() - .ok_or_else(|| { - eco_format!( - "cannot reference {} without numbering", - elem.func().name() - ) - }) - .hint(eco_format!( - "you can enable {} numbering with `#set {}(numbering: \"1.\")`", - elem.func().name(), - if elem.func() == EquationElem::elem() { - "math.equation" - } else { - elem.func().name() - } - )) - .at(span)?; - - let numbers = refable - .counter() - .at(vt, elem.location().unwrap())? - .display(vt, &numbering.trimmed())?; - - let supplement = match self.supplement(styles).as_ref() { - Smart::Auto => refable.supplement(), - Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => { - supplement.resolve(vt, [(*elem).clone()])? - } - }; - - let mut content = numbers; - if !supplement.is_empty() { - content = supplement + TextElem::packed("\u{a0}") + content; - } - - Ok(content.linked(Destination::Location(elem.location().unwrap()))) - })) - } -} - -impl RefElem { - /// Turn the reference into a citation. - pub fn to_citation(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<CiteElem> { - let mut elem = CiteElem::new(*self.target()); - elem.set_location(self.location().unwrap()); - elem.synthesize(vt, styles)?; - elem.push_supplement(match self.supplement(styles).clone() { - Smart::Custom(Some(Supplement::Content(content))) => Some(content), - _ => None, - }); - - Ok(elem) - } -} - -/// Additional content for a reference. -#[derive(Debug, Clone, PartialEq, Hash)] -pub enum Supplement { - Content(Content), - Func(Func), -} - -impl Supplement { - /// Tries to resolve the supplement into its content. - pub fn resolve<T: IntoValue>( - &self, - vt: &mut Vt, - args: impl IntoIterator<Item = T>, - ) -> SourceResult<Content> { - Ok(match self { - Supplement::Content(content) => content.clone(), - Supplement::Func(func) => func.call_vt(vt, args)?.display(), - }) - } -} - -cast! { - Supplement, - self => match self { - Self::Content(v) => v.into_value(), - Self::Func(v) => v.into_value(), - }, - v: Content => Self::Content(v), - v: Func => Self::Func(v), -} - -/// Marks an element as being able to be referenced. This is used to implement -/// the `@ref` element. -pub trait Refable { - /// The supplement, if not overridden by the reference. - fn supplement(&self) -> Content; - - /// Returns the counter of this element. - fn counter(&self) -> Counter; - - /// Returns the numbering of this element. - fn numbering(&self) -> Option<Numbering>; -} |
