diff options
| author | Laurenz <laurmaedje@gmail.com> | 2022-12-30 19:40:29 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2022-12-30 20:00:50 +0100 |
| commit | a6d90c1bf1e9fefa0af04206909a40e112d6bb14 (patch) | |
| tree | fc16276142f74b9a50102a2e855942f7e2593c25 /library/src/basics | |
| parent | f70cea508cd30fa40770ea989fe2a19e715a357b (diff) | |
Numbering functions
Diffstat (limited to 'library/src/basics')
| -rw-r--r-- | library/src/basics/enum.rs | 51 | ||||
| -rw-r--r-- | library/src/basics/heading.rs | 32 | ||||
| -rw-r--r-- | library/src/basics/table.rs | 23 |
3 files changed, 37 insertions, 69 deletions
diff --git a/library/src/basics/enum.rs b/library/src/basics/enum.rs index f1784a7e..c5d4d8ae 100644 --- a/library/src/basics/enum.rs +++ b/library/src/basics/enum.rs @@ -1,9 +1,8 @@ use std::str::FromStr; -use crate::compute::NumberingPattern; +use crate::compute::{Numbering, NumberingPattern}; use crate::layout::{BlockNode, GridNode, ParNode, Spacing, TrackSizing}; use crate::prelude::*; -use crate::text::TextNode; /// # Numbered List /// A numbered list. @@ -98,7 +97,7 @@ pub struct EnumNode { #[node] impl EnumNode { /// How to number the enumeration. Accepts a - /// [numbering pattern](@numbering). + /// [numbering pattern or function](@numbering). /// /// # Example /// ``` @@ -109,8 +108,8 @@ impl EnumNode { /// + Style /// ``` #[property(referenced)] - pub const NUMBERING: EnumNumbering = - EnumNumbering::Pattern(NumberingPattern::from_str("1.").unwrap()); + pub const NUMBERING: Numbering = + Numbering::Pattern(NumberingPattern::from_str("1.").unwrap()); /// The indentation of each item's label. #[property(resolve)] @@ -188,7 +187,7 @@ impl Layout for EnumNode { let mut number = NonZeroUsize::new(1).unwrap(); for ((n, item), map) in self.items.iter() { number = n.unwrap_or(number); - let resolved = numbering.resolve(vt, number)?; + let resolved = numbering.apply(vt.world(), &[number])?.display(); cells.push(Content::empty()); cells.push(resolved.styled_with_map(map.clone())); cells.push(Content::empty()); @@ -209,43 +208,3 @@ impl Layout for EnumNode { .layout(vt, styles, regions) } } - -/// How to number an enumeration. -#[derive(Debug, Clone, Hash)] -pub enum EnumNumbering { - /// A pattern with prefix, numbering, lower / upper case and suffix. - Pattern(NumberingPattern), - /// A closure mapping from an item's number to content. - Func(Func, Span), -} - -impl EnumNumbering { - /// Resolve the marker based on the number. - pub fn resolve(&self, vt: &Vt, number: NonZeroUsize) -> SourceResult<Content> { - Ok(match self { - Self::Pattern(pattern) => TextNode::packed(pattern.apply(&[number])), - Self::Func(func, span) => { - let args = Args::new(*span, [Value::Int(number.get() as i64)]); - func.call_detached(vt.world(), args)?.display() - } - }) - } -} - -impl Cast<Spanned<Value>> for EnumNumbering { - fn is(value: &Spanned<Value>) -> bool { - matches!(&value.v, Value::Content(_) | Value::Func(_)) - } - - fn cast(value: Spanned<Value>) -> StrResult<Self> { - match value.v { - Value::Str(v) => Ok(Self::Pattern(v.parse()?)), - Value::Func(v) => Ok(Self::Func(v, value.span)), - v => Self::error(v), - } - } - - fn describe() -> CastInfo { - CastInfo::Union(vec![CastInfo::Type("string"), CastInfo::Type("function")]) - } -} diff --git a/library/src/basics/heading.rs b/library/src/basics/heading.rs index 925d23a2..c2696dd6 100644 --- a/library/src/basics/heading.rs +++ b/library/src/basics/heading.rs @@ -1,6 +1,6 @@ use typst::font::FontWeight; -use crate::compute::NumberingPattern; +use crate::compute::Numbering; use crate::layout::{BlockNode, VNode}; use crate::prelude::*; use crate::text::{SpaceNode, TextNode, TextSize}; @@ -15,8 +15,8 @@ use crate::text::{SpaceNode, TextNode, TextSize}; /// (not the document's title). /// /// Typst can automatically number your headings for you. To enable numbering, -/// specify how you want your headings to be numbered with a [numbering -/// pattern](@numbering). +/// specify how you want your headings to be numbered with a +/// [numbering pattern or function](@numbering). /// /// Independently from the numbering, Typst can also automatically generate an /// [outline](@outline) of all headings for you. To exclude one or more headings @@ -60,7 +60,8 @@ pub struct HeadingNode { #[node] impl HeadingNode { - /// How to number the heading. Accepts a [numbering pattern](@numbering). + /// How to number the heading. Accepts a + /// [numbering pattern or function](@numbering). /// /// # Example /// ``` @@ -71,7 +72,7 @@ impl HeadingNode { /// === A sub-subsection /// ``` #[property(referenced)] - pub const NUMBERING: Option<NumberingPattern> = None; + pub const NUMBERING: Option<Numbering> = None; /// Whether the heading should appear in the outline. /// @@ -106,7 +107,12 @@ impl HeadingNode { } impl Prepare for HeadingNode { - fn prepare(&self, vt: &mut Vt, mut this: Content, styles: StyleChain) -> Content { + fn prepare( + &self, + vt: &mut Vt, + mut this: Content, + styles: StyleChain, + ) -> SourceResult<Content> { let my_id = vt.identify(&this); let mut counter = HeadingCounter::new(); @@ -115,30 +121,32 @@ impl Prepare for HeadingNode { break; } - if matches!(node.field("numbers"), Some(Value::Str(_))) { + let numbers = node.field("numbers").unwrap(); + if numbers != Value::None { let heading = node.to::<Self>().unwrap(); counter.advance(heading); } } let mut numbers = Value::None; - if let Some(pattern) = styles.get(Self::NUMBERING) { - numbers = Value::Str(pattern.apply(counter.advance(self)).into()); + if let Some(numbering) = styles.get(Self::NUMBERING) { + numbers = numbering.apply(vt.world(), counter.advance(self))?; } this.push_field("outlined", Value::Bool(styles.get(Self::OUTLINED))); this.push_field("numbers", numbers); let meta = Meta::Node(my_id, this.clone()); - this.styled(Meta::DATA, vec![meta]) + Ok(this.styled(Meta::DATA, vec![meta])) } } impl Show for HeadingNode { fn show(&self, _: &mut Vt, this: &Content, _: StyleChain) -> SourceResult<Content> { let mut realized = self.title.clone(); - if let Some(Value::Str(numbering)) = this.field("numbers") { - realized = TextNode::packed(numbering) + SpaceNode.pack() + realized; + let numbers = this.field("numbers").unwrap(); + if numbers != Value::None { + realized = numbers.display() + SpaceNode.pack() + realized; } Ok(BlockNode(realized).pack()) } diff --git a/library/src/basics/table.rs b/library/src/basics/table.rs index 01b16898..20881830 100644 --- a/library/src/basics/table.rs +++ b/library/src/basics/table.rs @@ -199,7 +199,7 @@ pub enum Celled<T> { /// A bare value, the same for all cells. Value(T), /// A closure mapping from cell coordinates to a value. - Func(Func, Span), + Func(Func), } impl<T: Cast + Clone> Celled<T> { @@ -207,24 +207,25 @@ impl<T: Cast + Clone> Celled<T> { pub fn resolve(&self, vt: &Vt, x: usize, y: usize) -> SourceResult<T> { Ok(match self { Self::Value(value) => value.clone(), - Self::Func(func, span) => { - let args = Args::new(*span, [Value::Int(x as i64), Value::Int(y as i64)]); - func.call_detached(vt.world(), args)?.cast().at(*span)? + Self::Func(func) => { + let args = + Args::new(func.span(), [Value::Int(x as i64), Value::Int(y as i64)]); + func.call_detached(vt.world(), args)?.cast().at(func.span())? } }) } } -impl<T: Cast> Cast<Spanned<Value>> for Celled<T> { - fn is(value: &Spanned<Value>) -> bool { - matches!(&value.v, Value::Func(_)) || T::is(&value.v) +impl<T: Cast> Cast for Celled<T> { + fn is(value: &Value) -> bool { + matches!(value, Value::Func(_)) || T::is(value) } - fn cast(value: Spanned<Value>) -> StrResult<Self> { - match value.v { - Value::Func(v) => Ok(Self::Func(v, value.span)), + fn cast(value: Value) -> StrResult<Self> { + match value { + Value::Func(v) => Ok(Self::Func(v)), v if T::is(&v) => Ok(Self::Value(T::cast(v)?)), - v => Self::error(v), + v => <Self as Cast>::error(v), } } |
