Fix heading supplement

Fixes #730
This commit is contained in:
Laurenz 2023-04-11 16:59:38 +02:00
parent 9720424884
commit 2606034ac7
5 changed files with 69 additions and 70 deletions

View File

@ -298,13 +298,12 @@ impl Refable for EquationElem {
fn reference( fn reference(
&self, &self,
vt: &mut Vt, vt: &mut Vt,
styles: StyleChain,
supplement: Option<Content>, supplement: Option<Content>,
lang: Lang,
) -> SourceResult<Content> { ) -> SourceResult<Content> {
// first we create the supplement of the heading // first we create the supplement of the heading
let mut supplement = supplement.unwrap_or_else(|| { let mut supplement =
TextElem::packed(self.local_name(TextElem::lang_in(styles))) supplement.unwrap_or_else(|| TextElem::packed(self.local_name(lang)));
});
// we append a space if the supplement is not empty // we append a space if the supplement is not empty
if !supplement.is_empty() { if !supplement.is_empty() {
@ -312,7 +311,7 @@ impl Refable for EquationElem {
}; };
// we check for a numbering // we check for a numbering
let Some(numbering) = self.numbering(styles) else { let Some(numbering) = self.numbering(StyleChain::default()) else {
bail!(self.span(), "only numbered equations can be referenced"); bail!(self.span(), "only numbered equations can be referenced");
}; };
@ -324,11 +323,11 @@ impl Refable for EquationElem {
Ok(supplement + numbers) Ok(supplement + numbers)
} }
fn numbering(&self, styles: StyleChain) -> Option<Numbering> { fn numbering(&self) -> Option<Numbering> {
self.numbering(styles) self.numbering(StyleChain::default())
} }
fn counter(&self, _: StyleChain) -> Counter { fn counter(&self) -> Counter {
Counter::of(Self::func()) Counter::of(Self::func())
} }
} }

View File

@ -223,12 +223,14 @@ impl Synthesize for FigureElem {
}), }),
))); )));
self.push_caption(self.caption(styles));
self.push_kind(Smart::Custom(kind)); self.push_kind(Smart::Custom(kind));
self.push_numbering(numbering);
self.push_counter(Some(counter));
self.push_supplement(Smart::Custom(Supplement::Content( self.push_supplement(Smart::Custom(Supplement::Content(
supplement.unwrap_or_default(), supplement.unwrap_or_default(),
))); )));
self.push_numbering(numbering);
self.push_outlined(self.outlined(styles));
self.push_counter(Some(counter));
Ok(()) Ok(())
} }
@ -242,7 +244,7 @@ impl Show for FigureElem {
// We build the caption, if any. // We build the caption, if any.
if self.caption(styles).is_some() { if self.caption(styles).is_some() {
realized += VElem::weak(self.gap(styles).into()).pack(); realized += VElem::weak(self.gap(styles).into()).pack();
realized += self.show_caption(vt, styles)?; realized += self.show_caption(vt)?;
} }
// We wrap the contents in a block. // We wrap the contents in a block.
@ -268,32 +270,32 @@ impl Refable for FigureElem {
fn reference( fn reference(
&self, &self,
vt: &mut Vt, vt: &mut Vt,
styles: StyleChain,
supplement: Option<Content>, supplement: Option<Content>,
_: Lang,
) -> SourceResult<Content> { ) -> SourceResult<Content> {
// If the figure is not numbered, we cannot reference it. // If the figure is not numbered, we cannot reference it.
// Otherwise we build the supplement and numbering scheme. // Otherwise we build the supplement and numbering scheme.
let Some(desc) = self.show_supplement_and_numbering(vt, styles, supplement)? else { let Some(desc) = self.show_supplement_and_numbering(vt, supplement)? else {
bail!(self.span(), "cannot reference unnumbered figure") bail!(self.span(), "cannot reference unnumbered figure")
}; };
Ok(desc) Ok(desc)
} }
fn outline(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Option<Content>> { fn outline(&self, vt: &mut Vt, _: Lang) -> SourceResult<Option<Content>> {
// If the figure is not outlined, it is not referenced. // If the figure is not outlined, it is not referenced.
if !self.outlined(styles) { if !self.outlined(StyleChain::default()) {
return Ok(None); return Ok(None);
} }
self.show_caption(vt, styles).map(Some) self.show_caption(vt).map(Some)
} }
fn numbering(&self, styles: StyleChain) -> Option<Numbering> { fn numbering(&self) -> Option<Numbering> {
self.numbering(styles) self.numbering(StyleChain::default())
} }
fn counter(&self, _: StyleChain) -> Counter { fn counter(&self) -> Counter {
self.counter().unwrap_or_else(|| Counter::of(Self::func())) self.counter().unwrap_or_else(|| Counter::of(Self::func()))
} }
} }
@ -327,12 +329,13 @@ impl FigureElem {
pub fn show_supplement_and_numbering( pub fn show_supplement_and_numbering(
&self, &self,
vt: &mut Vt, vt: &mut Vt,
styles: StyleChain,
external_supplement: Option<Content>, external_supplement: Option<Content>,
) -> SourceResult<Option<Content>> { ) -> SourceResult<Option<Content>> {
if let (Some(numbering), Some(supplement), Some(counter)) = ( if let (Some(numbering), Some(supplement), Some(counter)) = (
self.numbering(styles), self.numbering(StyleChain::default()),
self.supplement(styles).as_custom().and_then(|s| s.as_content()), self.supplement(StyleChain::default())
.as_custom()
.and_then(|s| s.as_content()),
self.counter(), self.counter(),
) { ) {
let mut name = external_supplement.unwrap_or(supplement); let mut name = external_supplement.unwrap_or(supplement);
@ -356,12 +359,12 @@ impl FigureElem {
/// ///
/// # Errors /// # Errors
/// If a numbering is specified but the [`Self::element`] is `None`. /// If a numbering is specified but the [`Self::element`] is `None`.
pub fn show_caption(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> { pub fn show_caption(&self, vt: &mut Vt) -> SourceResult<Content> {
let Some(mut caption) = self.caption(styles) else { let Some(mut caption) = self.caption(StyleChain::default()) else {
return Ok(Content::empty()); return Ok(Content::empty());
}; };
if let Some(sup_and_num) = self.show_supplement_and_numbering(vt, styles, None)? { if let Some(sup_and_num) = self.show_supplement_and_numbering(vt, None)? {
caption = sup_and_num + TextElem::packed(": ") + caption; caption = sup_and_num + TextElem::packed(": ") + caption;
} }

View File

@ -59,21 +59,6 @@ pub struct HeadingElem {
/// ``` /// ```
pub numbering: Option<Numbering>, pub numbering: Option<Numbering>,
/// Whether the heading should appear in the outline.
///
/// ```example
/// #outline()
///
/// #heading[Normal]
/// This is a normal heading.
///
/// #heading(outlined: false)[Hidden]
/// This heading does not appear
/// in the outline.
/// ```
#[default(true)]
pub outlined: bool,
/// A supplement for the heading. /// A supplement for the heading.
/// ///
/// For references to headings, this is added before the /// For references to headings, this is added before the
@ -91,6 +76,21 @@ pub struct HeadingElem {
#[default(Smart::Auto)] #[default(Smart::Auto)]
pub supplement: Smart<Option<Supplement>>, pub supplement: Smart<Option<Supplement>>,
/// Whether the heading should appear in the outline.
///
/// ```example
/// #outline()
///
/// #heading[Normal]
/// This is a normal heading.
///
/// #heading(outlined: false)[Hidden]
/// This heading does not appear
/// in the outline.
/// ```
#[default(true)]
pub outlined: bool,
/// The heading's title. /// The heading's title.
#[required] #[required]
pub body: Content, pub body: Content,
@ -100,6 +100,7 @@ impl Synthesize for HeadingElem {
fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> { fn synthesize(&mut self, _vt: &mut Vt, styles: StyleChain) -> SourceResult<()> {
self.push_level(self.level(styles)); self.push_level(self.level(styles));
self.push_numbering(self.numbering(styles)); self.push_numbering(self.numbering(styles));
self.push_supplement(self.supplement(styles));
self.push_outlined(self.outlined(styles)); self.push_outlined(self.outlined(styles));
Ok(()) Ok(())
} }
@ -159,17 +160,15 @@ impl Refable for HeadingElem {
fn reference( fn reference(
&self, &self,
vt: &mut Vt, vt: &mut Vt,
styles: StyleChain,
supplement: Option<Content>, supplement: Option<Content>,
lang: Lang,
) -> SourceResult<Content> { ) -> SourceResult<Content> {
// Create the supplement of the heading. // Create the supplement of the heading.
let mut supplement = if let Some(supplement) = supplement { let mut supplement = if let Some(supplement) = supplement {
supplement supplement
} else { } else {
match self.supplement(styles) { match self.supplement(StyleChain::default()) {
Smart::Auto => { Smart::Auto => TextElem::packed(self.local_name(lang)),
TextElem::packed(self.local_name(TextElem::lang_in(styles)))
}
Smart::Custom(None) => Content::empty(), Smart::Custom(None) => Content::empty(),
Smart::Custom(Some(supplement)) => { Smart::Custom(Some(supplement)) => {
supplement.resolve(vt, std::iter::once(Value::from(self.clone())))? supplement.resolve(vt, std::iter::once(Value::from(self.clone())))?
@ -183,7 +182,7 @@ impl Refable for HeadingElem {
}; };
// Check for a numbering. // Check for a numbering.
let Some(numbering) = self.numbering(styles) else { let Some(numbering) = self.numbering(StyleChain::default()) else {
bail!(self.span(), "only numbered headings can be referenced"); bail!(self.span(), "only numbered headings can be referenced");
}; };
@ -195,21 +194,21 @@ impl Refable for HeadingElem {
Ok(supplement + numbers) Ok(supplement + numbers)
} }
fn level(&self, styles: StyleChain) -> usize { fn level(&self) -> usize {
self.level(styles).get() self.level(StyleChain::default()).get()
} }
fn numbering(&self, styles: StyleChain) -> Option<Numbering> { fn numbering(&self) -> Option<Numbering> {
self.numbering(styles) self.numbering(StyleChain::default())
} }
fn counter(&self, _: StyleChain) -> Counter { fn counter(&self) -> Counter {
Counter::of(Self::func()) Counter::of(Self::func())
} }
fn outline(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Option<Content>> { fn outline(&self, vt: &mut Vt, _: Lang) -> SourceResult<Option<Content>> {
// Check whether the heading is outlined. // Check whether the heading is outlined.
if !self.outlined(styles) { if !self.outlined(StyleChain::default()) {
return Ok(None); return Ok(None);
} }

View File

@ -151,6 +151,7 @@ impl Show for OutlineElem {
let indent = self.indent(styles); let indent = self.indent(styles);
let depth = self.depth(styles).map_or(usize::MAX, NonZeroUsize::get); let depth = self.depth(styles).map_or(usize::MAX, NonZeroUsize::get);
let lang = TextElem::lang_in(styles);
let mut ancestors: Vec<&Content> = vec![]; let mut ancestors: Vec<&Content> = vec![];
let elems = vt.introspector.query(self.target(styles)); let elems = vt.introspector.query(self.target(styles));
@ -161,11 +162,11 @@ impl Show for OutlineElem {
}; };
let location = elem.location().expect("missing location"); let location = elem.location().expect("missing location");
if depth < refable.level(StyleChain::default()) { if depth < refable.level() {
continue; continue;
} }
let Some(outline) = refable.outline(vt, StyleChain::default())? else { let Some(outline) = refable.outline(vt, lang)? else {
continue; continue;
}; };
@ -174,10 +175,7 @@ impl Show for OutlineElem {
while ancestors while ancestors
.last() .last()
.and_then(|ancestor| ancestor.with::<dyn Refable>()) .and_then(|ancestor| ancestor.with::<dyn Refable>())
.map_or(false, |last| { .map_or(false, |last| last.level() >= refable.level())
last.level(StyleChain::default())
>= refable.level(StyleChain::default())
})
{ {
ancestors.pop(); ancestors.pop();
} }
@ -188,11 +186,9 @@ impl Show for OutlineElem {
for ancestor in &ancestors { for ancestor in &ancestors {
let ancestor_refable = ancestor.with::<dyn Refable>().unwrap(); let ancestor_refable = ancestor.with::<dyn Refable>().unwrap();
if let Some(numbering) = if let Some(numbering) = ancestor_refable.numbering() {
ancestor_refable.numbering(StyleChain::default())
{
let numbers = ancestor_refable let numbers = ancestor_refable
.counter(StyleChain::default()) .counter()
.at(vt, ancestor.location().unwrap())? .at(vt, ancestor.location().unwrap())?
.display(vt, &numbering)?; .display(vt, &numbering)?;

View File

@ -1,5 +1,6 @@
use super::{BibliographyElem, CiteElem, Counter, Figurable, Numbering}; use super::{BibliographyElem, CiteElem, Counter, Figurable, Numbering};
use crate::prelude::*; use crate::prelude::*;
use crate::text::TextElem;
/// A reference to a label or bibliography. /// A reference to a label or bibliography.
/// ///
@ -131,10 +132,11 @@ impl Show for RefElem {
} }
}; };
let lang = TextElem::lang_in(styles);
let reference = elem let reference = elem
.with::<dyn Refable>() .with::<dyn Refable>()
.expect("element should be refable") .expect("element should be refable")
.reference(vt, styles, supplement)?; .reference(vt, supplement, lang)?;
Ok(reference.linked(Destination::Location(elem.location().unwrap()))) Ok(reference.linked(Destination::Location(elem.location().unwrap())))
} }
@ -212,27 +214,27 @@ pub trait Refable {
fn reference( fn reference(
&self, &self,
vt: &mut Vt, vt: &mut Vt,
styles: StyleChain,
supplement: Option<Content>, supplement: Option<Content>,
lang: Lang,
) -> SourceResult<Content>; ) -> SourceResult<Content>;
/// Tries to build an outline element for this element. /// Tries to build an outline element for this element.
/// If this returns `None`, the outline will not include this element. /// If this returns `None`, the outline will not include this element.
/// By default this just calls [`Refable::reference`]. /// By default this just calls [`Refable::reference`].
fn outline(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Option<Content>> { fn outline(&self, vt: &mut Vt, lang: Lang) -> SourceResult<Option<Content>> {
self.reference(vt, styles, None).map(Some) self.reference(vt, None, lang).map(Some)
} }
/// Returns the level of this element. /// Returns the level of this element.
/// This is used to determine the level of the outline. /// This is used to determine the level of the outline.
/// By default this returns `0`. /// By default this returns `0`.
fn level(&self, _styles: StyleChain) -> usize { fn level(&self) -> usize {
0 0
} }
/// Returns the numbering of this element. /// Returns the numbering of this element.
fn numbering(&self, styles: StyleChain) -> Option<Numbering>; fn numbering(&self) -> Option<Numbering>;
/// Returns the counter of this element. /// Returns the counter of this element.
fn counter(&self, styles: StyleChain) -> Counter; fn counter(&self) -> Counter;
} }