mirror of
https://github.com/typst/typst
synced 2025-06-15 16:46:24 +08:00
Guard against recursive built-in show rules again
This commit is contained in:
parent
3a12749bf1
commit
8d495f952c
@ -529,6 +529,11 @@ impl Debug for Recipe {
|
|||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct RecipeIndex(pub usize);
|
pub struct RecipeIndex(pub usize);
|
||||||
|
|
||||||
|
impl RecipeIndex {
|
||||||
|
/// The index reserved for a potential built-in recipe.
|
||||||
|
pub const BUILTIN: Self = Self(1);
|
||||||
|
}
|
||||||
|
|
||||||
/// A show rule transformation that can be applied to a match.
|
/// A show rule transformation that can be applied to a match.
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, PartialEq, Hash)]
|
||||||
pub enum Transformation {
|
pub enum Transformation {
|
||||||
|
@ -348,13 +348,13 @@ fn visit_show_rules<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create a fresh copy that we can mutate.
|
// Create a fresh copy that we can mutate.
|
||||||
let mut output = Cow::Borrowed(content);
|
let mut output = content.clone();
|
||||||
|
|
||||||
// If the element isn't yet prepared (we're seeing it for the first time),
|
// If the element isn't yet prepared (we're seeing it for the first time),
|
||||||
// prepare it.
|
// prepare it.
|
||||||
let mut tag = None;
|
let mut tag = None;
|
||||||
if !prepared {
|
if !prepared {
|
||||||
tag = prepare(s.engine, s.locator, output.to_mut(), &mut map, styles)?;
|
tag = prepare(s.engine, s.locator, &mut output, &mut map, styles)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply a show rule step, if there is one.
|
// Apply a show rule step, if there is one.
|
||||||
@ -364,17 +364,15 @@ fn visit_show_rules<'a>(
|
|||||||
// Apply a user-defined show rule.
|
// Apply a user-defined show rule.
|
||||||
ShowStep::Recipe(recipe, guard) => {
|
ShowStep::Recipe(recipe, guard) => {
|
||||||
let context = Context::new(output.location(), Some(chained));
|
let context = Context::new(output.location(), Some(chained));
|
||||||
recipe.apply(
|
recipe.apply(s.engine, context.track(), output.guarded(guard))
|
||||||
s.engine,
|
|
||||||
context.track(),
|
|
||||||
output.into_owned().guarded(guard),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply a built-in show rule.
|
// Apply a built-in show rule.
|
||||||
ShowStep::Builtin => {
|
ShowStep::Builtin => output
|
||||||
output.with::<dyn Show>().unwrap().show(s.engine, chained)
|
.guarded(RecipeIndex::BUILTIN)
|
||||||
}
|
.with::<dyn Show>()
|
||||||
|
.unwrap()
|
||||||
|
.show(s.engine, chained),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Errors in show rules don't terminate compilation immediately. We just
|
// Errors in show rules don't terminate compilation immediately. We just
|
||||||
@ -383,15 +381,9 @@ fn visit_show_rules<'a>(
|
|||||||
//
|
//
|
||||||
// This way, we can ignore errors that only occur in earlier iterations
|
// This way, we can ignore errors that only occur in earlier iterations
|
||||||
// and also show more useful errors at once.
|
// and also show more useful errors at once.
|
||||||
output = Cow::Owned(s.engine.delay(result));
|
output = s.engine.delay(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lifetime-extend the realized content if necessary.
|
|
||||||
let realized = match output {
|
|
||||||
Cow::Borrowed(realized) => realized,
|
|
||||||
Cow::Owned(realized) => s.store(realized),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Push start tag.
|
// Push start tag.
|
||||||
if let Some(tag) = &tag {
|
if let Some(tag) = &tag {
|
||||||
let start_tag = TagElem::packed(tag.clone());
|
let start_tag = TagElem::packed(tag.clone());
|
||||||
@ -403,7 +395,7 @@ fn visit_show_rules<'a>(
|
|||||||
s.engine.route.increase();
|
s.engine.route.increase();
|
||||||
s.engine.route.check_show_depth().at(content.span())?;
|
s.engine.route.check_show_depth().at(content.span())?;
|
||||||
|
|
||||||
visit_styled(s, realized, Cow::Owned(map), styles)?;
|
visit_styled(s, s.store(output), Cow::Owned(map), styles)?;
|
||||||
|
|
||||||
s.outside = prev_outside;
|
s.outside = prev_outside;
|
||||||
s.engine.route.decrease();
|
s.engine.route.decrease();
|
||||||
@ -443,11 +435,12 @@ fn verdict<'a>(
|
|||||||
target = &slot;
|
target = &slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lazily computes the total number of recipes in the style chain. We need
|
// Lazily computes the total number of recipes in the style chain, plus one
|
||||||
// it to determine whether a particular show rule was already applied to the
|
// for the built-in recipe. We need it to determine whether a particular
|
||||||
// `target` previously. For this purpose, show rules are indexed from the
|
// show rule was already applied to the `target` previously. For this
|
||||||
// top of the chain as the chain might grow to the bottom.
|
// purpose, show rules are indexed from the top of the chain as the chain
|
||||||
let depth = Lazy::new(|| styles.recipes().count());
|
// might grow to the bottom.
|
||||||
|
let depth = Lazy::new(|| 1 + styles.recipes().count());
|
||||||
|
|
||||||
for (r, recipe) in styles.recipes().enumerate() {
|
for (r, recipe) in styles.recipes().enumerate() {
|
||||||
// We're not interested in recipes that don't match.
|
// We're not interested in recipes that don't match.
|
||||||
@ -489,7 +482,10 @@ fn verdict<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If we found no user-defined rule, also consider the built-in show rule.
|
// If we found no user-defined rule, also consider the built-in show rule.
|
||||||
if step.is_none() && target.can::<dyn Show>() {
|
if step.is_none()
|
||||||
|
&& target.can::<dyn Show>()
|
||||||
|
&& !target.is_guarded(RecipeIndex::BUILTIN)
|
||||||
|
{
|
||||||
step = Some(ShowStep::Builtin);
|
step = Some(ShowStep::Builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1058,7 +1054,7 @@ fn find_regex_match_in_str<'a>(
|
|||||||
let mut revoked = SmallBitSet::new();
|
let mut revoked = SmallBitSet::new();
|
||||||
let mut leftmost: Option<(regex::Match, RecipeIndex, &Recipe)> = None;
|
let mut leftmost: Option<(regex::Match, RecipeIndex, &Recipe)> = None;
|
||||||
|
|
||||||
let depth = Lazy::new(|| styles.recipes().count());
|
let depth = Lazy::new(|| 1 + styles.recipes().count());
|
||||||
|
|
||||||
for entry in styles.entries() {
|
for entry in styles.entries() {
|
||||||
let recipe = match &**entry {
|
let recipe = match &**entry {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user