mirror of
https://github.com/typst/typst
synced 2025-05-14 04:56:26 +08:00
Refactor casts to use HintedStrResult
(#4229)
This commit is contained in:
parent
d360e753bc
commit
9adcd9a1f8
@ -20,6 +20,7 @@ use clap::Parser;
|
||||
use codespan_reporting::term;
|
||||
use codespan_reporting::term::termcolor::WriteColor;
|
||||
use once_cell::sync::Lazy;
|
||||
use typst::diag::HintedStrResult;
|
||||
|
||||
use crate::args::{CliArguments, Command};
|
||||
use crate::timings::Timer;
|
||||
@ -34,25 +35,32 @@ static ARGS: Lazy<CliArguments> = Lazy::new(CliArguments::parse);
|
||||
|
||||
/// Entry point.
|
||||
fn main() -> ExitCode {
|
||||
let timer = Timer::new(&ARGS);
|
||||
|
||||
let res = match &ARGS.command {
|
||||
Command::Compile(command) => crate::compile::compile(timer, command.clone()),
|
||||
Command::Watch(command) => crate::watch::watch(timer, command.clone()),
|
||||
Command::Init(command) => crate::init::init(command),
|
||||
Command::Query(command) => crate::query::query(command),
|
||||
Command::Fonts(command) => crate::fonts::fonts(command),
|
||||
Command::Update(command) => crate::update::update(command),
|
||||
};
|
||||
let res = dispatch();
|
||||
|
||||
if let Err(msg) = res {
|
||||
set_failed();
|
||||
print_error(&msg).expect("failed to print error");
|
||||
print_error(msg.message()).expect("failed to print error");
|
||||
}
|
||||
|
||||
EXIT.with(|cell| cell.get())
|
||||
}
|
||||
|
||||
/// Execute the requested command.
|
||||
fn dispatch() -> HintedStrResult<()> {
|
||||
let timer = Timer::new(&ARGS);
|
||||
|
||||
match &ARGS.command {
|
||||
Command::Compile(command) => crate::compile::compile(timer, command.clone())?,
|
||||
Command::Watch(command) => crate::watch::watch(timer, command.clone())?,
|
||||
Command::Init(command) => crate::init::init(command)?,
|
||||
Command::Query(command) => crate::query::query(command)?,
|
||||
Command::Fonts(command) => crate::fonts::fonts(command)?,
|
||||
Command::Update(command) => crate::update::update(command)?,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure a failure exit code.
|
||||
fn set_failed() {
|
||||
EXIT.with(|cell| cell.set(ExitCode::FAILURE));
|
||||
|
@ -1,7 +1,7 @@
|
||||
use comemo::Track;
|
||||
use ecow::{eco_format, EcoString};
|
||||
use serde::Serialize;
|
||||
use typst::diag::{bail, StrResult};
|
||||
use typst::diag::{bail, HintedStrResult, StrResult};
|
||||
use typst::eval::{eval_string, EvalMode, Tracer};
|
||||
use typst::foundations::{Content, IntoValue, LocatableSelector, Scope};
|
||||
use typst::model::Document;
|
||||
@ -14,7 +14,7 @@ use crate::set_failed;
|
||||
use crate::world::SystemWorld;
|
||||
|
||||
/// Execute a query command.
|
||||
pub fn query(command: &QueryCommand) -> StrResult<()> {
|
||||
pub fn query(command: &QueryCommand) -> HintedStrResult<()> {
|
||||
let mut world = SystemWorld::new(&command.common)?;
|
||||
|
||||
// Reset everything and ensure that the main file is present.
|
||||
@ -56,7 +56,7 @@ fn retrieve(
|
||||
world: &dyn World,
|
||||
command: &QueryCommand,
|
||||
document: &Document,
|
||||
) -> StrResult<Vec<Content>> {
|
||||
) -> HintedStrResult<Vec<Content>> {
|
||||
let selector = eval_string(
|
||||
world.track(),
|
||||
&command.selector,
|
||||
|
@ -108,7 +108,7 @@ pub fn cast(stream: TokenStream) -> Result<TokenStream> {
|
||||
let from_value = (!input.from_value.is_empty() || input.dynamic).then(|| {
|
||||
quote! {
|
||||
impl #foundations::FromValue for #ty {
|
||||
fn from_value(value: #foundations::Value) -> ::typst::diag::StrResult<Self> {
|
||||
fn from_value(value: #foundations::Value) -> ::typst::diag::HintedStrResult<Self> {
|
||||
#from_value_body
|
||||
}
|
||||
}
|
||||
|
@ -38,9 +38,14 @@ use crate::{World, WorldExt};
|
||||
#[doc(hidden)]
|
||||
macro_rules! __bail {
|
||||
// For bail!("just a {}", "string")
|
||||
($fmt:literal $(, $arg:expr)* $(,)?) => {
|
||||
(
|
||||
$fmt:literal $(, $arg:expr)*
|
||||
$(; hint: $hint:literal $(, $hint_arg:expr)*)*
|
||||
$(,)?
|
||||
) => {
|
||||
return Err($crate::diag::error!(
|
||||
$fmt, $($arg),*
|
||||
$fmt $(, $arg)*
|
||||
$(; hint: $hint $(, $hint_arg)*)*
|
||||
))
|
||||
};
|
||||
|
||||
@ -55,13 +60,25 @@ macro_rules! __bail {
|
||||
};
|
||||
}
|
||||
|
||||
/// Construct an [`EcoString`] or [`SourceDiagnostic`] with severity `Error`.
|
||||
/// Construct an [`EcoString`], [`HintedString`] 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),*)
|
||||
$crate::diag::eco_format!($fmt, $($arg),*).into()
|
||||
};
|
||||
|
||||
// For bail!("a hinted {}", "string"; hint: "some hint"; hint: "...")
|
||||
(
|
||||
$fmt:literal $(, $arg:expr)*
|
||||
$(; hint: $hint:literal $(, $hint_arg:expr)*)*
|
||||
$(,)?
|
||||
) => {
|
||||
$crate::diag::HintedString::new(
|
||||
$crate::diag::eco_format!($fmt, $($arg),*)
|
||||
) $(.with_hint($crate::diag::eco_format!($hint, $($hint_arg),*)))*
|
||||
};
|
||||
|
||||
// For bail!(span, ...)
|
||||
@ -296,13 +313,48 @@ where
|
||||
pub type HintedStrResult<T> = Result<T, HintedString>;
|
||||
|
||||
/// A string message with hints.
|
||||
///
|
||||
/// This is internally represented by a vector of strings.
|
||||
/// The first element of the vector contains the message.
|
||||
/// The remaining elements are the hints.
|
||||
/// This is done to reduce the size of a HintedString.
|
||||
/// The vector is guaranteed to not be empty.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||
pub struct HintedString {
|
||||
pub struct HintedString(EcoVec<EcoString>);
|
||||
|
||||
impl HintedString {
|
||||
/// Creates a new hinted string with the given message.
|
||||
pub fn new(message: EcoString) -> Self {
|
||||
Self(eco_vec![message])
|
||||
}
|
||||
|
||||
/// A diagnostic message describing the problem.
|
||||
pub message: EcoString,
|
||||
pub fn message(&self) -> &EcoString {
|
||||
self.0.first().unwrap()
|
||||
}
|
||||
|
||||
/// Additional hints to the user, indicating how this error could be avoided
|
||||
/// or worked around.
|
||||
pub hints: Vec<EcoString>,
|
||||
pub fn hints(&self) -> &[EcoString] {
|
||||
self.0.get(1..).unwrap_or(&[])
|
||||
}
|
||||
|
||||
/// Adds a single hint to the hinted string.
|
||||
pub fn hint(&mut self, hint: impl Into<EcoString>) {
|
||||
self.0.push(hint.into());
|
||||
}
|
||||
|
||||
/// Adds a single hint to the hinted string.
|
||||
pub fn with_hint(mut self, hint: impl Into<EcoString>) -> Self {
|
||||
self.hint(hint);
|
||||
self
|
||||
}
|
||||
|
||||
/// Adds user-facing hints to the hinted string.
|
||||
pub fn with_hints(mut self, hints: impl IntoIterator<Item = EcoString>) -> Self {
|
||||
self.0.extend(hints);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<S> for HintedString
|
||||
@ -310,14 +362,18 @@ where
|
||||
S: Into<EcoString>,
|
||||
{
|
||||
fn from(value: S) -> Self {
|
||||
Self { message: value.into(), hints: vec![] }
|
||||
Self::new(value.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> At<T> for Result<T, HintedString> {
|
||||
fn at(self, span: Span) -> SourceResult<T> {
|
||||
self.map_err(|diags| {
|
||||
eco_vec![SourceDiagnostic::error(span, diags.message).with_hints(diags.hints)]
|
||||
self.map_err(|err| {
|
||||
let mut components = err.0.into_iter();
|
||||
let message = components.next().unwrap();
|
||||
let diag = SourceDiagnostic::error(span, message).with_hints(components);
|
||||
|
||||
eco_vec![diag]
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -333,17 +389,14 @@ where
|
||||
S: Into<EcoString>,
|
||||
{
|
||||
fn hint(self, hint: impl Into<EcoString>) -> HintedStrResult<T> {
|
||||
self.map_err(|message| HintedString {
|
||||
message: message.into(),
|
||||
hints: vec![hint.into()],
|
||||
})
|
||||
self.map_err(|message| HintedString::new(message.into()).with_hint(hint))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Hint<T> for HintedStrResult<T> {
|
||||
fn hint(self, hint: impl Into<EcoString>) -> HintedStrResult<T> {
|
||||
self.map_err(|mut error| {
|
||||
error.hints.push(hint.into());
|
||||
error.hint(hint.into());
|
||||
error
|
||||
})
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use ecow::{eco_vec, EcoVec};
|
||||
|
||||
use crate::diag::{bail, error, At, SourceDiagnostic, SourceResult};
|
||||
use crate::diag::{bail, error, At, SourceResult};
|
||||
use crate::eval::{ops, CapturesVisitor, Eval, Vm};
|
||||
use crate::foundations::{
|
||||
Array, Capturer, Closure, Content, ContextElem, Dict, Func, NativeElement, Str, Value,
|
||||
@ -244,11 +244,11 @@ impl Eval for ast::Dict<'_> {
|
||||
ast::DictItem::Keyed(keyed) => {
|
||||
let raw_key = keyed.key();
|
||||
let key = raw_key.eval(vm)?;
|
||||
let key = key.cast::<Str>().unwrap_or_else(|error| {
|
||||
let error = SourceDiagnostic::error(raw_key.span(), error);
|
||||
invalid_keys.push(error);
|
||||
Str::default()
|
||||
});
|
||||
let key =
|
||||
key.cast::<Str>().at(raw_key.span()).unwrap_or_else(|errors| {
|
||||
invalid_keys.extend(errors);
|
||||
Str::default()
|
||||
});
|
||||
map.insert(key, keyed.expr().eval(vm)?);
|
||||
}
|
||||
ast::DictItem::Spread(spread) => match spread.expr().eval(vm)? {
|
||||
|
@ -4,7 +4,7 @@ use std::cmp::Ordering;
|
||||
|
||||
use ecow::eco_format;
|
||||
|
||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::eval::{access_dict, Access, Eval, Vm};
|
||||
use crate::foundations::{format_str, Datetime, IntoValue, Regex, Repr, Value};
|
||||
use crate::layout::{Alignment, Length, Rel};
|
||||
@ -59,7 +59,7 @@ impl Eval for ast::Binary<'_> {
|
||||
fn apply_binary(
|
||||
binary: ast::Binary,
|
||||
vm: &mut Vm,
|
||||
op: fn(Value, Value) -> StrResult<Value>,
|
||||
op: fn(Value, Value) -> HintedStrResult<Value>,
|
||||
) -> SourceResult<Value> {
|
||||
let lhs = binary.lhs().eval(vm)?;
|
||||
|
||||
@ -78,7 +78,7 @@ fn apply_binary(
|
||||
fn apply_assignment(
|
||||
binary: ast::Binary,
|
||||
vm: &mut Vm,
|
||||
op: fn(Value, Value) -> StrResult<Value>,
|
||||
op: fn(Value, Value) -> HintedStrResult<Value>,
|
||||
) -> SourceResult<Value> {
|
||||
let rhs = binary.rhs().eval(vm)?;
|
||||
let lhs = binary.lhs();
|
||||
@ -102,7 +102,7 @@ fn apply_assignment(
|
||||
/// Bail with a type mismatch error.
|
||||
macro_rules! mismatch {
|
||||
($fmt:expr, $($value:expr),* $(,)?) => {
|
||||
return Err(eco_format!($fmt, $($value.ty()),*))
|
||||
return Err(eco_format!($fmt, $($value.ty()),*).into())
|
||||
};
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ pub fn join(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Apply the unary plus operator to a value.
|
||||
pub fn pos(value: Value) -> StrResult<Value> {
|
||||
pub fn pos(value: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
Ok(match value {
|
||||
Int(v) => Int(v),
|
||||
@ -159,7 +159,7 @@ pub fn pos(value: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the negation of a value.
|
||||
pub fn neg(value: Value) -> StrResult<Value> {
|
||||
pub fn neg(value: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
Ok(match value {
|
||||
Int(v) => Int(v.checked_neg().ok_or_else(too_large)?),
|
||||
@ -176,7 +176,7 @@ pub fn neg(value: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the sum of two values.
|
||||
pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn add(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
Ok(match (lhs, rhs) {
|
||||
(a, None) => a,
|
||||
@ -252,7 +252,7 @@ pub fn add(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the difference of two values.
|
||||
pub fn sub(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn sub(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
Ok(match (lhs, rhs) {
|
||||
(Int(a), Int(b)) => Int(a.checked_sub(b).ok_or_else(too_large)?),
|
||||
@ -285,7 +285,7 @@ pub fn sub(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the product of two values.
|
||||
pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn mul(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
Ok(match (lhs, rhs) {
|
||||
(Int(a), Int(b)) => Int(a.checked_mul(b).ok_or_else(too_large)?),
|
||||
@ -344,7 +344,7 @@ pub fn mul(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the quotient of two values.
|
||||
pub fn div(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn div(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
use Value::*;
|
||||
if is_zero(&rhs) {
|
||||
bail!("cannot divide by zero");
|
||||
@ -416,7 +416,7 @@ fn try_div_relative(a: Rel<Length>, b: Rel<Length>) -> StrResult<f64> {
|
||||
}
|
||||
|
||||
/// Compute the logical "not" of a value.
|
||||
pub fn not(value: Value) -> StrResult<Value> {
|
||||
pub fn not(value: Value) -> HintedStrResult<Value> {
|
||||
match value {
|
||||
Value::Bool(b) => Ok(Value::Bool(!b)),
|
||||
v => mismatch!("cannot apply 'not' to {}", v),
|
||||
@ -424,7 +424,7 @@ pub fn not(value: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the logical "and" of two values.
|
||||
pub fn and(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn and(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
match (lhs, rhs) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a && b)),
|
||||
(a, b) => mismatch!("cannot apply 'and' to {} and {}", a, b),
|
||||
@ -432,7 +432,7 @@ pub fn and(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute the logical "or" of two values.
|
||||
pub fn or(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn or(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
match (lhs, rhs) {
|
||||
(Value::Bool(a), Value::Bool(b)) => Ok(Value::Bool(a || b)),
|
||||
(a, b) => mismatch!("cannot apply 'or' to {} and {}", a, b),
|
||||
@ -440,19 +440,19 @@ pub fn or(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Compute whether two values are equal.
|
||||
pub fn eq(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn eq(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
Ok(Value::Bool(equal(&lhs, &rhs)))
|
||||
}
|
||||
|
||||
/// Compute whether two values are unequal.
|
||||
pub fn neq(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn neq(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
Ok(Value::Bool(!equal(&lhs, &rhs)))
|
||||
}
|
||||
|
||||
macro_rules! comparison {
|
||||
($name:ident, $op:tt, $($pat:tt)*) => {
|
||||
/// Compute how a value compares with another value.
|
||||
pub fn $name(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn $name(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
let ordering = compare(&lhs, &rhs)?;
|
||||
Ok(Value::Bool(matches!(ordering, $($pat)*)))
|
||||
}
|
||||
@ -577,7 +577,7 @@ fn try_cmp_arrays(a: &[Value], b: &[Value]) -> StrResult<Ordering> {
|
||||
}
|
||||
|
||||
/// Test whether one value is "in" another one.
|
||||
pub fn in_(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn in_(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
if let Some(b) = contains(&lhs, &rhs) {
|
||||
Ok(Value::Bool(b))
|
||||
} else {
|
||||
@ -586,7 +586,7 @@ pub fn in_(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
}
|
||||
|
||||
/// Test whether one value is "not in" another one.
|
||||
pub fn not_in(lhs: Value, rhs: Value) -> StrResult<Value> {
|
||||
pub fn not_in(lhs: Value, rhs: Value) -> HintedStrResult<Value> {
|
||||
if let Some(b) = contains(&lhs, &rhs) {
|
||||
Ok(Value::Bool(!b))
|
||||
} else {
|
||||
|
@ -178,9 +178,9 @@ impl Args {
|
||||
};
|
||||
let span = item.value.span;
|
||||
let spanned = Spanned::new(std::mem::take(&mut item.value.v), span);
|
||||
match T::from_value(spanned) {
|
||||
match T::from_value(spanned).at(span) {
|
||||
Ok(val) => list.push(val),
|
||||
Err(err) => errors.push(SourceDiagnostic::error(span, err)),
|
||||
Err(diags) => errors.extend(diags),
|
||||
}
|
||||
false
|
||||
});
|
||||
|
@ -8,7 +8,7 @@ use ecow::{eco_format, EcoString, EcoVec};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::diag::{bail, At, SourceDiagnostic, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, HintedStrResult, SourceDiagnostic, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::eval::ops;
|
||||
use crate::foundations::{
|
||||
@ -594,7 +594,7 @@ impl Array {
|
||||
/// be empty.
|
||||
#[named]
|
||||
default: Option<Value>,
|
||||
) -> StrResult<Value> {
|
||||
) -> HintedStrResult<Value> {
|
||||
let mut iter = self.into_iter();
|
||||
let mut acc = iter
|
||||
.next()
|
||||
@ -615,7 +615,7 @@ impl Array {
|
||||
/// be empty.
|
||||
#[named]
|
||||
default: Option<Value>,
|
||||
) -> StrResult<Value> {
|
||||
) -> HintedStrResult<Value> {
|
||||
let mut iter = self.into_iter();
|
||||
let mut acc = iter
|
||||
.next()
|
||||
@ -1095,13 +1095,13 @@ impl<T: IntoValue, const N: usize> IntoValue for SmallVec<[T; N]> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Vec<T> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
value.cast::<Array>()?.into_iter().map(Value::cast).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromValue, const N: usize> FromValue for SmallVec<[T; N]> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
value.cast::<Array>()?.into_iter().map(Value::cast).collect()
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use ecow::EcoString;
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use crate::diag::StrResult;
|
||||
use crate::diag::HintedStrResult;
|
||||
use crate::foundations::{
|
||||
ty, CastInfo, Fold, FromValue, IntoValue, Reflect, Repr, Resolve, StyleChain, Type,
|
||||
Value,
|
||||
@ -26,7 +26,7 @@ impl IntoValue for AutoValue {
|
||||
}
|
||||
|
||||
impl FromValue for AutoValue {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::Auto => Ok(Self),
|
||||
_ => Err(Self::error(&value)),
|
||||
@ -236,7 +236,7 @@ impl<T: IntoValue> IntoValue for Smart<T> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Smart<T> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::Auto => Ok(Self::Auto),
|
||||
v if T::castable(&v) => Ok(Self::Custom(T::from_value(v)?)),
|
||||
|
@ -7,7 +7,7 @@ use ecow::{eco_format, EcoString};
|
||||
use smallvec::SmallVec;
|
||||
use unicode_math_class::MathClass;
|
||||
|
||||
use crate::diag::{At, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::diag::{At, HintedStrResult, HintedString, SourceResult, StrResult};
|
||||
use crate::foundations::{array, repr, NativeElement, Packed, Repr, Str, Type, Value};
|
||||
use crate::syntax::{Span, Spanned};
|
||||
|
||||
@ -50,8 +50,8 @@ pub trait Reflect {
|
||||
/// "expected integer, found none",
|
||||
/// );
|
||||
/// ```
|
||||
fn error(found: &Value) -> EcoString {
|
||||
Self::input().error(found)
|
||||
fn error(found: &Value) -> HintedString {
|
||||
Self::input().error(found).into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -249,17 +249,17 @@ impl<T: IntoValue> IntoValue for fn() -> T {
|
||||
/// See also: [`Reflect`].
|
||||
pub trait FromValue<V = Value>: Sized + Reflect {
|
||||
/// Try to cast the value into an instance of `Self`.
|
||||
fn from_value(value: V) -> StrResult<Self>;
|
||||
fn from_value(value: V) -> HintedStrResult<Self>;
|
||||
}
|
||||
|
||||
impl FromValue for Value {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NativeElement + FromValue> FromValue for Packed<T> {
|
||||
fn from_value(mut value: Value) -> StrResult<Self> {
|
||||
fn from_value(mut value: Value) -> HintedStrResult<Self> {
|
||||
if let Value::Content(content) = value {
|
||||
match content.into_packed::<T>() {
|
||||
Ok(packed) => return Ok(packed),
|
||||
@ -272,13 +272,13 @@ impl<T: NativeElement + FromValue> FromValue for Packed<T> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue<Spanned<Value>> for T {
|
||||
fn from_value(value: Spanned<Value>) -> StrResult<Self> {
|
||||
fn from_value(value: Spanned<Value>) -> HintedStrResult<Self> {
|
||||
T::from_value(value.v)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue<Spanned<Value>> for Spanned<T> {
|
||||
fn from_value(value: Spanned<Value>) -> StrResult<Self> {
|
||||
fn from_value(value: Spanned<Value>) -> HintedStrResult<Self> {
|
||||
let span = value.span;
|
||||
T::from_value(value.v).map(|t| Spanned::new(t, span))
|
||||
}
|
||||
@ -432,7 +432,7 @@ impl IntoValue for Never {
|
||||
}
|
||||
|
||||
impl FromValue for Never {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
Err(Self::error(&value))
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use std::fmt::{self, Debug, Formatter};
|
||||
use ecow::EcoString;
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
use crate::diag::StrResult;
|
||||
use crate::diag::HintedStrResult;
|
||||
use crate::foundations::{
|
||||
cast, ty, CastInfo, FromValue, IntoValue, Reflect, Repr, Type, Value,
|
||||
};
|
||||
@ -45,7 +45,7 @@ impl IntoValue for NoneValue {
|
||||
}
|
||||
|
||||
impl FromValue for NoneValue {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::None => Ok(Self),
|
||||
_ => Err(Self::error(&value)),
|
||||
@ -104,7 +104,7 @@ impl<T: IntoValue> IntoValue for Option<T> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Option<T> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::None => Ok(None),
|
||||
v if T::castable(&v) => Ok(Some(T::from_value(v)?)),
|
||||
|
@ -97,17 +97,14 @@ fn cannot_mutate_constant(var: &str) -> HintedString {
|
||||
/// The error message when a variable is not found.
|
||||
#[cold]
|
||||
fn unknown_variable(var: &str) -> HintedString {
|
||||
let mut res = HintedString {
|
||||
message: eco_format!("unknown variable: {}", var),
|
||||
hints: vec![],
|
||||
};
|
||||
let mut res = HintedString::new(eco_format!("unknown variable: {}", var));
|
||||
|
||||
if matches!(var, "none" | "auto" | "false" | "true") {
|
||||
res.hints.push(eco_format!(
|
||||
res.hint(eco_format!(
|
||||
"if you meant to use a literal, try adding a hash before it"
|
||||
));
|
||||
} else if var.contains('-') {
|
||||
res.hints.push(eco_format!(
|
||||
res.hint(eco_format!(
|
||||
"if you meant to use subtraction, try adding spaces around the minus sign",
|
||||
));
|
||||
}
|
||||
|
@ -339,7 +339,7 @@ cast! {
|
||||
}
|
||||
|
||||
impl FromValue for LocatableSelector {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
fn validate(selector: &Selector) -> StrResult<()> {
|
||||
match selector {
|
||||
Selector::Elem(elem, _) => {
|
||||
@ -421,8 +421,8 @@ cast! {
|
||||
}
|
||||
|
||||
impl FromValue for ShowableSelector {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn validate(selector: &Selector, nested: bool) -> StrResult<()> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
fn validate(selector: &Selector, nested: bool) -> HintedStrResult<()> {
|
||||
match selector {
|
||||
Selector::Elem(_, _) => {}
|
||||
Selector::Label(_) => {}
|
||||
|
@ -9,7 +9,7 @@ use serde::de::value::{MapAccessDeserializer, SeqAccessDeserializer};
|
||||
use serde::de::{Error, MapAccess, SeqAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use crate::diag::StrResult;
|
||||
use crate::diag::{HintedStrResult, HintedString, StrResult};
|
||||
use crate::eval::ops;
|
||||
use crate::foundations::{
|
||||
fields, repr, Args, Array, AutoValue, Bytes, CastInfo, Content, Datetime, Dict,
|
||||
@ -151,7 +151,7 @@ impl Value {
|
||||
}
|
||||
|
||||
/// Try to cast the value into a specific type.
|
||||
pub fn cast<T: FromValue>(self) -> StrResult<T> {
|
||||
pub fn cast<T: FromValue>(self) -> HintedStrResult<T> {
|
||||
T::from_value(self)
|
||||
}
|
||||
|
||||
@ -606,7 +606,7 @@ macro_rules! primitive {
|
||||
}
|
||||
|
||||
impl FromValue for $ty {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::$variant(v) => Ok(v),
|
||||
$(Value::$other$(($binding))? => Ok($out),)*
|
||||
@ -614,7 +614,7 @@ macro_rules! primitive {
|
||||
"expected {}, found {}",
|
||||
Type::of::<Self>(),
|
||||
v.ty(),
|
||||
)),
|
||||
).into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -682,7 +682,7 @@ impl<T: Reflect> Reflect for Arc<T> {
|
||||
T::castable(value)
|
||||
}
|
||||
|
||||
fn error(found: &Value) -> EcoString {
|
||||
fn error(found: &Value) -> HintedString {
|
||||
T::error(found)
|
||||
}
|
||||
}
|
||||
@ -694,7 +694,7 @@ impl<T: Clone + IntoValue> IntoValue for Arc<T> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Arc<T> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
v if T::castable(&v) => Ok(Arc::new(T::from_value(v)?)),
|
||||
_ => Err(Self::error(&value)),
|
||||
|
@ -5,7 +5,7 @@ use comemo::{Track, Tracked, TrackedMut};
|
||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, HintedStrResult, SourceResult};
|
||||
use crate::engine::{Engine, Route};
|
||||
use crate::eval::Tracer;
|
||||
use crate::foundations::{
|
||||
@ -709,7 +709,7 @@ cast! {
|
||||
array: Array => Self(array
|
||||
.into_iter()
|
||||
.map(Value::cast)
|
||||
.collect::<StrResult<_>>()?),
|
||||
.collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
/// Executes an update of a counter.
|
||||
|
@ -2,7 +2,7 @@ use std::ops::Add;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
|
||||
use crate::diag::{bail, SourceResult, StrResult};
|
||||
use crate::diag::{bail, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, func, scope, ty, CastInfo, Content, Fold, FromValue, IntoValue, Packed,
|
||||
@ -637,7 +637,7 @@ where
|
||||
H: Reflect + TryFrom<Alignment, Error = EcoString>,
|
||||
V: Reflect + TryFrom<Alignment, Error = EcoString>,
|
||||
{
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
if Alignment::castable(&value) {
|
||||
let align = Alignment::from_value(value)?;
|
||||
let result = match align {
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use crate::diag::StrResult;
|
||||
use crate::diag::HintedStrResult;
|
||||
use crate::foundations::{
|
||||
AlternativeFold, CastInfo, Dict, Fold, FromValue, IntoValue, Reflect, Resolve,
|
||||
StyleChain, Value,
|
||||
@ -175,7 +175,7 @@ impl<T> FromValue for Corners<Option<T>>
|
||||
where
|
||||
T: FromValue + Clone,
|
||||
{
|
||||
fn from_value(mut value: Value) -> StrResult<Self> {
|
||||
fn from_value(mut value: Value) -> HintedStrResult<Self> {
|
||||
let expected_keys = [
|
||||
"top-left",
|
||||
"top-right",
|
||||
@ -224,7 +224,7 @@ where
|
||||
let keys = dict.iter().map(|kv| kv.0.as_str()).collect();
|
||||
// Do not hint at expected_keys, because T may be castable from Dict
|
||||
// objects with other sets of expected keys.
|
||||
Err(Dict::unexpected_keys(keys, None))
|
||||
Err(Dict::unexpected_keys(keys, None).into())
|
||||
} else {
|
||||
Err(Self::error(&value))
|
||||
}
|
||||
|
@ -6,9 +6,7 @@ use ecow::eco_format;
|
||||
|
||||
use super::lines::Line;
|
||||
use super::repeated::{Footer, Header, Repeatable};
|
||||
use crate::diag::{
|
||||
bail, At, Hint, HintedStrResult, HintedString, SourceResult, StrResult,
|
||||
};
|
||||
use crate::diag::{bail, At, Hint, HintedStrResult, HintedString, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
Array, CastInfo, Content, Context, Fold, FromValue, Func, IntoValue, Reflect,
|
||||
@ -85,11 +83,11 @@ impl<T: IntoValue> IntoValue for Celled<T> {
|
||||
}
|
||||
|
||||
impl<T: FromValue> FromValue for Celled<T> {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
match value {
|
||||
Value::Func(v) => Ok(Self::Func(v)),
|
||||
Value::Array(array) => Ok(Self::Array(
|
||||
array.into_iter().map(T::from_value).collect::<StrResult<_>>()?,
|
||||
array.into_iter().map(T::from_value).collect::<HintedStrResult<_>>()?,
|
||||
)),
|
||||
v if T::castable(&v) => Ok(Self::Value(T::from_value(v)?)),
|
||||
v => Err(Self::error(&v)),
|
||||
|
@ -13,10 +13,10 @@ pub use self::lines::LinePosition;
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use ecow::eco_format;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::diag::{bail, SourceResult, StrResult, Trace, Tracepoint};
|
||||
use crate::diag::{bail, HintedStrResult, HintedString, SourceResult, Trace, Tracepoint};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Array, Content, Fold, NativeElement, Packed, Show, Smart,
|
||||
@ -406,7 +406,7 @@ cast! {
|
||||
self => self.0.into_value(),
|
||||
sizing: Sizing => Self(smallvec![sizing]),
|
||||
count: NonZeroUsize => Self(smallvec![Sizing::Auto; count.get()]),
|
||||
values: Array => Self(values.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
values: Array => Self(values.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
/// Any child of a grid element.
|
||||
@ -430,13 +430,19 @@ cast! {
|
||||
}
|
||||
|
||||
impl TryFrom<Content> for GridChild {
|
||||
type Error = EcoString;
|
||||
fn try_from(value: Content) -> StrResult<Self> {
|
||||
type Error = HintedString;
|
||||
fn try_from(value: Content) -> HintedStrResult<Self> {
|
||||
if value.is::<TableHeader>() {
|
||||
bail!("cannot use `table.header` as a grid header; use `grid.header` instead")
|
||||
bail!(
|
||||
"cannot use `table.header` as a grid header";
|
||||
hint: "use `grid.header` instead"
|
||||
)
|
||||
}
|
||||
if value.is::<TableFooter>() {
|
||||
bail!("cannot use `table.footer` as a grid footer; use `grid.footer` instead")
|
||||
bail!(
|
||||
"cannot use `table.footer` as a grid footer";
|
||||
hint: "use `grid.footer` instead"
|
||||
)
|
||||
}
|
||||
|
||||
value
|
||||
@ -506,8 +512,8 @@ cast! {
|
||||
}
|
||||
|
||||
impl TryFrom<Content> for GridItem {
|
||||
type Error = EcoString;
|
||||
fn try_from(value: Content) -> StrResult<Self> {
|
||||
type Error = HintedString;
|
||||
fn try_from(value: Content) -> HintedStrResult<Self> {
|
||||
if value.is::<GridHeader>() {
|
||||
bail!("cannot place a grid header within another header or footer");
|
||||
}
|
||||
@ -521,13 +527,22 @@ impl TryFrom<Content> for GridItem {
|
||||
bail!("cannot place a table footer within another footer or header");
|
||||
}
|
||||
if value.is::<TableCell>() {
|
||||
bail!("cannot use `table.cell` as a grid cell; use `grid.cell` instead");
|
||||
bail!(
|
||||
"cannot use `table.cell` as a grid cell";
|
||||
hint: "use `grid.cell` instead"
|
||||
);
|
||||
}
|
||||
if value.is::<TableHLine>() {
|
||||
bail!("cannot use `table.hline` as a grid line; use `grid.hline` instead");
|
||||
bail!(
|
||||
"cannot use `table.hline` as a grid line";
|
||||
hint: "use `grid.hline` instead"
|
||||
);
|
||||
}
|
||||
if value.is::<TableVLine>() {
|
||||
bail!("cannot use `table.vline` as a grid line; use `grid.vline` instead");
|
||||
bail!(
|
||||
"cannot use `table.vline` as a grid line";
|
||||
hint: "use `grid.vline` instead"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(value
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::ops::Add;
|
||||
|
||||
use crate::diag::{bail, StrResult};
|
||||
use crate::diag::{bail, HintedStrResult};
|
||||
use crate::foundations::{
|
||||
cast, AlternativeFold, CastInfo, Dict, Fold, FromValue, IntoValue, Reflect, Resolve,
|
||||
StyleChain, Value,
|
||||
@ -209,7 +209,7 @@ impl<T> FromValue for Sides<Option<T>>
|
||||
where
|
||||
T: Default + FromValue + Clone,
|
||||
{
|
||||
fn from_value(mut value: Value) -> StrResult<Self> {
|
||||
fn from_value(mut value: Value) -> HintedStrResult<Self> {
|
||||
let expected_keys = ["left", "top", "right", "bottom", "x", "y", "rest"];
|
||||
if let Value::Dict(dict) = &mut value {
|
||||
if dict.is_empty() {
|
||||
@ -237,7 +237,7 @@ where
|
||||
let keys = dict.iter().map(|kv| kv.0.as_str()).collect();
|
||||
// Do not hint at expected_keys, because T may be castable from Dict
|
||||
// objects with other sets of expected keys.
|
||||
Err(Dict::unexpected_keys(keys, None))
|
||||
Err(Dict::unexpected_keys(keys, None).into())
|
||||
} else {
|
||||
Err(Self::error(&value))
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use unicode_math_class::MathClass;
|
||||
|
||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
||||
use crate::diag::{bail, At, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::foundations::{
|
||||
array, cast, dict, elem, Array, Content, Dict, Fold, NoneValue, Packed, Resolve,
|
||||
Smart, StyleChain, Value,
|
||||
@ -712,5 +712,5 @@ cast! {
|
||||
AugmentOffsets,
|
||||
self => self.0.into_value(),
|
||||
v: isize => Self(smallvec![v]),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use once_cell::sync::Lazy;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use typed_arena::Arena;
|
||||
|
||||
use crate::diag::{bail, error, At, FileError, SourceResult, StrResult};
|
||||
use crate::diag::{bail, error, At, FileError, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::eval::{eval_string, EvalMode};
|
||||
use crate::foundations::{
|
||||
@ -150,7 +150,7 @@ cast! {
|
||||
BibliographyPaths,
|
||||
self => self.0.into_value(),
|
||||
v: EcoString => Self(vec![v]),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
impl BibliographyElem {
|
||||
@ -508,7 +508,7 @@ impl Reflect for CslStyle {
|
||||
}
|
||||
|
||||
impl FromValue for CslStyle {
|
||||
fn from_value(value: Value) -> StrResult<Self> {
|
||||
fn from_value(value: Value) -> HintedStrResult<Self> {
|
||||
if let Value::Dyn(dynamic) = &value {
|
||||
if let Some(concrete) = dynamic.downcast::<Self>() {
|
||||
return Ok(concrete.clone());
|
||||
|
@ -1,6 +1,6 @@
|
||||
use ecow::EcoString;
|
||||
|
||||
use crate::diag::{bail, SourceResult, StrResult};
|
||||
use crate::diag::{bail, HintedStrResult, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, Args, Array, Construct, Content, Datetime, Packed, Smart, StyleChain,
|
||||
@ -115,7 +115,7 @@ cast! {
|
||||
Author,
|
||||
self => self.0.into_value(),
|
||||
v: EcoString => Self(vec![v]),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
/// A list of keywords.
|
||||
@ -126,7 +126,7 @@ cast! {
|
||||
Keywords,
|
||||
self => self.0.into_value(),
|
||||
v: EcoString => Self(vec![v]),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
/// A finished document with metadata and page frames.
|
||||
|
@ -1,9 +1,9 @@
|
||||
use std::num::NonZeroUsize;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use ecow::eco_format;
|
||||
|
||||
use crate::diag::{bail, SourceResult, StrResult, Trace, Tracepoint};
|
||||
use crate::diag::{bail, HintedStrResult, HintedString, SourceResult, Trace, Tracepoint};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Content, Fold, NativeElement, Packed, Show, Smart, StyleChain,
|
||||
@ -346,17 +346,19 @@ cast! {
|
||||
}
|
||||
|
||||
impl TryFrom<Content> for TableChild {
|
||||
type Error = EcoString;
|
||||
type Error = HintedString;
|
||||
|
||||
fn try_from(value: Content) -> StrResult<Self> {
|
||||
fn try_from(value: Content) -> HintedStrResult<Self> {
|
||||
if value.is::<GridHeader>() {
|
||||
bail!(
|
||||
"cannot use `grid.header` as a table header; use `table.header` instead"
|
||||
"cannot use `grid.header` as a table header";
|
||||
hint: "use `table.header` instead"
|
||||
)
|
||||
}
|
||||
if value.is::<GridFooter>() {
|
||||
bail!(
|
||||
"cannot use `grid.footer` as a table footer; use `table.footer` instead"
|
||||
"cannot use `grid.footer` as a table footer";
|
||||
hint: "use `table.footer` instead"
|
||||
)
|
||||
}
|
||||
|
||||
@ -427,9 +429,9 @@ cast! {
|
||||
}
|
||||
|
||||
impl TryFrom<Content> for TableItem {
|
||||
type Error = EcoString;
|
||||
type Error = HintedString;
|
||||
|
||||
fn try_from(value: Content) -> StrResult<Self> {
|
||||
fn try_from(value: Content) -> HintedStrResult<Self> {
|
||||
if value.is::<GridHeader>() {
|
||||
bail!("cannot place a grid header within another header or footer");
|
||||
}
|
||||
@ -443,13 +445,22 @@ impl TryFrom<Content> for TableItem {
|
||||
bail!("cannot place a table footer within another footer or header");
|
||||
}
|
||||
if value.is::<GridCell>() {
|
||||
bail!("cannot use `grid.cell` as a table cell; use `table.cell` instead");
|
||||
bail!(
|
||||
"cannot use `grid.cell` as a table cell";
|
||||
hint: "use `table.cell` instead"
|
||||
);
|
||||
}
|
||||
if value.is::<GridHLine>() {
|
||||
bail!("cannot use `grid.hline` as a table line; use `table.hline` instead");
|
||||
bail!(
|
||||
"cannot use `grid.hline` as a table line";
|
||||
hint: "use `table.hline` instead"
|
||||
);
|
||||
}
|
||||
if value.is::<GridVLine>() {
|
||||
bail!("cannot use `grid.vline` as a table line; use `table.vline` instead");
|
||||
bail!(
|
||||
"cannot use `grid.vline` as a table line";
|
||||
hint: "use `table.vline` instead"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(value
|
||||
|
@ -1,7 +1,8 @@
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
use ecow::EcoString;
|
||||
use crate::diag::Hint;
|
||||
use ecow::{eco_format, EcoString};
|
||||
|
||||
use crate::foundations::{cast, StyleChain};
|
||||
use crate::layout::Dir;
|
||||
@ -121,7 +122,22 @@ impl FromStr for Lang {
|
||||
cast! {
|
||||
Lang,
|
||||
self => self.as_str().into_value(),
|
||||
string: EcoString => Self::from_str(&string)?,
|
||||
string: EcoString => {
|
||||
let result = Self::from_str(&string);
|
||||
if result.is_err() {
|
||||
if let Some((lang, region)) = string.split_once('-') {
|
||||
if Lang::from_str(lang).is_ok() && Region::from_str(region).is_ok() {
|
||||
return result
|
||||
.hint(eco_format!(
|
||||
"you should leave only \"{}\" in the `lang` parameter and specify \"{}\" in the `region` parameter",
|
||||
lang, region,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result?
|
||||
}
|
||||
}
|
||||
|
||||
/// An identifier for a region somewhere in the world.
|
||||
|
@ -29,14 +29,13 @@ pub use self::smartquote::*;
|
||||
pub use self::space::*;
|
||||
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use rustybuzz::{Feature, Tag};
|
||||
use smallvec::SmallVec;
|
||||
use ttf_parser::Rect;
|
||||
|
||||
use crate::diag::{bail, warning, At, Hint, SourceResult, StrResult};
|
||||
use crate::diag::{bail, warning, HintedStrResult, SourceResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, category, dict, elem, Args, Array, Cast, Category, Construct, Content, Dict,
|
||||
@ -394,7 +393,6 @@ pub struct TextElem {
|
||||
/// = Einleitung
|
||||
/// In diesem Dokument, ...
|
||||
/// ```
|
||||
#[parse(parse_lang(args)?)]
|
||||
#[default(Lang::ENGLISH)]
|
||||
#[ghost]
|
||||
pub lang: Lang,
|
||||
@ -812,7 +810,7 @@ cast! {
|
||||
self.0.into_value()
|
||||
},
|
||||
family: FontFamily => Self(vec![family]),
|
||||
values: Array => Self(values.into_iter().map(|v| v.cast()).collect::<StrResult<_>>()?),
|
||||
values: Array => Self(values.into_iter().map(|v| v.cast()).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
/// Resolve a prioritized iterator over the font families.
|
||||
@ -1131,7 +1129,7 @@ cast! {
|
||||
let tag = v.cast::<EcoString>()?;
|
||||
Ok((Tag::from_bytes_lossy(tag.as_bytes()), 1))
|
||||
})
|
||||
.collect::<StrResult<_>>()?),
|
||||
.collect::<HintedStrResult<_>>()?),
|
||||
values: Dict => Self(values
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
@ -1139,7 +1137,7 @@ cast! {
|
||||
let tag = Tag::from_bytes_lossy(k.as_bytes());
|
||||
Ok((tag, num))
|
||||
})
|
||||
.collect::<StrResult<_>>()?),
|
||||
.collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
impl Fold for FontFeatures {
|
||||
@ -1300,27 +1298,3 @@ cast! {
|
||||
ret
|
||||
},
|
||||
}
|
||||
|
||||
/// Function to parse the language argument.
|
||||
/// Provides a hint if a region is used in the language parameter.
|
||||
fn parse_lang(args: &mut Args) -> SourceResult<Option<Lang>> {
|
||||
let Some(Spanned { v: iso, span }) = args.named::<Spanned<EcoString>>("lang")? else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
||||
let result = Lang::from_str(&iso);
|
||||
if result.is_err() {
|
||||
if let Some((lang, region)) = iso.split_once('-') {
|
||||
if Lang::from_str(lang).is_ok() && Region::from_str(region).is_ok() {
|
||||
return result
|
||||
.hint(eco_format!(
|
||||
"you should leave only \"{}\" in the `lang` parameter and specify \"{}\" in the `region` parameter",
|
||||
lang, region,
|
||||
))
|
||||
.at(span)
|
||||
.map(Some);
|
||||
}
|
||||
}
|
||||
}
|
||||
result.at(span).map(Some)
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use syntect::parsing::{SyntaxDefinition, SyntaxSet, SyntaxSetBuilder};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use super::Lang;
|
||||
use crate::diag::{At, FileError, SourceResult, StrResult};
|
||||
use crate::diag::{At, FileError, HintedStrResult, SourceResult, StrResult};
|
||||
use crate::engine::Engine;
|
||||
use crate::foundations::{
|
||||
cast, elem, scope, Args, Array, Bytes, Content, Fold, NativeElement, Packed,
|
||||
@ -728,7 +728,7 @@ cast! {
|
||||
SyntaxPaths,
|
||||
self => self.0.into_value(),
|
||||
v: EcoString => Self(vec![v]),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<StrResult<_>>()?),
|
||||
v: Array => Self(v.into_iter().map(Value::cast).collect::<HintedStrResult<_>>()?),
|
||||
}
|
||||
|
||||
impl Fold for SyntaxPaths {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use ecow::EcoString;
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
|
||||
use crate::diag::{bail, StrResult};
|
||||
use crate::diag::{bail, HintedStrResult, StrResult};
|
||||
use crate::foundations::{
|
||||
array, cast, dict, elem, Array, Dict, FromValue, Packed, PlainText, Smart, Str,
|
||||
};
|
||||
@ -332,7 +332,7 @@ fn str_to_set(value: &str) -> StrResult<[EcoString; 2]> {
|
||||
}
|
||||
}
|
||||
|
||||
fn array_to_set(value: Array) -> StrResult<[EcoString; 2]> {
|
||||
fn array_to_set(value: Array) -> HintedStrResult<[EcoString; 2]> {
|
||||
let value = value.as_slice();
|
||||
if value.len() != 2 {
|
||||
bail!(
|
||||
|
@ -1,6 +1,6 @@
|
||||
use ecow::EcoString;
|
||||
|
||||
use crate::diag::{SourceResult, StrResult};
|
||||
use crate::diag::{HintedStrResult, SourceResult};
|
||||
use crate::foundations::{
|
||||
cast, dict, func, scope, ty, Args, Cast, Dict, Fold, FromValue, NoneValue, Repr,
|
||||
Resolve, Smart, StyleChain, Value,
|
||||
@ -378,7 +378,7 @@ cast! {
|
||||
},
|
||||
mut dict: Dict => {
|
||||
// Get a value by key, accepting either Auto or something convertible to type T.
|
||||
fn take<T: FromValue>(dict: &mut Dict, key: &str) -> StrResult<Smart<T>> {
|
||||
fn take<T: FromValue>(dict: &mut Dict, key: &str) -> HintedStrResult<Smart<T>> {
|
||||
Ok(dict.take(key).ok().map(Smart::<T>::from_value)
|
||||
.transpose()?.unwrap_or(Smart::Auto))
|
||||
}
|
||||
|
@ -128,5 +128,6 @@
|
||||
}
|
||||
|
||||
--- table-cell-in-grid ---
|
||||
// Error: 7-19 cannot use `table.cell` as a grid cell; use `grid.cell` instead
|
||||
// Error: 7-19 cannot use `table.cell` as a grid cell
|
||||
// Hint: 7-19 use `grid.cell` instead
|
||||
#grid(table.cell[])
|
||||
|
@ -131,14 +131,16 @@
|
||||
)
|
||||
|
||||
--- table-footer-in-grid ---
|
||||
// Error: 3:3-3:20 cannot use `table.footer` as a grid footer; use `grid.footer` instead
|
||||
// Error: 3:3-3:20 cannot use `table.footer` as a grid footer
|
||||
// Hint: 3:3-3:20 use `grid.footer` instead
|
||||
#grid(
|
||||
[a],
|
||||
table.footer([a]),
|
||||
)
|
||||
|
||||
--- grid-footer-in-table ---
|
||||
// Error: 3:3-3:19 cannot use `grid.footer` as a table footer; use `table.footer` instead
|
||||
// Error: 3:3-3:19 cannot use `grid.footer` as a table footer
|
||||
// Hint: 3:3-3:19 use `table.footer` instead
|
||||
#table(
|
||||
[a],
|
||||
grid.footer([a]),
|
||||
|
@ -133,14 +133,16 @@
|
||||
)
|
||||
|
||||
--- table-header-in-grid ---
|
||||
// Error: 2:3-2:20 cannot use `table.header` as a grid header; use `grid.header` instead
|
||||
// Error: 2:3-2:20 cannot use `table.header` as a grid header
|
||||
// Hint: 2:3-2:20 use `grid.header` instead
|
||||
#grid(
|
||||
table.header([a]),
|
||||
[a],
|
||||
)
|
||||
|
||||
--- grid-header-in-table ---
|
||||
// Error: 2:3-2:19 cannot use `grid.header` as a table header; use `table.header` instead
|
||||
// Error: 2:3-2:19 cannot use `grid.header` as a table header
|
||||
// Hint: 2:3-2:19 use `table.header` instead
|
||||
#table(
|
||||
grid.header([a]),
|
||||
[a],
|
||||
|
@ -385,19 +385,23 @@
|
||||
)
|
||||
|
||||
--- table-hline-in-grid ---
|
||||
// Error: 7-20 cannot use `table.hline` as a grid line; use `grid.hline` instead
|
||||
// Error: 7-20 cannot use `table.hline` as a grid line
|
||||
// Hint: 7-20 use `grid.hline` instead
|
||||
#grid(table.hline())
|
||||
|
||||
--- table-vline-in-grid ---
|
||||
// Error: 7-20 cannot use `table.vline` as a grid line; use `grid.vline` instead
|
||||
// Error: 7-20 cannot use `table.vline` as a grid line
|
||||
// Hint: 7-20 use `grid.vline` instead
|
||||
#grid(table.vline())
|
||||
|
||||
--- grid-hline-in-table ---
|
||||
// Error: 8-20 cannot use `grid.hline` as a table line; use `table.hline` instead
|
||||
// Error: 8-20 cannot use `grid.hline` as a table line
|
||||
// Hint: 8-20 use `table.hline` instead
|
||||
#table(grid.hline())
|
||||
|
||||
--- grid-vline-in-table ---
|
||||
// Error: 8-20 cannot use `grid.vline` as a table line; use `table.vline` instead
|
||||
// Error: 8-20 cannot use `grid.vline` as a table line
|
||||
// Hint: 8-20 use `table.vline` instead
|
||||
#table(grid.vline())
|
||||
|
||||
--- grid-hline-end-before-start-1 ---
|
||||
|
@ -262,7 +262,8 @@
|
||||
}
|
||||
|
||||
--- grid-cell-in-table ---
|
||||
// Error: 8-19 cannot use `grid.cell` as a table cell; use `table.cell` instead
|
||||
// Error: 8-19 cannot use `grid.cell` as a table cell
|
||||
// Hint: 8-19 use `table.cell` instead
|
||||
#table(grid.cell[])
|
||||
|
||||
--- issue-183-table-lines ---
|
||||
|
Loading…
x
Reference in New Issue
Block a user