summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library/src/layout/enum.rs12
-rw-r--r--library/src/meta/counter.rs14
-rw-r--r--library/src/meta/numbering.rs33
-rw-r--r--src/eval/library.rs2
-rw-r--r--src/syntax/ast.rs2
-rw-r--r--src/syntax/lexer.rs10
-rw-r--r--tests/ref/layout/enum.pngbin8727 -> 11276 bytes
-rw-r--r--tests/ref/meta/numbering.pngbin7479 -> 8235 bytes
-rw-r--r--tests/typ/layout/enum.typ12
-rw-r--r--tests/typ/meta/numbering.typ8
10 files changed, 51 insertions, 42 deletions
diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs
index 1be57d4c..ec4fbc18 100644
--- a/library/src/layout/enum.rs
+++ b/library/src/layout/enum.rs
@@ -100,8 +100,8 @@ pub struct EnumElem {
/// [Ahead],
/// )
/// ```
- #[default(NonZeroUsize::ONE)]
- pub start: NonZeroUsize,
+ #[default(1)]
+ pub start: usize,
/// Whether to display the full numbering, including the numbers of
/// all parent enumerations.
@@ -225,7 +225,7 @@ impl Layout for EnumElem {
pub struct EnumItem {
/// The item's number.
#[positional]
- pub number: Option<NonZeroUsize>,
+ pub number: Option<usize>,
/// The item's body.
#[required]
@@ -245,11 +245,11 @@ cast_from_value! {
v: Content => v.to::<Self>().cloned().unwrap_or_else(|| Self::new(v.clone())),
}
-struct Parent(NonZeroUsize);
+struct Parent(usize);
cast_from_value! {
Parent,
- v: NonZeroUsize => Self(v),
+ v: usize => Self(v),
}
cast_to_value! {
@@ -257,7 +257,7 @@ cast_to_value! {
}
impl Fold for Parent {
- type Output = Vec<NonZeroUsize>;
+ type Output = Vec<usize>;
fn fold(self, mut outer: Self::Output) -> Self::Output {
outer.push(self.0);
diff --git a/library/src/meta/counter.rs b/library/src/meta/counter.rs
index 0ebf144c..fb656c76 100644
--- a/library/src/meta/counter.rs
+++ b/library/src/meta/counter.rs
@@ -372,8 +372,8 @@ impl Counter {
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
let mut vt = Vt { world, tracer, provider, introspector };
let mut state = CounterState(match &self.0 {
- CounterKey::Selector(_) => smallvec![],
- _ => smallvec![NonZeroUsize::ONE],
+ CounterKey::Selector(_) => smallvec![0],
+ _ => smallvec![1],
});
let mut page = NonZeroUsize::ONE;
let mut stops = eco_vec![(state.clone(), page)];
@@ -506,7 +506,7 @@ pub trait Count {
/// Counts through elements with different levels.
#[derive(Debug, Clone, PartialEq, Hash)]
-pub struct CounterState(pub SmallVec<[NonZeroUsize; 3]>);
+pub struct CounterState(pub SmallVec<[usize; 3]>);
impl CounterState {
/// Advance the counter and return the numbers for the given heading.
@@ -534,13 +534,13 @@ impl CounterState {
}
while self.0.len() < level {
- self.0.push(NonZeroUsize::ONE);
+ self.0.push(1);
}
}
/// Get the first number of the state.
- pub fn first(&self) -> NonZeroUsize {
- self.0.first().copied().unwrap_or(NonZeroUsize::ONE)
+ pub fn first(&self) -> usize {
+ self.0.first().copied().unwrap_or(1)
}
/// Display the counter state with a numbering.
@@ -551,7 +551,7 @@ impl CounterState {
cast_from_value! {
CounterState,
- num: NonZeroUsize => Self(smallvec![num]),
+ num: usize => Self(smallvec![num]),
array: Array => Self(array
.into_iter()
.map(Value::cast)
diff --git a/library/src/meta/numbering.rs b/library/src/meta/numbering.rs
index 6facb833..0827e160 100644
--- a/library/src/meta/numbering.rs
+++ b/library/src/meta/numbering.rs
@@ -62,7 +62,7 @@ pub fn numbering(
/// If `numbering` is a pattern and more numbers than counting symbols are
/// given, the last counting symbol with its prefix is repeated.
#[variadic]
- numbers: Vec<NonZeroUsize>,
+ numbers: Vec<usize>,
) -> Value {
numbering.apply_vm(vm, &numbers)?
}
@@ -78,25 +78,23 @@ pub enum Numbering {
impl Numbering {
/// Apply the pattern to the given numbers.
- pub fn apply_vm(&self, vm: &mut Vm, numbers: &[NonZeroUsize]) -> SourceResult<Value> {
+ pub fn apply_vm(&self, vm: &mut Vm, numbers: &[usize]) -> SourceResult<Value> {
Ok(match self {
Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()),
Self::Func(func) => {
- let args = Args::new(
- func.span(),
- numbers.iter().map(|n| Value::Int(n.get() as i64)),
- );
+ let args =
+ Args::new(func.span(), numbers.iter().map(|&n| Value::Int(n as i64)));
func.call_vm(vm, args)?
}
})
}
/// Apply the pattern to the given numbers.
- pub fn apply_vt(&self, vt: &mut Vt, numbers: &[NonZeroUsize]) -> SourceResult<Value> {
+ pub fn apply_vt(&self, vt: &mut Vt, numbers: &[usize]) -> SourceResult<Value> {
Ok(match self {
Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()),
Self::Func(func) => {
- func.call_vt(vt, numbers.iter().map(|n| Value::Int(n.get() as i64)))?
+ func.call_vt(vt, numbers.iter().map(|&n| Value::Int(n as i64)))?
}
})
}
@@ -147,7 +145,7 @@ pub struct NumberingPattern {
impl NumberingPattern {
/// Apply the pattern to the given number.
- pub fn apply(&self, numbers: &[NonZeroUsize]) -> EcoString {
+ pub fn apply(&self, numbers: &[usize]) -> EcoString {
let mut fmt = EcoString::new();
let mut numbers = numbers.into_iter();
@@ -179,7 +177,7 @@ impl NumberingPattern {
}
/// Apply only the k-th segment of the pattern to a number.
- pub fn apply_kth(&self, k: usize, number: NonZeroUsize) -> EcoString {
+ pub fn apply_kth(&self, k: usize, number: usize) -> EcoString {
let mut fmt = EcoString::new();
if let Some((prefix, _, _)) = self.pieces.first() {
fmt.push_str(prefix);
@@ -282,13 +280,16 @@ impl NumberingKind {
}
/// Apply the numbering to the given number.
- pub fn apply(self, n: NonZeroUsize, case: Case) -> EcoString {
- let mut n = n.get();
+ pub fn apply(self, mut n: usize, case: Case) -> EcoString {
match self {
Self::Arabic => {
eco_format!("{n}")
}
Self::Letter => {
+ if n == 0 {
+ return '-'.into();
+ }
+
n -= 1;
let mut letters = vec![];
@@ -308,6 +309,10 @@ impl NumberingKind {
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();
@@ -347,6 +352,10 @@ impl NumberingKind {
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;
diff --git a/src/eval/library.rs b/src/eval/library.rs
index 85d5647b..5b0ff8e6 100644
--- a/src/eval/library.rs
+++ b/src/eval/library.rs
@@ -74,7 +74,7 @@ pub struct LangItems {
/// An item in a bullet list: `- ...`.
pub list_item: fn(body: Content) -> Content,
/// An item in an enumeration (numbered list): `+ ...` or `1. ...`.
- pub enum_item: fn(number: Option<NonZeroUsize>, body: Content) -> Content,
+ pub enum_item: fn(number: Option<usize>, body: Content) -> Content,
/// An item in a term list: `/ Term: Details`.
pub term_item: fn(term: Content, description: Content) -> Content,
/// A mathematical equation: `$x$`, `$ x^2 $`.
diff --git a/src/syntax/ast.rs b/src/syntax/ast.rs
index bd8fa230..b064da88 100644
--- a/src/syntax/ast.rs
+++ b/src/syntax/ast.rs
@@ -681,7 +681,7 @@ node! {
impl EnumItem {
/// The explicit numbering, if any: `23.`.
- pub fn number(&self) -> Option<NonZeroUsize> {
+ pub fn number(&self) -> Option<usize> {
self.0.children().find_map(|node| match node.kind() {
SyntaxKind::EnumMarker => node.text().trim_end_matches('.').parse().ok(),
_ => Option::None,
diff --git a/src/syntax/lexer.rs b/src/syntax/lexer.rs
index 90a10f52..c46fa37b 100644
--- a/src/syntax/lexer.rs
+++ b/src/syntax/lexer.rs
@@ -170,7 +170,6 @@ impl Lexer<'_> {
'`' => self.raw(),
'h' if self.s.eat_if("ttp://") => self.link(),
'h' if self.s.eat_if("ttps://") => self.link(),
- '0'..='9' => self.numbering(start),
'<' if self.s.at(is_id_continue) => self.label(),
'@' => self.ref_marker(),
@@ -200,6 +199,7 @@ impl Lexer<'_> {
'-' if self.space_or_end() => SyntaxKind::ListMarker,
'+' if self.space_or_end() => SyntaxKind::EnumMarker,
'/' if self.space_or_end() => SyntaxKind::TermMarker,
+ '0'..='9' => self.numbering(start),
_ => self.text(),
}
@@ -284,12 +284,8 @@ impl Lexer<'_> {
self.s.eat_while(char::is_ascii_digit);
let read = self.s.from(start);
- if self.s.eat_if('.') {
- if let Ok(number) = read.parse::<usize>() {
- if number == 0 {
- return self.error("must be positive");
- }
-
+ if self.s.eat_if('.') && self.space_or_end() {
+ if read.parse::<usize>().is_ok() {
return SyntaxKind::EnumMarker;
}
}
diff --git a/tests/ref/layout/enum.png b/tests/ref/layout/enum.png
index d80a584c..a52ad989 100644
--- a/tests/ref/layout/enum.png
+++ b/tests/ref/layout/enum.png
Binary files differ
diff --git a/tests/ref/meta/numbering.png b/tests/ref/meta/numbering.png
index 93b9f394..036889e3 100644
--- a/tests/ref/meta/numbering.png
+++ b/tests/ref/meta/numbering.png
Binary files differ
diff --git a/tests/typ/layout/enum.typ b/tests/typ/layout/enum.typ
index 9512e1b5..341afed4 100644
--- a/tests/typ/layout/enum.typ
+++ b/tests/typ/layout/enum.typ
@@ -4,6 +4,7 @@
#enum[Embrace][Extend][Extinguish]
---
+0. Before first!
1. First.
2. Indented
@@ -22,7 +23,14 @@
/ Term: List
---
+// In the line.
+1.2 \
+This is 0. \
+See 0.3. \
+
+---
// Edge cases.
+
-Empty
-+Nope
+Empty \
++Nope \
+a + 0.
diff --git a/tests/typ/meta/numbering.typ b/tests/typ/meta/numbering.typ
index 63e45362..ecc3bdbf 100644
--- a/tests/typ/meta/numbering.typ
+++ b/tests/typ/meta/numbering.typ
@@ -1,7 +1,7 @@
// Test integrated numbering patterns.
---
-#for i in range(1, 9) {
+#for i in range(0, 9) {
numbering("*", i)
[ and ]
numbering("I.a", i, i)
@@ -10,9 +10,5 @@
}
---
-// Error: 17-18 number must be positive
-#numbering("1", 0)
-
----
-// Error: 17-19 number must be positive
+// Error: 17-19 number must be at least zero
#numbering("1", -1)