parent
10d8fd9661
commit
a5c88c19b3
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 $`.
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 8.0 KiB |
@ -4,6 +4,7 @@
|
||||
#enum[Embrace][Extend][Extinguish]
|
||||
|
||||
---
|
||||
0. Before first!
|
||||
1. First.
|
||||
2. Indented
|
||||
|
||||
@ -21,8 +22,15 @@
|
||||
+ Numbered List
|
||||
/ Term: List
|
||||
|
||||
---
|
||||
// In the line.
|
||||
1.2 \
|
||||
This is 0. \
|
||||
See 0.3. \
|
||||
|
||||
---
|
||||
// Edge cases.
|
||||
+
|
||||
Empty
|
||||
+Nope
|
||||
Empty \
|
||||
+Nope \
|
||||
a + 0.
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user