mirror of
https://github.com/typst/typst
synced 2025-05-16 18:15:29 +08:00
parent
19bf1f5894
commit
378ebe5f56
@ -50,6 +50,7 @@ use std::mem;
|
||||
use typed_arena::Arena;
|
||||
use typst::diag::SourceResult;
|
||||
use typst::eval::Tracer;
|
||||
use typst::model::DelayedErrors;
|
||||
use typst::model::{applicable, realize, StyleVecBuilder};
|
||||
|
||||
use crate::math::{EquationElem, LayoutMath};
|
||||
@ -116,13 +117,20 @@ impl LayoutRoot for Content {
|
||||
fn cached(
|
||||
content: &Content,
|
||||
world: Tracked<dyn World + '_>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
styles: StyleChain,
|
||||
) -> SourceResult<Document> {
|
||||
let mut locator = Locator::chained(locator);
|
||||
let mut vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
let scratch = Scratch::default();
|
||||
let (realized, styles) = realize_root(&mut vt, &scratch, content, styles)?;
|
||||
realized
|
||||
@ -132,13 +140,13 @@ impl LayoutRoot for Content {
|
||||
}
|
||||
|
||||
tracing::info!("Starting layout");
|
||||
|
||||
cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
vt.locator.track(),
|
||||
vt.introspector,
|
||||
vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
styles,
|
||||
)
|
||||
}
|
||||
@ -168,9 +176,10 @@ pub trait Layout {
|
||||
let mut locator = Locator::chained(vt.locator.track());
|
||||
let mut vt = Vt {
|
||||
world: vt.world,
|
||||
tracer: TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
locator: &mut locator,
|
||||
introspector: vt.introspector,
|
||||
locator: &mut locator,
|
||||
tracer: TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
delayed: TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
};
|
||||
self.layout(&mut vt, styles, regions)
|
||||
}
|
||||
@ -184,18 +193,26 @@ impl Layout for Content {
|
||||
styles: StyleChain,
|
||||
regions: Regions,
|
||||
) -> SourceResult<Fragment> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[comemo::memoize]
|
||||
fn cached(
|
||||
content: &Content,
|
||||
world: Tracked<dyn World + '_>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
styles: StyleChain,
|
||||
regions: Regions,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut locator = Locator::chained(locator);
|
||||
let mut vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
let scratch = Scratch::default();
|
||||
let (realized, styles) = realize_block(&mut vt, &scratch, content, styles)?;
|
||||
realized
|
||||
@ -209,9 +226,10 @@ impl Layout for Content {
|
||||
let fragment = cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
vt.locator.track(),
|
||||
vt.introspector,
|
||||
vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
styles,
|
||||
regions,
|
||||
)?;
|
||||
|
@ -5,6 +5,7 @@ use icu_provider_blob::BlobDataProvider;
|
||||
use icu_segmenter::{LineBreakIteratorUtf8, LineSegmenter};
|
||||
use once_cell::sync::Lazy;
|
||||
use typst::eval::Tracer;
|
||||
use typst::model::DelayedErrors;
|
||||
use unicode_bidi::{BidiInfo, Level as BidiLevel};
|
||||
use unicode_script::{Script, UnicodeScript};
|
||||
|
||||
@ -148,16 +149,23 @@ impl ParElem {
|
||||
fn cached(
|
||||
par: &ParElem,
|
||||
world: Tracked<dyn World + '_>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
styles: StyleChain,
|
||||
consecutive: bool,
|
||||
region: Size,
|
||||
expand: bool,
|
||||
) -> SourceResult<Fragment> {
|
||||
let mut locator = Locator::chained(locator);
|
||||
let mut vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
let children = par.children();
|
||||
|
||||
// Collect all text into one string for BiDi analysis.
|
||||
@ -178,9 +186,10 @@ impl ParElem {
|
||||
let fragment = cached(
|
||||
self,
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
vt.locator.track(),
|
||||
vt.introspector,
|
||||
vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
styles,
|
||||
consecutive,
|
||||
region,
|
||||
|
@ -96,11 +96,11 @@ impl BibliographyElem {
|
||||
pub fn find(introspector: Tracked<Introspector>) -> StrResult<Self> {
|
||||
let mut iter = introspector.query(&Self::func().select()).into_iter();
|
||||
let Some(elem) = iter.next() else {
|
||||
return Err("the document does not contain a bibliography".into());
|
||||
bail!("the document does not contain a bibliography");
|
||||
};
|
||||
|
||||
if iter.next().is_some() {
|
||||
Err("multiple bibliographies are not supported")?;
|
||||
bail!("multiple bibliographies are not supported");
|
||||
}
|
||||
|
||||
Ok(elem.to::<Self>().unwrap().clone())
|
||||
@ -162,42 +162,40 @@ impl Show for BibliographyElem {
|
||||
seq.push(HeadingElem::new(title).with_level(NonZeroUsize::ONE).pack());
|
||||
}
|
||||
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::sequence(seq));
|
||||
}
|
||||
Ok(vt.delayed(|vt| {
|
||||
let works = Works::new(vt).at(self.span())?;
|
||||
|
||||
let works = Works::new(vt).at(self.span())?;
|
||||
let row_gutter = BlockElem::below_in(styles).amount();
|
||||
if works.references.iter().any(|(prefix, _)| prefix.is_some()) {
|
||||
let mut cells = vec![];
|
||||
for (prefix, reference) in &works.references {
|
||||
cells.push(prefix.clone().unwrap_or_default());
|
||||
cells.push(reference.clone());
|
||||
}
|
||||
|
||||
let row_gutter = BlockElem::below_in(styles).amount();
|
||||
if works.references.iter().any(|(prefix, _)| prefix.is_some()) {
|
||||
let mut cells = vec![];
|
||||
for (prefix, reference) in &works.references {
|
||||
cells.push(prefix.clone().unwrap_or_default());
|
||||
cells.push(reference.clone());
|
||||
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||
seq.push(
|
||||
GridElem::new(cells)
|
||||
.with_columns(TrackSizings(vec![Sizing::Auto; 2]))
|
||||
.with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()]))
|
||||
.with_row_gutter(TrackSizings(vec![row_gutter.into()]))
|
||||
.pack(),
|
||||
);
|
||||
} else {
|
||||
let mut entries = vec![];
|
||||
for (_, reference) in &works.references {
|
||||
entries.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||
entries.push(reference.clone());
|
||||
}
|
||||
|
||||
seq.push(
|
||||
Content::sequence(entries)
|
||||
.styled(ParElem::set_hanging_indent(INDENT.into())),
|
||||
);
|
||||
}
|
||||
|
||||
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||
seq.push(
|
||||
GridElem::new(cells)
|
||||
.with_columns(TrackSizings(vec![Sizing::Auto; 2]))
|
||||
.with_column_gutter(TrackSizings(vec![COLUMN_GUTTER.into()]))
|
||||
.with_row_gutter(TrackSizings(vec![row_gutter.into()]))
|
||||
.pack(),
|
||||
);
|
||||
} else {
|
||||
let mut entries = vec![];
|
||||
for (_, reference) in &works.references {
|
||||
entries.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||
entries.push(reference.clone());
|
||||
}
|
||||
|
||||
seq.push(
|
||||
Content::sequence(entries)
|
||||
.styled(ParElem::set_hanging_indent(INDENT.into())),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Content::sequence(seq))
|
||||
Ok(Content::sequence(seq))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@ -357,19 +355,17 @@ impl Synthesize for CiteElem {
|
||||
impl Show for CiteElem {
|
||||
#[tracing::instrument(name = "CiteElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
|
||||
let works = Works::new(vt).at(self.span())?;
|
||||
let location = self.0.location().unwrap();
|
||||
works
|
||||
.citations
|
||||
.get(&location)
|
||||
.cloned()
|
||||
.flatten()
|
||||
.ok_or("bibliography does not contain this key")
|
||||
.at(self.span())
|
||||
Ok(vt.delayed(|vt| {
|
||||
let works = Works::new(vt).at(self.span())?;
|
||||
let location = self.0.location().unwrap();
|
||||
works
|
||||
.citations
|
||||
.get(&location)
|
||||
.cloned()
|
||||
.flatten()
|
||||
.ok_or("bibliography does not contain this key")
|
||||
.at(self.span())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,12 +73,10 @@ struct LocateElem {
|
||||
impl Show for LocateElem {
|
||||
#[tracing::instrument(name = "LocateElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
|
||||
let location = self.0.location().unwrap();
|
||||
Ok(self.func().call_vt(vt, [location])?.display())
|
||||
Ok(vt.delayed(|vt| {
|
||||
let location = self.0.location().unwrap();
|
||||
Ok(self.func().call_vt(vt, [location])?.display())
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@ use std::str::FromStr;
|
||||
use ecow::{eco_vec, EcoVec};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use typst::eval::Tracer;
|
||||
use typst::model::DelayedErrors;
|
||||
|
||||
use super::{FigureElem, HeadingElem, Numbering, NumberingPattern};
|
||||
use crate::layout::PageElem;
|
||||
@ -397,9 +398,10 @@ impl Counter {
|
||||
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
|
||||
self.sequence_impl(
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
vt.locator.track(),
|
||||
vt.introspector,
|
||||
vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
)
|
||||
}
|
||||
|
||||
@ -408,12 +410,19 @@ impl Counter {
|
||||
fn sequence_impl(
|
||||
&self,
|
||||
world: Tracked<dyn World + '_>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
) -> SourceResult<EcoVec<(CounterState, NonZeroUsize)>> {
|
||||
let mut locator = Locator::chained(locator);
|
||||
let mut vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
let mut state = CounterState(match &self.0 {
|
||||
// special case, because pages always start at one.
|
||||
CounterKey::Page => smallvec![1],
|
||||
@ -618,37 +627,36 @@ struct DisplayElem {
|
||||
impl Show for DisplayElem {
|
||||
#[tracing::instrument(name = "DisplayElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
Ok(vt.delayed(|vt| {
|
||||
let location = self.0.location().unwrap();
|
||||
let counter = self.counter();
|
||||
let numbering = self
|
||||
.numbering()
|
||||
.or_else(|| {
|
||||
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let location = self.0.location().unwrap();
|
||||
let counter = self.counter();
|
||||
let numbering = self
|
||||
.numbering()
|
||||
.or_else(|| {
|
||||
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
|
||||
return None;
|
||||
if func == HeadingElem::func() {
|
||||
HeadingElem::numbering_in(styles)
|
||||
} else if func == FigureElem::func() {
|
||||
FigureElem::numbering_in(styles)
|
||||
} else if func == EquationElem::func() {
|
||||
EquationElem::numbering_in(styles)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
|
||||
|
||||
let state = if self.both() {
|
||||
counter.both(vt, location)?
|
||||
} else {
|
||||
counter.at(vt, location)?
|
||||
};
|
||||
|
||||
if func == HeadingElem::func() {
|
||||
HeadingElem::numbering_in(styles)
|
||||
} else if func == FigureElem::func() {
|
||||
FigureElem::numbering_in(styles)
|
||||
} else if func == EquationElem::func() {
|
||||
EquationElem::numbering_in(styles)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
|
||||
|
||||
let state = if self.both() {
|
||||
counter.both(vt, location)?
|
||||
} else {
|
||||
counter.at(vt, location)?
|
||||
};
|
||||
state.display(vt, &numbering)
|
||||
state.display(vt, &numbering)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,21 +91,18 @@ impl Show for LinkElem {
|
||||
#[tracing::instrument(name = "LinkElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
let body = self.body();
|
||||
let dest = match self.dest() {
|
||||
LinkTarget::Dest(dest) => dest,
|
||||
LinkTarget::Label(label) => {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(body);
|
||||
}
|
||||
|
||||
let elem = vt.introspector.query_label(&label).at(self.span())?;
|
||||
Destination::Location(elem.location().unwrap())
|
||||
}
|
||||
let linked = match self.dest() {
|
||||
LinkTarget::Dest(dest) => body.linked(dest),
|
||||
LinkTarget::Label(label) => vt
|
||||
.delayed(|vt| {
|
||||
let elem = vt.introspector.query_label(&label).at(self.span())?;
|
||||
let dest = Destination::Location(elem.location().unwrap());
|
||||
Ok(Some(body.clone().linked(dest)))
|
||||
})
|
||||
.unwrap_or(body),
|
||||
};
|
||||
|
||||
Ok(body
|
||||
.linked(dest)
|
||||
.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))))
|
||||
Ok(linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ impl Synthesize for RefElem {
|
||||
self.push_element(None);
|
||||
|
||||
let target = self.target();
|
||||
if vt.introspector.init() && !BibliographyElem::has(vt, &target.0) {
|
||||
if !BibliographyElem::has(vt, &target.0) {
|
||||
if let Ok(elem) = vt.introspector.query_label(&target) {
|
||||
self.push_element(Some(elem.into_inner()));
|
||||
return Ok(());
|
||||
@ -146,63 +146,65 @@ impl Synthesize for RefElem {
|
||||
impl Show for RefElem {
|
||||
#[tracing::instrument(name = "RefElem::show", skip_all)]
|
||||
fn show(&self, vt: &mut Vt, styles: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
Ok(vt.delayed(|vt| {
|
||||
let target = self.target();
|
||||
let elem = vt.introspector.query_label(&self.target());
|
||||
let span = self.span();
|
||||
|
||||
let target = self.target();
|
||||
let elem = vt.introspector.query_label(&self.target());
|
||||
let span = self.span();
|
||||
if BibliographyElem::has(vt, &target.0) {
|
||||
if elem.is_ok() {
|
||||
bail!(span, "label occurs in the document and its bibliography");
|
||||
}
|
||||
|
||||
if BibliographyElem::has(vt, &target.0) {
|
||||
if elem.is_ok() {
|
||||
bail!(span, "label occurs in the document and its bibliography");
|
||||
return Ok(self.to_citation(vt, styles)?.pack().spanned(span));
|
||||
}
|
||||
|
||||
return Ok(self.to_citation(vt, styles)?.pack().spanned(span));
|
||||
}
|
||||
let elem = elem.at(span)?;
|
||||
let refable = elem
|
||||
.with::<dyn Refable>()
|
||||
.ok_or_else(|| {
|
||||
if elem.can::<dyn Figurable>() {
|
||||
eco_format!(
|
||||
"cannot reference {} directly, try putting it into a figure",
|
||||
elem.func().name()
|
||||
)
|
||||
} else {
|
||||
eco_format!("cannot reference {}", elem.func().name())
|
||||
}
|
||||
})
|
||||
.at(span)?;
|
||||
|
||||
let elem = elem.at(span)?;
|
||||
let refable = elem
|
||||
.with::<dyn Refable>()
|
||||
.ok_or_else(|| {
|
||||
if elem.can::<dyn Figurable>() {
|
||||
let numbering = refable
|
||||
.numbering()
|
||||
.ok_or_else(|| {
|
||||
eco_format!(
|
||||
"cannot reference {} directly, try putting it into a figure",
|
||||
"cannot reference {0} without numbering \
|
||||
- did you mean to use `#set {0}(numbering: \"1.\")`?",
|
||||
elem.func().name()
|
||||
)
|
||||
} else {
|
||||
eco_format!("cannot reference {}", elem.func().name())
|
||||
})
|
||||
.at(span)?;
|
||||
|
||||
let numbers = refable
|
||||
.counter()
|
||||
.at(vt, elem.location().unwrap())?
|
||||
.display(vt, &numbering.trimmed())?;
|
||||
|
||||
let supplement = match self.supplement(styles) {
|
||||
Smart::Auto => refable.supplement(),
|
||||
Smart::Custom(None) => Content::empty(),
|
||||
Smart::Custom(Some(supplement)) => {
|
||||
supplement.resolve(vt, [(*elem).clone()])?
|
||||
}
|
||||
})
|
||||
.at(span)?;
|
||||
};
|
||||
|
||||
let numbering = refable
|
||||
.numbering()
|
||||
.ok_or_else(|| {
|
||||
eco_format!("cannot reference {0} without numbering - did you mean to use `#set {0}(numbering: \"1.\")`?", elem.func().name())
|
||||
})
|
||||
.at(span)?;
|
||||
|
||||
let numbers = refable
|
||||
.counter()
|
||||
.at(vt, elem.location().unwrap())?
|
||||
.display(vt, &numbering.trimmed())?;
|
||||
|
||||
let supplement = match self.supplement(styles) {
|
||||
Smart::Auto => refable.supplement(),
|
||||
Smart::Custom(None) => Content::empty(),
|
||||
Smart::Custom(Some(supplement)) => {
|
||||
supplement.resolve(vt, [(*elem).clone()])?
|
||||
let mut content = numbers;
|
||||
if !supplement.is_empty() {
|
||||
content = supplement + TextElem::packed("\u{a0}") + content;
|
||||
}
|
||||
};
|
||||
|
||||
let mut content = numbers;
|
||||
if !supplement.is_empty() {
|
||||
content = supplement + TextElem::packed("\u{a0}") + content;
|
||||
}
|
||||
|
||||
Ok(content.linked(Destination::Location(elem.location().unwrap())))
|
||||
Ok(content.linked(Destination::Location(elem.location().unwrap())))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ use std::fmt::{self, Debug, Formatter, Write};
|
||||
|
||||
use ecow::{eco_vec, EcoVec};
|
||||
use typst::eval::Tracer;
|
||||
use typst::model::DelayedErrors;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
@ -306,9 +307,10 @@ impl State {
|
||||
fn sequence(&self, vt: &mut Vt) -> SourceResult<EcoVec<Value>> {
|
||||
self.sequence_impl(
|
||||
vt.world,
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
vt.locator.track(),
|
||||
vt.introspector,
|
||||
vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
)
|
||||
}
|
||||
|
||||
@ -317,12 +319,19 @@ impl State {
|
||||
fn sequence_impl(
|
||||
&self,
|
||||
world: Tracked<dyn World + '_>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
) -> SourceResult<EcoVec<Value>> {
|
||||
let mut locator = Locator::chained(locator);
|
||||
let mut vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let mut vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
let mut state = self.init.clone();
|
||||
let mut stops = eco_vec![state.clone()];
|
||||
|
||||
@ -397,16 +406,14 @@ struct DisplayElem {
|
||||
impl Show for DisplayElem {
|
||||
#[tracing::instrument(name = "DisplayElem::show", skip(self, vt))]
|
||||
fn show(&self, vt: &mut Vt, _: StyleChain) -> SourceResult<Content> {
|
||||
if !vt.introspector.init() {
|
||||
return Ok(Content::empty());
|
||||
}
|
||||
|
||||
let location = self.0.location().unwrap();
|
||||
let value = self.state().at(vt, location)?;
|
||||
Ok(match self.func() {
|
||||
Some(func) => func.call_vt(vt, [value])?.display(),
|
||||
None => value.display(),
|
||||
})
|
||||
Ok(vt.delayed(|vt| {
|
||||
let location = self.0.location().unwrap();
|
||||
let value = self.state().at(vt, location)?;
|
||||
Ok(match self.func() {
|
||||
Some(func) => func.call_vt(vt, [value])?.display(),
|
||||
None => value.display(),
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ use super::{
|
||||
Value, Vm,
|
||||
};
|
||||
use crate::diag::{bail, SourceResult, StrResult};
|
||||
use crate::model::{ElemFunc, Introspector, Locator, Vt};
|
||||
use crate::model::{DelayedErrors, ElemFunc, Introspector, Locator, Vt};
|
||||
use crate::syntax::ast::{self, AstNode, Expr, Ident};
|
||||
use crate::syntax::{SourceId, Span, SyntaxNode};
|
||||
use crate::World;
|
||||
@ -102,9 +102,10 @@ impl Func {
|
||||
self,
|
||||
vm.world(),
|
||||
route,
|
||||
TrackedMut::reborrow_mut(&mut vm.vt.tracer),
|
||||
vm.vt.locator.track(),
|
||||
vm.vt.introspector,
|
||||
vm.vt.locator.track(),
|
||||
TrackedMut::reborrow_mut(&mut vm.vt.delayed),
|
||||
TrackedMut::reborrow_mut(&mut vm.vt.tracer),
|
||||
vm.depth + 1,
|
||||
args,
|
||||
)
|
||||
@ -129,9 +130,10 @@ impl Func {
|
||||
let mut locator = Locator::chained(vt.locator.track());
|
||||
let vt = Vt {
|
||||
world: vt.world,
|
||||
tracer: TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
locator: &mut locator,
|
||||
introspector: vt.introspector,
|
||||
locator: &mut locator,
|
||||
delayed: TrackedMut::reborrow_mut(&mut vt.delayed),
|
||||
tracer: TrackedMut::reborrow_mut(&mut vt.tracer),
|
||||
};
|
||||
let mut vm = Vm::new(vt, route.track(), id, scopes);
|
||||
let args = Args::new(self.span(), args);
|
||||
@ -326,9 +328,10 @@ impl Closure {
|
||||
this: &Func,
|
||||
world: Tracked<dyn World + '_>,
|
||||
route: Tracked<Route>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
locator: Tracked<Locator>,
|
||||
introspector: Tracked<Introspector>,
|
||||
locator: Tracked<Locator>,
|
||||
delayed: TrackedMut<DelayedErrors>,
|
||||
tracer: TrackedMut<Tracer>,
|
||||
depth: usize,
|
||||
mut args: Args,
|
||||
) -> SourceResult<Value> {
|
||||
@ -344,7 +347,13 @@ impl Closure {
|
||||
|
||||
// Prepare VT.
|
||||
let mut locator = Locator::chained(locator);
|
||||
let vt = Vt { world, tracer, locator: &mut locator, introspector };
|
||||
let vt = Vt {
|
||||
world,
|
||||
introspector,
|
||||
locator: &mut locator,
|
||||
delayed,
|
||||
tracer,
|
||||
};
|
||||
|
||||
// Prepare VM.
|
||||
let mut vm = Vm::new(vt, route, closure.location, scopes);
|
||||
|
@ -62,9 +62,6 @@ use ecow::{EcoString, EcoVec};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use self::func::{CapturesVisitor, Closure};
|
||||
use crate::diag::{
|
||||
bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint,
|
||||
};
|
||||
use crate::model::{
|
||||
Content, Introspector, Label, Locator, Recipe, ShowableSelector, Styles, Transform,
|
||||
Unlabellable, Vt,
|
||||
@ -75,6 +72,10 @@ use crate::syntax::{
|
||||
};
|
||||
use crate::util::PathExt;
|
||||
use crate::World;
|
||||
use crate::{
|
||||
diag::{bail, error, At, SourceError, SourceResult, StrResult, Trace, Tracepoint},
|
||||
model::DelayedErrors,
|
||||
};
|
||||
|
||||
const MAX_ITERATIONS: usize = 10_000;
|
||||
const MAX_CALL_DEPTH: usize = 64;
|
||||
@ -102,11 +103,13 @@ pub fn eval(
|
||||
// Prepare VT.
|
||||
let mut locator = Locator::default();
|
||||
let introspector = Introspector::default();
|
||||
let mut delayed = DelayedErrors::default();
|
||||
let vt = Vt {
|
||||
world,
|
||||
tracer,
|
||||
locator: &mut locator,
|
||||
introspector: introspector.track(),
|
||||
locator: &mut locator,
|
||||
delayed: delayed.track_mut(),
|
||||
tracer,
|
||||
};
|
||||
|
||||
// Prepare VM.
|
||||
@ -151,12 +154,14 @@ pub fn eval_string(
|
||||
// Prepare VT.
|
||||
let mut tracer = Tracer::default();
|
||||
let mut locator = Locator::default();
|
||||
let mut delayed = DelayedErrors::default();
|
||||
let introspector = Introspector::default();
|
||||
let vt = Vt {
|
||||
world,
|
||||
tracer: tracer.track_mut(),
|
||||
locator: &mut locator,
|
||||
introspector: introspector.track(),
|
||||
locator: &mut locator,
|
||||
delayed: delayed.track_mut(),
|
||||
tracer: tracer.track_mut(),
|
||||
};
|
||||
|
||||
// Prepare VM.
|
||||
|
@ -241,11 +241,6 @@ impl Introspector {
|
||||
|
||||
#[comemo::track]
|
||||
impl Introspector {
|
||||
/// Whether this introspector is not yet initialized.
|
||||
pub fn init(&self) -> bool {
|
||||
self.pages > 0
|
||||
}
|
||||
|
||||
/// Query for all matching elements.
|
||||
pub fn query(&self, selector: &Selector) -> EcoVec<Prehashed<Content>> {
|
||||
let hash = crate::util::hash128(selector);
|
||||
|
@ -28,7 +28,7 @@ use std::mem::ManuallyDrop;
|
||||
|
||||
use comemo::{Track, Tracked, TrackedMut, Validate};
|
||||
|
||||
use crate::diag::SourceResult;
|
||||
use crate::diag::{SourceError, SourceResult};
|
||||
use crate::doc::Document;
|
||||
use crate::eval::Tracer;
|
||||
use crate::World;
|
||||
@ -46,8 +46,9 @@ pub fn typeset(
|
||||
let library = world.library();
|
||||
let styles = StyleChain::new(&library.styles);
|
||||
|
||||
let mut document;
|
||||
let mut iter = 0;
|
||||
let mut document;
|
||||
let mut delayed;
|
||||
|
||||
// We need `ManuallyDrop` until this lands in stable:
|
||||
// https://github.com/rust-lang/rust/issues/70919
|
||||
@ -58,6 +59,8 @@ pub fn typeset(
|
||||
loop {
|
||||
tracing::info!("Layout iteration {iter}");
|
||||
|
||||
delayed = DelayedErrors::default();
|
||||
|
||||
let constraint = <Introspector as Validate>::Constraint::new();
|
||||
let mut locator = Locator::new();
|
||||
let mut vt = Vt {
|
||||
@ -65,6 +68,7 @@ pub fn typeset(
|
||||
tracer: TrackedMut::reborrow_mut(&mut tracer),
|
||||
locator: &mut locator,
|
||||
introspector: introspector.track_with(&constraint),
|
||||
delayed: delayed.track_mut(),
|
||||
};
|
||||
|
||||
// Layout!
|
||||
@ -86,6 +90,11 @@ pub fn typeset(
|
||||
// Drop the introspector.
|
||||
ManuallyDrop::into_inner(introspector);
|
||||
|
||||
// Promote delayed errors.
|
||||
if !delayed.0.is_empty() {
|
||||
return Err(Box::new(delayed.0));
|
||||
}
|
||||
|
||||
Ok(document)
|
||||
}
|
||||
|
||||
@ -95,10 +104,45 @@ pub fn typeset(
|
||||
pub struct Vt<'a> {
|
||||
/// The compilation environment.
|
||||
pub world: Tracked<'a, dyn World + 'a>,
|
||||
/// The tracer for inspection of the values an expression produces.
|
||||
pub tracer: TrackedMut<'a, Tracer>,
|
||||
/// Provides stable identities to elements.
|
||||
pub locator: &'a mut Locator<'a>,
|
||||
/// Provides access to information about the document.
|
||||
pub introspector: Tracked<'a, Introspector>,
|
||||
/// Provides stable identities to elements.
|
||||
pub locator: &'a mut Locator<'a>,
|
||||
/// Delayed errors that do not immediately terminate execution.
|
||||
pub delayed: TrackedMut<'a, DelayedErrors>,
|
||||
/// The tracer for inspection of the values an expression produces.
|
||||
pub tracer: TrackedMut<'a, Tracer>,
|
||||
}
|
||||
|
||||
impl Vt<'_> {
|
||||
/// Perform a fallible operation that does not immediately terminate further
|
||||
/// execution. Instead it produces a delayed error that is only promoted to
|
||||
/// a fatal one if it remains at the end of the introspection loop.
|
||||
pub fn delayed<F, T>(&mut self, f: F) -> T
|
||||
where
|
||||
F: FnOnce(&mut Self) -> SourceResult<T>,
|
||||
T: Default,
|
||||
{
|
||||
match f(self) {
|
||||
Ok(value) => value,
|
||||
Err(errors) => {
|
||||
for error in *errors {
|
||||
self.delayed.push(error);
|
||||
}
|
||||
T::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Holds delayed errors.
|
||||
#[derive(Default, Clone)]
|
||||
pub struct DelayedErrors(Vec<SourceError>);
|
||||
|
||||
#[comemo::track]
|
||||
impl DelayedErrors {
|
||||
/// Push a delayed error.
|
||||
fn push(&mut self, error: SourceError) {
|
||||
self.0.push(error);
|
||||
}
|
||||
}
|
||||
|
BIN
tests/ref/bugs/cite-locate.png
Normal file
BIN
tests/ref/bugs/cite-locate.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
23
tests/typ/bugs/cite-locate.typ
Normal file
23
tests/typ/bugs/cite-locate.typ
Normal file
@ -0,0 +1,23 @@
|
||||
// Test citation in other introspection.
|
||||
|
||||
---
|
||||
#set page(width: 180pt)
|
||||
#set heading(numbering: "1")
|
||||
|
||||
#outline(
|
||||
title: [List of Figures],
|
||||
target: figure.where(kind: image),
|
||||
)
|
||||
|
||||
#pagebreak()
|
||||
|
||||
= Introduction <intro>
|
||||
#figure(
|
||||
rect[-- PIRATE --],
|
||||
caption: [A pirate @arrgh in @intro],
|
||||
)
|
||||
|
||||
#locate(loc => [Citation @distress on page #loc.page()])
|
||||
|
||||
#pagebreak()
|
||||
#bibliography("/works.bib", style: "chicago-notes")
|
Loading…
x
Reference in New Issue
Block a user