Delay errors for all show rules (#3323)

This commit is contained in:
Laurenz 2024-02-05 10:56:09 +01:00 committed by GitHub
parent 6a9866dc80
commit 302b870321
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 190 additions and 194 deletions

View File

@ -635,7 +635,6 @@ struct DisplayElem {
impl Show for Packed<DisplayElem> {
#[typst_macros::time(name = "counter.display", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let location = self.location().unwrap();
let counter = self.counter();
let numbering = self
@ -665,7 +664,6 @@ impl Show for Packed<DisplayElem> {
};
state.display(engine, &numbering)
}))
}
}

View File

@ -44,9 +44,7 @@ struct LocateElem {
impl Show for Packed<LocateElem> {
#[typst_macros::time(name = "locate", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let location = self.location().unwrap();
Ok(self.func().call(engine, [location])?.display())
}))
}
}

View File

@ -388,14 +388,12 @@ struct DisplayElem {
impl Show for Packed<DisplayElem> {
#[typst_macros::time(name = "state.display", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let location = self.location().unwrap();
let value = self.state().at(engine, location)?;
Ok(match self.func() {
Some(func) => func.call(engine, [value])?.display(),
None => value.display(),
})
}))
}
}

View File

@ -225,7 +225,6 @@ impl Show for Packed<BibliographyElem> {
);
}
Ok(engine.delayed(|engine| {
let span = self.span();
let works = Works::generate(engine.world, engine.introspector).at(span)?;
let references = works
@ -242,9 +241,7 @@ impl Show for Packed<BibliographyElem> {
Packed::new(GridCell::new(prefix.clone().unwrap_or_default()))
.spanned(span),
);
cells.push(
Packed::new(GridCell::new(reference.clone())).spanned(span),
);
cells.push(Packed::new(GridCell::new(reference.clone())).spanned(span));
}
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
@ -269,7 +266,6 @@ impl Show for Packed<BibliographyElem> {
}
Ok(content)
}))
}
}

View File

@ -152,7 +152,6 @@ pub struct CiteGroup {
impl Show for Packed<CiteGroup> {
#[typst_macros::time(name = "cite", span = self.span())]
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let location = self.location().unwrap();
let span = self.span();
Works::generate(engine.world, engine.introspector)
@ -160,9 +159,6 @@ impl Show for Packed<CiteGroup> {
.citations
.get(&location)
.cloned()
.unwrap_or_else(|| {
bail!(span, "failed to format citation (this is a bug)")
})
}))
.unwrap_or_else(|| bail!(span, "failed to format citation (this is a bug)"))
}
}

View File

@ -126,7 +126,6 @@ impl Packed<FootnoteElem> {
impl Show for Packed<FootnoteElem> {
#[typst_macros::time(name = "footnote", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let loc = self.declaration_location(engine).at(self.span())?;
let numbering = self.numbering(styles);
let counter = Counter::of(FootnoteElem::elem());
@ -135,7 +134,6 @@ impl Show for Packed<FootnoteElem> {
let loc = loc.variant(1);
// Add zero-width weak spacing to make the footnote "sticky".
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc)))
}))
}
}

View File

@ -95,13 +95,11 @@ impl Show for Packed<LinkElem> {
let body = self.body().clone();
let linked = match self.dest() {
LinkTarget::Dest(dest) => body.linked(dest.clone()),
LinkTarget::Label(label) => engine
.delayed(|engine| {
LinkTarget::Label(label) => {
let elem = engine.introspector.query_label(*label).at(self.span())?;
let dest = Destination::Location(elem.location().unwrap());
Ok(Some(body.clone().linked(dest)))
})
.unwrap_or(body),
body.clone().linked(dest)
}
};
Ok(linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))))

View File

