From 05c8c6045cd831a98776b418a7b176af8c6ec546 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 13 Feb 2023 16:51:30 +0100 Subject: [PATCH] Configurable numbering for nested enums --- library/src/compute/utility.rs | 18 ++++++++ library/src/layout/enum.rs | 64 ++++++++++++++++++++++++++-- tests/ref/layout/enum-numbering.png | Bin 0 -> 20863 bytes tests/typ/layout/enum-numbering.typ | 55 ++++++++++++++++++++++++ 4 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 tests/ref/layout/enum-numbering.png create mode 100644 tests/typ/layout/enum-numbering.typ diff --git a/library/src/compute/utility.rs b/library/src/compute/utility.rs index cb7655776..2220c890b 100644 --- a/library/src/compute/utility.rs +++ b/library/src/compute/utility.rs @@ -176,6 +176,24 @@ impl NumberingPattern { fmt.push_str(&self.suffix); fmt } + + /// Apply only the k-th segment of the pattern to a number. + pub fn apply_kth(&self, k: usize, number: NonZeroUsize) -> EcoString { + let mut fmt = EcoString::new(); + if let Some((prefix, _, _)) = self.pieces.first() { + fmt.push_str(prefix); + } + if let Some((_, kind, case)) = self + .pieces + .iter() + .chain(self.pieces.last().into_iter().cycle()) + .nth(k) + { + fmt.push_str(&kind.apply(number, *case)); + } + fmt.push_str(&self.suffix); + fmt + } } impl FromStr for NumberingPattern { diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs index 585b20e5d..9b7ea1996 100644 --- a/library/src/layout/enum.rs +++ b/library/src/layout/enum.rs @@ -3,6 +3,7 @@ use std::str::FromStr; use crate::compute::{Numbering, NumberingPattern}; use crate::layout::{BlockNode, GridNode, ParNode, Sizing, Spacing}; use crate::prelude::*; +use crate::text::TextNode; /// # Numbered List /// A numbered list. @@ -105,10 +106,16 @@ impl EnumNode { /// How to number the enumeration. Accepts a /// [numbering pattern or function]($func/numbering). /// + /// If the numbering pattern contains multiple counting symbols, they apply + /// to nested enums. If given a function, the function receives one argument + /// if `full` is `{false}` and multiple arguments if `full` is `{true}`. + /// /// ```example - /// #set enum(numbering: "(a)") + /// #set enum(numbering: "1.a)") /// + Different /// + Numbering + /// + Nested + /// + Items /// + Style /// /// #set enum(numbering: n => super[#n]) @@ -119,6 +126,20 @@ impl EnumNode { pub const NUMBERING: Numbering = Numbering::Pattern(NumberingPattern::from_str("1.").unwrap()); + /// Whether to display the full numbering, including the numbers of + /// all parent enumerations. + /// + /// Defaults to `{false}`. + /// + /// ```example + /// #set enum(numbering: "1.a)", full: true) + /// + Cook + /// + Heat water + /// + Add integredients + /// + Eat + /// ``` + pub const FULL: bool = false; + /// The indentation of each item's label. #[property(resolve)] pub const INDENT: Length = Length::zero(); @@ -132,6 +153,10 @@ impl EnumNode { /// If set to `{auto}` uses the spacing [below blocks]($func/block.below). pub const SPACING: Smart = Smart::Auto; + /// The numbers of parent items. + #[property(skip, fold)] + const PARENTS: Parent = vec![]; + fn construct(_: &Vm, args: &mut Args) -> SourceResult { let mut number: NonZeroUsize = args.named("start")?.unwrap_or(NonZeroUsize::new(1).unwrap()); @@ -193,13 +218,34 @@ impl Layout for EnumNode { let mut cells = vec![]; let mut number = NonZeroUsize::new(1).unwrap(); + let mut parents = styles.get(Self::PARENTS); + let full = styles.get(Self::FULL); + for ((n, item), map) in self.items.iter() { number = n.unwrap_or(number); - let resolved = numbering.apply(vt.world(), &[number])?.display(); + + let resolved = if full { + parents.push(number); + let content = numbering.apply(vt.world(), &parents)?.display(); + parents.pop(); + content + } else { + match numbering { + Numbering::Pattern(pattern) => { + TextNode::packed(pattern.apply_kth(parents.len(), number)) + } + other => other.apply(vt.world(), &[number])?.display(), + } + }; + cells.push(Content::empty()); cells.push(resolved.styled_with_map(map.clone())); cells.push(Content::empty()); - cells.push(item.clone().styled_with_map(map.clone())); + cells.push( + item.clone() + .styled_with_map(map.clone()) + .styled(Self::PARENTS, Parent(number)), + ); number = number.saturating_add(1); } @@ -216,3 +262,15 @@ impl Layout for EnumNode { .layout(vt, styles, regions) } } + +#[derive(Debug, Clone, Hash)] +struct Parent(NonZeroUsize); + +impl Fold for Parent { + type Output = Vec; + + fn fold(self, mut outer: Self::Output) -> Self::Output { + outer.push(self.0); + outer + } +} diff --git a/tests/ref/layout/enum-numbering.png b/tests/ref/layout/enum-numbering.png new file mode 100644 index 0000000000000000000000000000000000000000..6745a2f5f56538dd23134950ae607b38984e1eb5 GIT binary patch literal 20863 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 oSmrkD*ylh literal 0 HcmV?d00001 diff --git a/tests/typ/layout/enum-numbering.typ b/tests/typ/layout/enum-numbering.typ new file mode 100644 index 000000000..1d905f69a --- /dev/null +++ b/tests/typ/layout/enum-numbering.typ @@ -0,0 +1,55 @@ +// Test enum numbering styles. + +--- +// Test numbering pattern. +#set enum(numbering: "(1.a.*)") ++ First ++ Second + 2. Nested + + Deep ++ Normal + +--- +// Test full numbering. +#set enum(numbering: "1.a.", full: true) ++ First + + Nested + +--- +// Test numbering with closure. +#enum( + start: 3, + spacing: 0.65em - 3pt, + tight: false, + numbering: n => text( + fill: (red, green, blue).at(calc.mod(n, 3)), + numbering("A", n), + ), + [Red], [Green], [Blue], [Red], +) + +--- +// Test numbering with closure and nested lists. +#set enum(numbering: n => super[#n]) ++ A + + B ++ C + +--- +// Test numbering with closure and nested lists. +#set text("Latin Modern Roman") +#set enum(numbering: (..args) => math.mat(args.pos()), full: true) ++ A + + B + + C + + D ++ E ++ F + +--- +// Error: 22-24 invalid numbering pattern +#set enum(numbering: "") + +--- +// Error: 22-28 invalid numbering pattern +#set enum(numbering: "(())")