diff options
| author | Laurenz <laurmaedje@gmail.com> | 2023-05-22 20:50:15 +0200 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2023-05-22 20:56:30 +0200 |
| commit | f4fd6855e7fb833a2125d2e81aa3b9f548b18170 (patch) | |
| tree | 6e3675ca8c4b9f9fae05a598e753e3a410d2cce2 /library/src/meta | |
| parent | 183997d5fe76cf0b41fd26bfa29d166071d239eb (diff) | |
Fix and simplify reference supplements
- Fixes #873 by properly handling `none` supplement for`ref`.
- Fixes #523 by adding a `supplement` parameter to `math.equation`
- In the future, we can remove supplement functions in favor of show-set rules with fine-grained selectors. Currently, this is not possible because show-set + synthesis doesn't play well together
Diffstat (limited to 'library/src/meta')
| -rw-r--r-- | library/src/meta/figure.rs | 215 | ||||
| -rw-r--r-- | library/src/meta/heading.rs | 101 | ||||
| -rw-r--r-- | library/src/meta/mod.rs | 6 | ||||
| -rw-r--r-- | library/src/meta/outline.rs | 43 | ||||
| -rw-r--r-- | library/src/meta/reference.rs | 122 |
5 files changed, 208 insertions, 279 deletions
diff --git a/library/src/meta/figure.rs b/library/src/meta/figure.rs index 945a812a..67087832 100644 --- a/library/src/meta/figure.rs +++ b/library/src/meta/figure.rs @@ -4,7 +4,7 @@ use super::{ Count, Counter, CounterKey, CounterUpdate, LocalName, Numbering, NumberingPattern, }; use crate::layout::{BlockElem, VElem}; -use crate::meta::{Refable, Supplement}; +use crate::meta::{Outlinable, Refable, Supplement}; use crate::prelude::*; use crate::text::TextElem; use crate::visualize::ImageElem; @@ -77,7 +77,7 @@ use crate::visualize::ImageElem; /// /// Display: Figure /// Category: meta -#[element(Locatable, Synthesize, Count, Show, Finalize, Refable)] +#[element(Locatable, Synthesize, Count, Show, Finalize, Refable, Outlinable)] pub struct FigureElem { /// The content of the figure. Often, an [image]($func/image). #[required] @@ -120,8 +120,9 @@ pub struct FigureElem { /// language]($func/text.lang). If you are using a custom figure type, you /// will need to manually specify the supplement. /// - /// This can also be set to a function that receives the figure's body to - /// select the supplement based on the figure's contents. + /// If a function is specified, it is passed the first descendant of the + /// specified `kind` (typically, the figure's body) and should return + /// content. /// /// ```example /// #figure( @@ -131,8 +132,7 @@ pub struct FigureElem { /// kind: "foo", /// ) /// ``` - #[default(Smart::Auto)] - pub supplement: Smart<Supplement>, + pub supplement: Smart<Option<Supplement>>, /// How to number the figure. Accepts a /// [numbering pattern or function]($func/numbering). @@ -163,52 +163,54 @@ pub struct FigureElem { impl Synthesize for FigureElem { fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + let numbering = self.numbering(styles); + // Determine the figure's kind. - let kind = match self.kind(styles) { - Smart::Auto => self - .find_figurable() + let kind = self.kind(styles).unwrap_or_else(|| { + self.body() + .query_first(Selector::can::<dyn Figurable>()) + .cloned() .map(|elem| FigureKind::Elem(elem.func())) - .unwrap_or_else(|| FigureKind::Elem(ImageElem::func())), - Smart::Custom(kind) => kind, - }; - - let content = match &kind { - FigureKind::Elem(func) => self.find_of_elem(*func), - FigureKind::Name(_) => None, - } - .unwrap_or_else(|| self.body()); + .unwrap_or_else(|| FigureKind::Elem(ImageElem::func())) + }); - let numbering = self.numbering(styles); - - // We get the supplement or `None`. The supplement must either be set - // manually or the content identification must have succeeded. + // Resolve the supplement. let supplement = match self.supplement(styles) { - Smart::Auto => match &kind { - FigureKind::Elem(func) => { - let elem = Content::new(*func).with::<dyn LocalName>().map(|c| { - TextElem::packed(c.local_name( - TextElem::lang_in(styles), - TextElem::region_in(styles), - )) - }); - - if numbering.is_some() { - Some(elem - .ok_or("unable to determine the figure's `supplement`, please specify it manually") - .at(self.span())?) - } else { - elem + Smart::Auto => { + // Default to the local name for the kind, if available. + let name = match &kind { + FigureKind::Elem(func) => { + let empty = Content::new(*func); + empty.with::<dyn LocalName>().map(|c| { + TextElem::packed(c.local_name( + TextElem::lang_in(styles), + TextElem::region_in(styles), + )) + }) } + FigureKind::Name(_) => None, + }; + + if numbering.is_some() && name.is_none() { + bail!(self.span(), "please specify the figure's supplement") } - FigureKind::Name(_) => { - if numbering.is_some() { - bail!(self.span(), "please specify the figure's supplement") - } else { - None + + name.unwrap_or_default() + } + Smart::Custom(None) => Content::empty(), + Smart::Custom(Some(supplement)) => { + // Resolve the supplement with the first descendant of the kind or + // just the body, if none was found. + let descendant = match kind { + FigureKind::Elem(func) => { + self.body().query_first(Selector::Elem(func, None)).cloned() } - } - }, - Smart::Custom(supp) => Some(supp.resolve(vt, [content.into()])?), + FigureKind::Name(_) => None, + }; + + let target = descendant.unwrap_or_else(|| self.body()); + supplement.resolve(vt, [target.into()])? + } }; // Construct the figure's counter. @@ -221,9 +223,7 @@ impl Synthesize for FigureElem { self.push_caption(self.caption(styles)); self.push_kind(Smart::Custom(kind)); - self.push_supplement(Smart::Custom(Supplement::Content( - supplement.unwrap_or_default(), - ))); + self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); self.push_numbering(numbering); self.push_outlined(self.outlined(styles)); self.push_counter(Some(counter)); @@ -235,16 +235,15 @@ impl Synthesize for FigureElem { impl Show for FigureElem { #[tracing::instrument(name = "FigureElem::show", skip_all)] fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { - // We build the body of the figure. let mut realized = self.body(); - // We build the caption, if any. - if self.caption(styles).is_some() { + // Build the caption, if any. + if let Some(caption) = self.full_caption(vt)? { realized += VElem::weak(self.gap(styles).into()).pack(); - realized += self.show_caption(vt)?; + realized += caption; } - // We wrap the contents in a block. + // Wrap the contents in a block. Ok(BlockElem::new() .with_body(Some(realized)) .pack() @@ -270,100 +269,60 @@ impl Count for FigureElem { } impl Refable for FigureElem { - fn reference( - &self, - vt: &mut Vt, - supplement: Option<Content>, - _: Lang, - _: Option<Region>, - ) -> SourceResult<Content> { - // If the figure is not numbered, we cannot reference it. - // Otherwise we build the supplement and numbering scheme. - let Some(desc) = self.show_supplement_and_numbering(vt, supplement)? else { - bail!(self.span(), "cannot reference unnumbered figure") - }; - - Ok(desc) - } - - fn outline( - &self, - vt: &mut Vt, - _: Lang, - _: Option<Region>, - ) -> SourceResult<Option<Content>> { - // If the figure is not outlined, it is not referenced. - if !self.outlined(StyleChain::default()) { - return Ok(None); + fn supplement(&self) -> Content { + // After synthesis, this should always be custom content. + match self.supplement(StyleChain::default()) { + Smart::Custom(Some(Supplement::Content(content))) => content, + _ => Content::empty(), } + } - self.show_caption(vt).map(Some) + fn counter(&self) -> Counter { + self.counter().unwrap_or_else(|| Counter::of(Self::func())) } fn numbering(&self) -> Option<Numbering> { self.numbering(StyleChain::default()) } +} - fn counter(&self) -> Counter { - self.counter().unwrap_or_else(|| Counter::of(Self::func())) +impl Outlinable for FigureElem { + fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + if !self.outlined(StyleChain::default()) { + return Ok(None); + } + + self.full_caption(vt) } } impl FigureElem { - /// Determines the type of the figure by looking at the content, finding all - /// [`Figurable`] elements and sorting them by priority then returning the highest. - pub fn find_figurable(&self) -> Option<Content> { - self.body().query_first(Selector::can::<dyn Figurable>()).cloned() - } - - /// Finds the element with the given function in the figure's content. - /// Returns `None` if no element with the given function is found. - pub fn find_of_elem(&self, func: ElemFunc) -> Option<Content> { - self.body().query_first(Selector::Elem(func, None)).cloned() - } + /// Builds the full caption for the figure (with supplement and numbering). + pub fn full_caption(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { + let Some(mut caption) = self.caption(StyleChain::default()) else { + return Ok(None); + }; - /// Builds the supplement and numbering of the figure. Returns [`None`] if - /// there is no numbering. - pub fn show_supplement_and_numbering( - &self, - vt: &mut Vt, - external_supplement: Option<Content>, - ) -> SourceResult<Option<Content>> { - if let (Some(numbering), Some(supplement), Some(counter)) = ( - self.numbering(StyleChain::default()), - self.supplement(StyleChain::default()) - .as_custom() - .and_then(|s| s.as_content()), + if let ( + Smart::Custom(Some(Supplement::Content(mut supplement))), + Some(counter), + Some(numbering), + ) = ( + self.supplement(StyleChain::default()), self.counter(), + self.numbering(StyleChain::default()), ) { - let mut name = external_supplement.unwrap_or(supplement); - if !name.is_empty() { - name += TextElem::packed("\u{a0}"); - } - - let number = counter - .at(vt, self.0.location().unwrap())? - .display(vt, &numbering)? - .spanned(self.span()); + let numbers = + counter.at(vt, self.0.location().unwrap())?.display(vt, &numbering)?; - Ok(Some(name + number)) - } else { - Ok(None) - } - } - - /// Builds the caption for the figure. If there is a numbering, will also - /// try to show the supplement and the numbering. - pub fn show_caption(&self, vt: &mut Vt) -> SourceResult<Content> { - let Some(mut caption) = self.caption(StyleChain::default()) else { - return Ok(Content::empty()); - }; + if !supplement.is_empty() { + supplement += TextElem::packed("\u{a0}"); + } - if let Some(sup_and_num) = self.show_supplement_and_numbering(vt, None)? { - caption = sup_and_num + TextElem::packed(": ") + caption; + caption = supplement + numbers + TextElem::packed(": ") + caption; } - Ok(caption) + Ok(Some(caption)) } } diff --git a/library/src/meta/heading.rs b/library/src/meta/heading.rs index a5fa7441..494807d5 100644 --- a/library/src/meta/heading.rs +++ b/library/src/meta/heading.rs @@ -1,7 +1,7 @@ use typst::font::FontWeight; use typst::util::option_eq; -use super::{Counter, CounterUpdate, LocalName, Numbering, Refable}; +use super::{Counter, CounterUpdate, LocalName, Numbering, Outlinable, Refable}; use crate::layout::{BlockElem, HElem, VElem}; use crate::meta::{Count, Supplement}; use crate::prelude::*; @@ -42,7 +42,7 @@ use crate::text::{SpaceElem, TextElem, TextSize}; /// /// Display: Heading /// Category: meta -#[element(Locatable, Synthesize, Count, Show, Finalize, LocalName, Refable)] +#[element(Locatable, Synthesize, Count, Show, Finalize, LocalName, Refable, Outlinable)] pub struct HeadingElem { /// The logical nesting depth of the heading, starting from one. #[default(NonZeroUsize::ONE)] @@ -62,11 +62,13 @@ pub struct HeadingElem { /// 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. + /// + /// If a function is specified, it is passed the referenced heading and + /// should return content. /// /// ```example - /// #set heading(numbering: "1.", supplement: "Chapter") + /// #set heading(numbering: "1.", supplement: [Chapter]) /// /// = Introduction <intro> /// In @intro, we see how to turn @@ -74,7 +76,6 @@ pub struct HeadingElem { /// in @intro[Part], it is done /// manually. /// ``` - #[default(Smart::Auto)] pub supplement: Smart<Option<Supplement>>, /// Whether the heading should appear in the outline. @@ -98,12 +99,21 @@ pub struct HeadingElem { } impl Synthesize for HeadingElem { - fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + fn synthesize(&mut self, vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { + // Resolve the supplement. + let supplement = match self.supplement(styles) { + Smart::Auto => TextElem::packed(self.local_name_in(styles)), + Smart::Custom(None) => Content::empty(), + Smart::Custom(Some(supplement)) => { + supplement.resolve(vt, [self.clone().into()])? + } + }; + self.push_level(self.level(styles)); self.push_numbering(self.numbering(styles)); - self.push_supplement(self.supplement(styles)); + self.push_supplement(Smart::Custom(Some(Supplement::Content(supplement)))); self.push_outlined(self.outlined(styles)); - self.push_supplement(self.supplement(styles)); + Ok(()) } } @@ -160,77 +170,42 @@ cast_from_value! { } impl Refable for HeadingElem { - fn reference( - &self, - vt: &mut Vt, - supplement: Option<Content>, - lang: Lang, - region: Option<Region>, - ) -> SourceResult<Content> { - // Create the supplement of the heading. - let mut supplement = if let Some(supplement) = supplement { - supplement - } else { - match self.supplement(StyleChain::default()) { - Smart::Auto => TextElem::packed(self.local_name(lang, region)), - Smart::Custom(None) => Content::empty(), - Smart::Custom(Some(supplement)) => { - supplement.resolve(vt, std::iter::once(Value::from(self.clone())))? - } - } - }; - - // Append a non-breaking space if the supplement is not empty. - if !supplement.is_empty() { - supplement += TextElem::packed('\u{a0}') - }; - - // Check for a numbering. - let Some(numbering) = self.numbering(StyleChain::default()) else { - bail!(self.span(), "only numbered headings can be referenced"); - }; - - // Get the counter and display it. - let numbers = Counter::of(Self::func()) - .at(vt, self.0.location().unwrap())? - .display(vt, &numbering.trimmed())?; - - Ok(supplement + numbers) + fn supplement(&self) -> Content { + // After synthesis, this should always be custom content. + match self.supplement(StyleChain::default()) { + Smart::Custom(Some(Supplement::Content(content))) => content, + _ => Content::empty(), + } } - fn level(&self) -> usize { - self.level(StyleChain::default()).get() + fn counter(&self) -> Counter { + Counter::of(Self::func()) } fn numbering(&self) -> Option<Numbering> { self.numbering(StyleChain::default()) } +} - fn counter(&self) -> Counter { - Counter::of(Self::func()) - } - - fn outline( - &self, - vt: &mut Vt, - _: Lang, - _: Option<Region>, - ) -> SourceResult<Option<Content>> { - // Check whether the heading is outlined. +impl Outlinable for HeadingElem { + fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>> { if !self.outlined(StyleChain::default()) { return Ok(None); } - // Build the numbering followed by the title. - let mut start = self.body(); + let mut content = self.body(); if let Some(numbering) = self.numbering(StyleChain::default()) { - let numbers = Counter::of(HeadingElem::func()) + let numbers = Counter::of(Self::func()) .at(vt, self.0.location().unwrap())? .display(vt, &numbering)?; - start = numbers + SpaceElem::new().pack() + start; + content = numbers + SpaceElem::new().pack() + content; }; - Ok(Some(start)) + Ok(Some(content)) + } + + fn level(&self) -> NonZeroUsize { + self.level(StyleChain::default()) } } diff --git a/library/src/meta/mod.rs b/library/src/meta/mod.rs index 0cbbafff..724e5d20 100644 --- a/library/src/meta/mod.rs +++ b/library/src/meta/mod.rs @@ -29,6 +29,7 @@ pub use self::reference::*; pub use self::state::*; use crate::prelude::*; +use crate::text::TextElem; /// Hook up all meta definitions. pub(super) fn define(global: &mut Scope) { @@ -55,4 +56,9 @@ pub(super) fn define(global: &mut Scope) { pub trait LocalName { /// Get the name in the given language and (optionally) region. fn local_name(&self, lang: Lang, region: Option<Region>) -> &'static str; + + /// Resolve the local name with a style chain. + fn local_name_in(&self, styles: StyleChain) -> &'static str { + self.local_name(TextElem::lang_in(styles), TextElem::region_in(styles)) + } } diff --git a/library/src/meta/outline.rs b/library/src/meta/outline.rs index 3114aa38..c309e742 100644 --- a/library/src/meta/outline.rs +++ b/library/src/meta/outline.rs @@ -86,8 +86,11 @@ pub struct OutlineElem { /// caption: [Experiment results], /// ) /// ``` - #[default(Selector::Elem(HeadingElem::func(), Some(dict! { "outlined" => true })))] - pub target: Selector, + #[default(LocatableSelector(Selector::Elem( + HeadingElem::func(), + Some(dict! { "outlined" => true }) + )))] + pub target: LocatableSelector, /// The maximum level up to which elements are included in the outline. When /// this argument is `{none}`, all elements are included. @@ -157,23 +160,21 @@ impl Show for OutlineElem { } let indent = self.indent(styles); - let depth = self.depth(styles).map_or(usize::MAX, NonZeroUsize::get); - let lang = TextElem::lang_in(styles); - let region = TextElem::region_in(styles); + let depth = self.depth(styles).unwrap_or(NonZeroUsize::new(usize::MAX).unwrap()); let mut ancestors: Vec<&Content> = vec![]; - let elems = vt.introspector.query(&self.target(styles)); + let elems = vt.introspector.query(&self.target(styles).0); for elem in &elems { - let Some(refable) = elem.with::<dyn Refable>() else { - bail!(elem.span(), "outlined elements must be referenceable"); + let Some(outlinable) = elem.with::<dyn Outlinable>() else { + bail!(self.span(), "cannot outline {}", elem.func().name()); }; - if depth < refable.level() { + if depth < outlinable.level() { continue; } - let Some(outline) = refable.outline(vt, lang, region)? else { + let Some(outline) = outlinable.outline(vt)? else { continue; }; @@ -183,8 +184,8 @@ impl Show for OutlineElem { // This is only applicable for elements with a hierarchy/level. while ancestors .last() - .and_then(|ancestor| ancestor.with::<dyn Refable>()) - .map_or(false, |last| last.level() >= refable.level()) + .and_then(|ancestor| ancestor.with::<dyn Outlinable>()) + .map_or(false, |last| last.level() >= outlinable.level()) { ancestors.pop(); } @@ -193,10 +194,10 @@ impl Show for OutlineElem { if indent { let mut hidden = Content::empty(); for ancestor in &ancestors { - let ancestor_refable = ancestor.with::<dyn Refable>().unwrap(); + let ancestor_outlinable = ancestor.with::<dyn Outlinable>().unwrap(); - if let Some(numbering) = ancestor_refable.numbering() { - let numbers = ancestor_refable + if let Some(numbering) = ancestor_outlinable.numbering() { + let numbers = ancestor_outlinable .counter() .at(vt, ancestor.location().unwrap())? .display(vt, &numbering)?; @@ -285,3 +286,15 @@ impl LocalName for OutlineElem { } } } + +/// Marks an element as being able to be outlined. This is used to implement the +/// `#outline()` element. +pub trait Outlinable: Refable { + /// Produce an outline item for this element. + fn outline(&self, vt: &mut Vt) -> SourceResult<Option<Content>>; + + /// Returns the nesting level of this element. + fn level(&self) -> NonZeroUsize { + NonZeroUsize::ONE + } +} diff --git a/library/src/meta/reference.rs b/library/src/meta/reference.rs index 328e6098..c538b696 100644 --- a/library/src/meta/reference.rs +++ b/library/src/meta/reference.rs @@ -95,6 +95,9 @@ pub struct RefElem { /// 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 => { @@ -149,43 +152,57 @@ impl Show for RefElem { let target = self.target(); let elem = vt.introspector.query_label(&self.target()); + let span = self.span(); if BibliographyElem::has(vt, &target.0) { if elem.is_ok() { - bail!(self.span(), "label occurs in the document and its bibliography"); + bail!(span, "label occurs in the document and its bibliography"); } - return Ok(self.to_citation(vt, styles)?.pack().spanned(self.span())); + return Ok(self.to_citation(vt, styles)?.pack().spanned(span)); } - let elem = elem.at(self.span())?; - if !elem.can::<dyn Refable>() { - if elem.can::<dyn Figurable>() { - bail!( - self.span(), - "cannot reference {} directly, try putting it into a figure", - elem.func().name() - ); - } else { - bail!(self.span(), "cannot reference {}", elem.func().name()); - } - } + let elem = elem.at(span)?; + 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()) + }) + .at(span)?; + + let numbers = refable + .counter() + .at(vt, elem.location().unwrap())? + .display(vt, &numbering.trimmed())?; let supplement = match self.supplement(styles) { - Smart::Auto | Smart::Custom(None) => None, + Smart::Auto => refable.supplement(), + Smart::Custom(None) => Content::empty(), Smart::Custom(Some(supplement)) => { - Some(supplement.resolve(vt, [(*elem).clone().into()])?) + supplement.resolve(vt, [(*elem).clone().into()])? } }; - let lang = TextElem::lang_in(styles); - let region = TextElem::region_in(styles); - let reference = elem - .with::<dyn Refable>() - .expect("element should be refable") - .reference(vt, supplement, lang, region)?; + let mut content = numbers; + if !supplement.is_empty() { + content = supplement + TextElem::packed("\u{a0}") + content; + } - Ok(reference.linked(Destination::Location(elem.location().unwrap()))) + Ok(content.linked(Destination::Location(elem.location().unwrap()))) } } @@ -217,19 +234,10 @@ impl Supplement { vt: &mut Vt, args: impl IntoIterator<Item = Value>, ) -> SourceResult<Content> { - match self { - Supplement::Content(content) => Ok(content.clone()), - Supplement::Func(func) => func.call_vt(vt, args).map(|v| v.display()), - } - } - - /// Tries to get the content of the supplement. - /// Returns `None` if the supplement is a function. - pub fn as_content(self) -> Option<Content> { - match self { - Supplement::Content(content) => Some(content), - _ => None, - } + Ok(match self { + Supplement::Content(content) => content.clone(), + Supplement::Func(func) => func.call_vt(vt, args)?.display(), + }) } } @@ -247,46 +255,14 @@ cast_to_value! { } /// Marks an element as being able to be referenced. This is used to implement -/// the `@ref` element. It is expected to build the [`Content`] that gets linked -/// by the [`RefElem`]. +/// the `@ref` element. pub trait Refable { - /// Tries to build a reference content for this element. - /// - /// # Arguments - /// - `vt` - The virtual typesetter. - /// - `supplement` - The supplement of the reference. - /// - `lang`: The language of the reference. - /// - `region`: The region of the reference. - fn reference( - &self, - vt: &mut Vt, - supplement: Option<Content>, - lang: Lang, - region: Option<Region>, - ) -> SourceResult<Content>; - - /// Tries to build an outline element for this element. - /// If this returns `None`, the outline will not include this element. - /// By default this just calls [`Refable::reference`]. - fn outline( - &self, - vt: &mut Vt, - lang: Lang, - region: Option<Region>, - ) -> SourceResult<Option<Content>> { - self.reference(vt, None, lang, region).map(Some) - } + /// The supplement, if not overriden by the reference. + fn supplement(&self) -> Content; - /// Returns the level of this element. - /// This is used to determine the level of the outline. - /// By default this returns `0`. - fn level(&self) -> usize { - 0 - } + /// Returns the counter of this element. + fn counter(&self) -> Counter; /// Returns the numbering of this element. fn numbering(&self) -> Option<Numbering>; - - /// Returns the counter of this element. - fn counter(&self) -> Counter; } |