@ -163,7 +163,6 @@ impl Synthesize for Packed<RefElem> {
impl Show for Packed<RefElem> {
#[typst_macros::time(name = "ref", span = self.span())]
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
Ok(engine.delayed(|engine| {
let target = *self.target();
let elem = engine.introspector.query_label(target);
let span = self.span();
@ -200,10 +199,7 @@ impl Show for Packed<RefElem> {
let numbering = refable
.numbering()
.ok_or_else(|| {
eco_format!(
"cannot reference {} without numbering",
elem.func().name()
)
eco_format!("cannot reference {} without numbering", elem.func().name())
})
.hint(eco_format!(
"you can enable {} numbering with `#set {}(numbering: \"1.\")`",
@ -234,7 +230,6 @@ impl Show for Packed<RefElem> {
}
Ok(content.linked(Destination::Location(loc)))
}))
}
}

View File

@ -92,18 +92,17 @@ pub fn realize(
meta = prepare(engine, &mut target, &mut map, styles)?;
}
// Apply the step.
// Apply a step, if there is one.
let mut output = match step {
// Apply a user-defined show rule.
Some(Step::Recipe(recipe, guard)) => show(engine, target, recipe, guard)?,
// If the verdict picks this step, the `target` is guaranteed
// to have a built-in show rule.
Some(Step::Builtin) => {
target.with::<dyn Show>().unwrap().show(engine, styles.chain(&map))?
Some(step) => {
// Errors in show rules don't terminate compilation immediately. We
// just continue with empty content for them and show all errors
// together, if they remain by the end of the introspection loop.
//
// This way, we can ignore errors that only occur in earlier
// iterations and also show more useful errors at once.
engine.delayed(|engine| show(engine, target, step, styles.chain(&map)))
}
// Nothing to do.
None => target,
};
@ -122,12 +121,12 @@ struct Verdict<'a> {
prepared: bool,
/// A map of styles to apply to the element.
map: Styles,
/// An optional transformation step to apply to the element.
step: Option<Step<'a>>,
/// An optional show rule transformation to apply to the element.
step: Option<ShowStep<'a>>,
}
/// An optional transformation step to apply to an element.
enum Step<'a> {
/// An optional show rule transformation to apply to the element.
enum ShowStep<'a> {
/// A user-defined transformational show rule.
Recipe(&'a Recipe, RecipeIndex),
/// The built-in show rule.
@ -200,7 +199,7 @@ fn verdict<'a>(
// If we find a matching, unguarded replacement show rule,
// remember it, but still continue searching for potential
// show-set styles that might change the verdict.
step = Some(Step::Recipe(recipe, index));
step = Some(ShowStep::Recipe(recipe, index));
// If we found a show rule and are already prepared, there is
// nothing else to do, so we can just break.
@ -215,7 +214,7 @@ fn verdict<'a>(
// If we found no user-defined rule, also consider the built-in show rule.
if step.is_none() && target.can::<dyn Show>() {
step = Some(Step::Builtin);
step = Some(ShowStep::Builtin);
}
// If there's no nothing to do, there is also no verdict.
@ -286,21 +285,30 @@ fn prepare(
Ok(None)
}
/// Apply a user-defined show rule.
/// Apply a step.
fn show(
engine: &mut Engine,
target: Content,
recipe: &Recipe,
index: RecipeIndex,
step: ShowStep,
styles: StyleChain,
) -> SourceResult<Content> {
match &recipe.selector {
match step {
// Apply a user-defined show rule.
ShowStep::Recipe(recipe, guard) => match &recipe.selector {
// If the selector is a regex, the `target` is guaranteed to be a
// text element. This invokes special regex handling.
Some(Selector::Regex(regex)) => {
// If the verdict picks this rule, the `target` is guaranteed
// to be a text element.
let text = target.into_packed::<TextElem>().unwrap();
show_regex(engine, &text, regex, recipe, index)
show_regex(engine, &text, regex, recipe, guard)
}
_ => recipe.apply(engine, target.guarded(index)),
// Just apply the recipe.
_ => recipe.apply(engine, target.guarded(guard)),
},
// If the verdict picks this step, the `target` is guaranteed to have a
// built-in show rule.
ShowStep::Builtin => target.with::<dyn Show>().unwrap().show(engine, styles),
}
}

View File

@ -0,0 +1,11 @@
// Test that errors in show rules are delayed: There can be multiple at once.
---
// Error: 26-34 panicked with: "hey1"
#show heading: _ => panic("hey1")
// Error: 25-33 panicked with: "hey2"
#show strong: _ => panic("hey2")
= Hello
*strong*