mirror of
https://github.com/typst/typst
synced 2025-06-28 08:12:53 +08:00
Scope deprecations (#5798)
This commit is contained in:
parent
5b3593e571
commit
50ccd7d60f
@ -315,13 +315,15 @@ fn eval_field_call(
|
|||||||
(target, args)
|
(target, args)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let field_span = field.span();
|
||||||
|
let sink = (&mut vm.engine, field_span);
|
||||||
if let Some(callee) = target.ty().scope().get(&field) {
|
if let Some(callee) = target.ty().scope().get(&field) {
|
||||||
args.insert(0, target_expr.span(), target);
|
args.insert(0, target_expr.span(), target);
|
||||||
Ok(FieldCall::Normal(callee.read().clone(), args))
|
Ok(FieldCall::Normal(callee.read_checked(sink).clone(), args))
|
||||||
} else if let Value::Content(content) = &target {
|
} else if let Value::Content(content) = &target {
|
||||||
if let Some(callee) = content.elem().scope().get(&field) {
|
if let Some(callee) = content.elem().scope().get(&field) {
|
||||||
args.insert(0, target_expr.span(), target);
|
args.insert(0, target_expr.span(), target);
|
||||||
Ok(FieldCall::Normal(callee.read().clone(), args))
|
Ok(FieldCall::Normal(callee.read_checked(sink).clone(), args))
|
||||||
} else {
|
} else {
|
||||||
bail!(missing_field_call_error(target, field))
|
bail!(missing_field_call_error(target, field))
|
||||||
}
|
}
|
||||||
@ -331,7 +333,7 @@ fn eval_field_call(
|
|||||||
) {
|
) {
|
||||||
// Certain value types may have their own ways to access method fields.
|
// Certain value types may have their own ways to access method fields.
|
||||||
// e.g. `$arrow.r(v)$`, `table.cell[..]`
|
// e.g. `$arrow.r(v)$`, `table.cell[..]`
|
||||||
let value = target.field(&field).at(field.span())?;
|
let value = target.field(&field, sink).at(field_span)?;
|
||||||
Ok(FieldCall::Normal(value, args))
|
Ok(FieldCall::Normal(value, args))
|
||||||
} else {
|
} else {
|
||||||
// Otherwise we cannot call this field.
|
// Otherwise we cannot call this field.
|
||||||
@ -364,7 +366,7 @@ fn missing_field_call_error(target: Value, field: Ident) -> SourceDiagnostic {
|
|||||||
field.as_str(),
|
field.as_str(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
_ if target.field(&field).is_ok() => {
|
_ if target.field(&field, ()).is_ok() => {
|
||||||
error.hint(eco_format!(
|
error.hint(eco_format!(
|
||||||
"did you mean to access the field `{}`?",
|
"did you mean to access the field `{}`?",
|
||||||
field.as_str(),
|
field.as_str(),
|
||||||
|
@ -154,7 +154,13 @@ impl Eval for ast::Ident<'_> {
|
|||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||||
Ok(vm.scopes.get(&self).at(self.span())?.read().clone())
|
let span = self.span();
|
||||||
|
Ok(vm
|
||||||
|
.scopes
|
||||||
|
.get(&self)
|
||||||
|
.at(span)?
|
||||||
|
.read_checked((&mut vm.engine, span))
|
||||||
|
.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,8 +316,9 @@ impl Eval for ast::FieldAccess<'_> {
|
|||||||
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||||
let value = self.target().eval(vm)?;
|
let value = self.target().eval(vm)?;
|
||||||
let field = self.field();
|
let field = self.field();
|
||||||
|
let field_span = field.span();
|
||||||
|
|
||||||
let err = match value.field(&field).at(field.span()) {
|
let err = match value.field(&field, (&mut vm.engine, field_span)).at(field_span) {
|
||||||
Ok(value) => return Ok(value),
|
Ok(value) => return Ok(value),
|
||||||
Err(err) => err,
|
Err(err) => err,
|
||||||
};
|
};
|
||||||
|
@ -35,7 +35,13 @@ impl Eval for ast::MathIdent<'_> {
|
|||||||
type Output = Value;
|
type Output = Value;
|
||||||
|
|
||||||
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
fn eval(self, vm: &mut Vm) -> SourceResult<Self::Output> {
|
||||||
Ok(vm.scopes.get_in_math(&self).at(self.span())?.read().clone())
|
let span = self.span();
|
||||||
|
Ok(vm
|
||||||
|
.scopes
|
||||||
|
.get_in_math(&self)
|
||||||
|
.at(span)?
|
||||||
|
.read_checked((&mut vm.engine, span))
|
||||||
|
.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,7 +414,7 @@ fn field_access_completions(
|
|||||||
// with method syntax;
|
// with method syntax;
|
||||||
// 2. We can unwrap the field's value since it's a field belonging to
|
// 2. We can unwrap the field's value since it's a field belonging to
|
||||||
// this value's type, so accessing it should not fail.
|
// this value's type, so accessing it should not fail.
|
||||||
ctx.value_completion(field, &value.field(field).unwrap());
|
ctx.value_completion(field, &value.field(field, ()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
|
@ -11,6 +11,7 @@ use ecow::{eco_vec, EcoVec};
|
|||||||
use typst_syntax::package::{PackageSpec, PackageVersion};
|
use typst_syntax::package::{PackageSpec, PackageVersion};
|
||||||
use typst_syntax::{Span, Spanned, SyntaxError};
|
use typst_syntax::{Span, Spanned, SyntaxError};
|
||||||
|
|
||||||
|
use crate::engine::Engine;
|
||||||
use crate::{World, WorldExt};
|
use crate::{World, WorldExt};
|
||||||
|
|
||||||
/// Early-return with a [`StrResult`] or [`SourceResult`].
|
/// Early-return with a [`StrResult`] or [`SourceResult`].
|
||||||
@ -228,6 +229,23 @@ impl From<SyntaxError> for SourceDiagnostic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destination for a deprecation message when accessing a deprecated value.
|
||||||
|
pub trait DeprecationSink {
|
||||||
|
/// Emits the given deprecation message into this sink.
|
||||||
|
fn emit(self, message: &str);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeprecationSink for () {
|
||||||
|
fn emit(self, _: &str) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeprecationSink for (&mut Engine<'_>, Span) {
|
||||||
|
/// Emits the deprecation message as a warning.
|
||||||
|
fn emit(self, message: &str) {
|
||||||
|
self.0.sink.warn(SourceDiagnostic::warning(self.1, message));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A part of a diagnostic's [trace](SourceDiagnostic::trace).
|
/// A part of a diagnostic's [trace](SourceDiagnostic::trace).
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub enum Tracepoint {
|
pub enum Tracepoint {
|
||||||
|
@ -9,7 +9,7 @@ use ecow::{eco_format, EcoString};
|
|||||||
use typst_syntax::{ast, Span, SyntaxNode};
|
use typst_syntax::{ast, Span, SyntaxNode};
|
||||||
use typst_utils::{singleton, LazyHash, Static};
|
use typst_utils::{singleton, LazyHash, Static};
|
||||||
|
|
||||||
use crate::diag::{bail, At, SourceResult, StrResult};
|
use crate::diag::{bail, At, DeprecationSink, SourceResult, StrResult};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, repr, scope, ty, Args, Bytes, CastInfo, Content, Context, Element, IntoArgs,
|
cast, repr, scope, ty, Args, Bytes, CastInfo, Content, Context, Element, IntoArgs,
|
||||||
@ -255,11 +255,15 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a field from this function's scope, if possible.
|
/// Get a field from this function's scope, if possible.
|
||||||
pub fn field(&self, field: &str) -> StrResult<&'static Value> {
|
pub fn field(
|
||||||
|
&self,
|
||||||
|
field: &str,
|
||||||
|
sink: impl DeprecationSink,
|
||||||
|
) -> StrResult<&'static Value> {
|
||||||
let scope =
|
let scope =
|
||||||
self.scope().ok_or("cannot access fields on user-defined functions")?;
|
self.scope().ok_or("cannot access fields on user-defined functions")?;
|
||||||
match scope.get(field) {
|
match scope.get(field) {
|
||||||
Some(binding) => Ok(binding.read()),
|
Some(binding) => Ok(binding.read_checked(sink)),
|
||||||
None => match self.name() {
|
None => match self.name() {
|
||||||
Some(name) => bail!("function `{name}` does not contain field `{field}`"),
|
Some(name) => bail!("function `{name}` does not contain field `{field}`"),
|
||||||
None => bail!("function does not contain field `{field}`"),
|
None => bail!("function does not contain field `{field}`"),
|
||||||
|
@ -4,7 +4,7 @@ use std::sync::Arc;
|
|||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use typst_syntax::FileId;
|
use typst_syntax::FileId;
|
||||||
|
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, DeprecationSink, StrResult};
|
||||||
use crate::foundations::{repr, ty, Content, Scope, Value};
|
use crate::foundations::{repr, ty, Content, Scope, Value};
|
||||||
|
|
||||||
/// An module of definitions.
|
/// An module of definitions.
|
||||||
@ -118,9 +118,9 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to access a definition in the module.
|
/// Try to access a definition in the module.
|
||||||
pub fn field(&self, field: &str) -> StrResult<&Value> {
|
pub fn field(&self, field: &str, sink: impl DeprecationSink) -> StrResult<&Value> {
|
||||||
match self.scope().get(field) {
|
match self.scope().get(field) {
|
||||||
Some(binding) => Ok(binding.read()),
|
Some(binding) => Ok(binding.read_checked(sink)),
|
||||||
None => match &self.name {
|
None => match &self.name {
|
||||||
Some(name) => bail!("module `{name}` does not contain `{field}`"),
|
Some(name) => bail!("module `{name}` does not contain `{field}`"),
|
||||||
None => bail!("module does not contain `{field}`"),
|
None => bail!("module does not contain `{field}`"),
|
||||||
|
@ -10,7 +10,7 @@ use indexmap::IndexMap;
|
|||||||
use typst_syntax::Span;
|
use typst_syntax::Span;
|
||||||
use typst_utils::Static;
|
use typst_utils::Static;
|
||||||
|
|
||||||
use crate::diag::{bail, HintedStrResult, HintedString, StrResult};
|
use crate::diag::{bail, DeprecationSink, HintedStrResult, HintedString, StrResult};
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
Element, Func, IntoValue, NativeElement, NativeFunc, NativeFuncData, NativeType,
|
Element, Func, IntoValue, NativeElement, NativeFunc, NativeFuncData, NativeType,
|
||||||
Type, Value,
|
Type, Value,
|
||||||
@ -258,6 +258,8 @@ pub struct Binding {
|
|||||||
span: Span,
|
span: Span,
|
||||||
/// The category of the binding.
|
/// The category of the binding.
|
||||||
category: Option<Category>,
|
category: Option<Category>,
|
||||||
|
/// A deprecation message for the definition.
|
||||||
|
deprecation: Option<&'static str>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The different kinds of slots.
|
/// The different kinds of slots.
|
||||||
@ -277,6 +279,7 @@ impl Binding {
|
|||||||
span,
|
span,
|
||||||
kind: BindingKind::Normal,
|
kind: BindingKind::Normal,
|
||||||
category: None,
|
category: None,
|
||||||
|
deprecation: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,11 +288,29 @@ impl Binding {
|
|||||||
Self::new(value, Span::detached())
|
Self::new(value, Span::detached())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Marks this binding as deprecated, with the given `message`.
|
||||||
|
pub fn deprecated(&mut self, message: &'static str) -> &mut Self {
|
||||||
|
self.deprecation = Some(message);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Read the value.
|
/// Read the value.
|
||||||
pub fn read(&self) -> &Value {
|
pub fn read(&self) -> &Value {
|
||||||
&self.value
|
&self.value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the value, checking for deprecation.
|
||||||
|
///
|
||||||
|
/// As the `sink`
|
||||||
|
/// - pass `()` to ignore the message.
|
||||||
|
/// - pass `(&mut engine, span)` to emit a warning into the engine.
|
||||||
|
pub fn read_checked(&self, sink: impl DeprecationSink) -> &Value {
|
||||||
|
if let Some(message) = self.deprecation {
|
||||||
|
sink.emit(message);
|
||||||
|
}
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
|
||||||
/// Try to write to the value.
|
/// Try to write to the value.
|
||||||
///
|
///
|
||||||
/// This fails if the value is a read-only closure capture.
|
/// This fails if the value is a read-only closure capture.
|
||||||
@ -320,6 +341,11 @@ impl Binding {
|
|||||||
self.span
|
self.span
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A deprecation message for the value, if any.
|
||||||
|
pub fn deprecation(&self) -> Option<&'static str> {
|
||||||
|
self.deprecation
|
||||||
|
}
|
||||||
|
|
||||||
/// The category of the value, if any.
|
/// The category of the value, if any.
|
||||||
pub fn category(&self) -> Option<Category> {
|
pub fn category(&self) -> Option<Category> {
|
||||||
self.category
|
self.category
|
||||||
|
@ -8,7 +8,7 @@ use std::sync::LazyLock;
|
|||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use typst_utils::Static;
|
use typst_utils::Static;
|
||||||
|
|
||||||
use crate::diag::{bail, StrResult};
|
use crate::diag::{bail, DeprecationSink, StrResult};
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, func, AutoValue, Func, NativeFuncData, NoneValue, Repr, Scope, Value,
|
cast, func, AutoValue, Func, NativeFuncData, NoneValue, Repr, Scope, Value,
|
||||||
};
|
};
|
||||||
@ -94,9 +94,13 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a field from this type's scope, if possible.
|
/// Get a field from this type's scope, if possible.
|
||||||
pub fn field(&self, field: &str) -> StrResult<&'static Value> {
|
pub fn field(
|
||||||
|
&self,
|
||||||
|
field: &str,
|
||||||
|
sink: impl DeprecationSink,
|
||||||
|
) -> StrResult<&'static Value> {
|
||||||
match self.scope().get(field) {
|
match self.scope().get(field) {
|
||||||
Some(binding) => Ok(binding.read()),
|
Some(binding) => Ok(binding.read_checked(sink)),
|
||||||
None => bail!("type {self} does not contain field `{field}`"),
|
None => bail!("type {self} does not contain field `{field}`"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|||||||
use typst_syntax::{ast, Span};
|
use typst_syntax::{ast, Span};
|
||||||
use typst_utils::ArcExt;
|
use typst_utils::ArcExt;
|
||||||
|
|
||||||
use crate::diag::{HintedStrResult, HintedString, StrResult};
|
use crate::diag::{DeprecationSink, HintedStrResult, HintedString, StrResult};
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
fields, ops, repr, Args, Array, AutoValue, Bytes, CastInfo, Content, Datetime,
|
fields, ops, repr, Args, Array, AutoValue, Bytes, CastInfo, Content, Datetime,
|
||||||
Decimal, Dict, Duration, Fold, FromValue, Func, IntoValue, Label, Module,
|
Decimal, Dict, Duration, Fold, FromValue, Func, IntoValue, Label, Module,
|
||||||
@ -155,15 +155,15 @@ impl Value {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Try to access a field on the value.
|
/// Try to access a field on the value.
|
||||||
pub fn field(&self, field: &str) -> StrResult<Value> {
|
pub fn field(&self, field: &str, sink: impl DeprecationSink) -> StrResult<Value> {
|
||||||
match self {
|
match self {
|
||||||
Self::Symbol(symbol) => symbol.clone().modified(field).map(Self::Symbol),
|
Self::Symbol(symbol) => symbol.clone().modified(field).map(Self::Symbol),
|
||||||
Self::Version(version) => version.component(field).map(Self::Int),
|
Self::Version(version) => version.component(field).map(Self::Int),
|
||||||
Self::Dict(dict) => dict.get(field).cloned(),
|
Self::Dict(dict) => dict.get(field).cloned(),
|
||||||
Self::Content(content) => content.field_by_name(field),
|
Self::Content(content) => content.field_by_name(field),
|
||||||
Self::Type(ty) => ty.field(field).cloned(),
|
Self::Type(ty) => ty.field(field, sink).cloned(),
|
||||||
Self::Func(func) => func.field(field).cloned(),
|
Self::Func(func) => func.field(field, sink).cloned(),
|
||||||
Self::Module(module) => module.field(field).cloned(),
|
Self::Module(module) => module.field(field, sink).cloned(),
|
||||||
_ => fields::field(self, field),
|
_ => fields::field(self, field),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ impl cbor {
|
|||||||
/// This function is deprecated. The [`cbor`] function now accepts bytes
|
/// This function is deprecated. The [`cbor`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode CBOR")]
|
#[func(title = "Decode CBOR")]
|
||||||
|
#[deprecated = "`cbor.decode` is deprecated, directly pass bytes to `cbor` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// CBOR data.
|
/// CBOR data.
|
||||||
|
@ -100,6 +100,7 @@ impl csv {
|
|||||||
/// This function is deprecated. The [`csv`] function now accepts bytes
|
/// This function is deprecated. The [`csv`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode CSV")]
|
#[func(title = "Decode CSV")]
|
||||||
|
#[deprecated = "`csv.decode` is deprecated, directly pass bytes to `csv` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// CSV data.
|
/// CSV data.
|
||||||
|
@ -69,6 +69,7 @@ impl json {
|
|||||||
/// This function is deprecated. The [`json`] function now accepts bytes
|
/// This function is deprecated. The [`json`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode JSON")]
|
#[func(title = "Decode JSON")]
|
||||||
|
#[deprecated = "`json.decode` is deprecated, directly pass bytes to `json` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// JSON data.
|
/// JSON data.
|
||||||
|
@ -48,6 +48,7 @@ impl toml {
|
|||||||
/// This function is deprecated. The [`toml`] function now accepts bytes
|
/// This function is deprecated. The [`toml`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode TOML")]
|
#[func(title = "Decode TOML")]
|
||||||
|
#[deprecated = "`toml.decode` is deprecated, directly pass bytes to `toml` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// TOML data.
|
/// TOML data.
|
||||||
|
@ -81,6 +81,7 @@ impl xml {
|
|||||||
/// This function is deprecated. The [`xml`] function now accepts bytes
|
/// This function is deprecated. The [`xml`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode XML")]
|
#[func(title = "Decode XML")]
|
||||||
|
#[deprecated = "`xml.decode` is deprecated, directly pass bytes to `xml` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// XML data.
|
/// XML data.
|
||||||
|
@ -59,6 +59,7 @@ impl yaml {
|
|||||||
/// This function is deprecated. The [`yaml`] function now accepts bytes
|
/// This function is deprecated. The [`yaml`] function now accepts bytes
|
||||||
/// directly.
|
/// directly.
|
||||||
#[func(title = "Decode YAML")]
|
#[func(title = "Decode YAML")]
|
||||||
|
#[deprecated = "`yaml.decode` is deprecated, directly pass bytes to `yaml` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
engine: &mut Engine,
|
engine: &mut Engine,
|
||||||
/// YAML data.
|
/// YAML data.
|
||||||
|
@ -171,6 +171,7 @@ impl ImageElem {
|
|||||||
/// #image.decode(changed)
|
/// #image.decode(changed)
|
||||||
/// ```
|
/// ```
|
||||||
#[func(title = "Decode Image")]
|
#[func(title = "Decode Image")]
|
||||||
|
#[deprecated = "`image.decode` is deprecated, directly pass bytes to `image` instead"]
|
||||||
pub fn decode(
|
pub fn decode(
|
||||||
span: Span,
|
span: Span,
|
||||||
/// The data to decode as an image. Can be a string for SVGs.
|
/// The data to decode as an image. Can be a string for SVGs.
|
||||||
|
@ -24,7 +24,7 @@ pub use self::shape::*;
|
|||||||
pub use self::stroke::*;
|
pub use self::stroke::*;
|
||||||
pub use self::tiling::*;
|
pub use self::tiling::*;
|
||||||
|
|
||||||
use crate::foundations::{category, Category, Scope, Type};
|
use crate::foundations::{category, Category, Element, Scope, Type};
|
||||||
|
|
||||||
/// Drawing and data visualization.
|
/// Drawing and data visualization.
|
||||||
///
|
///
|
||||||
@ -49,8 +49,10 @@ pub(super) fn define(global: &mut Scope) {
|
|||||||
global.define_elem::<CircleElem>();
|
global.define_elem::<CircleElem>();
|
||||||
global.define_elem::<PolygonElem>();
|
global.define_elem::<PolygonElem>();
|
||||||
global.define_elem::<CurveElem>();
|
global.define_elem::<CurveElem>();
|
||||||
global.define_elem::<PathElem>();
|
global
|
||||||
|
.define("path", Element::of::<PathElem>())
|
||||||
// Compatibility.
|
.deprecated("the `path` function is deprecated, use `curve` instead");
|
||||||
global.define("pattern", Type::of::<Tiling>());
|
global
|
||||||
|
.define("pattern", Type::of::<Tiling>())
|
||||||
|
.deprecated("the name `pattern` is deprecated, use `tiling` instead");
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ use crate::visualize::{FillRule, Paint, Stroke};
|
|||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// # Deprecation
|
/// # Deprecation
|
||||||
/// This element is deprecated. The [`curve`] element should be used instead.
|
/// This function is deprecated. The [`curve`] function should be used instead.
|
||||||
#[elem(Show)]
|
#[elem(Show)]
|
||||||
pub struct PathElem {
|
pub struct PathElem {
|
||||||
/// How to fill the path.
|
/// How to fill the path.
|
||||||
|
@ -31,18 +31,37 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> {
|
|||||||
let mut definitions = vec![];
|
let mut definitions = vec![];
|
||||||
let mut constructor = quote! { None };
|
let mut constructor = quote! { None };
|
||||||
for child in &mut item.items {
|
for child in &mut item.items {
|
||||||
let def = match child {
|
let bare: BareType;
|
||||||
syn::ImplItem::Const(item) => handle_const(&self_ty_expr, item)?,
|
let (mut def, attrs) = match child {
|
||||||
syn::ImplItem::Fn(item) => match handle_fn(self_ty, item)? {
|
syn::ImplItem::Const(item) => {
|
||||||
FnKind::Member(tokens) => tokens,
|
(handle_const(&self_ty_expr, item)?, &item.attrs)
|
||||||
FnKind::Constructor(tokens) => {
|
}
|
||||||
constructor = tokens;
|
syn::ImplItem::Fn(item) => (
|
||||||
continue;
|
match handle_fn(self_ty, item)? {
|
||||||
}
|
FnKind::Member(tokens) => tokens,
|
||||||
},
|
FnKind::Constructor(tokens) => {
|
||||||
syn::ImplItem::Verbatim(item) => handle_type_or_elem(item)?,
|
constructor = tokens;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&item.attrs,
|
||||||
|
),
|
||||||
|
syn::ImplItem::Verbatim(item) => {
|
||||||
|
bare = syn::parse2(item.clone())?;
|
||||||
|
(handle_type_or_elem(&bare)?, &bare.attrs)
|
||||||
|
}
|
||||||
_ => bail!(child, "unexpected item in scope"),
|
_ => bail!(child, "unexpected item in scope"),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(message) = attrs.iter().find_map(|attr| match &attr.meta {
|
||||||
|
syn::Meta::NameValue(pair) if pair.path.is_ident("deprecated") => {
|
||||||
|
Some(&pair.value)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
def = quote! { #def.deprecated(#message) }
|
||||||
|
}
|
||||||
|
|
||||||
definitions.push(def);
|
definitions.push(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +80,7 @@ pub fn scope(_: TokenStream, item: syn::Item) -> Result<TokenStream> {
|
|||||||
#constructor
|
#constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
fn scope() -> #foundations::Scope {
|
fn scope() -> #foundations::Scope {
|
||||||
let mut scope = #foundations::Scope::deduplicating();
|
let mut scope = #foundations::Scope::deduplicating();
|
||||||
#(#definitions;)*
|
#(#definitions;)*
|
||||||
@ -78,8 +98,7 @@ fn handle_const(self_ty: &TokenStream, item: &syn::ImplItemConst) -> Result<Toke
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Process a type item.
|
/// Process a type item.
|
||||||
fn handle_type_or_elem(item: &TokenStream) -> Result<TokenStream> {
|
fn handle_type_or_elem(item: &BareType) -> Result<TokenStream> {
|
||||||
let item: BareType = syn::parse2(item.clone())?;
|
|
||||||
let ident = &item.ident;
|
let ident = &item.ident;
|
||||||
let define = if item.attrs.iter().any(|attr| attr.path().is_ident("elem")) {
|
let define = if item.attrs.iter().any(|attr| attr.path().is_ident("elem")) {
|
||||||
quote! { define_elem }
|
quote! { define_elem }
|
||||||
|
@ -69,7 +69,7 @@ fn resolve_definition(head: &str, base: &str) -> StrResult<String> {
|
|||||||
let Some(category) = category else { bail!("{head} has no category") };
|
let Some(category) = category else { bail!("{head} has no category") };
|
||||||
|
|
||||||
let name = parts.next().ok_or("link is missing first part")?;
|
let name = parts.next().ok_or("link is missing first part")?;
|
||||||
let value = focus.field(name)?;
|
let value = focus.field(name, ())?;
|
||||||
|
|
||||||
// Handle grouped functions.
|
// Handle grouped functions.
|
||||||
if let Some(group) = GROUPS.iter().find(|group| {
|
if let Some(group) = GROUPS.iter().find(|group| {
|
||||||
@ -88,7 +88,7 @@ fn resolve_definition(head: &str, base: &str) -> StrResult<String> {
|
|||||||
|
|
||||||
let mut route = format!("{}reference/{}/{name}", base, category.name());
|
let mut route = format!("{}reference/{}/{name}", base, category.name());
|
||||||
if let Some(next) = parts.next() {
|
if let Some(next) = parts.next() {
|
||||||
if let Ok(field) = value.field(next) {
|
if let Ok(field) = value.field(next, ()) {
|
||||||
route.push_str("/#definitions-");
|
route.push_str("/#definitions-");
|
||||||
route.push_str(next);
|
route.push_str(next);
|
||||||
if let Some(next) = parts.next() {
|
if let Some(next) = parts.next() {
|
||||||
|
3
tests/suite/loading/cbor.typ
Normal file
3
tests/suite/loading/cbor.typ
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
--- cbor-decode-deprecated ---
|
||||||
|
// Warning: 15-21 `cbor.decode` is deprecated, directly pass bytes to `cbor` instead
|
||||||
|
#let _ = cbor.decode
|
@ -29,3 +29,7 @@
|
|||||||
--- csv-invalid-delimiter ---
|
--- csv-invalid-delimiter ---
|
||||||
// Error: 41-51 delimiter must be an ASCII character
|
// Error: 41-51 delimiter must be an ASCII character
|
||||||
#csv("/assets/data/zoo.csv", delimiter: "\u{2008}")
|
#csv("/assets/data/zoo.csv", delimiter: "\u{2008}")
|
||||||
|
|
||||||
|
--- csv-decode-deprecated ---
|
||||||
|
// Warning: 14-20 `csv.decode` is deprecated, directly pass bytes to `csv` instead
|
||||||
|
#let _ = csv.decode
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
// Error: 7-30 failed to parse JSON (expected value at line 3 column 14)
|
// Error: 7-30 failed to parse JSON (expected value at line 3 column 14)
|
||||||
#json("/assets/data/bad.json")
|
#json("/assets/data/bad.json")
|
||||||
|
|
||||||
|
--- json-decode-deprecated ---
|
||||||
|
// Warning: 15-21 `json.decode` is deprecated, directly pass bytes to `json` instead
|
||||||
|
#let _ = json.decode
|
||||||
|
|
||||||
--- issue-3363-json-large-number ---
|
--- issue-3363-json-large-number ---
|
||||||
// Big numbers (larger than what i64 can store) should just lose some precision
|
// Big numbers (larger than what i64 can store) should just lose some precision
|
||||||
// but not overflow
|
// but not overflow
|
||||||
|
@ -39,3 +39,7 @@
|
|||||||
--- toml-invalid ---
|
--- toml-invalid ---
|
||||||
// Error: 7-30 failed to parse TOML (expected `.`, `=` at line 1 column 16)
|
// Error: 7-30 failed to parse TOML (expected `.`, `=` at line 1 column 16)
|
||||||
#toml("/assets/data/bad.toml")
|
#toml("/assets/data/bad.toml")
|
||||||
|
|
||||||
|
--- toml-decode-deprecated ---
|
||||||
|
// Warning: 15-21 `toml.decode` is deprecated, directly pass bytes to `toml` instead
|
||||||
|
#let _ = toml.decode
|
||||||
|
@ -26,3 +26,7 @@
|
|||||||
--- xml-invalid ---
|
--- xml-invalid ---
|
||||||
// Error: 6-28 failed to parse XML (found closing tag 'data' instead of 'hello' in line 3)
|
// Error: 6-28 failed to parse XML (found closing tag 'data' instead of 'hello' in line 3)
|
||||||
#xml("/assets/data/bad.xml")
|
#xml("/assets/data/bad.xml")
|
||||||
|
|
||||||
|
--- xml-decode-deprecated ---
|
||||||
|
// Warning: 14-20 `xml.decode` is deprecated, directly pass bytes to `xml` instead
|
||||||
|
#let _ = xml.decode
|
||||||
|
@ -15,3 +15,7 @@
|
|||||||
--- yaml-invalid ---
|
--- yaml-invalid ---
|
||||||
// Error: 7-30 failed to parse YAML (did not find expected ',' or ']' at line 2 column 1, while parsing a flow sequence at line 1 column 18)
|
// Error: 7-30 failed to parse YAML (did not find expected ',' or ']' at line 2 column 1, while parsing a flow sequence at line 1 column 18)
|
||||||
#yaml("/assets/data/bad.yaml")
|
#yaml("/assets/data/bad.yaml")
|
||||||
|
|
||||||
|
--- yaml-decode-deprecated ---
|
||||||
|
// Warning: 15-21 `yaml.decode` is deprecated, directly pass bytes to `yaml` instead
|
||||||
|
#let _ = yaml.decode
|
||||||
|
@ -161,22 +161,27 @@ A #box(image("/assets/images/tiger.jpg", height: 1cm, width: 80%)) B
|
|||||||
|
|
||||||
--- image-decode-svg ---
|
--- image-decode-svg ---
|
||||||
// Test parsing from svg data
|
// Test parsing from svg data
|
||||||
|
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||||
#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
#image.decode(`<svg xmlns="http://www.w3.org/2000/svg" height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||||
|
|
||||||
--- image-decode-bad-svg ---
|
--- image-decode-bad-svg ---
|
||||||
// Error: 2-168 failed to parse SVG (missing root node)
|
// Error: 2-168 failed to parse SVG (missing root node)
|
||||||
|
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||||
#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
#image.decode(`<svg height="140" width="500"><ellipse cx="200" cy="80" rx="100" ry="50" style="fill:yellow;stroke:purple;stroke-width:2" /></svg>`.text, format: "svg")
|
||||||
|
|
||||||
--- image-decode-detect-format ---
|
--- image-decode-detect-format ---
|
||||||
// Test format auto detect
|
// Test format auto detect
|
||||||
|
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%)
|
#image.decode(read("/assets/images/tiger.jpg", encoding: none), width: 80%)
|
||||||
|
|
||||||
--- image-decode-specify-format ---
|
--- image-decode-specify-format ---
|
||||||
// Test format manual
|
// Test format manual
|
||||||
|
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%)
|
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "jpg", width: 80%)
|
||||||
|
|
||||||
--- image-decode-specify-wrong-format ---
|
--- image-decode-specify-wrong-format ---
|
||||||
// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.)
|
// Error: 2-91 failed to decode image (Format error decoding Png: Invalid PNG signature.)
|
||||||
|
// Warning: 8-14 `image.decode` is deprecated, directly pass bytes to `image` instead
|
||||||
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%)
|
#image.decode(read("/assets/images/tiger.jpg", encoding: none), format: "png", width: 80%)
|
||||||
|
|
||||||
--- image-pixmap-empty ---
|
--- image-pixmap-empty ---
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
columns: (1fr, 1fr),
|
columns: (1fr, 1fr),
|
||||||
rows: (1fr, 1fr, 1fr),
|
rows: (1fr, 1fr, 1fr),
|
||||||
align: center + horizon,
|
align: center + horizon,
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
fill: red,
|
fill: red,
|
||||||
closed: true,
|
closed: true,
|
||||||
@ -14,6 +15,7 @@
|
|||||||
((0%, 50%), (4%, 4%)),
|
((0%, 50%), (4%, 4%)),
|
||||||
((50%, 0%), (4%, 4%)),
|
((50%, 0%), (4%, 4%)),
|
||||||
),
|
),
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
fill: purple,
|
fill: purple,
|
||||||
stroke: 1pt,
|
stroke: 1pt,
|
||||||
@ -22,6 +24,7 @@
|
|||||||
(0pt, 30pt),
|
(0pt, 30pt),
|
||||||
(30pt, 0pt),
|
(30pt, 0pt),
|
||||||
),
|
),
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
fill: blue,
|
fill: blue,
|
||||||
stroke: 1pt,
|
stroke: 1pt,
|
||||||
@ -30,6 +33,7 @@
|
|||||||
((30%, 60%), (-20%, 0%), (0%, 0%)),
|
((30%, 60%), (-20%, 0%), (0%, 0%)),
|
||||||
((50%, 30%), (60%, -30%), (60%, 0%)),
|
((50%, 30%), (60%, -30%), (60%, 0%)),
|
||||||
),
|
),
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
stroke: 5pt,
|
stroke: 5pt,
|
||||||
closed: true,
|
closed: true,
|
||||||
@ -37,6 +41,7 @@
|
|||||||
(30pt, 30pt),
|
(30pt, 30pt),
|
||||||
(15pt, 0pt),
|
(15pt, 0pt),
|
||||||
),
|
),
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
fill: red,
|
fill: red,
|
||||||
fill-rule: "non-zero",
|
fill-rule: "non-zero",
|
||||||
@ -47,6 +52,7 @@
|
|||||||
(0pt, 20pt),
|
(0pt, 20pt),
|
||||||
(40pt, 50pt),
|
(40pt, 50pt),
|
||||||
),
|
),
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
fill: red,
|
fill: red,
|
||||||
fill-rule: "even-odd",
|
fill-rule: "even-odd",
|
||||||
@ -61,18 +67,22 @@
|
|||||||
|
|
||||||
--- path-bad-vertex ---
|
--- path-bad-vertex ---
|
||||||
// Error: 7-9 path vertex must have 1, 2, or 3 points
|
// Error: 7-9 path vertex must have 1, 2, or 3 points
|
||||||
|
// Warning: 2-6 the `path` function is deprecated, use `curve` instead
|
||||||
#path(())
|
#path(())
|
||||||
|
|
||||||
--- path-bad-point-count ---
|
--- path-bad-point-count ---
|
||||||
// Error: 7-47 path vertex must have 1, 2, or 3 points
|
// Error: 7-47 path vertex must have 1, 2, or 3 points
|
||||||
|
// Warning: 2-6 the `path` function is deprecated, use `curve` instead
|
||||||
#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%)))
|
#path(((0%, 0%), (0%, 0%), (0%, 0%), (0%, 0%)))
|
||||||
|
|
||||||
--- path-bad-point-array ---
|
--- path-bad-point-array ---
|
||||||
// Error: 7-31 point array must contain exactly two entries
|
// Error: 7-31 point array must contain exactly two entries
|
||||||
|
// Warning: 2-6 the `path` function is deprecated, use `curve` instead
|
||||||
#path(((0%, 0%), (0%, 0%, 0%)))
|
#path(((0%, 0%), (0%, 0%, 0%)))
|
||||||
|
|
||||||
--- path-infinite-length ---
|
--- path-infinite-length ---
|
||||||
// Error: 2-42 cannot create path with infinite length
|
// Error: 2-42 cannot create path with infinite length
|
||||||
|
// Warning: 2-6 the `path` function is deprecated, use `curve` instead
|
||||||
#path((0pt, 0pt), (float.inf * 1pt, 0pt))
|
#path((0pt, 0pt), (float.inf * 1pt, 0pt))
|
||||||
|
|
||||||
--- issue-path-in-sized-container ---
|
--- issue-path-in-sized-container ---
|
||||||
@ -82,6 +92,7 @@
|
|||||||
fill: aqua,
|
fill: aqua,
|
||||||
width: 20pt,
|
width: 20pt,
|
||||||
height: 15pt,
|
height: 15pt,
|
||||||
|
// Warning: 3-7 the `path` function is deprecated, use `curve` instead
|
||||||
path(
|
path(
|
||||||
(0pt, 0pt),
|
(0pt, 0pt),
|
||||||
(10pt, 10pt),
|
(10pt, 10pt),
|
||||||
|
@ -159,5 +159,7 @@
|
|||||||
|
|
||||||
--- tiling-pattern-compatibility ---
|
--- tiling-pattern-compatibility ---
|
||||||
#set page(width: auto, height: auto, margin: 0pt)
|
#set page(width: auto, height: auto, margin: 0pt)
|
||||||
|
|
||||||
|
// Warning: 10-17 the name `pattern` is deprecated, use `tiling` instead
|
||||||
#let t = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%)))
|
#let t = pattern(size: (10pt, 10pt), line(stroke: 4pt, start: (0%, 0%), end: (100%, 100%)))
|
||||||
#rect(width: 50pt, height: 50pt, fill: t)
|
#rect(width: 50pt, height: 50pt, fill: t)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user