mirror of
https://github.com/typst/typst
synced 2025-05-20 03:55:29 +08:00
Delay errors for all show rules (#3323)
This commit is contained in:
parent
6a9866dc80
commit
302b870321
@ -635,37 +635,35 @@ struct DisplayElem {
|
|||||||
impl Show for Packed<DisplayElem> {
|
impl Show for Packed<DisplayElem> {
|
||||||
#[typst_macros::time(name = "counter.display", span = self.span())]
|
#[typst_macros::time(name = "counter.display", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let location = self.location().unwrap();
|
||||||
let location = self.location().unwrap();
|
let counter = self.counter();
|
||||||
let counter = self.counter();
|
let numbering = self
|
||||||
let numbering = self
|
.numbering()
|
||||||
.numbering()
|
.clone()
|
||||||
.clone()
|
.or_else(|| {
|
||||||
.or_else(|| {
|
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
|
||||||
let CounterKey::Selector(Selector::Elem(func, _)) = counter.0 else {
|
return None;
|
||||||
return None;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
if func == HeadingElem::elem() {
|
if func == HeadingElem::elem() {
|
||||||
HeadingElem::numbering_in(styles).clone()
|
HeadingElem::numbering_in(styles).clone()
|
||||||
} else if func == FigureElem::elem() {
|
} else if func == FigureElem::elem() {
|
||||||
FigureElem::numbering_in(styles).clone()
|
FigureElem::numbering_in(styles).clone()
|
||||||
} else if func == EquationElem::elem() {
|
} else if func == EquationElem::elem() {
|
||||||
EquationElem::numbering_in(styles).clone()
|
EquationElem::numbering_in(styles).clone()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
|
.unwrap_or_else(|| NumberingPattern::from_str("1.1").unwrap().into());
|
||||||
|
|
||||||
let state = if *self.both() {
|
let state = if *self.both() {
|
||||||
counter.both(engine, location)?
|
counter.both(engine, location)?
|
||||||
} else {
|
} else {
|
||||||
counter.at(engine, location)?
|
counter.at(engine, location)?
|
||||||
};
|
};
|
||||||
|
|
||||||
state.display(engine, &numbering)
|
state.display(engine, &numbering)
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +44,7 @@ struct LocateElem {
|
|||||||
impl Show for Packed<LocateElem> {
|
impl Show for Packed<LocateElem> {
|
||||||
#[typst_macros::time(name = "locate", span = self.span())]
|
#[typst_macros::time(name = "locate", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let location = self.location().unwrap();
|
||||||
let location = self.location().unwrap();
|
Ok(self.func().call(engine, [location])?.display())
|
||||||
Ok(self.func().call(engine, [location])?.display())
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,14 +388,12 @@ struct DisplayElem {
|
|||||||
impl Show for Packed<DisplayElem> {
|
impl Show for Packed<DisplayElem> {
|
||||||
#[typst_macros::time(name = "state.display", span = self.span())]
|
#[typst_macros::time(name = "state.display", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let location = self.location().unwrap();
|
||||||
let location = self.location().unwrap();
|
let value = self.state().at(engine, location)?;
|
||||||
let value = self.state().at(engine, location)?;
|
Ok(match self.func() {
|
||||||
Ok(match self.func() {
|
Some(func) => func.call(engine, [value])?.display(),
|
||||||
Some(func) => func.call(engine, [value])?.display(),
|
None => value.display(),
|
||||||
None => value.display(),
|
})
|
||||||
})
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,51 +225,47 @@ impl Show for Packed<BibliographyElem> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(engine.delayed(|engine| {
|
let span = self.span();
|
||||||
let span = self.span();
|
let works = Works::generate(engine.world, engine.introspector).at(span)?;
|
||||||
let works = Works::generate(engine.world, engine.introspector).at(span)?;
|
let references = works
|
||||||
let references = works
|
.references
|
||||||
.references
|
.as_ref()
|
||||||
.as_ref()
|
.ok_or("CSL style is not suitable for bibliographies")
|
||||||
.ok_or("CSL style is not suitable for bibliographies")
|
.at(span)?;
|
||||||
.at(span)?;
|
|
||||||
|
|
||||||
let row_gutter = *BlockElem::below_in(styles).amount();
|
let row_gutter = *BlockElem::below_in(styles).amount();
|
||||||
if references.iter().any(|(prefix, _)| prefix.is_some()) {
|
if references.iter().any(|(prefix, _)| prefix.is_some()) {
|
||||||
let mut cells = vec![];
|
let mut cells = vec![];
|
||||||
for (prefix, reference) in references {
|
for (prefix, reference) in references {
|
||||||
cells.push(
|
cells.push(
|
||||||
Packed::new(GridCell::new(prefix.clone().unwrap_or_default()))
|
Packed::new(GridCell::new(prefix.clone().unwrap_or_default()))
|
||||||
.spanned(span),
|
.spanned(span),
|
||||||
);
|
|
||||||
cells.push(
|
|
||||||
Packed::new(GridCell::new(reference.clone())).spanned(span),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
|
||||||
seq.push(
|
|
||||||
GridElem::new(cells)
|
|
||||||
.with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
|
|
||||||
.with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
|
|
||||||
.with_row_gutter(TrackSizings(smallvec![(row_gutter).into()]))
|
|
||||||
.pack()
|
|
||||||
.spanned(self.span()),
|
|
||||||
);
|
);
|
||||||
} else {
|
cells.push(Packed::new(GridCell::new(reference.clone())).spanned(span));
|
||||||
for (_, reference) in references {
|
|
||||||
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
|
||||||
seq.push(reference.clone());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut content = Content::sequence(seq);
|
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||||
if works.hanging_indent {
|
seq.push(
|
||||||
content = content.styled(ParElem::set_hanging_indent(INDENT.into()));
|
GridElem::new(cells)
|
||||||
|
.with_columns(TrackSizings(smallvec![Sizing::Auto; 2]))
|
||||||
|
.with_column_gutter(TrackSizings(smallvec![COLUMN_GUTTER.into()]))
|
||||||
|
.with_row_gutter(TrackSizings(smallvec![(row_gutter).into()]))
|
||||||
|
.pack()
|
||||||
|
.spanned(self.span()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
for (_, reference) in references {
|
||||||
|
seq.push(VElem::new(row_gutter).with_weakness(3).pack());
|
||||||
|
seq.push(reference.clone());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(content)
|
let mut content = Content::sequence(seq);
|
||||||
}))
|
if works.hanging_indent {
|
||||||
|
content = content.styled(ParElem::set_hanging_indent(INDENT.into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(content)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,17 +152,13 @@ pub struct CiteGroup {
|
|||||||
impl Show for Packed<CiteGroup> {
|
impl Show for Packed<CiteGroup> {
|
||||||
#[typst_macros::time(name = "cite", span = self.span())]
|
#[typst_macros::time(name = "cite", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, _: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let location = self.location().unwrap();
|
||||||
let location = self.location().unwrap();
|
let span = self.span();
|
||||||
let span = self.span();
|
Works::generate(engine.world, engine.introspector)
|
||||||
Works::generate(engine.world, engine.introspector)
|
.at(span)?
|
||||||
.at(span)?
|
.citations
|
||||||
.citations
|
.get(&location)
|
||||||
.get(&location)
|
.cloned()
|
||||||
.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)")
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,16 +126,14 @@ impl Packed<FootnoteElem> {
|
|||||||
impl Show for Packed<FootnoteElem> {
|
impl Show for Packed<FootnoteElem> {
|
||||||
#[typst_macros::time(name = "footnote", span = self.span())]
|
#[typst_macros::time(name = "footnote", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let loc = self.declaration_location(engine).at(self.span())?;
|
||||||
let loc = self.declaration_location(engine).at(self.span())?;
|
let numbering = self.numbering(styles);
|
||||||
let numbering = self.numbering(styles);
|
let counter = Counter::of(FootnoteElem::elem());
|
||||||
let counter = Counter::of(FootnoteElem::elem());
|
let num = counter.at(engine, loc)?.display(engine, numbering)?;
|
||||||
let num = counter.at(engine, loc)?.display(engine, numbering)?;
|
let sup = SuperElem::new(num).pack().spanned(self.span());
|
||||||
let sup = SuperElem::new(num).pack().spanned(self.span());
|
let loc = loc.variant(1);
|
||||||
let loc = loc.variant(1);
|
// Add zero-width weak spacing to make the footnote "sticky".
|
||||||
// Add zero-width weak spacing to make the footnote "sticky".
|
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc)))
|
||||||
Ok(HElem::hole().pack() + sup.linked(Destination::Location(loc)))
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,13 +95,11 @@ impl Show for Packed<LinkElem> {
|
|||||||
let body = self.body().clone();
|
let body = self.body().clone();
|
||||||
let linked = match self.dest() {
|
let linked = match self.dest() {
|
||||||
LinkTarget::Dest(dest) => body.linked(dest.clone()),
|
LinkTarget::Dest(dest) => body.linked(dest.clone()),
|
||||||
LinkTarget::Label(label) => engine
|
LinkTarget::Label(label) => {
|
||||||
.delayed(|engine| {
|
let elem = engine.introspector.query_label(*label).at(self.span())?;
|
||||||
let elem = engine.introspector.query_label(*label).at(self.span())?;
|
let dest = Destination::Location(elem.location().unwrap());
|
||||||
let dest = Destination::Location(elem.location().unwrap());
|
body.clone().linked(dest)
|
||||||
Ok(Some(body.clone().linked(dest)))
|
}
|
||||||
})
|
|
||||||
.unwrap_or(body),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))))
|
Ok(linked.styled(TextElem::set_hyphenate(Hyphenate(Smart::Custom(false)))))
|
||||||
|
@ -163,78 +163,73 @@ impl Synthesize for Packed<RefElem> {
|
|||||||
impl Show for Packed<RefElem> {
|
impl Show for Packed<RefElem> {
|
||||||
#[typst_macros::time(name = "ref", span = self.span())]
|
#[typst_macros::time(name = "ref", span = self.span())]
|
||||||
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
fn show(&self, engine: &mut Engine, styles: StyleChain) -> SourceResult<Content> {
|
||||||
Ok(engine.delayed(|engine| {
|
let target = *self.target();
|
||||||
let target = *self.target();
|
let elem = engine.introspector.query_label(target);
|
||||||
let elem = engine.introspector.query_label(target);
|
let span = self.span();
|
||||||
let span = self.span();
|
|
||||||
|
|
||||||
if BibliographyElem::has(engine, target) {
|
if BibliographyElem::has(engine, target) {
|
||||||
if elem.is_ok() {
|
if elem.is_ok() {
|
||||||
bail!(span, "label occurs in the document and its bibliography");
|
bail!(span, "label occurs in the document and its bibliography");
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(to_citation(self, engine, styles)?.pack().spanned(span));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let elem = elem.at(span)?;
|
return Ok(to_citation(self, engine, styles)?.pack().spanned(span));
|
||||||
|
}
|
||||||
|
|
||||||
if elem.func() == FootnoteElem::elem() {
|
let elem = elem.at(span)?;
|
||||||
return Ok(FootnoteElem::with_label(target).pack().spanned(span));
|
|
||||||
}
|
|
||||||
|
|
||||||
let elem = elem.clone();
|
if elem.func() == FootnoteElem::elem() {
|
||||||
let refable = elem
|
return Ok(FootnoteElem::with_label(target).pack().spanned(span));
|
||||||
.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 numbering = refable
|
let elem = elem.clone();
|
||||||
.numbering()
|
let refable = elem
|
||||||
.ok_or_else(|| {
|
.with::<dyn Refable>()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
if elem.can::<dyn Figurable>() {
|
||||||
eco_format!(
|
eco_format!(
|
||||||
"cannot reference {} without numbering",
|
"cannot reference {} directly, try putting it into a figure",
|
||||||
elem.func().name()
|
elem.func().name()
|
||||||
)
|
)
|
||||||
})
|
} else {
|
||||||
.hint(eco_format!(
|
eco_format!("cannot reference {}", elem.func().name())
|
||||||
"you can enable {} numbering with `#set {}(numbering: \"1.\")`",
|
}
|
||||||
elem.func().name(),
|
})
|
||||||
if elem.func() == EquationElem::elem() {
|
.at(span)?;
|
||||||
"math.equation"
|
|
||||||
} else {
|
|
||||||
elem.func().name()
|
|
||||||
}
|
|
||||||
))
|
|
||||||
.at(span)?;
|
|
||||||
|
|
||||||
let loc = elem.location().unwrap();
|
let numbering = refable
|
||||||
let numbers = refable
|
.numbering()
|
||||||
.counter()
|
.ok_or_else(|| {
|
||||||
.at(engine, loc)?
|
eco_format!("cannot reference {} without numbering", elem.func().name())
|
||||||
.display(engine, &numbering.clone().trimmed())?;
|
})
|
||||||
|
.hint(eco_format!(
|
||||||
|
"you can enable {} numbering with `#set {}(numbering: \"1.\")`",
|
||||||
|
elem.func().name(),
|
||||||
|
if elem.func() == EquationElem::elem() {
|
||||||
|
"math.equation"
|
||||||
|
} else {
|
||||||
|
elem.func().name()
|
||||||
|
}
|
||||||
|
))
|
||||||
|
.at(span)?;
|
||||||
|
|
||||||
let supplement = match self.supplement(styles).as_ref() {
|
let loc = elem.location().unwrap();
|
||||||
Smart::Auto => refable.supplement(),
|
let numbers = refable
|
||||||
Smart::Custom(None) => Content::empty(),
|
.counter()
|
||||||
Smart::Custom(Some(supplement)) => supplement.resolve(engine, [elem])?,
|
.at(engine, loc)?
|
||||||
};
|
.display(engine, &numbering.clone().trimmed())?;
|
||||||
|
|
||||||
let mut content = numbers;
|
let supplement = match self.supplement(styles).as_ref() {
|
||||||
if !supplement.is_empty() {
|
Smart::Auto => refable.supplement(),
|
||||||
content = supplement + TextElem::packed("\u{a0}") + content;
|
Smart::Custom(None) => Content::empty(),
|
||||||
}
|
Smart::Custom(Some(supplement)) => supplement.resolve(engine, [elem])?,
|
||||||
|
};
|
||||||
|
|
||||||
Ok(content.linked(Destination::Location(loc)))
|
let mut content = numbers;
|
||||||
}))
|
if !supplement.is_empty() {
|
||||||
|
content = supplement + TextElem::packed("\u{a0}") + content;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(content.linked(Destination::Location(loc)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,18 +92,17 @@ pub fn realize(
|
|||||||
meta = prepare(engine, &mut target, &mut map, styles)?;
|
meta = prepare(engine, &mut target, &mut map, styles)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the step.
|
// Apply a step, if there is one.
|
||||||
let mut output = match step {
|
let mut output = match step {
|
||||||
// Apply a user-defined show rule.
|
Some(step) => {
|
||||||
Some(Step::Recipe(recipe, guard)) => show(engine, target, recipe, guard)?,
|
// Errors in show rules don't terminate compilation immediately. We
|
||||||
|
// just continue with empty content for them and show all errors
|
||||||
// If the verdict picks this step, the `target` is guaranteed
|
// together, if they remain by the end of the introspection loop.
|
||||||
// to have a built-in show rule.
|
//
|
||||||
Some(Step::Builtin) => {
|
// This way, we can ignore errors that only occur in earlier
|
||||||
target.with::<dyn Show>().unwrap().show(engine, styles.chain(&map))?
|
// iterations and also show more useful errors at once.
|
||||||
|
engine.delayed(|engine| show(engine, target, step, styles.chain(&map)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to do.
|
|
||||||
None => target,
|
None => target,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -122,12 +121,12 @@ struct Verdict<'a> {
|
|||||||
prepared: bool,
|
prepared: bool,
|
||||||
/// A map of styles to apply to the element.
|
/// A map of styles to apply to the element.
|
||||||
map: Styles,
|
map: Styles,
|
||||||
/// An optional transformation step to apply to the element.
|
/// An optional show rule transformation to apply to the element.
|
||||||
step: Option<Step<'a>>,
|
step: Option<ShowStep<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An optional transformation step to apply to an element.
|
/// An optional show rule transformation to apply to the element.
|
||||||
enum Step<'a> {
|
enum ShowStep<'a> {
|
||||||
/// A user-defined transformational show rule.
|
/// A user-defined transformational show rule.
|
||||||
Recipe(&'a Recipe, RecipeIndex),
|
Recipe(&'a Recipe, RecipeIndex),
|
||||||
/// The built-in show rule.
|
/// The built-in show rule.
|
||||||
@ -200,7 +199,7 @@ fn verdict<'a>(
|
|||||||
// If we find a matching, unguarded replacement show rule,
|
// If we find a matching, unguarded replacement show rule,
|
||||||
// remember it, but still continue searching for potential
|
// remember it, but still continue searching for potential
|
||||||
// show-set styles that might change the verdict.
|
// 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
|
// If we found a show rule and are already prepared, there is
|
||||||
// nothing else to do, so we can just break.
|
// 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 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>() {
|
||||||
step = Some(Step::Builtin);
|
step = Some(ShowStep::Builtin);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's no nothing to do, there is also no verdict.
|
// If there's no nothing to do, there is also no verdict.
|
||||||
@ -286,21 +285,30 @@ fn prepare(
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply a user-defined show rule.
|
/// Apply a step.
|
||||||
fn show(
|
fn show(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
target: Content,
|
target: Content,
|
||||||
recipe: &Recipe,
|
step: ShowStep,
|
||||||
index: RecipeIndex,
|
styles: StyleChain,
|
||||||
) -> SourceResult<Content> {
|
) -> SourceResult<Content> {
|
||||||
match &recipe.selector {
|
match step {
|
||||||
Some(Selector::Regex(regex)) => {
|
// Apply a user-defined show rule.
|
||||||
// If the verdict picks this rule, the `target` is guaranteed
|
ShowStep::Recipe(recipe, guard) => match &recipe.selector {
|
||||||
// to be a text element.
|
// If the selector is a regex, the `target` is guaranteed to be a
|
||||||
let text = target.into_packed::<TextElem>().unwrap();
|
// text element. This invokes special regex handling.
|
||||||
show_regex(engine, &text, regex, recipe, index)
|
Some(Selector::Regex(regex)) => {
|
||||||
}
|
let text = target.into_packed::<TextElem>().unwrap();
|
||||||
_ => recipe.apply(engine, target.guarded(index)),
|
show_regex(engine, &text, regex, recipe, guard)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
tests/typ/compiler/delayed-error.typ
Normal file
11
tests/typ/compiler/delayed-error.typ
Normal 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*
|
Loading…
x
Reference in New Issue
Block a user