summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library/src/base/string.rs99
-rw-r--r--library/src/core/mod.rs7
-rw-r--r--library/src/layout/mod.rs2
-rw-r--r--library/src/lib.rs2
-rw-r--r--library/src/prelude.rs4
-rw-r--r--library/src/shared/behave.rs (renamed from library/src/core/behave.rs)0
-rw-r--r--library/src/shared/ext.rs (renamed from library/src/core/ext.rs)0
-rw-r--r--library/src/shared/mod.rs9
-rw-r--r--library/src/shared/numbering.rs139
-rw-r--r--library/src/structure/list.rs33
-rw-r--r--src/model/eval.rs4
-rw-r--r--tests/typ/structure/enum.typ4
12 files changed, 166 insertions, 137 deletions
diff --git a/library/src/base/string.rs b/library/src/base/string.rs
index 058ee248..262dd5c6 100644
--- a/library/src/base/string.rs
+++ b/library/src/base/string.rs
@@ -1,6 +1,7 @@
use typst::model::Regex;
use crate::prelude::*;
+use crate::shared::NumberingKind;
/// The string representation of a value.
pub fn repr(_: &Vm, args: &mut Args) -> SourceResult<Value> {
@@ -32,110 +33,20 @@ pub fn regex(_: &Vm, args: &mut Args) -> SourceResult<Value> {
/// Converts an integer into one or multiple letters.
pub fn letter(_: &Vm, args: &mut Args) -> SourceResult<Value> {
- numbered(Numbering::Letter, args)
+ numbered(NumberingKind::Letter, args)
}
/// Converts an integer into a roman numeral.
pub fn roman(_: &Vm, args: &mut Args) -> SourceResult<Value> {
- numbered(Numbering::Roman, args)
+ numbered(NumberingKind::Roman, args)
}
/// Convert a number into a symbol.
pub fn symbol(_: &Vm, args: &mut Args) -> SourceResult<Value> {
- numbered(Numbering::Symbol, args)
+ numbered(NumberingKind::Symbol, args)
}
-fn numbered(numbering: Numbering, args: &mut Args) -> SourceResult<Value> {
+fn numbered(numbering: NumberingKind, args: &mut Args) -> SourceResult<Value> {
let n = args.expect::<usize>("non-negative integer")?;
Ok(Value::Str(numbering.apply(n).into()))
}
-
-/// Allows to convert a number into letters, roman numerals and symbols.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum Numbering {
- Arabic,
- Letter,
- Roman,
- Symbol,
-}
-
-impl Numbering {
- /// Apply the numbering to the given number.
- pub fn apply(self, mut n: usize) -> EcoString {
- match self {
- Self::Arabic => {
- format_eco!("{}", n)
- }
- Self::Letter => {
- if n == 0 {
- return '-'.into();
- }
-
- n -= 1;
-
- let mut letters = vec![];
- loop {
- letters.push(b'a' + (n % 26) as u8);
- n /= 26;
- if n == 0 {
- break;
- }
- }
-
- letters.reverse();
- String::from_utf8(letters).unwrap().into()
- }
- Self::Roman => {
- if n == 0 {
- return 'N'.into();
- }
-
- // Adapted from Yann Villessuzanne's roman.rs under the Unlicense, at
- // https://github.com/linfir/roman.rs/
- let mut fmt = EcoString::new();
- for &(name, value) in ROMANS {
- while n >= value {
- n -= value;
- fmt.push_str(name);
- }
- }
-
- fmt
- }
- Self::Symbol => {
- if n == 0 {
- return '-'.into();
- }
-
- let symbol = SYMBOLS[(n - 1) % SYMBOLS.len()];
- let amount = ((n - 1) / SYMBOLS.len()) + 1;
- std::iter::repeat(symbol).take(amount).collect()
- }
- }
- }
-}
-
-const ROMANS: &[(&str, usize)] = &[
- ("M̅", 1000000),
- ("D̅", 500000),
- ("C̅", 100000),
- ("L̅", 50000),
- ("X̅", 10000),
- ("V̅", 5000),
- ("I̅V̅", 4000),
- ("M", 1000),
- ("CM", 900),
- ("D", 500),
- ("CD", 400),
- ("C", 100),
- ("XC", 90),
- ("L", 50),
- ("XL", 40),
- ("X", 10),
- ("IX", 9),
- ("V", 5),
- ("IV", 4),
- ("I", 1),
-];
-
-const SYMBOLS: &[char] = &['*', '†', '‡', '§', '‖', '¶'];
diff --git a/library/src/core/mod.rs b/library/src/core/mod.rs
deleted file mode 100644
index 6cafa9fc..00000000
--- a/library/src/core/mod.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-//! Central definitions for the standard library.
-
-mod behave;
-mod ext;
-
-pub use behave::*;
-pub use ext::*;
diff --git a/library/src/layout/mod.rs b/library/src/layout/mod.rs
index 44b7b6d8..100e0611 100644
--- a/library/src/layout/mod.rs
+++ b/library/src/layout/mod.rs
@@ -37,8 +37,8 @@ use typst::model::{
};
use typst::World;
-use crate::core::BehavedBuilder;
use crate::prelude::*;
+use crate::shared::BehavedBuilder;
use crate::structure::{
DescNode, DocNode, EnumNode, ListItem, ListNode, DESC, ENUM, LIST,
};
diff --git a/library/src/lib.rs b/library/src/lib.rs
index c2234446..dd527ed1 100644
--- a/library/src/lib.rs
+++ b/library/src/lib.rs
@@ -1,11 +1,11 @@
//! Typst's standard library.
pub mod base;
-pub mod core;
pub mod graphics;
pub mod layout;
pub mod math;
pub mod prelude;
+pub mod shared;
pub mod structure;
pub mod text;
diff --git a/library/src/prelude.rs b/library/src/prelude.rs
index 36ff0561..d2d82d3b 100644
--- a/library/src/prelude.rs
+++ b/library/src/prelude.rs
@@ -27,6 +27,6 @@ pub use typst::util::{format_eco, EcoString};
pub use typst::World;
#[doc(no_inline)]
-pub use crate::core::{Behave, Behaviour, ContentExt, StyleMapExt};
-#[doc(no_inline)]
pub use crate::layout::{LayoutBlock, LayoutInline, Regions};
+#[doc(no_inline)]
+pub use crate::shared::{Behave, Behaviour, ContentExt, StyleMapExt};
diff --git a/library/src/core/behave.rs b/library/src/shared/behave.rs
index ec8fade9..ec8fade9 100644
--- a/library/src/core/behave.rs
+++ b/library/src/shared/behave.rs
diff --git a/library/src/core/ext.rs b/library/src/shared/ext.rs
index f90260ad..f90260ad 100644
--- a/library/src/core/ext.rs
+++ b/library/src/shared/ext.rs
diff --git a/library/src/shared/mod.rs b/library/src/shared/mod.rs
new file mode 100644
index 00000000..55522190
--- /dev/null
+++ b/library/src/shared/mod.rs
@@ -0,0 +1,9 @@
+//! Shared definitions for the standard library.
+
+mod behave;
+mod ext;
+mod numbering;
+
+pub use behave::*;
+pub use ext::*;
+pub use numbering::*;
diff --git a/library/src/shared/numbering.rs b/library/src/shared/numbering.rs
new file mode 100644
index 00000000..739edafe
--- /dev/null
+++ b/library/src/shared/numbering.rs
@@ -0,0 +1,139 @@
+use std::str::FromStr;
+
+use typst::model::{castable, Value};
+use typst::util::{format_eco, EcoString};
+use unscanny::Scanner;
+
+/// A numbering pattern for lists or headings.
+#[derive(Debug, Clone, Eq, PartialEq, Hash)]
+pub struct NumberingPattern {
+ prefix: EcoString,
+ numbering: NumberingKind,
+ upper: bool,
+ suffix: EcoString,
+}
+
+impl NumberingPattern {
+ /// Apply the pattern to the given number.
+ pub fn apply(&self, n: usize) -> EcoString {
+ let fmt = self.numbering.apply(n);
+ let mid = if self.upper { fmt.to_uppercase() } else { fmt.to_lowercase() };
+ format_eco!("{}{}{}", self.prefix, mid, self.suffix)
+ }
+}
+
+impl FromStr for NumberingPattern {
+ type Err = &'static str;
+
+ fn from_str(pattern: &str) -> Result<Self, Self::Err> {
+ let mut s = Scanner::new(pattern);
+ let mut prefix;
+ let numbering = loop {
+ prefix = s.before();
+ match s.eat().map(|c| c.to_ascii_lowercase()) {
+ Some('1') => break NumberingKind::Arabic,
+ Some('a') => break NumberingKind::Letter,
+ Some('i') => break NumberingKind::Roman,
+ Some('*') => break NumberingKind::Symbol,
+ Some(_) => {}
+ None => Err("invalid numbering pattern")?,
+ }
+ };
+ let upper = s.scout(-1).map_or(false, char::is_uppercase);
+ let suffix = s.after().into();
+ Ok(Self { prefix: prefix.into(), numbering, upper, suffix })
+ }
+}
+
+castable! {
+ NumberingPattern,
+ Expected: "numbering pattern",
+ Value::Str(s) => s.parse()?,
+}
+
+/// Different kinds of numberings.
+#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+pub enum NumberingKind {
+ Arabic,
+ Letter,
+ Roman,
+ Symbol,
+}
+
+impl NumberingKind {
+ /// Apply the numbering to the given number.
+ pub fn apply(self, mut n: usize) -> EcoString {
+ match self {
+ Self::Arabic => {
+ format_eco!("{n}")
+ }
+ Self::Letter => {
+ if n == 0 {
+ return '-'.into();
+ }
+
+ n -= 1;
+
+ let mut letters = vec![];
+ loop {
+ letters.push(b'a' + (n % 26) as u8);
+ n /= 26;
+ if n == 0 {
+ break;
+ }
+ }
+
+ letters.reverse();
+ String::from_utf8(letters).unwrap().into()
+ }
+ Self::Roman => {
+ if n == 0 {
+ return 'N'.into();
+ }
+
+ // Adapted from Yann Villessuzanne's roman.rs under the
+ // Unlicense, at https://github.com/linfir/roman.rs/
+ let mut fmt = EcoString::new();
+ for &(name, value) in &[
+ ("M̅", 1000000),
+ ("D̅", 500000),
+ ("C̅", 100000),
+ ("L̅", 50000),
+ ("X̅", 10000),
+ ("V̅", 5000),
+ ("I̅V̅", 4000),
+ ("M", 1000),
+ ("CM", 900),
+ ("D", 500),
+ ("CD", 400),
+ ("C", 100),
+ ("XC", 90),
+ ("L", 50),
+ ("XL", 40),
+ ("X", 10),
+ ("IX", 9),
+ ("V", 5),
+ ("IV", 4),
+ ("I", 1),
+ ] {
+ while n >= value {
+ n -= value;
+ fmt.push_str(name);
+ }
+ }
+
+ fmt
+ }
+ Self::Symbol => {
+ if n == 0 {
+ return '-'.into();
+ }
+
+ const SYMBOLS: &[char] = &['*', '†', '‡', '§', '‖', '¶'];
+ let symbol = SYMBOLS[(n - 1) % SYMBOLS.len()];
+ let amount = ((n - 1) / SYMBOLS.len()) + 1;
+ std::iter::repeat(symbol).take(amount).collect()
+ }
+ }
+ }
+}
diff --git a/library/src/structure/list.rs b/library/src/structure/list.rs
index c35ffd44..d1727087 100644
--- a/library/src/structure/list.rs
+++ b/library/src/structure/list.rs
@@ -1,8 +1,6 @@
-use unscanny::Scanner;
-
-use crate::base::Numbering;
use crate::layout::{BlockNode, GridNode, HNode, Spacing, TrackSizing};
use crate::prelude::*;
+use crate::shared::NumberingPattern;
use crate::text::{ParNode, SpaceNode, TextNode};
/// An unordered (bulleted) or ordered (numbered) list.
@@ -223,7 +221,7 @@ pub enum Label {
/// The default labelling.
Default,
/// A pattern with prefix, numbering, lower / upper case and suffix.
- Pattern(EcoString, Numbering, bool, EcoString),
+ Pattern(NumberingPattern),
/// Bare content.
Content(Content),
/// A closure mapping from an item number to a value.
@@ -231,7 +229,7 @@ pub enum Label {
}
impl Label {
- /// Resolve the value based on the level.
+ /// Resolve the label based on the level.
pub fn resolve(
&self,
world: Tracked<dyn World>,
@@ -244,11 +242,7 @@ impl Label {
ENUM => TextNode::packed(format_eco!("{}.", number)),
DESC | _ => panic!("description lists don't have a label"),
},
- Self::Pattern(prefix, numbering, upper, suffix) => {
- let fmt = numbering.apply(number);
- let mid = if *upper { fmt.to_uppercase() } else { fmt.to_lowercase() };
- TextNode::packed(format_eco!("{}{}{}", prefix, mid, suffix))
- }
+ Self::Pattern(pattern) => TextNode::packed(pattern.apply(number)),
Self::Content(content) => content.clone(),
Self::Func(func, span) => {
let args = Args::new(*span, [Value::Int(number as i64)]);
@@ -266,24 +260,7 @@ impl Cast<Spanned<Value>> for Label {
fn cast(value: Spanned<Value>) -> StrResult<Self> {
match value.v {
Value::None => Ok(Self::Content(Content::empty())),
- Value::Str(pattern) => {
- let mut s = Scanner::new(&pattern);
- let mut prefix;
- let numbering = loop {
- prefix = s.before();
- match s.eat().map(|c| c.to_ascii_lowercase()) {
- Some('1') => break Numbering::Arabic,
- Some('a') => break Numbering::Letter,
- Some('i') => break Numbering::Roman,
- Some('*') => break Numbering::Symbol,
- Some(_) => {}
- None => Err("invalid pattern")?,
- }
- };
- let upper = s.scout(-1).map_or(false, char::is_uppercase);
- let suffix = s.after().into();
- Ok(Self::Pattern(prefix.into(), numbering, upper, suffix))
- }
+ Value::Str(v) => Ok(Self::Pattern(v.parse()?)),
Value::Content(v) => Ok(Self::Content(v)),
Value::Func(v) => Ok(Self::Func(v, value.span)),
v => Err(format!(
diff --git a/src/model/eval.rs b/src/model/eval.rs
index 6a93ca13..9ed6195e 100644
--- a/src/model/eval.rs
+++ b/src/model/eval.rs
@@ -59,7 +59,7 @@ pub fn eval(
/// A virtual machine.
///
-/// Holds the state needed to [evaluate](super::eval()) Typst sources. A new
+/// Holds the state needed to [evaluate](eval) Typst sources. A new
/// virtual machine is created for each module evaluation and function call.
pub struct Vm<'a> {
/// The compilation environment.
@@ -78,7 +78,7 @@ pub struct Vm<'a> {
impl<'a> Vm<'a> {
/// Create a new virtual machine.
- pub fn new(
+ pub(super) fn new(
world: Tracked<'a, dyn World>,
route: Tracked<'a, Route>,
location: SourceId,
diff --git a/tests/typ/structure/enum.typ b/tests/typ/structure/enum.typ
index 4ff13ff4..40aad625 100644
--- a/tests/typ/structure/enum.typ
+++ b/tests/typ/structure/enum.typ
@@ -57,9 +57,9 @@
No enum
---
-// Error: 18-20 invalid pattern
+// Error: 18-20 invalid numbering pattern
#set enum(label: "")
---
-// Error: 18-24 invalid pattern
+// Error: 18-24 invalid numbering pattern
#set enum(label: "(())")