diff --git a/crates/typst-library/src/foundations/scope.rs b/crates/typst-library/src/foundations/scope.rs index 8ac7fde10..22691869d 100644 --- a/crates/typst-library/src/foundations/scope.rs +++ b/crates/typst-library/src/foundations/scope.rs @@ -253,12 +253,8 @@ pub struct Binding { span: Span, /// The category of the binding. category: Option, - /// A deprecation message for the definition. - deprecation_message: Option<&'static str>, - /// A version in which the deprecated binding is planned to be removed. - /// - /// This is ignored if `deprecation` is `None`. - deprecation_until: Option<&'static str>, + /// The deprecation information if this item is deprecated. + deprecation: Option>, } /// The different kinds of slots. @@ -278,8 +274,7 @@ impl Binding { span, kind: BindingKind::Normal, category: None, - deprecation_message: None, - deprecation_until: None, + deprecation: None, } } @@ -290,7 +285,9 @@ impl Binding { /// Marks this binding as deprecated, with the given `message`. pub fn deprecated(&mut self, message: &'static str) -> &mut Self { - self.deprecation_message = Some(message); + self.deprecation + .get_or_insert_with(|| Box::new(DeprecationInfo::new())) + .deprecated_message(message); self } @@ -298,7 +295,9 @@ impl Binding { /// /// This is ignored if [`Binding::deprecated`] isn't also set. pub fn deprecated_until(&mut self, version: &'static str) -> &mut Self { - self.deprecation_until = Some(version); + self.deprecation + .get_or_insert_with(|| Box::new(DeprecationInfo::new())) + .deprecated_until(version); self } @@ -313,8 +312,8 @@ impl Binding { /// - 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_message { - sink.emit(message, self.deprecation_until); + if let Some(info) = &self.deprecation { + sink.emit(info.message, info.until); } &self.value } @@ -350,13 +349,8 @@ impl Binding { } /// A deprecation message for the value, if any. - pub fn deprecation_message(&self) -> Option<&'static str> { - self.deprecation_message - } - - /// The version in which a deprecated binding is planned to be removed. - pub fn deprecation_until(&self) -> Option<&'static str> { - self.deprecation_until + pub fn deprecation(&self) -> Option<&DeprecationInfo> { + self.deprecation.as_deref() } /// The category of the value, if any. @@ -374,6 +368,51 @@ pub enum Capturer { Context, } +/// Information about a deprecated binding. +#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +pub struct DeprecationInfo { + /// A deprecation message for the definition. + message: &'static str, + /// A version in which the deprecated binding is planned to be removed. + until: Option<&'static str>, +} + +impl DeprecationInfo { + /// Creates new deprecation info with a default message to display when + /// emitting the deprecation warning. + pub fn new() -> Self { + Self { message: "item is deprecated", until: None } + } + + /// Set the message to display when emitting the deprecation warning. + pub fn deprecated_message(&mut self, message: &'static str) -> &mut Self { + self.message = message; + self + } + + /// Set the version in which the binding is planned to be removed. + pub fn deprecated_until(&mut self, version: &'static str) -> &mut Self { + self.until = Some(version); + self + } + + /// The message to display when emitting the deprecation warning. + pub fn message(&self) -> &'static str { + self.message + } + + /// The version in which the binding is planned to be removed. + pub fn until(&self) -> Option<&'static str> { + self.until + } +} + +impl Default for DeprecationInfo { + fn default() -> Self { + Self::new() + } +} + /// The error message when trying to mutate a variable from the standard /// library. #[cold] diff --git a/docs/src/lib.rs b/docs/src/lib.rs index 81093b1d3..4844619af 100644 --- a/docs/src/lib.rs +++ b/docs/src/lib.rs @@ -17,6 +17,7 @@ use serde::Deserialize; use serde_yaml as yaml; use std::sync::LazyLock; use typst::diag::{StrResult, bail}; +use typst::foundations::DeprecationInfo; use typst::foundations::{ AutoValue, Binding, Bytes, CastInfo, Func, Module, NoneValue, ParamInfo, Repr, Scope, Smart, Type, Value, @@ -291,14 +292,8 @@ fn category_page(resolver: &dyn Resolver, category: Category) -> PageModel { match binding.read() { Value::Func(func) => { let name = func.name().unwrap(); - let subpage = func_page( - resolver, - &route, - func, - path, - binding.deprecation_message(), - binding.deprecation_until(), - ); + let subpage = + func_page(resolver, &route, func, path, binding.deprecation()); items.push(CategoryItem { name: name.into(), route: subpage.route.clone(), @@ -387,11 +382,9 @@ fn func_page( parent: &str, func: &Func, path: &[&str], - deprecation_message: Option<&'static str>, - deprecation_until: Option<&'static str>, + deprecation: Option<&DeprecationInfo>, ) -> PageModel { - let model = - func_model(resolver, func, path, false, deprecation_message, deprecation_until); + let model = func_model(resolver, func, path, false, deprecation); let name = func.name().unwrap(); PageModel { route: eco_format!("{parent}{}/", urlify(name)), @@ -410,8 +403,7 @@ fn func_model( func: &Func, path: &[&str], nested: bool, - deprecation_message: Option<&'static str>, - deprecation_until: Option<&'static str>, + deprecation: Option<&DeprecationInfo>, ) -> FuncModel { let name = func.name().unwrap(); let scope = func.scope().unwrap(); @@ -447,8 +439,8 @@ fn func_model( oneliner: oneliner(details), element: func.element().is_some(), contextual: func.contextual().unwrap_or(false), - deprecation_message, - deprecation_until, + deprecation_message: deprecation.map(DeprecationInfo::message), + deprecation_until: deprecation.and_then(DeprecationInfo::until), details: Html::markdown(resolver, details, nesting), example: example.map(|md| Html::markdown(resolver, md, None)), self_, @@ -531,14 +523,7 @@ fn scope_models(resolver: &dyn Resolver, name: &str, scope: &Scope) -> Vec() else { panic!("not a function") }; - let func = func_model( - resolver, - func, - &path, - true, - binding.deprecation_message(), - binding.deprecation_until(), - ); + let func = func_model(resolver, func, &path, true, binding.deprecation()); let id_base = urlify(&eco_format!("functions-{}", func.name)); let children = func_outline(&func, &id_base); outline_items.push(OutlineItem { @@ -693,7 +671,7 @@ fn type_model(resolver: &dyn Resolver, ty: &Type) -> TypeModel { constructor: ty .constructor() .ok() - .map(|func| func_model(resolver, &func, &[], true, None, None)), + .map(|func| func_model(resolver, &func, &[], true, None)), scope: scope_models(resolver, ty.short_name(), ty.scope()), } } @@ -762,8 +740,8 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel { .map(|(other, _, _)| complete(other)) .collect(), deprecation_message: deprecation_message - .or_else(|| binding.deprecation_message()), - deprecation_until: binding.deprecation_until(), + .or_else(|| binding.deprecation().map(DeprecationInfo::message)), + deprecation_until: binding.deprecation().and_then(DeprecationInfo::until), }); } }