summaryrefslogtreecommitdiff
path: root/library/src/basics
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2022-12-30 19:40:29 +0100
committerLaurenz <laurmaedje@gmail.com>2022-12-30 20:00:50 +0100
commita6d90c1bf1e9fefa0af04206909a40e112d6bb14 (patch)
treefc16276142f74b9a50102a2e855942f7e2593c25 /library/src/basics
parentf70cea508cd30fa40770ea989fe2a19e715a357b (diff)
Numbering functions
Diffstat (limited to 'library/src/basics')
-rw-r--r--library/src/basics/enum.rs51
-rw-r--r--library/src/basics/heading.rs32
-rw-r--r--library/src/basics/table.rs23
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),
}
}