Added hint
to bail!
, warning!
, and error!
(#2756)
This commit is contained in:
parent
219c1c9ed0
commit
2c85161a27
@ -18,69 +18,105 @@ use crate::{World, WorldExt};
|
||||
/// `StrResult`. If called with a span, a string and format args, returns
|
||||
/// a `SourceResult`.
|
||||
///
|
||||
/// You can also emit hints with the `; hint: "..."` syntax.
|
||||
///
|
||||
/// ```
|
||||
/// bail!("bailing with a {}", "string result");
|
||||
/// bail!(span, "bailing with a {}", "source result");
|
||||
/// bail!(
|
||||
/// span, "bailing with a {}", "source result";
|
||||
/// hint: "hint 1"
|
||||
/// );
|
||||
/// bail!(
|
||||
/// span, "bailing with a {}", "source result";
|
||||
/// hint: "hint 1";
|
||||
/// hint: "hint 2";
|
||||
/// );
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __bail {
|
||||
// For bail!("just a {}", "string")
|
||||
($fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
return Err($crate::diag::eco_format!($fmt, $($arg),*))
|
||||
return Err($crate::diag::error!(
|
||||
$fmt, $($arg),*
|
||||
))
|
||||
};
|
||||
|
||||
// For bail!(error!(..))
|
||||
($error:expr) => {
|
||||
return Err(::ecow::eco_vec![$error])
|
||||
};
|
||||
|
||||
($span:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
return Err(::ecow::eco_vec![$crate::diag::SourceDiagnostic::error(
|
||||
$span,
|
||||
$crate::diag::eco_format!($fmt, $($arg),*),
|
||||
)])
|
||||
// For bail(span, ...)
|
||||
($($tts:tt)*) => {
|
||||
return Err(::ecow::eco_vec![$crate::diag::error!($($tts)*)])
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(inline)]
|
||||
pub use crate::__bail as bail;
|
||||
#[doc(inline)]
|
||||
pub use crate::__error as error;
|
||||
#[doc(inline)]
|
||||
pub use crate::__warning as warning;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use ecow::eco_format;
|
||||
#[doc(hidden)]
|
||||
pub use ecow::EcoString;
|
||||
|
||||
/// Construct an [`EcoString`] or [`SourceDiagnostic`] with severity `Error`.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __error {
|
||||
// For bail!("just a {}", "string").
|
||||
($fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
$crate::diag::eco_format!($fmt, $($arg),*)
|
||||
};
|
||||
|
||||
($span:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
// For bail!(span, ...)
|
||||
(
|
||||
$span:expr, $fmt:literal $(, $arg:expr)*
|
||||
$(; hint: $hint:literal $(, $hint_arg:expr)*)*
|
||||
$(,)?
|
||||
) => {
|
||||
$crate::diag::SourceDiagnostic::error(
|
||||
$span,
|
||||
$crate::diag::eco_format!($fmt, $($arg),*),
|
||||
)
|
||||
) $(.with_hint($crate::diag::eco_format!($hint, $($hint_arg),*)))*
|
||||
};
|
||||
}
|
||||
|
||||
/// Construct a [`SourceDiagnostic`] with severity `Warning`.
|
||||
///
|
||||
/// You can also emit hints with the `; hint: "..."` syntax.
|
||||
///
|
||||
/// ```
|
||||
/// warning!(span, "warning with a {}", "source result");
|
||||
/// warning!(
|
||||
/// span, "warning with a {}", "source result";
|
||||
/// hint: "hint 1"
|
||||
/// );
|
||||
/// warning!(
|
||||
/// span, "warning with a {}", "source result";
|
||||
/// hint: "hint 1";
|
||||
/// hint: "hint 2";
|
||||
/// );
|
||||
/// ```
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! __warning {
|
||||
($span:expr, $fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
(
|
||||
$span:expr,
|
||||
$fmt:literal $(, $arg:expr)*
|
||||
$(; hint: $hint:literal $(, $hint_arg:expr)*)*
|
||||
$(,)?
|
||||
) => {
|
||||
$crate::diag::SourceDiagnostic::warning(
|
||||
$span,
|
||||
$crate::diag::eco_format!($fmt, $($arg),*),
|
||||
)
|
||||
) $(.with_hint($crate::diag::eco_format!($hint, $($hint_arg),*)))*
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
#[doc(inline)]
|
||||
pub use {
|
||||
crate::__bail as bail,
|
||||
crate::__error as error,
|
||||
crate::__warning as warning,
|
||||
ecow::{eco_format, EcoString},
|
||||
};
|
||||
|
||||
/// A result that can carry multiple source errors.
|
||||
pub type SourceResult<T> = Result<T, EcoVec<SourceDiagnostic>>;
|
||||
|
||||
|
@ -139,11 +139,12 @@ impl Eval for ast::Strong<'_> {
|
||||
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||
let body = self.body();
|
||||
if body.exprs().next().is_none() {
|
||||
vm.engine.tracer.warn(
|
||||
warning!(self.span(), "no text within stars").with_hint(
|
||||
"using multiple consecutive stars (e.g. **) has no additional effect",
|
||||
),
|
||||
);
|
||||
vm.engine
|
||||
.tracer
|
||||
.warn(warning!(
|
||||
self.span(), "no text within stars";
|
||||
hint: "using multiple consecutive stars (e.g. **) has no additional effect",
|
||||
));
|
||||
}
|
||||
|
||||
Ok(StrongElem::new(body.eval(vm)?).pack())
|
||||
@ -159,9 +160,10 @@ impl Eval for ast::Emph<'_> {
|
||||
if body.exprs().next().is_none() {
|
||||
vm.engine
|
||||
.tracer
|
||||
.warn(warning!(self.span(), "no text within underscores").with_hint(
|
||||
"using multiple consecutive underscores (e.g. __) has no additional effect"
|
||||
));
|
||||
.warn(warning!(
|
||||
self.span(), "no text within underscores";
|
||||
hint: "using multiple consecutive underscores (e.g. __) has no additional effect"
|
||||
));
|
||||
}
|
||||
|
||||
Ok(EmphElem::new(body.eval(vm)?).pack())
|
||||
|
@ -5,7 +5,7 @@ use std::iter::repeat;
|
||||
|
||||
use ecow::{eco_format, EcoString, EcoVec};
|
||||
|
||||
use crate::diag::{bail, error, StrResult};
|
||||
use crate::diag::{bail, StrResult};
|
||||
use crate::foundations::{cast, func, repr, scope, ty, Repr};
|
||||
|
||||
/// A version with an arbitrary number of components.
|
||||
@ -43,7 +43,7 @@ impl Version {
|
||||
.iter()
|
||||
.zip(Self::COMPONENTS)
|
||||
.find_map(|(&i, s)| (s == name).then_some(i as i64))
|
||||
.ok_or_else(|| error!("unknown version component"))
|
||||
.ok_or_else(|| "unknown version component".into())
|
||||
}
|
||||
|
||||
/// Push a component to the end of this version.
|
||||
|
@ -71,7 +71,7 @@ pub(crate) use self::inline::*;
|
||||
|
||||
use comemo::{Tracked, TrackedMut};
|
||||
|
||||
use crate::diag::{bail, error, SourceResult};
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::engine::{Engine, Route};
|
||||
use crate::eval::Tracer;
|
||||
use crate::foundations::{category, Category, Content, Scope, StyleChain};
|
||||
@ -238,8 +238,10 @@ impl Layout for Content {
|
||||
};
|
||||
|
||||
if engine.route.exceeding() {
|
||||
bail!(error!(content.span(), "maximum layout depth exceeded")
|
||||
.with_hint("try to reduce the amount of nesting in your layout"));
|
||||
bail!(
|
||||
content.span(), "maximum layout depth exceeded";
|
||||
hint: "try to reduce the amount of nesting in your layout",
|
||||
);
|
||||
}
|
||||
|
||||
let scratch = Scratch::default();
|
||||
|
@ -143,10 +143,10 @@ fn typeset(
|
||||
}
|
||||
|
||||
if iter >= 5 {
|
||||
tracer.warn(
|
||||
warning!(Span::detached(), "layout did not converge within 5 attempts",)
|
||||
.with_hint("check if any states or queries are updating themselves"),
|
||||
);
|
||||
tracer.warn(warning!(
|
||||
Span::detached(), "layout did not converge within 5 attempts";
|
||||
hint: "check if any states or queries are updating themselves"
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::str::FromStr;
|
||||
|
||||
use comemo::Prehashed;
|
||||
|
||||
use crate::diag::{bail, error, At, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Content, Finalize, Label, NativeElement, Show, Smart, StyleChain,
|
||||
@ -280,9 +280,10 @@ impl Show for FootnoteEntry {
|
||||
let numbering = note.numbering(default);
|
||||
let counter = Counter::of(FootnoteElem::elem());
|
||||
let Some(loc) = note.location() else {
|
||||
bail!(error!(self.span(), "footnote entry must have a location").with_hint(
|
||||
"try using a query or a show rule to customize the footnote instead"
|
||||
))
|
||||
bail!(
|
||||
self.span(), "footnote entry must have a location";
|
||||
hint: "try using a query or a show rule to customize the footnote instead"
|
||||
);
|
||||
};
|
||||
|
||||
let num = counter.at(engine, loc)?.display(engine, numbering)?;
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::num::NonZeroUsize;
|
||||
use std::str::FromStr;
|
||||
|
||||
use crate::diag::{bail, error, At, SourceResult};
|
||||
use crate::diag::{bail, At, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, select_where, Content, Finalize, Func, LocatableSelector,
|
||||
@ -492,10 +492,10 @@ impl Show for OutlineEntry {
|
||||
// In case a user constructs an outline entry with an arbitrary element.
|
||||
let Some(location) = elem.location() else {
|
||||
if elem.can::<dyn Locatable>() && elem.can::<dyn Outlinable>() {
|
||||
bail!(error!(self.span(), "{} must have a location", elem.func().name())
|
||||
.with_hint(
|
||||
"try using a query or a show rule to customize the outline.entry instead",
|
||||
))
|
||||
bail!(
|
||||
self.span(), "{} must have a location", elem.func().name();
|
||||
hint: "try using a query or a show rule to customize the outline.entry instead",
|
||||
)
|
||||
} else {
|
||||
bail!(self.span(), "cannot outline {}", elem.func().name())
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use std::mem;
|
||||
use smallvec::smallvec;
|
||||
use typed_arena::Arena;
|
||||
|
||||
use crate::diag::{bail, error, SourceResult};
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
Content, Finalize, Guard, NativeElement, Recipe, Selector, Show, StyleChain,
|
||||
@ -308,11 +308,11 @@ impl<'a, 'v, 't> Builder<'a, 'v, 't> {
|
||||
if let Some(realized) = realize(self.engine, content, styles)? {
|
||||
self.engine.route.increase();
|
||||
if self.engine.route.exceeding() {
|
||||
bail!(error!(content.span(), "maximum show rule depth exceeded")
|
||||
.with_hint("check whether the show rule matches its own output")
|
||||
.with_hint(
|
||||
"this is a current compiler limitation that will be resolved in the future"
|
||||
));
|
||||
bail!(
|
||||
content.span(), "maximum show rule depth exceeded";
|
||||
hint: "check whether the show rule matches its own output";
|
||||
hint: "this is a current compiler limitation that will be resolved in the future",
|
||||
);
|
||||
}
|
||||
let stored = self.scratch.content.alloc(realized);
|
||||
let v = self.accept(stored, styles);
|
||||
|
@ -34,7 +34,7 @@ use ecow::{eco_format, EcoString};
|
||||
use rustybuzz::{Feature, Tag};
|
||||
use ttf_parser::Rect;
|
||||
|
||||
use crate::diag::{bail, error, SourceResult, StrResult};
|
||||
use crate::diag::{bail, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, category, elem, Args, Array, Cast, Category, Construct, Content, Dict, Fold,
|
||||
@ -228,11 +228,9 @@ pub struct TextElem {
|
||||
if let Some(paint) = &paint {
|
||||
if paint.v.relative() == Smart::Custom(RelativeTo::Self_) {
|
||||
bail!(
|
||||
error!(
|
||||
paint.span,
|
||||
"gradients and patterns on text must be relative to the parent"
|
||||
)
|
||||
.with_hint("make sure to set `relative: auto` on your text fill")
|
||||
paint.span,
|
||||
"gradients and patterns on text must be relative to the parent";
|
||||
hint: "make sure to set `relative: auto` on your text fill"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use palette::{
|
||||
Darken, Desaturate, FromColor, Lighten, Okhsva, OklabHue, RgbHue, Saturate, ShiftHue,
|
||||
};
|
||||
|
||||
use crate::diag::{bail, error, At, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||
use crate::foundations::{
|
||||
array, cast, func, repr, scope, ty, Args, Array, IntoValue, Module, Repr, Scope, Str,
|
||||
Value,
|
||||
@ -922,8 +922,10 @@ impl Color {
|
||||
) -> SourceResult<Color> {
|
||||
Ok(match self {
|
||||
Self::Luma(_) => {
|
||||
bail!(error!(span, "cannot saturate grayscale color")
|
||||
.with_hint("try converting your color to RGB first"));
|
||||
bail!(
|
||||
span, "cannot saturate grayscale color";
|
||||
hint: "try converting your color to RGB first"
|
||||
);
|
||||
}
|
||||
Self::Oklab(_) => self.to_hsv().saturate(span, factor)?.to_oklab(),
|
||||
Self::Oklch(_) => self.to_hsv().saturate(span, factor)?.to_oklch(),
|
||||
@ -946,8 +948,10 @@ impl Color {
|
||||
) -> SourceResult<Color> {
|
||||
Ok(match self {
|
||||
Self::Luma(_) => {
|
||||
bail!(error!(span, "cannot desaturate grayscale color")
|
||||
.with_hint("try converting your color to RGB first"));
|
||||
bail!(
|
||||
span, "cannot desaturate grayscale color";
|
||||
hint: "try converting your color to RGB first"
|
||||
);
|
||||
}
|
||||
Self::Oklab(_) => self.to_hsv().desaturate(span, factor)?.to_oklab(),
|
||||
Self::Oklch(_) => self.to_hsv().desaturate(span, factor)?.to_oklch(),
|
||||
|
@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
use ecow::EcoString;
|
||||
use kurbo::Vec2;
|
||||
|
||||
use crate::diag::{bail, error, SourceResult};
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::foundations::{
|
||||
array, cast, func, scope, ty, Args, Array, Cast, Func, IntoValue, Repr, Smart,
|
||||
};
|
||||
@ -231,8 +231,10 @@ impl Gradient {
|
||||
};
|
||||
|
||||
if stops.len() < 2 {
|
||||
bail!(error!(span, "a gradient must have at least two stops")
|
||||
.with_hint("try filling the shape with a single color instead"));
|
||||
bail!(
|
||||
span, "a gradient must have at least two stops";
|
||||
hint: "try filling the shape with a single color instead"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Self::Linear(Arc::new(LinearGradient {
|
||||
@ -332,24 +334,29 @@ impl Gradient {
|
||||
focal_radius: Spanned<Ratio>,
|
||||
) -> SourceResult<Gradient> {
|
||||
if stops.len() < 2 {
|
||||
bail!(error!(span, "a gradient must have at least two stops")
|
||||
.with_hint("try filling the shape with a single color instead"));
|
||||
bail!(
|
||||
span, "a gradient must have at least two stops";
|
||||
hint: "try filling the shape with a single color instead"
|
||||
);
|
||||
}
|
||||
|
||||
if focal_radius.v > radius.v {
|
||||
bail!(error!(
|
||||
bail!(
|
||||
focal_radius.span,
|
||||
"the focal radius must be smaller than the end radius"
|
||||
)
|
||||
.with_hint("try using a focal radius of `0%` instead"));
|
||||
"the focal radius must be smaller than the end radius";
|
||||
hint: "try using a focal radius of `0%` instead"
|
||||
);
|
||||
}
|
||||
|
||||
let focal_center = focal_center.unwrap_or(center);
|
||||
let d_center_sqr = (focal_center.x - center.x).get().powi(2)
|
||||
+ (focal_center.y - center.y).get().powi(2);
|
||||
if d_center_sqr.sqrt() >= (radius.v - focal_radius.v).get() {
|
||||
bail!(error!(span, "the focal circle must be inside of the end circle")
|
||||
.with_hint("try using a focal center of `auto` instead"));
|
||||
bail!(
|
||||
span,
|
||||
"the focal circle must be inside of the end circle";
|
||||
hint: "try using a focal center of `auto` instead"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Gradient::Radial(Arc::new(RadialGradient {
|
||||
@ -419,8 +426,10 @@ impl Gradient {
|
||||
center: Axes<Ratio>,
|
||||
) -> SourceResult<Gradient> {
|
||||
if stops.len() < 2 {
|
||||
bail!(error!(span, "a gradient must have at least two stops")
|
||||
.with_hint("try filling the shape with a single color instead"));
|
||||
bail!(
|
||||
span, "a gradient must have at least two stops";
|
||||
hint: "try filling the shape with a single color instead"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Gradient::Conic(Arc::new(ConicGradient {
|
||||
@ -1154,11 +1163,10 @@ fn process_stops(stops: &[Spanned<GradientStop>]) -> SourceResult<Vec<(Color, Ra
|
||||
let mut last_stop = f64::NEG_INFINITY;
|
||||
for Spanned { v: stop, span } in stops.iter() {
|
||||
let Some(stop) = stop.offset else {
|
||||
bail!(error!(
|
||||
*span,
|
||||
"either all stops must have an offset or none of them can"
|
||||
)
|
||||
.with_hint("try adding an offset to all stops"));
|
||||
bail!(
|
||||
*span, "either all stops must have an offset or none of them can";
|
||||
hint: "try adding an offset to all stops"
|
||||
);
|
||||
};
|
||||
|
||||
if stop.get() < last_stop {
|
||||
@ -1179,13 +1187,19 @@ fn process_stops(stops: &[Spanned<GradientStop>]) -> SourceResult<Vec<(Color, Ra
|
||||
.collect::<SourceResult<Vec<_>>>()?;
|
||||
|
||||
if out[0].1 != Ratio::zero() {
|
||||
bail!(error!(stops[0].span, "first stop must have an offset of 0%")
|
||||
.with_hint("try setting this stop to `0%`"));
|
||||
bail!(
|
||||
stops[0].span,
|
||||
"first stop must have an offset of 0";
|
||||
hint: "try setting this stop to `0%`"
|
||||
);
|
||||
}
|
||||
|
||||
if out[out.len() - 1].1 != Ratio::one() {
|
||||
bail!(error!(stops[0].span, "last stop must have an offset of 100%")
|
||||
.with_hint("try setting this stop to `100%`"));
|
||||
bail!(
|
||||
stops[out.len() - 1].span,
|
||||
"last stop must have an offset of 100%";
|
||||
hint: "try setting this stop to `100%`"
|
||||
);
|
||||
}
|
||||
|
||||
return Ok(out);
|
||||
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
||||
use comemo::Prehashed;
|
||||
use ecow::{eco_format, EcoString};
|
||||
|
||||
use crate::diag::{bail, error, SourceResult};
|
||||
use crate::diag::{bail, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{func, scope, ty, Content, Repr, Smart, StyleChain};
|
||||
use crate::layout::{Abs, Axes, Em, Frame, Layout, Length, Regions, Size};
|
||||
@ -181,8 +181,10 @@ impl Pattern {
|
||||
|
||||
// Check that the frame is non-zero.
|
||||
if size.is_auto() && frame.size().is_zero() {
|
||||
bail!(error!(span, "pattern tile size must be non-zero")
|
||||
.with_hint("try setting the size manually"));
|
||||
bail!(
|
||||
span, "pattern tile size must be non-zero";
|
||||
hint: "try setting the size manually"
|
||||
);
|
||||
}
|
||||
|
||||
// Set the size of the frame if the size is enforced.
|
||||
|
Loading…
x
Reference in New Issue
Block a user