Compare commits
5 Commits
1b2714e1a7
...
1f1c133878
Author | SHA1 | Date | |
---|---|---|---|
|
1f1c133878 | ||
|
1e591ac8dc | ||
|
38213ed534 | ||
|
636eea18bc | ||
|
91956d1f03 |
6
Cargo.lock
generated
@ -3796,18 +3796,16 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.2.2"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae9c1ea7b3a5e1f4b922ff856a129881167511563dc219869afe3787fc0c1a45"
|
||||
checksum = "27c03817464f64e23f6f37574b4fdc8cf65925b5bfd2b0f2aedf959791941f88"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"displaydoc",
|
||||
"flate2",
|
||||
"indexmap 2.7.1",
|
||||
"memchr",
|
||||
"thiserror 2.0.11",
|
||||
"zopfli",
|
||||
]
|
||||
|
||||
|
@ -143,7 +143,7 @@ xmlwriter = "0.1.0"
|
||||
xmp-writer = "0.3.1"
|
||||
xz2 = { version = "0.1", features = ["static"] }
|
||||
yaml-front-matter = "0.1"
|
||||
zip = { version = "2", default-features = false, features = ["deflate"] }
|
||||
zip = { version = "2.5", default-features = false, features = ["deflate"] }
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 2
|
||||
|
@ -96,9 +96,13 @@ pub fn layout_enum(
|
||||
|
||||
let mut cells = vec![];
|
||||
let mut locator = locator.split();
|
||||
let mut number =
|
||||
elem.start(styles)
|
||||
.unwrap_or_else(|| if reversed { elem.children.len() } else { 1 });
|
||||
let mut number = elem.start(styles).unwrap_or_else(|| {
|
||||
if reversed {
|
||||
elem.children.len() as u64
|
||||
} else {
|
||||
1
|
||||
}
|
||||
});
|
||||
let mut parents = EnumElem::parents_in(styles);
|
||||
|
||||
let full = elem.full(styles);
|
||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::{self, Sum};
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::{Add, AddAssign, Deref, DerefMut};
|
||||
use std::ops::{Add, AddAssign, ControlFlow, Deref, DerefMut};
|
||||
use std::sync::Arc;
|
||||
|
||||
use comemo::Tracked;
|
||||
@ -414,10 +414,11 @@ impl Content {
|
||||
/// Elements produced in `show` rules will not be included in the results.
|
||||
pub fn query(&self, selector: Selector) -> Vec<Content> {
|
||||
let mut results = Vec::new();
|
||||
self.traverse(&mut |element| {
|
||||
self.traverse(&mut |element| -> ControlFlow<()> {
|
||||
if selector.matches(&element, None) {
|
||||
results.push(element);
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
results
|
||||
}
|
||||
@ -427,54 +428,58 @@ impl Content {
|
||||
///
|
||||
/// Elements produced in `show` rules will not be included in the results.
|
||||
pub fn query_first(&self, selector: &Selector) -> Option<Content> {
|
||||
let mut result = None;
|
||||
self.traverse(&mut |element| {
|
||||
if result.is_none() && selector.matches(&element, None) {
|
||||
result = Some(element);
|
||||
self.traverse(&mut |element| -> ControlFlow<Content> {
|
||||
if selector.matches(&element, None) {
|
||||
ControlFlow::Break(element)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
});
|
||||
result
|
||||
})
|
||||
.break_value()
|
||||
}
|
||||
|
||||
/// Extracts the plain text of this content.
|
||||
pub fn plain_text(&self) -> EcoString {
|
||||
let mut text = EcoString::new();
|
||||
self.traverse(&mut |element| {
|
||||
self.traverse(&mut |element| -> ControlFlow<()> {
|
||||
if let Some(textable) = element.with::<dyn PlainText>() {
|
||||
textable.plain_text(&mut text);
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
});
|
||||
text
|
||||
}
|
||||
|
||||
/// Traverse this content.
|
||||
fn traverse<F>(&self, f: &mut F)
|
||||
fn traverse<F, B>(&self, f: &mut F) -> ControlFlow<B>
|
||||
where
|
||||
F: FnMut(Content),
|
||||
F: FnMut(Content) -> ControlFlow<B>,
|
||||
{
|
||||
f(self.clone());
|
||||
|
||||
self.inner
|
||||
.elem
|
||||
.fields()
|
||||
.into_iter()
|
||||
.for_each(|(_, value)| walk_value(value, f));
|
||||
|
||||
/// Walks a given value to find any content that matches the selector.
|
||||
fn walk_value<F>(value: Value, f: &mut F)
|
||||
///
|
||||
/// Returns early if the function gives `ControlFlow::Break`.
|
||||
fn walk_value<F, B>(value: Value, f: &mut F) -> ControlFlow<B>
|
||||
where
|
||||
F: FnMut(Content),
|
||||
F: FnMut(Content) -> ControlFlow<B>,
|
||||
{
|
||||
match value {
|
||||
Value::Content(content) => content.traverse(f),
|
||||
Value::Array(array) => {
|
||||
for value in array {
|
||||
walk_value(value, f);
|
||||
walk_value(value, f)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
_ => ControlFlow::Continue(()),
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
// Call f on the element itself before recursively iterating its fields.
|
||||
f(self.clone())?;
|
||||
for (_, value) in self.inner.elem.fields() {
|
||||
walk_value(value, f)?;
|
||||
}
|
||||
ControlFlow::Continue(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -229,10 +229,10 @@ impl Counter {
|
||||
if self.is_page() {
|
||||
let at_delta =
|
||||
engine.introspector.page(location).get().saturating_sub(at_page.get());
|
||||
at_state.step(NonZeroUsize::ONE, at_delta);
|
||||
at_state.step(NonZeroUsize::ONE, at_delta as u64);
|
||||
let final_delta =
|
||||
engine.introspector.pages().get().saturating_sub(final_page.get());
|
||||
final_state.step(NonZeroUsize::ONE, final_delta);
|
||||
final_state.step(NonZeroUsize::ONE, final_delta as u64);
|
||||
}
|
||||
Ok(CounterState(smallvec![at_state.first(), final_state.first()]))
|
||||
}
|
||||
@ -250,7 +250,7 @@ impl Counter {
|
||||
if self.is_page() {
|
||||
let delta =
|
||||
engine.introspector.page(location).get().saturating_sub(page.get());
|
||||
state.step(NonZeroUsize::ONE, delta);
|
||||
state.step(NonZeroUsize::ONE, delta as u64);
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
@ -319,7 +319,7 @@ impl Counter {
|
||||
|
||||
let delta = page.get() - prev.get();
|
||||
if delta > 0 {
|
||||
state.step(NonZeroUsize::ONE, delta);
|
||||
state.step(NonZeroUsize::ONE, delta as u64);
|
||||
}
|
||||
}
|
||||
|
||||
@ -500,7 +500,7 @@ impl Counter {
|
||||
let (mut state, page) = sequence.last().unwrap().clone();
|
||||
if self.is_page() {
|
||||
let delta = engine.introspector.pages().get().saturating_sub(page.get());
|
||||
state.step(NonZeroUsize::ONE, delta);
|
||||
state.step(NonZeroUsize::ONE, delta as u64);
|
||||
}
|
||||
Ok(state)
|
||||
}
|
||||
@ -616,13 +616,13 @@ pub trait Count {
|
||||
|
||||
/// Counts through elements with different levels.
|
||||
#[derive(Debug, Clone, PartialEq, Hash)]
|
||||
pub struct CounterState(pub SmallVec<[usize; 3]>);
|
||||
pub struct CounterState(pub SmallVec<[u64; 3]>);
|
||||
|
||||
impl CounterState {
|
||||
/// Get the initial counter state for the key.
|
||||
pub fn init(page: bool) -> Self {
|
||||
// Special case, because pages always start at one.
|
||||
Self(smallvec![usize::from(page)])
|
||||
Self(smallvec![u64::from(page)])
|
||||
}
|
||||
|
||||
/// Advance the counter and return the numbers for the given heading.
|
||||
@ -645,7 +645,7 @@ impl CounterState {
|
||||
}
|
||||
|
||||
/// Advance the number of the given level by the specified amount.
|
||||
pub fn step(&mut self, level: NonZeroUsize, by: usize) {
|
||||
pub fn step(&mut self, level: NonZeroUsize, by: u64) {
|
||||
let level = level.get();
|
||||
|
||||
while self.0.len() < level {
|
||||
@ -657,7 +657,7 @@ impl CounterState {
|
||||
}
|
||||
|
||||
/// Get the first number of the state.
|
||||
pub fn first(&self) -> usize {
|
||||
pub fn first(&self) -> u64 {
|
||||
self.0.first().copied().unwrap_or(1)
|
||||
}
|
||||
|
||||
@ -675,7 +675,7 @@ impl CounterState {
|
||||
cast! {
|
||||
CounterState,
|
||||
self => Value::Array(self.0.into_iter().map(IntoValue::into_value).collect()),
|
||||
num: usize => Self(smallvec![num]),
|
||||
num: u64 => Self(smallvec![num]),
|
||||
array: Array => Self(array
|
||||
.into_iter()
|
||||
.map(Value::cast)
|
||||
@ -758,7 +758,7 @@ impl Show for Packed<CounterDisplayElem> {
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct ManualPageCounter {
|
||||
physical: NonZeroUsize,
|
||||
logical: usize,
|
||||
logical: u64,
|
||||
}
|
||||
|
||||
impl ManualPageCounter {
|
||||
@ -773,7 +773,7 @@ impl ManualPageCounter {
|
||||
}
|
||||
|
||||
/// Get the current logical page counter state.
|
||||
pub fn logical(&self) -> usize {
|
||||
pub fn logical(&self) -> u64 {
|
||||
self.logical
|
||||
}
|
||||
|
||||
|
@ -75,9 +75,10 @@ pub struct PageElem {
|
||||
/// The height of the page.
|
||||
///
|
||||
/// If this is set to `{auto}`, page breaks can only be triggered manually
|
||||
/// by inserting a [page break]($pagebreak). Most examples throughout this
|
||||
/// documentation use `{auto}` for the height of the page to dynamically
|
||||
/// grow and shrink to fit their content.
|
||||
/// by inserting a [page break]($pagebreak) or by adding another non-empty
|
||||
/// page set rule. Most examples throughout this documentation use `{auto}`
|
||||
/// for the height of the page to dynamically grow and shrink to fit their
|
||||
/// content.
|
||||
#[resolve]
|
||||
#[parse(
|
||||
args.named("height")?
|
||||
@ -483,7 +484,7 @@ pub struct Page {
|
||||
pub supplement: Content,
|
||||
/// The logical page number (controlled by `counter(page)` and may thus not
|
||||
/// match the physical number).
|
||||
pub number: usize,
|
||||
pub number: u64,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
|
@ -129,7 +129,7 @@ pub struct EnumElem {
|
||||
/// [Ahead],
|
||||
/// )
|
||||
/// ```
|
||||
pub start: Smart<usize>,
|
||||
pub start: Smart<u64>,
|
||||
|
||||
/// Whether to display the full numbering, including the numbers of
|
||||
/// all parent enumerations.
|
||||
@ -217,7 +217,7 @@ pub struct EnumElem {
|
||||
#[internal]
|
||||
#[fold]
|
||||
#[ghost]
|
||||
pub parents: SmallVec<[usize; 4]>,
|
||||
pub parents: SmallVec<[u64; 4]>,
|
||||
}
|
||||
|
||||
#[scope]
|
||||
@ -274,7 +274,7 @@ impl Show for Packed<EnumElem> {
|
||||
pub struct EnumItem {
|
||||
/// The item's number.
|
||||
#[positional]
|
||||
pub number: Option<usize>,
|
||||
pub number: Option<u64>,
|
||||
|
||||
/// The item's body.
|
||||
#[required]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use chinese_number::{
|
||||
from_usize_to_chinese_ten_thousand as usize_to_chinese, ChineseCase, ChineseVariant,
|
||||
from_u64_to_chinese_ten_thousand as u64_to_chinese, ChineseCase, ChineseVariant,
|
||||
};
|
||||
use comemo::Tracked;
|
||||
use ecow::{eco_format, EcoString, EcoVec};
|
||||
@ -85,7 +85,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<usize>,
|
||||
numbers: Vec<u64>,
|
||||
) -> SourceResult<Value> {
|
||||
numbering.apply(engine, context, &numbers)
|
||||
}
|
||||
@ -105,7 +105,7 @@ impl Numbering {
|
||||
&self,
|
||||
engine: &mut Engine,
|
||||
context: Tracked<Context>,
|
||||
numbers: &[usize],
|
||||
numbers: &[u64],
|
||||
) -> SourceResult<Value> {
|
||||
Ok(match self {
|
||||
Self::Pattern(pattern) => Value::Str(pattern.apply(numbers).into()),
|
||||
@ -156,7 +156,7 @@ pub struct NumberingPattern {
|
||||
|
||||
impl NumberingPattern {
|
||||
/// Apply the pattern to the given number.
|
||||
pub fn apply(&self, numbers: &[usize]) -> EcoString {
|
||||
pub fn apply(&self, numbers: &[u64]) -> EcoString {
|
||||
let mut fmt = EcoString::new();
|
||||
let mut numbers = numbers.iter();
|
||||
|
||||
@ -185,7 +185,7 @@ impl NumberingPattern {
|
||||
}
|
||||
|
||||
/// Apply only the k-th segment of the pattern to a number.
|
||||
pub fn apply_kth(&self, k: usize, number: usize) -> EcoString {
|
||||
pub fn apply_kth(&self, k: usize, number: u64) -> EcoString {
|
||||
let mut fmt = EcoString::new();
|
||||
if let Some((prefix, _)) = self.pieces.first() {
|
||||
fmt.push_str(prefix);
|
||||
@ -379,7 +379,7 @@ impl NumberingKind {
|
||||
}
|
||||
|
||||
/// Apply the numbering to the given number.
|
||||
pub fn apply(self, n: usize) -> EcoString {
|
||||
pub fn apply(self, n: u64) -> EcoString {
|
||||
match self {
|
||||
Self::Arabic => eco_format!("{n}"),
|
||||
Self::LowerRoman => roman_numeral(n, Case::Lower),
|
||||
@ -392,9 +392,10 @@ impl NumberingKind {
|
||||
}
|
||||
|
||||
const SYMBOLS: &[char] = &['*', '†', '‡', '§', '¶', '‖'];
|
||||
let symbol = SYMBOLS[(n - 1) % SYMBOLS.len()];
|
||||
let amount = ((n - 1) / SYMBOLS.len()) + 1;
|
||||
std::iter::repeat_n(symbol, amount).collect()
|
||||
let n_symbols = SYMBOLS.len() as u64;
|
||||
let symbol = SYMBOLS[((n - 1) % n_symbols) as usize];
|
||||
let amount = ((n - 1) / n_symbols) + 1;
|
||||
std::iter::repeat_n(symbol, amount.try_into().unwrap()).collect()
|
||||
}
|
||||
Self::Hebrew => hebrew_numeral(n),
|
||||
|
||||
@ -489,18 +490,16 @@ impl NumberingKind {
|
||||
}
|
||||
|
||||
Self::LowerSimplifiedChinese => {
|
||||
usize_to_chinese(ChineseVariant::Simple, ChineseCase::Lower, n).into()
|
||||
u64_to_chinese(ChineseVariant::Simple, ChineseCase::Lower, n).into()
|
||||
}
|
||||
Self::UpperSimplifiedChinese => {
|
||||
usize_to_chinese(ChineseVariant::Simple, ChineseCase::Upper, n).into()
|
||||
u64_to_chinese(ChineseVariant::Simple, ChineseCase::Upper, n).into()
|
||||
}
|
||||
Self::LowerTraditionalChinese => {
|
||||
usize_to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, n)
|
||||
.into()
|
||||
u64_to_chinese(ChineseVariant::Traditional, ChineseCase::Lower, n).into()
|
||||
}
|
||||
Self::UpperTraditionalChinese => {
|
||||
usize_to_chinese(ChineseVariant::Traditional, ChineseCase::Upper, n)
|
||||
.into()
|
||||
u64_to_chinese(ChineseVariant::Traditional, ChineseCase::Upper, n).into()
|
||||
}
|
||||
|
||||
Self::EasternArabic => decimal('\u{0660}', n),
|
||||
@ -512,7 +511,7 @@ impl NumberingKind {
|
||||
}
|
||||
|
||||
/// Stringify an integer to a Hebrew number.
|
||||
fn hebrew_numeral(mut n: usize) -> EcoString {
|
||||
fn hebrew_numeral(mut n: u64) -> EcoString {
|
||||
if n == 0 {
|
||||
return '-'.into();
|
||||
}
|
||||
@ -566,7 +565,7 @@ fn hebrew_numeral(mut n: usize) -> EcoString {
|
||||
}
|
||||
|
||||
/// Stringify an integer to a Roman numeral.
|
||||
fn roman_numeral(mut n: usize, case: Case) -> EcoString {
|
||||
fn roman_numeral(mut n: u64, case: Case) -> EcoString {
|
||||
if n == 0 {
|
||||
return match case {
|
||||
Case::Lower => 'n'.into(),
|
||||
@ -622,7 +621,7 @@ fn roman_numeral(mut n: usize, case: Case) -> EcoString {
|
||||
///
|
||||
/// [converter]: https://www.russellcottrell.com/greek/utilities/GreekNumberConverter.htm
|
||||
/// [numbers]: https://mathshistory.st-andrews.ac.uk/HistTopics/Greek_numbers/
|
||||
fn greek_numeral(n: usize, case: Case) -> EcoString {
|
||||
fn greek_numeral(n: u64, case: Case) -> EcoString {
|
||||
let thousands = [
|
||||
["͵α", "͵Α"],
|
||||
["͵β", "͵Β"],
|
||||
@ -683,7 +682,7 @@ fn greek_numeral(n: usize, case: Case) -> EcoString {
|
||||
let mut decimal_digits: Vec<usize> = Vec::new();
|
||||
let mut n = n;
|
||||
while n > 0 {
|
||||
decimal_digits.push(n % 10);
|
||||
decimal_digits.push((n % 10) as usize);
|
||||
n /= 10;
|
||||
}
|
||||
|
||||
@ -778,18 +777,16 @@ fn greek_numeral(n: usize, case: Case) -> EcoString {
|
||||
///
|
||||
/// You might be familiar with this scheme from the way spreadsheet software
|
||||
/// tends to label its columns.
|
||||
fn zeroless<const N_DIGITS: usize>(
|
||||
alphabet: [char; N_DIGITS],
|
||||
mut n: usize,
|
||||
) -> EcoString {
|
||||
fn zeroless<const N_DIGITS: usize>(alphabet: [char; N_DIGITS], mut n: u64) -> EcoString {
|
||||
if n == 0 {
|
||||
return '-'.into();
|
||||
}
|
||||
let n_digits = N_DIGITS as u64;
|
||||
let mut cs = EcoString::new();
|
||||
while n > 0 {
|
||||
n -= 1;
|
||||
cs.push(alphabet[n % N_DIGITS]);
|
||||
n /= N_DIGITS;
|
||||
cs.push(alphabet[(n % n_digits) as usize]);
|
||||
n /= n_digits;
|
||||
}
|
||||
cs.chars().rev().collect()
|
||||
}
|
||||
@ -797,7 +794,7 @@ fn zeroless<const N_DIGITS: usize>(
|
||||
/// Stringify a number using a base-10 counting system with a zero digit.
|
||||
///
|
||||
/// This function assumes that the digits occupy contiguous codepoints.
|
||||
fn decimal(start: char, mut n: usize) -> EcoString {
|
||||
fn decimal(start: char, mut n: u64) -> EcoString {
|
||||
if n == 0 {
|
||||
return start.into();
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::num::NonZeroU64;
|
||||
|
||||
use ecow::EcoString;
|
||||
use pdf_writer::types::{ActionType, AnnotationFlags, AnnotationType, NumberingStyle};
|
||||
@ -48,7 +48,7 @@ pub fn traverse_pages(
|
||||
// the real (not logical) page numbers. Here, the final PDF page number
|
||||
// will differ, but we can at least use labels to indicate what was
|
||||
// the corresponding real page number in the Typst document.
|
||||
(skipped_pages > 0).then(|| PdfPageLabel::arabic(i + 1))
|
||||
(skipped_pages > 0).then(|| PdfPageLabel::arabic((i + 1) as u64))
|
||||
});
|
||||
pages.push(Some(encoded));
|
||||
}
|
||||
@ -219,7 +219,7 @@ pub(crate) struct PdfPageLabel {
|
||||
///
|
||||
/// Describes where to start counting from when setting a style.
|
||||
/// (Has to be greater or equal than 1)
|
||||
pub offset: Option<NonZeroUsize>,
|
||||
pub offset: Option<NonZeroU64>,
|
||||
}
|
||||
|
||||
/// A PDF page label number style.
|
||||
@ -242,7 +242,7 @@ pub enum PdfPageLabelStyle {
|
||||
impl PdfPageLabel {
|
||||
/// Create a new `PdfNumbering` from a `Numbering` applied to a page
|
||||
/// number.
|
||||
fn generate(numbering: &Numbering, number: usize) -> Option<PdfPageLabel> {
|
||||
fn generate(numbering: &Numbering, number: u64) -> Option<PdfPageLabel> {
|
||||
let Numbering::Pattern(pat) = numbering else {
|
||||
return None;
|
||||
};
|
||||
@ -275,18 +275,18 @@ impl PdfPageLabel {
|
||||
(!prefix.is_empty()).then(|| prefix.clone())
|
||||
};
|
||||
|
||||
let offset = style.and(NonZeroUsize::new(number));
|
||||
let offset = style.and(NonZeroU64::new(number));
|
||||
Some(PdfPageLabel { prefix, style, offset })
|
||||
}
|
||||
|
||||
/// Creates an arabic page label with the specified page number.
|
||||
/// For example, this will display page label `11` when given the page
|
||||
/// number 11.
|
||||
fn arabic(number: usize) -> PdfPageLabel {
|
||||
fn arabic(number: u64) -> PdfPageLabel {
|
||||
PdfPageLabel {
|
||||
prefix: None,
|
||||
style: Some(PdfPageLabelStyle::Arabic),
|
||||
offset: NonZeroUsize::new(number),
|
||||
offset: NonZeroU64::new(number),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -778,7 +778,7 @@ node! {
|
||||
|
||||
impl<'a> EnumItem<'a> {
|
||||
/// The explicit numbering, if any: `23.`.
|
||||
pub fn number(self) -> Option<usize> {
|
||||
pub fn number(self) -> Option<u64> {
|
||||
self.0.children().find_map(|node| match node.kind() {
|
||||
SyntaxKind::EnumMarker => node.text().trim_end_matches('.').parse().ok(),
|
||||
_ => Option::None,
|
||||
|
@ -480,7 +480,7 @@ impl Lexer<'_> {
|
||||
self.s.eat_while(char::is_ascii_digit);
|
||||
|
||||
let read = self.s.from(start);
|
||||
if self.s.eat_if('.') && self.space_or_end() && read.parse::<usize>().is_ok() {
|
||||
if self.s.eat_if('.') && self.space_or_end() && read.parse::<u64>().is_ok() {
|
||||
return SyntaxKind::EnumMarker;
|
||||
}
|
||||
|
||||
|
BIN
tests/ref/enum-numbering-huge.png
Normal file
After Width: | Height: | Size: 900 B |
Before Width: | Height: | Size: 365 B |
BIN
tests/ref/grid-footer-moved-to-bottom-of-rowspans.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tests/ref/grid-footer-top-hlines-with-only-row-pos-cell.png
Normal file
After Width: | Height: | Size: 385 B |
BIN
tests/ref/grid-footer-top-hlines-with-row-and-auto-pos-cell.png
Normal file
After Width: | Height: | Size: 579 B |
BIN
tests/ref/grid-header-cell-with-x.png
Normal file
After Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 2.0 KiB |
BIN
tests/ref/issue-5359-column-override-stays-inside-footer.png
Normal file
After Width: | Height: | Size: 674 B |
BIN
tests/ref/page-numbering-huge.png
Normal file
After Width: | Height: | Size: 913 B |
@ -244,7 +244,7 @@ fn lines(
|
||||
engine: &mut Engine,
|
||||
context: Tracked<Context>,
|
||||
span: Span,
|
||||
count: usize,
|
||||
count: u64,
|
||||
#[default(Numbering::Pattern(NumberingPattern::from_str("A").unwrap()))]
|
||||
numbering: Numbering,
|
||||
) -> SourceResult<Value> {
|
||||
|
@ -164,3 +164,13 @@ B
|
||||
#context test(c.get(), (1,))
|
||||
#c.step(level: 3)
|
||||
#context test(c.get(), (1, 0, 1))
|
||||
|
||||
--- counter-huge ---
|
||||
// Test values greater than 32-bits
|
||||
#let c = counter("c")
|
||||
#c.update(100000000001)
|
||||
#context test(c.get(), (100000000001,))
|
||||
#c.step()
|
||||
#context test(c.get(), (100000000002,))
|
||||
#c.update(n => n + 2)
|
||||
#context test(c.get(), (100000000004,))
|
||||
|
@ -83,12 +83,55 @@
|
||||
grid.cell(y: 1)[c],
|
||||
)
|
||||
|
||||
--- grid-footer-expand ---
|
||||
// Ensure footer properly expands
|
||||
--- grid-footer-cell-with-x ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
stroke: black,
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1)[a],
|
||||
// Error: 3-56 footer must end at the last row
|
||||
grid.footer(grid.cell(x: 0)[b1], grid.cell(x: 0)[b2]),
|
||||
// This should skip the footer
|
||||
grid.cell(x: 1)[c]
|
||||
)
|
||||
|
||||
--- grid-footer-no-expand-with-col-and-row-pos-cell ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
[a], [],
|
||||
[b], [],
|
||||
fill: (_, y) => if calc.odd(y) { blue } else { red },
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1, y: 3, rowspan: 4)[b],
|
||||
grid.cell(y: 2, rowspan: 2)[a],
|
||||
grid.footer(),
|
||||
// Error: 3-27 cell would conflict with footer spanning the same position
|
||||
// Hint: 3-27 try reducing the cell's rowspan or moving the footer
|
||||
grid.cell(x: 1, y: 7)[d],
|
||||
)
|
||||
|
||||
--- grid-footer-no-expand-with-row-pos-cell ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
[a], [],
|
||||
[b], [],
|
||||
fill: (_, y) => if calc.odd(y) { blue } else { red },
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1, y: 3, rowspan: 4)[b],
|
||||
grid.cell(y: 2, rowspan: 2)[a],
|
||||
grid.footer(),
|
||||
// Error: 3-33 cell would conflict with footer spanning the same position
|
||||
// Hint: 3-33 try reducing the cell's rowspan or moving the footer
|
||||
grid.cell(y: 6, rowspan: 2)[d],
|
||||
)
|
||||
|
||||
--- grid-footer-moved-to-bottom-of-rowspans ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
[a], [],
|
||||
[b], [],
|
||||
stroke: red,
|
||||
inset: 5pt,
|
||||
grid.cell(x: 1, y: 3, rowspan: 4)[b],
|
||||
grid.cell(y: 2, rowspan: 2)[a],
|
||||
grid.footer(),
|
||||
@ -113,13 +156,13 @@
|
||||
)
|
||||
|
||||
--- grid-footer-overlap ---
|
||||
// Error: 4:3-4:19 footer would conflict with a cell placed before it at column 1 row 0
|
||||
// Hint: 4:3-4:19 try reducing that cell's rowspan or moving the footer
|
||||
#grid(
|
||||
columns: 2,
|
||||
grid.header(),
|
||||
grid.footer([a]),
|
||||
grid.cell(x: 1, y: 0, rowspan: 2)[a],
|
||||
grid.footer(grid.cell(y: 2)[a]),
|
||||
// Error: 3-39 cell would conflict with footer spanning the same position
|
||||
// Hint: 3-39 try reducing the cell's rowspan or moving the footer
|
||||
grid.cell(x: 1, y: 1, rowspan: 2)[a],
|
||||
)
|
||||
|
||||
--- grid-footer-multiple ---
|
||||
@ -374,8 +417,8 @@
|
||||
table.hline(stroke: red),
|
||||
table.vline(stroke: green),
|
||||
[b],
|
||||
[c]
|
||||
),
|
||||
table.cell(x: 1, y: 3)[c]
|
||||
)
|
||||
|
||||
--- grid-footer-hline-and-vline-2 ---
|
||||
@ -385,8 +428,8 @@
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 0)[a],
|
||||
table.footer(
|
||||
table.cell(y: 0)[a],
|
||||
table.hline(stroke: red),
|
||||
table.hline(y: 1, stroke: aqua),
|
||||
table.cell(y: 0)[b],
|
||||
@ -394,6 +437,38 @@
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-footer-top-hlines-with-only-row-pos-cell ---
|
||||
// Top hlines should attach to the top of the footer.
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 2.5pt,
|
||||
table.footer(
|
||||
table.hline(stroke: red),
|
||||
table.vline(stroke: blue),
|
||||
table.cell(x: 2, y: 2)[a],
|
||||
table.hline(stroke: 3pt),
|
||||
table.vline(stroke: 3pt),
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-footer-top-hlines-with-row-and-auto-pos-cell ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 2.5pt,
|
||||
table.footer(
|
||||
table.hline(stroke: red),
|
||||
table.vline(stroke: blue),
|
||||
table.cell(x: 2, y: 2)[a],
|
||||
[b],
|
||||
table.hline(stroke: 3pt),
|
||||
table.vline(stroke: 3pt),
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-footer-below-rowspans ---
|
||||
// Footer should go below the rowspans.
|
||||
#set page(margin: 2pt)
|
||||
@ -404,3 +479,71 @@
|
||||
table.cell(rowspan: 2)[a], table.cell(rowspan: 2)[b],
|
||||
table.footer()
|
||||
)
|
||||
|
||||
--- grid-footer-row-pos-cell-inside-conflicts-with-row-before ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 0)[a],
|
||||
table.footer(
|
||||
table.hline(stroke: red),
|
||||
table.hline(y: 1, stroke: aqua),
|
||||
// Error: 5-24 cell would cause footer to expand to non-empty row 0
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 0)[b],
|
||||
[c]
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-footer-auto-pos-cell-inside-conflicts-with-row-after ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 2,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 1)[a],
|
||||
table.footer(
|
||||
[b], [c],
|
||||
// Error: 6-7 cell would cause footer to expand to non-empty row 1
|
||||
// Hint: 6-7 try moving its cells to available rows
|
||||
[d],
|
||||
),
|
||||
)
|
||||
|
||||
--- grid-footer-row-pos-cell-inside-conflicts-with-row-after ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 2,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 2)[a],
|
||||
table.footer(
|
||||
[b], [c],
|
||||
// Error: 5-24 cell would cause footer to expand to non-empty row 2
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 3)[d],
|
||||
),
|
||||
)
|
||||
|
||||
--- grid-footer-conflicts-with-empty-header ---
|
||||
#table(
|
||||
columns: 2,
|
||||
table.header(),
|
||||
table.footer(
|
||||
// Error: 5-24 cell would cause footer to expand to non-empty row 0
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 0)[a]
|
||||
),
|
||||
)
|
||||
|
||||
--- issue-5359-column-override-stays-inside-footer ---
|
||||
#table(
|
||||
columns: 3,
|
||||
[Outside],
|
||||
table.footer(
|
||||
[A], table.cell(x: 1)[B], [C],
|
||||
table.cell(x: 1)[D],
|
||||
),
|
||||
)
|
||||
|
@ -60,6 +60,16 @@
|
||||
grid.cell(y: 2)[c]
|
||||
)
|
||||
|
||||
--- grid-header-cell-with-x ---
|
||||
#grid(
|
||||
columns: 2,
|
||||
stroke: black,
|
||||
inset: 5pt,
|
||||
grid.header(grid.cell(x: 0)[b1], grid.cell(x: 0)[b2]),
|
||||
// This should skip the header
|
||||
grid.cell(x: 1)[c]
|
||||
)
|
||||
|
||||
--- grid-header-last-child ---
|
||||
// When the header is the last grid child, it shouldn't include the gutter row
|
||||
// after it, because there is none.
|
||||
@ -273,8 +283,7 @@
|
||||
)
|
||||
#context count.display()
|
||||
|
||||
--- grid-header-expand ---
|
||||
// Ensure header expands to fit cell placed in it after its declaration
|
||||
--- grid-header-no-expand-with-col-and-row-pos-cell ---
|
||||
#set page(height: 10em)
|
||||
#table(
|
||||
columns: 2,
|
||||
@ -282,9 +291,24 @@
|
||||
[a], [b],
|
||||
[c],
|
||||
),
|
||||
// Error: 3-48 cell would conflict with header spanning the same position
|
||||
// Hint: 3-48 try moving the cell or the header
|
||||
table.cell(x: 1, y: 1, rowspan: 2, lorem(80))
|
||||
)
|
||||
|
||||
--- grid-header-no-expand-with-row-pos-cell ---
|
||||
#set page(height: 10em)
|
||||
#table(
|
||||
columns: 2,
|
||||
table.header(
|
||||
[a], [b],
|
||||
[c],
|
||||
),
|
||||
// Error: 3-42 cell would conflict with header spanning the same position
|
||||
// Hint: 3-42 try moving the cell or the header
|
||||
table.cell(y: 1, rowspan: 2, lorem(80))
|
||||
)
|
||||
|
||||
--- grid-nested-with-headers ---
|
||||
// Nested table with header should repeat both headers
|
||||
#set page(height: 10em)
|
||||
@ -368,3 +392,81 @@
|
||||
[b]
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-header-row-pos-cell-inside-conflicts-with-row-before ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 0)[a],
|
||||
table.header(
|
||||
table.hline(stroke: red),
|
||||
table.hline(y: 1, stroke: aqua),
|
||||
// Error: 5-24 cell would cause header to expand to non-empty row 0
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 0)[b],
|
||||
[c]
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-header-row-pos-cell-inside-conflicts-with-row-before-after-first-empty-row ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 3,
|
||||
inset: 1.5pt,
|
||||
// Rows: Occupied, Empty, Occupied, Empty, Empty, ...
|
||||
// Should not be able to expand header from the second Empty to the second Occupied.
|
||||
table.cell(y: 0)[a],
|
||||
table.cell(y: 2)[a],
|
||||
table.header(
|
||||
table.hline(stroke: red),
|
||||
table.hline(y: 3, stroke: aqua),
|
||||
// Error: 5-24 cell would cause header to expand to non-empty row 2
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 2)[b],
|
||||
)
|
||||
)
|
||||
|
||||
--- grid-header-auto-pos-cell-inside-conflicts-with-row-after ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 2,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 1)[a],
|
||||
table.header(
|
||||
[b], [c],
|
||||
// Error: 6-7 cell would cause header to expand to non-empty row 1
|
||||
// Hint: 6-7 try moving its cells to available rows
|
||||
[d],
|
||||
),
|
||||
)
|
||||
|
||||
--- grid-header-row-pos-cell-inside-conflicts-with-row-after ---
|
||||
#set page(margin: 2pt)
|
||||
#set text(6pt)
|
||||
#table(
|
||||
columns: 2,
|
||||
inset: 1.5pt,
|
||||
table.cell(y: 2)[a],
|
||||
table.header(
|
||||
[b], [c],
|
||||
// Error: 5-24 cell would cause header to expand to non-empty row 2
|
||||
// Hint: 5-24 try moving its cells to available rows
|
||||
table.cell(y: 3)[d],
|
||||
),
|
||||
)
|
||||
|
||||
--- issue-5359-column-override-stays-inside-header ---
|
||||
#table(
|
||||
columns: 3,
|
||||
[Outside],
|
||||
// Error: 1:3-4:4 header must start at the first row
|
||||
// Hint: 1:3-4:4 remove any rows before the header
|
||||
table.header(
|
||||
[A], table.cell(x: 1)[B], [C],
|
||||
table.cell(x: 1)[D],
|
||||
),
|
||||
)
|
||||
|
@ -246,6 +246,16 @@ Look, ma, no page numbers!
|
||||
#set page(header: auto, footer: auto)
|
||||
Default page numbers now.
|
||||
|
||||
--- page-numbering-huge ---
|
||||
#set page(margin: (bottom: 20pt, rest: 0pt))
|
||||
#let filler = lines(1)
|
||||
|
||||
// Test values greater than 32-bits
|
||||
#set page(numbering: "1/1")
|
||||
#counter(page).update(100000000001)
|
||||
#pagebreak()
|
||||
#pagebreak()
|
||||
|
||||
--- page-marginal-style-text-set ---
|
||||
#set page(numbering: "1", margin: (bottom: 20pt))
|
||||
#set text(red)
|
||||
|
@ -134,6 +134,11 @@ a + 0.
|
||||
// Error: 22-28 invalid numbering pattern
|
||||
#set enum(numbering: "(())")
|
||||
|
||||
--- enum-numbering-huge ---
|
||||
// Test values greater than 32-bits
|
||||
100000000001. A
|
||||
+ B
|
||||
|
||||
--- enum-number-align-unaffected ---
|
||||
// Alignment shouldn't affect number
|
||||
#set align(horizon)
|
||||
|
@ -49,6 +49,7 @@
|
||||
2000000001, "βΜκʹ, αʹ",
|
||||
2000010001, "βΜκʹ, αΜαʹ, αʹ",
|
||||
2056839184, "βΜκʹ, αΜ͵εχπγ, ͵θρπδ",
|
||||
12312398676, "βΜρκγʹ, αΜ͵ασλθ, ͵ηχοϛ",
|
||||
)
|
||||
#t(
|
||||
pat: sym.Alpha,
|
||||
|