mirror of
https://github.com/typst/typst
synced 2025-06-28 00:03:17 +08:00
Allow deprecating symbol variants (#6441)
This commit is contained in:
parent
6a1d6c08e2
commit
04fd0acaca
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -413,7 +413,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "codex"
|
name = "codex"
|
||||||
version = "0.1.1"
|
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]]
|
[[package]]
|
||||||
name = "color-print"
|
name = "color-print"
|
||||||
|
@ -47,7 +47,7 @@ clap = { version = "4.4", features = ["derive", "env", "wrap_help"] }
|
|||||||
clap_complete = "4.2.1"
|
clap_complete = "4.2.1"
|
||||||
clap_mangen = "0.2.10"
|
clap_mangen = "0.2.10"
|
||||||
codespan-reporting = "0.11"
|
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"
|
color-print = "0.3.6"
|
||||||
comemo = "0.4"
|
comemo = "0.4"
|
||||||
csv = "1"
|
csv = "1"
|
||||||
|
@ -448,7 +448,7 @@ fn field_access_completions(
|
|||||||
match value {
|
match value {
|
||||||
Value::Symbol(symbol) => {
|
Value::Symbol(symbol) => {
|
||||||
for modifier in symbol.modifiers() {
|
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 {
|
ctx.completions.push(Completion {
|
||||||
kind: CompletionKind::Symbol(modified.get()),
|
kind: CompletionKind::Symbol(modified.get()),
|
||||||
label: modifier.into(),
|
label: modifier.into(),
|
||||||
|
@ -8,7 +8,7 @@ use serde::{Serialize, Serializer};
|
|||||||
use typst_syntax::{is_ident, Span, Spanned};
|
use typst_syntax::{is_ident, Span, Spanned};
|
||||||
use typst_utils::hash128;
|
use typst_utils::hash128;
|
||||||
|
|
||||||
use crate::diag::{bail, SourceResult, StrResult};
|
use crate::diag::{bail, DeprecationSink, SourceResult, StrResult};
|
||||||
use crate::foundations::{
|
use crate::foundations::{
|
||||||
cast, elem, func, scope, ty, Array, Content, Func, NativeElement, NativeFunc, Packed,
|
cast, elem, func, scope, ty, Array, Content, Func, NativeElement, NativeFunc, Packed,
|
||||||
PlainText, Repr as _,
|
PlainText, Repr as _,
|
||||||
@ -54,18 +54,22 @@ enum Repr {
|
|||||||
/// A native symbol that has no named variant.
|
/// A native symbol that has no named variant.
|
||||||
Single(char),
|
Single(char),
|
||||||
/// A native symbol with multiple named variants.
|
/// 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
|
/// A symbol with multiple named variants, where some modifiers may have
|
||||||
/// been applied. Also used for symbols defined at runtime by the user with
|
/// been applied. Also used for symbols defined at runtime by the user with
|
||||||
/// no modifier applied.
|
/// no modifier applied.
|
||||||
Modified(Arc<(List, ModifierSet<EcoString>)>),
|
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.
|
/// A collection of symbols.
|
||||||
#[derive(Clone, Eq, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
enum List {
|
enum List {
|
||||||
Static(&'static [(ModifierSet<&'static str>, char)]),
|
Static(&'static [Variant<&'static str>]),
|
||||||
Runtime(Box<[(ModifierSet<EcoString>, char)]>),
|
Runtime(Box<[Variant<EcoString>]>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Symbol {
|
impl Symbol {
|
||||||
@ -76,14 +80,14 @@ impl Symbol {
|
|||||||
|
|
||||||
/// Create a symbol with a static variant list.
|
/// Create a symbol with a static variant list.
|
||||||
#[track_caller]
|
#[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());
|
debug_assert!(!list.is_empty());
|
||||||
Self(Repr::Complex(list))
|
Self(Repr::Complex(list))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a symbol with a runtime variant list.
|
/// Create a symbol with a runtime variant list.
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
pub fn runtime(list: Box<[(ModifierSet<EcoString>, char)]>) -> Self {
|
pub fn runtime(list: Box<[Variant<EcoString>]>) -> Self {
|
||||||
debug_assert!(!list.is_empty());
|
debug_assert!(!list.is_empty());
|
||||||
Self(Repr::Modified(Arc::new((List::Runtime(list), ModifierSet::default()))))
|
Self(Repr::Modified(Arc::new((List::Runtime(list), ModifierSet::default()))))
|
||||||
}
|
}
|
||||||
@ -93,9 +97,11 @@ impl Symbol {
|
|||||||
match &self.0 {
|
match &self.0 {
|
||||||
Repr::Single(c) => *c,
|
Repr::Single(c) => *c,
|
||||||
Repr::Complex(_) => ModifierSet::<&'static str>::default()
|
Repr::Complex(_) => ModifierSet::<&'static str>::default()
|
||||||
.best_match_in(self.variants())
|
.best_match_in(self.variants().map(|(m, c, _)| (m, c)))
|
||||||
.unwrap(),
|
.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.
|
/// 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 {
|
if let Repr::Complex(list) = self.0 {
|
||||||
self.0 =
|
self.0 =
|
||||||
Repr::Modified(Arc::new((List::Static(list), ModifierSet::default())));
|
Repr::Modified(Arc::new((List::Static(list), ModifierSet::default())));
|
||||||
@ -137,7 +147,12 @@ impl Symbol {
|
|||||||
if let Repr::Modified(arc) = &mut self.0 {
|
if let Repr::Modified(arc) = &mut self.0 {
|
||||||
let (list, modifiers) = Arc::make_mut(arc);
|
let (list, modifiers) = Arc::make_mut(arc);
|
||||||
modifiers.insert_raw(modifier);
|
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);
|
return Ok(self);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +161,7 @@ impl Symbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The characters that are covered by this 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 {
|
match &self.0 {
|
||||||
Repr::Single(c) => Variants::Single(Some(*c).into_iter()),
|
Repr::Single(c) => Variants::Single(Some(*c).into_iter()),
|
||||||
Repr::Complex(list) => Variants::Static(list.iter()),
|
Repr::Complex(list) => Variants::Static(list.iter()),
|
||||||
@ -161,7 +176,7 @@ impl Symbol {
|
|||||||
_ => ModifierSet::default(),
|
_ => ModifierSet::default(),
|
||||||
};
|
};
|
||||||
self.variants()
|
self.variants()
|
||||||
.flat_map(|(m, _)| m)
|
.flat_map(|(m, _, _)| m)
|
||||||
.filter(|modifier| !modifier.is_empty() && !modifiers.contains(modifier))
|
.filter(|modifier| !modifier.is_empty() && !modifiers.contains(modifier))
|
||||||
.collect::<BTreeSet<_>>()
|
.collect::<BTreeSet<_>>()
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@ -256,7 +271,7 @@ impl Symbol {
|
|||||||
|
|
||||||
let list = variants
|
let list = variants
|
||||||
.into_iter()
|
.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();
|
.collect();
|
||||||
Ok(Symbol::runtime(list))
|
Ok(Symbol::runtime(list))
|
||||||
}
|
}
|
||||||
@ -316,17 +331,17 @@ impl crate::foundations::Repr for Symbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn repr_variants<'a>(
|
fn repr_variants<'a>(
|
||||||
variants: impl Iterator<Item = (ModifierSet<&'a str>, char)>,
|
variants: impl Iterator<Item = Variant<&'a str>>,
|
||||||
applied_modifiers: ModifierSet<&str>,
|
applied_modifiers: ModifierSet<&str>,
|
||||||
) -> String {
|
) -> String {
|
||||||
crate::foundations::repr::pretty_array_like(
|
crate::foundations::repr::pretty_array_like(
|
||||||
&variants
|
&variants
|
||||||
.filter(|(modifiers, _)| {
|
.filter(|(modifiers, _, _)| {
|
||||||
// Only keep variants that can still be accessed, i.e., variants
|
// Only keep variants that can still be accessed, i.e., variants
|
||||||
// that contain all applied modifiers.
|
// that contain all applied modifiers.
|
||||||
applied_modifiers.iter().all(|am| modifiers.contains(am))
|
applied_modifiers.iter().all(|am| modifiers.contains(am))
|
||||||
})
|
})
|
||||||
.map(|(modifiers, c)| {
|
.map(|(modifiers, c, _)| {
|
||||||
let trimmed_modifiers =
|
let trimmed_modifiers =
|
||||||
modifiers.into_iter().filter(|&m| !applied_modifiers.contains(m));
|
modifiers.into_iter().filter(|&m| !applied_modifiers.contains(m));
|
||||||
if trimmed_modifiers.clone().all(|m| m.is_empty()) {
|
if trimmed_modifiers.clone().all(|m| m.is_empty()) {
|
||||||
@ -379,18 +394,20 @@ cast! {
|
|||||||
/// Iterator over variants.
|
/// Iterator over variants.
|
||||||
enum Variants<'a> {
|
enum Variants<'a> {
|
||||||
Single(std::option::IntoIter<char>),
|
Single(std::option::IntoIter<char>),
|
||||||
Static(std::slice::Iter<'static, (ModifierSet<&'static str>, char)>),
|
Static(std::slice::Iter<'static, Variant<&'static str>>),
|
||||||
Runtime(std::slice::Iter<'a, (ModifierSet<EcoString>, char)>),
|
Runtime(std::slice::Iter<'a, Variant<EcoString>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Variants<'a> {
|
impl<'a> Iterator for Variants<'a> {
|
||||||
type Item = (ModifierSet<&'a str>, char);
|
type Item = Variant<&'a str>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
match self {
|
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::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()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,7 +157,9 @@ impl Value {
|
|||||||
/// Try to access a field on the value.
|
/// Try to access a field on the value.
|
||||||
pub fn field(&self, field: &str, sink: impl DeprecationSink) -> 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(sink, 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),
|
||||||
|
@ -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)]| {
|
let shorthand = |list: &[(&'static str, char)]| {
|
||||||
list.iter().copied().find(|&(_, x)| x == c).map(|(s, _)| s)
|
list.iter().copied().find(|&(_, x)| x == c).map(|(s, _)| s)
|
||||||
};
|
};
|
||||||
|
|
||||||
let name = complete(variant);
|
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 {
|
list.push(SymbolModel {
|
||||||
name,
|
name,
|
||||||
@ -742,10 +736,10 @@ fn symbols_model(resolver: &dyn Resolver, group: &GroupData) -> SymbolsModel {
|
|||||||
accent: typst::math::Accent::combine(c).is_some(),
|
accent: typst::math::Accent::combine(c).is_some(),
|
||||||
alternates: symbol
|
alternates: symbol
|
||||||
.variants()
|
.variants()
|
||||||
.filter(|(other, _)| other != &variant)
|
.filter(|(other, _, _)| other != &variant)
|
||||||
.map(|(other, _)| complete(other))
|
.map(|(other, _, _)| complete(other))
|
||||||
.collect(),
|
.collect(),
|
||||||
deprecation,
|
deprecation: deprecation.or_else(|| binding.deprecation()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,8 +121,8 @@ $a scripts(=)^"def" b quad a scripts(lt.eq)_"really" b quad a scripts(arrow.r.lo
|
|||||||
|
|
||||||
--- math-attach-integral ---
|
--- math-attach-integral ---
|
||||||
// Test default of scripts attachments on integrals at display size.
|
// 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.inter_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$
|
||||||
|
|
||||||
--- math-attach-large-operator ---
|
--- math-attach-large-operator ---
|
||||||
// Test default of limit attachments on large operators at display size only.
|
// Test default of limit attachments on large operators at display size only.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user