diff --git a/cli/src/main.rs b/cli/src/main.rs index 7ecf34612..f8affa0dd 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -21,7 +21,7 @@ use same_file::{is_same_file, Handle}; use siphasher::sip128::{Hasher128, SipHasher13}; use std::cell::OnceCell; use termcolor::{ColorChoice, StandardStream, WriteColor}; -use typst::diag::{FileError, FileResult, SourceError, StrResult}; +use typst::diag::{bail, FileError, FileResult, SourceError, StrResult}; use typst::doc::Document; use typst::eval::{Datetime, Library}; use typst::font::{Font, FontBook, FontInfo, FontVariant}; @@ -314,7 +314,7 @@ fn export(document: &Document, command: &CompileSettings) -> StrResult<()> { let string = command.output.to_str().unwrap_or_default(); let numbered = string.contains("{n}"); if !numbered && document.pages.len() > 1 { - Err("cannot export multiple PNGs without `{n}` in output path")?; + bail!("cannot export multiple PNGs without `{{n}}` in output path"); } // Find a number width that accommodates all pages. For instance, the diff --git a/library/src/compute/construct.rs b/library/src/compute/construct.rs index 5ccefb187..cbb50fd6b 100644 --- a/library/src/compute/construct.rs +++ b/library/src/compute/construct.rs @@ -171,12 +171,12 @@ cast! { Component, v: i64 => match v { 0 ..= 255 => Self(v as u8), - _ => Err("number must be between 0 and 255")?, + _ => bail!("number must be between 0 and 255"), }, v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { - Err("ratio must be between 0% and 100%")? + bail!("ratio must be between 0% and 100%"); }, } @@ -375,7 +375,7 @@ cast! { v: Ratio => if (0.0 ..= 1.0).contains(&v.get()) { Self((v.get() * 255.0).round() as u8) } else { - Err("ratio must be between 0% and 100%")? + bail!("ratio must be between 0% and 100%"); }, } @@ -437,7 +437,7 @@ cast! { let mut iter = array.into_iter(); match (iter.next(), iter.next(), iter.next()) { (Some(a), Some(b), None) => Self(a.cast()?, b.cast()?), - _ => Err("point array must contain exactly two entries")?, + _ => bail!("point array must contain exactly two entries"), } }, } diff --git a/library/src/compute/data.rs b/library/src/compute/data.rs index 1238c3c3c..0d4d48650 100644 --- a/library/src/compute/data.rs +++ b/library/src/compute/data.rs @@ -105,11 +105,11 @@ cast! { let mut chars = v.chars(); let first = chars.next().ok_or("delimiter must not be empty")?; if chars.next().is_some() { - Err("delimiter must be a single character")? + bail!("delimiter must be a single character"); } if !first.is_ascii() { - Err("delimiter must be an ASCII character")? + bail!("delimiter must be an ASCII character"); } Self(first) diff --git a/library/src/layout/enum.rs b/library/src/layout/enum.rs index 2204b284b..91866d155 100644 --- a/library/src/layout/enum.rs +++ b/library/src/layout/enum.rs @@ -294,7 +294,7 @@ cast! { let mut iter = array.into_iter(); let (number, body) = match (iter.next(), iter.next(), iter.next()) { (Some(a), Some(b), None) => (a.cast()?, b.cast()?), - _ => Err("array must contain exactly two entries")?, + _ => bail!("array must contain exactly two entries"), }; Self::new(body).with_number(number) }, diff --git a/library/src/layout/list.rs b/library/src/layout/list.rs index a11b019f2..9dce466d4 100644 --- a/library/src/layout/list.rs +++ b/library/src/layout/list.rs @@ -216,7 +216,7 @@ cast! { v: Content => Self::Content(vec![v]), array: Array => { if array.is_empty() { - Err("array must contain at least one marker")?; + bail!("array must contain at least one marker"); } Self::Content(array.into_iter().map(Value::display).collect()) }, diff --git a/library/src/layout/page.rs b/library/src/layout/page.rs index 9789b4684..3b81f92c1 100644 --- a/library/src/layout/page.rs +++ b/library/src/layout/page.rs @@ -595,7 +595,7 @@ cast! { v: GenAlign => match v { GenAlign::Specific(Align::Left) => Self::Left, GenAlign::Specific(Align::Right) => Self::Right, - _ => Err("must be `left` or `right`")?, + _ => bail!("must be `left` or `right`"), }, } diff --git a/library/src/layout/terms.rs b/library/src/layout/terms.rs index 8b8a72233..d693f100c 100644 --- a/library/src/layout/terms.rs +++ b/library/src/layout/terms.rs @@ -158,7 +158,7 @@ cast! { let mut iter = array.into_iter(); let (term, description) = match (iter.next(), iter.next(), iter.next()) { (Some(a), Some(b), None) => (a.cast()?, b.cast()?), - _ => Err("array must contain exactly two entries")?, + _ => bail!("array must contain exactly two entries"), }; Self::new(term, description) }, diff --git a/library/src/math/accent.rs b/library/src/math/accent.rs index 4a12f5c55..273979119 100644 --- a/library/src/math/accent.rs +++ b/library/src/math/accent.rs @@ -134,6 +134,6 @@ cast! { v: char => Self::new(v), v: Content => match v.to::() { Some(elem) => Value::Str(elem.text().into()).cast()?, - None => Err("expected text")?, + None => bail!("expected text"), }, } diff --git a/library/src/meta/bibliography.rs b/library/src/meta/bibliography.rs index f020f730a..661257b41 100644 --- a/library/src/meta/bibliography.rs +++ b/library/src/meta/bibliography.rs @@ -633,7 +633,7 @@ fn parse_bib(path_str: &str, src: &str) -> StrResult> { .map(|error| format_biblatex_error(path_str, src, error)) .unwrap_or_else(|| eco_format!("failed to parse {path_str}")) }), - _ => Err("unknown bibliography format (must be .yml/.yaml or .bib)".into()), + _ => bail!("unknown bibliography format (must be .yml/.yaml or .bib)"), } } diff --git a/library/src/meta/numbering.rs b/library/src/meta/numbering.rs index 08d354580..ed71c1bef 100644 --- a/library/src/meta/numbering.rs +++ b/library/src/meta/numbering.rs @@ -218,7 +218,7 @@ impl FromStr for NumberingPattern { let suffix = pattern[handled..].into(); if pieces.is_empty() { - Err("invalid numbering pattern")?; + return Err("invalid numbering pattern"); } Ok(Self { pieces, suffix, trimmed: false }) diff --git a/library/src/meta/outline.rs b/library/src/meta/outline.rs index 3ba1b2e55..b78cd7650 100644 --- a/library/src/meta/outline.rs +++ b/library/src/meta/outline.rs @@ -407,9 +407,8 @@ cast! { /// == Setup /// ``` /// -/// To completely customize an entry's line, you can also build it from -/// scratch by accessing the `level`, `element`, `outline`, and `fill` -/// fields on the entry. +/// To completely customize an entry's line, you can also build it from scratch +/// by accessing the `level`, `element`, `body`, and `fill` fields on the entry. /// /// Display: Outline Entry /// Category: meta diff --git a/library/src/text/mod.rs b/library/src/text/mod.rs index 6090094ab..bde5dbac6 100644 --- a/library/src/text/mod.rs +++ b/library/src/text/mod.rs @@ -644,7 +644,7 @@ cast! { self => self.0.into_value(), v: Smart => { if v.map_or(false, |dir| dir.axis() == Axis::Y) { - Err("text direction must be horizontal")?; + bail!("text direction must be horizontal"); } Self(v) }, @@ -703,7 +703,7 @@ cast! { self => self.0.into_value(), v: i64 => match v { 1 ..= 20 => Self::new(v as u8), - _ => Err("stylistic set must be between 1 and 20")?, + _ => bail!("stylistic set must be between 1 and 20"), }, } diff --git a/library/src/visualize/image.rs b/library/src/visualize/image.rs index 7ea3c8712..43983e077 100644 --- a/library/src/visualize/image.rs +++ b/library/src/visualize/image.rs @@ -185,7 +185,7 @@ fn load( "jpg" | "jpeg" => ImageFormat::Raster(RasterFormat::Jpg), "gif" => ImageFormat::Raster(RasterFormat::Gif), "svg" | "svgz" => ImageFormat::Vector(VectorFormat::Svg), - _ => return Err("unknown image format".into()), + _ => bail!("unknown image format"), }; Image::with_fonts(buffer, format, world, fallback_family, alt) } diff --git a/library/src/visualize/path.rs b/library/src/visualize/path.rs index 641095c5e..d78abce19 100644 --- a/library/src/visualize/path.rs +++ b/library/src/visualize/path.rs @@ -205,7 +205,7 @@ cast! { (Some(a), Some(b), Some(c), None) => { AllControlPoints(a.cast()?, b.cast()?, c.cast()?) }, - _ => Err("path vertex must have 1, 2, or 3 points")?, + _ => bail!("path vertex must have 1, 2, or 3 points"), } }, } diff --git a/src/diag.rs b/src/diag.rs index d9f880248..4fb9ecc06 100644 --- a/src/diag.rs +++ b/src/diag.rs @@ -13,6 +13,15 @@ use crate::syntax::{ErrorPos, Span, Spanned}; use crate::World; /// Early-return with a [`StrResult`] or [`SourceResult`]. +/// +/// If called with just a string and format args, returns with a +/// `StrResult`. If called with a span, a string and format args, returns +/// a `SourceResult`. +/// +/// ``` +/// bail!("bailing with a {}", "string result"); +/// bail!(span, "bailing with a {}", "source result"); +/// ``` #[macro_export] #[doc(hidden)] macro_rules! __bail { diff --git a/src/eval/mod.rs b/src/eval/mod.rs index fe11606ae..93a73ea44 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -256,7 +256,7 @@ impl<'a> Vm<'a> { } } - Err("cannot access file system from here".into()) + bail!("cannot access file system from here") } } diff --git a/src/eval/ops.rs b/src/eval/ops.rs index bea2ea827..0880a87e9 100644 --- a/src/eval/ops.rs +++ b/src/eval/ops.rs @@ -6,7 +6,7 @@ use std::fmt::Debug; use ecow::eco_format; use super::{format_str, Regex, Value}; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; use crate::geom::{Axes, Axis, GenAlign, Length, Numeric, PartialStroke, Rel, Smart}; use Value::*; @@ -219,7 +219,7 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult { /// Compute the quotient of two values. pub fn div(lhs: Value, rhs: Value) -> StrResult { if is_zero(&rhs) { - Err("cannot divide by zero")?; + bail!("cannot divide by zero"); } Ok(match (lhs, rhs) { diff --git a/src/eval/scope.rs b/src/eval/scope.rs index f2aa26fb1..f3e137151 100644 --- a/src/eval/scope.rs +++ b/src/eval/scope.rs @@ -5,7 +5,7 @@ use std::hash::Hash; use ecow::{eco_format, EcoString}; use super::{IntoValue, Library, Value}; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; /// A stack of scopes. #[derive(Debug, Default, Clone)] @@ -171,7 +171,7 @@ impl Slot { match self.kind { Kind::Normal => Ok(&mut self.value), Kind::Captured => { - Err("variables from outside the function are read-only and cannot be modified")? + bail!("variables from outside the function are read-only and cannot be modified") } } } diff --git a/src/eval/str.rs b/src/eval/str.rs index e3e83f3a7..f5e5ab00a 100644 --- a/src/eval/str.rs +++ b/src/eval/str.rs @@ -7,7 +7,7 @@ use ecow::EcoString; use unicode_segmentation::UnicodeSegmentation; use super::{cast, dict, Args, Array, Dict, Func, IntoValue, Value, Vm}; -use crate::diag::{At, SourceResult, StrResult}; +use crate::diag::{bail, At, SourceResult, StrResult}; use crate::geom::GenAlign; /// Create a new [`Str`] from a format string. @@ -507,7 +507,7 @@ cast! { let mut chars = string.chars(); match (chars.next(), chars.next()) { (Some(c), None) => c, - _ => Err("expected exactly one character")?, + _ => bail!("expected exactly one character"), } }, } @@ -600,7 +600,7 @@ cast! { align: GenAlign => match align { GenAlign::Start => Self::Start, GenAlign::End => Self::End, - _ => Err("expected either `start` or `end`")?, + _ => bail!("expected either `start` or `end`"), }, } diff --git a/src/eval/symbol.rs b/src/eval/symbol.rs index 8f4c93f8c..0925202ec 100644 --- a/src/eval/symbol.rs +++ b/src/eval/symbol.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use ecow::EcoString; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; /// A symbol, possibly with variants. #[derive(Clone, Eq, PartialEq, Hash)] @@ -72,7 +72,7 @@ impl Symbol { } } - Err("unknown symbol modifier".into()) + bail!("unknown symbol modifier") } /// The characters that are covered by this symbol. diff --git a/src/geom/align.rs b/src/geom/align.rs index dca35891f..47acd3a6c 100644 --- a/src/geom/align.rs +++ b/src/geom/align.rs @@ -216,7 +216,7 @@ cast! { self => self.0.into_value(), align: GenAlign => { if align.axis() != Axis::X { - Err("alignment must be horizontal")?; + bail!("alignment must be horizontal"); } Self(align) }, @@ -232,7 +232,7 @@ cast! { self => self.0.into_value(), align: GenAlign => { if align.axis() != Axis::Y { - Err("alignment must be vertical")?; + bail!("alignment must be vertical"); } Self(align) }, diff --git a/src/geom/axes.rs b/src/geom/axes.rs index 35c941297..059d3bb22 100644 --- a/src/geom/axes.rs +++ b/src/geom/axes.rs @@ -280,7 +280,7 @@ cast! { let mut iter = array.into_iter(); match (iter.next(), iter.next(), iter.next()) { (Some(a), Some(b), None) => Axes::new(a.cast()?, b.cast()?), - _ => Err("point array must contain exactly two entries")?, + _ => bail!("point array must contain exactly two entries"), } }, } diff --git a/src/geom/mod.rs b/src/geom/mod.rs index 4a9ecfe1b..b7a7ff409 100644 --- a/src/geom/mod.rs +++ b/src/geom/mod.rs @@ -61,7 +61,7 @@ use std::hash::{Hash, Hasher}; use std::iter::Sum; use std::ops::*; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; use crate::eval::{array, cast, Array, Dict, Value}; use crate::model::{Fold, Resolve, StyleChain}; diff --git a/src/model/introspect.rs b/src/model/introspect.rs index b150fabff..42c1a9e1f 100644 --- a/src/model/introspect.rs +++ b/src/model/introspect.rs @@ -9,7 +9,7 @@ use ecow::EcoVec; use indexmap::IndexMap; use super::{Content, Selector}; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; use crate::doc::{Frame, FrameItem, Meta, Position}; use crate::eval::{cast, Value}; use crate::geom::{Point, Transform}; @@ -313,7 +313,7 @@ impl Introspector { let mut found = None; for elem in self.all().filter(|elem| elem.label() == Some(label)) { if found.is_some() { - return Err("label occurs multiple times in the document".into()); + bail!("label occurs multiple times in the document"); } found = Some(elem.clone()); } diff --git a/src/model/selector.rs b/src/model/selector.rs index 5a2b11cbc..9723ee4f3 100644 --- a/src/model/selector.rs +++ b/src/model/selector.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use ecow::{eco_format, EcoString, EcoVec}; use super::{Content, ElemFunc, Label, Location}; -use crate::diag::StrResult; +use crate::diag::{bail, StrResult}; use crate::eval::{ cast, CastInfo, Dict, FromValue, Func, IntoValue, Reflect, Regex, Value, }; @@ -201,8 +201,8 @@ impl FromValue for LocatableSelector { } Selector::Location(_) => {} Selector::Label(_) => {} - Selector::Regex(_) => Err("text is not locatable")?, - Selector::Can(_) => Err("capability is not locatable")?, + Selector::Regex(_) => bail!("text is not locatable"), + Selector::Can(_) => bail!("capability is not locatable"), Selector::Or(list) | Selector::And(list) => { for selector in list { validate(selector)?; @@ -279,7 +279,7 @@ impl FromValue for ShowableSelector { | Selector::Can(_) | Selector::Before { .. } | Selector::After { .. } => { - Err("this selector cannot be used with show")? + bail!("this selector cannot be used with show") } } Ok(())