summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMalo <57839069+MDLC01@users.noreply.github.com>2025-06-26 09:24:21 +0100
committerGitHub <noreply@github.com>2025-06-26 08:24:21 +0000
commit04fd0acacab8cf2e82268da9c18ef4bcf37507dc (patch)
treed01aa881ebdab6f3925af65c18d71b1103836c90
parent6a1d6c08e2d6e4c184c6d177e67796b23ccbe4c7 (diff)
Allow deprecating symbol variants (#6441)
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--crates/typst-ide/src/complete.rs2
-rw-r--r--crates/typst-library/src/foundations/symbol.rs59
-rw-r--r--crates/typst-library/src/foundations/value.rs4
-rw-r--r--docs/src/lib.rs14
-rw-r--r--tests/suite/math/attach.typ6
7 files changed, 51 insertions, 38 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 3ea423f5..91ff4843 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -413,7 +413,7 @@ dependencies = [
[[package]]
name = "codex"
version = "0.1.1"
-source = "git+https://github.com/typst/codex?rev=56eb217#56eb2172fc0670f4c1c8b79a63d11f9354e5babe"
+source = "git+https://github.com/typst/codex?rev=a5428cb#a5428cb9c81a41354d44b44dbd5a16a710bbd928"
[[package]]
name = "color-print"
diff --git a/Cargo.toml b/Cargo.toml
index 3cfb7200..76d83995 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -47,7 +47,7 @@ clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
clap_complete = "4.2.1"
clap_mangen = "0.2.10"
codespan-reporting = "0.11"
-codex = { git = "https://github.com/typst/codex", rev = "56eb217" }
+codex = { git = "https://github.com/typst/codex", rev = "a5428cb" }
color-print = "0.3.6"
comemo = "0.4"
csv = "1"
diff --git a/crates/typst-ide/src/complete.rs b/crates/typst-ide/src/complete.rs
index 53642331..bc5b3e10 100644
--- a/crates/typst-ide/src/complete.rs
+++ b/crates/typst-ide/src/complete.rs
@@ -448,7 +448,7 @@ fn field_access_completions(
match value {
Value::Symbol(symbol) => {
for modifier in symbol.modifiers() {
- if let Ok(modified) = symbol.clone().modified(modifier) {
+ if let Ok(modified) = symbol.clone().modified((), modifier) {
ctx.completions.push(Completion {
kind: CompletionKind::Symbol(modified.get()),
label: modifier.into(),
diff --git a/crates/typst-library/src/foundations/symbol.rs b/crates/typst-library/src/foundations/symbol.rs
index 0f503edd..f57bb0c2 100644
--- a/crates/typst-library/src/foundations/symbol.rs
+++ b/crates/typst-library/src/foundations/symbol.rs
@@ -8,7 +8,7 @@ use serde::{Serialize, Serializer};
use typst_syntax::{is_ident, Span, Spanned};
use typst_utils::hash128;
-use crate::diag::{bail, SourceResult, StrResult};
+use crate::diag::{bail, DeprecationSink, SourceResult, StrResult};
use crate::foundations::{
cast, elem, func, scope, ty, Array, Content, Func, NativeElement, NativeFunc, Packed,
PlainText, Repr as _,
@@ -54,18 +54,22 @@ enum Repr {
/// A native symbol that has no named variant.
Single(char),
/// A native symbol with multiple named variants.
- Complex(&'static [(ModifierSet<&'static str>, char)]),
+ Complex(&'static [Variant<&'static str>]),
/// A symbol with multiple named variants, where some modifiers may have
/// been applied. Also used for symbols defined at runtime by the user with
/// no modifier applied.
Modified(Arc<(List, ModifierSet<EcoString>)>),
}
+/// A symbol variant, consisting of a set of modifiers, a character, and an
+/// optional deprecation message.
+type Variant<S> = (ModifierSet<S>, char, Option<S>);
+
/// A collection of symbols.
#[derive(Clone, Eq, PartialEq, Hash)]
enum List {
- Static(&'static [(ModifierSet<&'static str>, char)]),
- Runtime(Box<[(ModifierSet<EcoString>, char)]>),
+ Static(&'static [Variant<&'static str>]),
+ Runtime(Box<[Variant<EcoString>]>),
}
impl Symbol {
@@ -76,14 +80,14 @@ impl Symbol {
/// Create a symbol with a static variant list.
#[track_caller]
- pub const fn list(list: &'static [(ModifierSet<&'static str>, char)]) -> Self {
+ pub const fn list(list: &'static [Variant<&'static str>]) -> Self {
debug_assert!(!list.is_empty());
Self(Repr::Complex(list))
}
/// Create a symbol with a runtime variant list.
#[track_caller]
- pub fn runtime(list: Box<[(ModifierSet<EcoString>, char)]>) -> Self {
+ pub fn runtime(list: Box<[Variant<EcoString>]>) -> Self {
debug_assert!(!list.is_empty());
Self(Repr::Modified(Arc::new((List::Runtime(list), ModifierSet::default()))))
}
@@ -93,9 +97,11 @@ impl Symbol {
match &self.0 {
Repr::Single(c) => *c,
Repr::Complex(_) => ModifierSet::<&'static str>::default()
- .best_match_in(self.variants())
+ .best_match_in(self.variants().map(|(m, c, _)| (m, c)))
.unwrap(),
- Repr::Modified(arc) => arc.1.best_match_in(self.variants()).unwrap(),
+ Repr::Modified(arc) => {
+ arc.1.best_match_in(self.variants().map(|(m, c, _)| (m, c))).unwrap()
+ }
}
}
@@ -128,7 +134,11 @@ impl Symbol {
}
/// Apply a modifier to the symbol.
- pub fn modified(mut self, modifier: &str) -> StrResult<Self> {
+ pub fn modified(
+ mut self,
+ sink: impl DeprecationSink,
+ modifier: &str,
+ ) -> StrResult<Self> {
if let Repr::Complex(list) = self.0 {
self.0 =
Repr::Modified(Arc::new((List::Static(list), ModifierSet::default())));
@@ -137,7 +147,12 @@ impl Symbol {
if let Repr::Modified(arc) = &mut self.0 {
let (list, modifiers) = Arc::make_mut(arc);
modifiers.insert_raw(modifier);
- if modifiers.best_match_in(list.variants()).is_some() {
+ if let Some(deprecation) =
+ modifiers.best_match_in(list.variants().map(|(m, _, d)| (m, d)))
+ {
+ if let Some(message) = deprecation {
+ sink.emit(message)
+ }
return Ok(self);
}
}
@@ -146,7 +161,7 @@ impl Symbol {
}
/// The characters that are covered by this symbol.
- pub fn variants(&self) -> impl Iterator<Item = (ModifierSet<&str>, char)> {
+ pub fn variants(&self) -> impl Iterator<Item = Variant<&str>> {
match &self.0 {
Repr::Single(c) => Variants::Single(Some(*c).into_iter()),
Repr::Complex(list) => Variants::Static(list.iter()),
@@ -161,7 +176,7 @@ impl Symbol {
_ => ModifierSet::default(),
};
self.variants()
- .flat_map(|(m, _)| m)
+ .flat_map(|(m, _, _)| m)
.filter(|modifier| !modifier.is_empty() && !modifiers.contains(modifier))
.collect::<BTreeSet<_>>()
.into_iter()
@@ -256,7 +271,7 @@ impl Symbol {
let list = variants
.into_iter()
- .map(|s| (ModifierSet::from_raw_dotted(s.v.0), s.v.1))
+ .map(|s| (ModifierSet::from_raw_dotted(s.v.0), s.v.1, None))
.collect();
Ok(Symbol::runtime(list))
}
@@ -316,17 +331,17 @@ impl crate::foundations::Repr for Symbol {
}
fn repr_variants<'a>(
- variants: impl Iterator<Item = (ModifierSet<&'a str>, char)>,
+ variants: impl Iterator<Item = Variant<&'a str>>,
applied_modifiers: ModifierSet<&str>,
) -> String {
crate::foundations::repr::pretty_array_like(
&variants
- .filter(|(modifiers, _)| {
+ .filter(|(modifiers, _, _)| {
// Only keep variants that can still be accessed, i.e., variants
// that contain all applied modifiers.
applied_modifiers.iter().all(|am| modifiers.contains(am))
})
- .map(|(modifiers, c)| {
+ .map(|(modifiers, c, _)| {
let trimmed_modifiers =
modifiers.into_iter().filter(|&m| !applied_modifiers.contains(m));
if trimmed_modifiers.clone().all(|m| m.is_empty()) {
@@ -379,18 +394,20 @@ cast! {
/// Iterator over variants.
enum Variants<'a> {
Single(std::option::IntoIter<char>),
- Static(std::slice::Iter<'static, (ModifierSet<&'static str>, char)>),
- Runtime(std::slice::Iter<'a, (ModifierSet<EcoString>, char)>),
+ Static(std::slice::Iter<'static, Variant<&'static str>>),
+ Runtime(std::slice::Iter<'a, Variant<EcoString>>),
}
impl<'a> Iterator for Variants<'a> {
- type Item = (ModifierSet<&'a str>, char);
+ type Item = Variant<&'a str>;
fn next(&mut self) -> Option<Self::Item> {
match self {
- Self::Single(iter) => Some((ModifierSet::default(), iter.next()?)),
+ Self::Single(iter) => Some((ModifierSet::default(), iter.next()?, None)),
Self::Static(list) => list.next().copied(),
- Self::Runtime(list) => list.next().map(|(m, c)| (m.as_deref(), *c)),
+ Self::Runtime(list) => {
+ list.next().map(|(m, c, d)| (m.as_deref(), *c, d.as_deref()))
+ }
}
}
}
diff --git a/crates/typst-library/src/foundations/value.rs b/crates/typst-library/src/foundations/value.rs
index 854c2486..4bcf2d4e 100644
--- a/crates/typst-library/src/foundations/value.rs
+++ b/crates/typst-library/src/foundations/value.rs
@@ -157,7 +157,9 @@ impl Value {
/// Try to access a field on the value.
pub fn field(&self, field: &str, sink: impl DeprecationSink) -> StrResult<Value> {
match self {
- Self::Symbol(symbol) => symbol.clone().modified(field).map(Self::Symbol),
+ Self::Symbol(symbol) => {
+ symbol.clone().modified(sink, field).map(Self::Symbol)
+ }
Self::Version(version) => version.component(field).map(Self::Int),
Self::Dict(dict) => dict.get(field).cloned(),
Self::Content(content) => content.field_by_name(field),
diff --git a/docs/src/lib.rs b/docs/src/lib.rs
index 9bd21c2e..dc6b62c7 100644
--- a/docs/src/lib.rs
+++ b/docs/src/lib.rs
@@ -720,18 +720,12 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
}
};
- for (variant, c) in symbol.variants() {
+ for (variant, c, deprecation) in symbol.variants() {
let shorthand = |list: &[(&'static str, char)]| {
list.iter().copied().find(|&(_, x)| x == c).map(|(s, _)| s)
};
let name = complete(variant);
- let deprecation = match name.as_str() {
- "integral.sect" => {
- Some("`integral.sect` is deprecated, use `integral.inter` instead")
- }
- _ => binding.deprecation(),
- };
list.push(SymbolModel {
name,
@@ -742,10 +736,10 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
accent: typst::math::Accent::combine(c).is_some(),
alternates: symbol
.variants()
- .filter(|(other, _)| other != &variant)
- .map(|(other, _)| complete(other))
+ .filter(|(other, _, _)| other != &variant)
+ .map(|(other, _, _)| complete(other))
.collect(),
- deprecation,
+ deprecation: deprecation.or_else(|| binding.deprecation()),
});
}
}
diff --git a/tests/suite/math/attach.typ b/tests/suite/math/attach.typ
index cedc3a4a..97901847 100644
--- a/tests/suite/math/attach.typ
+++ b/tests/suite/math/attach.typ
@@ -121,8 +121,8 @@ $a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.lo
--- math-attach-integral ---
// Test default of scripts attachments on integrals at display size.
-$ integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $
-$integral.sect_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$
+$ integral.inter_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b $
+$integral.inter_a^b quad \u{2a1b}_a^b quad limits(\u{2a1b})_a^b$
--- math-attach-large-operator ---
// Test default of limit attachments on large operators at display size only.
@@ -179,7 +179,7 @@ $ a0 + a1 + a0_2 \
#{
let var = $x^1$
for i in range(24) {
- var = $var$
+ var = $var$
}
$var_2$
}