diff --git a/crates/typst-layout/src/lists.rs b/crates/typst-layout/src/lists.rs index 08c2a2f45..0d51a1e4e 100644 --- a/crates/typst-layout/src/lists.rs +++ b/crates/typst-layout/src/lists.rs @@ -74,6 +74,7 @@ pub fn layout_enum( regions: Regions, ) -> SourceResult { let numbering = elem.numbering(styles); + let reversed = elem.reversed(styles); let indent = elem.indent(styles); let body_indent = elem.body_indent(styles); let gutter = elem.spacing(styles).unwrap_or_else(|| { @@ -86,7 +87,9 @@ pub fn layout_enum( let mut cells = vec![]; let mut locator = locator.split(); - let mut number = elem.start(styles); + let mut number = + elem.start(styles) + .unwrap_or_else(|| if reversed { elem.children.len() } else { 1 }); let mut parents = EnumElem::parents_in(styles); let full = elem.full(styles); @@ -127,7 +130,8 @@ pub fn layout_enum( item.body.clone().styled(EnumElem::set_parents(smallvec![number])), locator.next(&item.body.span()), )); - number = number.saturating_add(1); + number = + if reversed { number.saturating_sub(1) } else { number.saturating_add(1) }; } let grid = CellGrid::new( diff --git a/crates/typst-library/src/model/enum.rs b/crates/typst-library/src/model/enum.rs index e0121ba24..eb3c2ea45 100644 --- a/crates/typst-library/src/model/enum.rs +++ b/crates/typst-library/src/model/enum.rs @@ -9,7 +9,7 @@ use crate::foundations::{ cast, elem, scope, Array, Content, NativeElement, Packed, Show, Smart, StyleChain, Styles, TargetElem, }; -use crate::html::{attr, tag, HtmlElem}; +use crate::html::{attr, tag, HtmlAttr, HtmlElem}; use crate::layout::{Alignment, BlockElem, Em, HAlignment, Length, VAlignment, VElem}; use crate::model::{ListItemLike, ListLike, Numbering, NumberingPattern, ParElem}; @@ -127,8 +127,7 @@ pub struct EnumElem { /// [Ahead], /// ) /// ``` - #[default(1)] - pub start: usize, + pub start: Smart, /// Whether to display the full numbering, including the numbers of /// all parent enumerations. @@ -144,6 +143,17 @@ pub struct EnumElem { #[default(false)] pub full: bool, + /// Whether to reverse the numbering for this enumeration. + /// + /// ```example + /// #set enum(reversed: true) + /// + Coffee + /// + Tea + /// + Milk + /// ``` + #[default(false)] + pub reversed: bool, + /// The indentation of each item. #[resolve] pub indent: Length, @@ -217,7 +227,12 @@ impl EnumElem { impl Show for Packed { fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult { if TargetElem::target_in(styles).is_html() { - return Ok(HtmlElem::new(tag::ol) + let mut elem = HtmlElem::new(tag::ol); + if self.reversed(styles) { + elem = + elem.with_attr(const { HtmlAttr::constant("reversed") }, "reversed"); + } + return Ok(elem .with_body(Some(Content::sequence(self.children.iter().map(|item| { let mut li = HtmlElem::new(tag::li); if let Some(nr) = item.number(styles) { diff --git a/tests/ref/enum-numbering-reversed-overriden.png b/tests/ref/enum-numbering-reversed-overriden.png new file mode 100644 index 000000000..827f38d1d Binary files /dev/null and b/tests/ref/enum-numbering-reversed-overriden.png differ diff --git a/tests/ref/enum-numbering-reversed.png b/tests/ref/enum-numbering-reversed.png new file mode 100644 index 000000000..12d77df45 Binary files /dev/null and b/tests/ref/enum-numbering-reversed.png differ diff --git a/tests/suite/model/enum.typ b/tests/suite/model/enum.typ index c5e562159..258c6f6bc 100644 --- a/tests/suite/model/enum.typ +++ b/tests/suite/model/enum.typ @@ -71,6 +71,23 @@ a + 0. + First + Nested +--- enum-numbering-reversed --- +// Test reverse numbering. +#set enum(reversed: true) ++ Coffee ++ Tea ++ Milk + +--- enum-numbering-reversed-overriden --- +// Test reverse numbering with overriden numbers. +#set enum(reversed: true) ++ A ++ B ++ C +9. D ++ E ++ F + --- enum-numbering-closure --- // Test numbering with closure. #enum(