mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-07-24 13:13:43 +00:00
refactor: move expr and ty defs to analysis crate (#1633)
This commit is contained in:
parent
72e33e461d
commit
ac506dcc31
58 changed files with 968 additions and 890 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -4086,15 +4086,31 @@ dependencies = [
|
|||
name = "tinymist-analysis"
|
||||
version = "0.13.10"
|
||||
dependencies = [
|
||||
"comemo",
|
||||
"dashmap",
|
||||
"ecow",
|
||||
"ena",
|
||||
"hashbrown 0.14.5",
|
||||
"if_chain",
|
||||
"insta",
|
||||
"itertools 0.13.0",
|
||||
"log",
|
||||
"lsp-types",
|
||||
"parking_lot",
|
||||
"regex",
|
||||
"rpds",
|
||||
"rustc-hash 2.1.1",
|
||||
"serde",
|
||||
"serde_yaml",
|
||||
"strum",
|
||||
"tinymist-derive",
|
||||
"tinymist-std",
|
||||
"tinymist-world",
|
||||
"toml",
|
||||
"triomphe",
|
||||
"typst",
|
||||
"typst-shim",
|
||||
"unscanny",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4226,7 +4242,6 @@ dependencies = [
|
|||
"dirs",
|
||||
"ecow",
|
||||
"ena",
|
||||
"hashbrown 0.14.5",
|
||||
"hex",
|
||||
"if_chain",
|
||||
"indexmap 2.8.0",
|
||||
|
@ -4255,7 +4270,6 @@ dependencies = [
|
|||
"tinymist-std",
|
||||
"tinymist-world",
|
||||
"toml",
|
||||
"triomphe",
|
||||
"ttf-parser",
|
||||
"typlite",
|
||||
"typst",
|
||||
|
|
|
@ -13,13 +13,30 @@ repository.workspace = true
|
|||
rust-version.workspace = true
|
||||
|
||||
[dependencies]
|
||||
comemo.workspace = true
|
||||
dashmap.workspace = true
|
||||
ecow.workspace = true
|
||||
ena.workspace = true
|
||||
hashbrown.workspace = true
|
||||
if_chain.workspace = true
|
||||
itertools.workspace = true
|
||||
log.workspace = true
|
||||
lsp-types.workspace = true
|
||||
parking_lot.workspace = true
|
||||
regex.workspace = true
|
||||
rpds.workspace = true
|
||||
rustc-hash.workspace = true
|
||||
serde.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
strum.workspace = true
|
||||
toml.workspace = true
|
||||
tinymist-derive.workspace = true
|
||||
tinymist-std.workspace = true
|
||||
tinymist-world.workspace = true
|
||||
toml.workspace = true
|
||||
triomphe.workspace = true
|
||||
typst.workspace = true
|
||||
typst-shim.workspace = true
|
||||
unscanny.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
insta.workspace = true
|
||||
|
|
|
@ -341,8 +341,7 @@ impl<T: Display + Internable + ?Sized> Display for Interned<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) static MAPS: Mutex<EcoVec<(&'static str, usize, Arc<AllocStats>)>> =
|
||||
Mutex::new(EcoVec::new());
|
||||
pub static MAPS: Mutex<EcoVec<(&'static str, usize, Arc<AllocStats>)>> = Mutex::new(EcoVec::new());
|
||||
|
||||
pub struct InternStorage<T: ?Sized> {
|
||||
alloc: OnceLock<Arc<AllocStats>>,
|
||||
|
@ -407,6 +406,6 @@ macro_rules! _impl_internable {
|
|||
}
|
||||
|
||||
pub use crate::_impl_internable as impl_internable;
|
||||
use crate::analysis::AllocStats;
|
||||
use crate::stats::AllocStats;
|
||||
|
||||
impl_internable!(str,);
|
4
crates/tinymist-analysis/src/adt/mod.rs
Normal file
4
crates/tinymist-analysis/src/adt/mod.rs
Normal file
|
@ -0,0 +1,4 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
pub mod interner;
|
||||
pub mod snapshot_map;
|
6
crates/tinymist-analysis/src/docs.rs
Normal file
6
crates/tinymist-analysis/src/docs.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
mod def;
|
||||
pub use def::*;
|
||||
mod tidy;
|
||||
pub use tidy::*;
|
296
crates/tinymist-analysis/src/docs/def.rs
Normal file
296
crates/tinymist-analysis/src/docs/def.rs
Normal file
|
@ -0,0 +1,296 @@
|
|||
use core::fmt;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::tidy::*;
|
||||
use crate::ty::{Interned, ParamAttrs, ParamTy, Ty};
|
||||
use crate::upstream::plain_docs_sentence;
|
||||
|
||||
type TypeRepr = Option<(
|
||||
/* short */ EcoString,
|
||||
/* long */ EcoString,
|
||||
/* value */ EcoString,
|
||||
)>;
|
||||
|
||||
/// Documentation about a definition (without type information).
|
||||
pub type UntypedDefDocs = DefDocsT<()>;
|
||||
/// Documentation about a definition.
|
||||
pub type DefDocs = DefDocsT<TypeRepr>;
|
||||
|
||||
/// Documentation about a definition.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum DefDocsT<T> {
|
||||
/// Documentation about a function.
|
||||
#[serde(rename = "func")]
|
||||
Function(Box<SignatureDocsT<T>>),
|
||||
/// Documentation about a variable.
|
||||
#[serde(rename = "var")]
|
||||
Variable(VarDocsT<T>),
|
||||
/// Documentation about a module.
|
||||
#[serde(rename = "module")]
|
||||
Module(TidyModuleDocs),
|
||||
/// Other kinds of documentation.
|
||||
#[serde(rename = "plain")]
|
||||
Plain {
|
||||
/// The content of the documentation.
|
||||
docs: EcoString,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> DefDocsT<T> {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn docs(&self) -> &EcoString {
|
||||
match self {
|
||||
Self::Function(docs) => &docs.docs,
|
||||
Self::Variable(docs) => &docs.docs,
|
||||
Self::Module(docs) => &docs.docs,
|
||||
Self::Plain { docs } => docs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefDocs {
|
||||
/// Get full documentation for the signature.
|
||||
pub fn hover_docs(&self) -> EcoString {
|
||||
match self {
|
||||
DefDocs::Function(docs) => docs.hover_docs().clone(),
|
||||
_ => plain_docs_sentence(self.docs()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignatureDocsT<T> {
|
||||
/// Documentation for the function.
|
||||
pub docs: EcoString,
|
||||
/// The positional parameters.
|
||||
pub pos: Vec<ParamDocsT<T>>,
|
||||
/// The named parameters.
|
||||
pub named: BTreeMap<Interned<str>, ParamDocsT<T>>,
|
||||
/// The rest parameter.
|
||||
pub rest: Option<ParamDocsT<T>>,
|
||||
/// The return type.
|
||||
pub ret_ty: T,
|
||||
/// The full documentation for the signature.
|
||||
#[serde(skip)]
|
||||
pub hover_docs: OnceLock<EcoString>,
|
||||
}
|
||||
|
||||
impl SignatureDocsT<TypeRepr> {
|
||||
/// Get full documentation for the signature.
|
||||
pub fn hover_docs(&self) -> &EcoString {
|
||||
self.hover_docs
|
||||
.get_or_init(|| plain_docs_sentence(&format!("{}", SigHoverDocs(self))))
|
||||
}
|
||||
}
|
||||
|
||||
struct SigHoverDocs<'a>(&'a SignatureDocs);
|
||||
|
||||
impl fmt::Display for SigHoverDocs<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let docs = self.0;
|
||||
let base_docs = docs.docs.trim();
|
||||
|
||||
if !base_docs.is_empty() {
|
||||
f.write_str(base_docs)?;
|
||||
}
|
||||
|
||||
fn write_param_docs(
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
docs: &ParamDocsT<TypeRepr>,
|
||||
kind: &str,
|
||||
is_first: &mut bool,
|
||||
) -> fmt::Result {
|
||||
if *is_first {
|
||||
*is_first = false;
|
||||
write!(f, "\n\n## {}\n\n", docs.name)?;
|
||||
} else {
|
||||
write!(f, "\n\n## {} ({kind})\n\n", docs.name)?;
|
||||
}
|
||||
|
||||
// p.cano_type.0
|
||||
if let Some(t) = &docs.cano_type {
|
||||
write!(f, "```typc\ntype: {}\n```\n\n", t.2)?;
|
||||
}
|
||||
|
||||
f.write_str(docs.docs.trim())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if !docs.pos.is_empty() {
|
||||
f.write_str("\n\n# Positional Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
for pos_docs in &docs.pos {
|
||||
write_param_docs(f, pos_docs, "positional", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
if docs.rest.is_some() {
|
||||
f.write_str("\n\n# Rest Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
if let Some(rest) = &docs.rest {
|
||||
write_param_docs(f, rest, "spread right", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !docs.named.is_empty() {
|
||||
f.write_str("\n\n# Named Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
for named_docs in docs.named.values() {
|
||||
write_param_docs(f, named_docs, "named", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a signature.
|
||||
pub type UntypedSignatureDocs = SignatureDocsT<()>;
|
||||
/// Documentation about a signature.
|
||||
pub type SignatureDocs = SignatureDocsT<TypeRepr>;
|
||||
|
||||
impl SignatureDocs {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn print(&self, f: &mut impl std::fmt::Write) -> fmt::Result {
|
||||
let mut is_first = true;
|
||||
let mut write_sep = |f: &mut dyn std::fmt::Write| {
|
||||
if is_first {
|
||||
is_first = false;
|
||||
return f.write_str("\n ");
|
||||
}
|
||||
f.write_str(",\n ")
|
||||
};
|
||||
|
||||
f.write_char('(')?;
|
||||
for pos_docs in &self.pos {
|
||||
write_sep(f)?;
|
||||
f.write_str(&pos_docs.name)?;
|
||||
if let Some(t) = &pos_docs.cano_type {
|
||||
write!(f, ": {}", t.0)?;
|
||||
}
|
||||
}
|
||||
if let Some(rest) = &self.rest {
|
||||
write_sep(f)?;
|
||||
f.write_str("..")?;
|
||||
f.write_str(&rest.name)?;
|
||||
if let Some(t) = &rest.cano_type {
|
||||
write!(f, ": {}", t.0)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.named.is_empty() {
|
||||
let mut name_prints = vec![];
|
||||
for v in self.named.values() {
|
||||
let ty = v.cano_type.as_ref().map(|t| &t.0);
|
||||
name_prints.push((v.name.clone(), ty, v.default.clone()))
|
||||
}
|
||||
name_prints.sort();
|
||||
for (name, ty, val) in name_prints {
|
||||
write_sep(f)?;
|
||||
let val = val.as_deref().unwrap_or("any");
|
||||
let mut default = val.trim();
|
||||
if default.starts_with('{') && default.ends_with('}') && default.len() > 30 {
|
||||
default = "{ .. }"
|
||||
}
|
||||
if default.starts_with('`') && default.ends_with('`') && default.len() > 30 {
|
||||
default = "raw"
|
||||
}
|
||||
if default.starts_with('[') && default.ends_with(']') && default.len() > 30 {
|
||||
default = "content"
|
||||
}
|
||||
f.write_str(&name)?;
|
||||
if let Some(ty) = ty {
|
||||
write!(f, ": {ty}")?;
|
||||
}
|
||||
if default.contains('\n') {
|
||||
write!(f, " = {}", default.replace("\n", "\n "))?;
|
||||
} else {
|
||||
write!(f, " = {default}")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !is_first {
|
||||
f.write_str(",\n")?;
|
||||
}
|
||||
f.write_char(')')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a variable (without type information).
|
||||
pub type UntypedVarDocs = VarDocsT<()>;
|
||||
/// Documentation about a variable.
|
||||
pub type VarDocs = VarDocsT<Option<(EcoString, EcoString, EcoString)>>;
|
||||
|
||||
/// Describes a primary pattern binding.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VarDocsT<T> {
|
||||
/// Documentation for the pattern binding.
|
||||
pub docs: EcoString,
|
||||
/// The inferred type of the pattern binding source.
|
||||
pub return_ty: T,
|
||||
/// Cached documentation for the definition.
|
||||
#[serde(skip)]
|
||||
pub def_docs: OnceLock<String>,
|
||||
}
|
||||
|
||||
impl VarDocs {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn def_docs(&self) -> &String {
|
||||
self.def_docs
|
||||
.get_or_init(|| plain_docs_sentence(&self.docs).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a parameter (without type information).
|
||||
pub type TypelessParamDocs = ParamDocsT<()>;
|
||||
/// Documentation about a parameter.
|
||||
pub type ParamDocs = ParamDocsT<TypeRepr>;
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ParamDocsT<T> {
|
||||
/// The parameter's name.
|
||||
pub name: Interned<str>,
|
||||
/// Documentation for the parameter.
|
||||
pub docs: EcoString,
|
||||
/// Inferred type of the parameter.
|
||||
pub cano_type: T,
|
||||
/// The parameter's default name as value.
|
||||
pub default: Option<EcoString>,
|
||||
/// The attribute of the parameter.
|
||||
#[serde(flatten)]
|
||||
pub attrs: ParamAttrs,
|
||||
}
|
||||
|
||||
impl ParamDocs {
|
||||
pub fn new(param: &ParamTy, ty: Option<&Ty>) -> Self {
|
||||
Self {
|
||||
name: param.name.as_ref().into(),
|
||||
docs: param.docs.clone().unwrap_or_default(),
|
||||
cano_type: format_ty(ty.or(Some(¶m.ty))),
|
||||
default: param.default.clone(),
|
||||
attrs: param.attrs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn format_ty(ty: Option<&Ty>) -> TypeRepr {
|
||||
let ty = ty?;
|
||||
let short = ty.repr().unwrap_or_else(|| "any".into());
|
||||
let long = eco_format!("{ty:?}");
|
||||
let value = ty.value_repr().unwrap_or_else(|| "".into());
|
||||
|
||||
Some((short, long, value))
|
||||
}
|
|
@ -1,8 +1,19 @@
|
|||
//! Tinymist Analysis
|
||||
|
||||
pub mod adt;
|
||||
pub mod docs;
|
||||
pub mod location;
|
||||
mod prelude;
|
||||
mod sig;
|
||||
pub mod stats;
|
||||
pub mod syntax;
|
||||
pub mod ty;
|
||||
pub mod upstream;
|
||||
|
||||
pub use sig::*;
|
||||
pub use track_values::*;
|
||||
|
||||
mod prelude;
|
||||
mod track_values;
|
||||
|
||||
/// Completely disabled log
|
||||
#[macro_export]
|
||||
|
|
377
crates/tinymist-analysis/src/sig.rs
Normal file
377
crates/tinymist-analysis/src/sig.rs
Normal file
|
@ -0,0 +1,377 @@
|
|||
//! Analysis of function signatures.
|
||||
|
||||
use core::fmt;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_format, eco_vec, EcoString, EcoVec};
|
||||
use typst::foundations::{Closure, Func};
|
||||
use typst::syntax::ast::AstNode;
|
||||
use typst::syntax::{ast, SyntaxKind};
|
||||
use typst::utils::LazyHash;
|
||||
|
||||
// use super::{BoundChecker, Definition};
|
||||
use crate::ty::{InsTy, ParamTy, SigTy, StrRef, Ty};
|
||||
use crate::ty::{Interned, ParamAttrs};
|
||||
use crate::upstream::truncated_repr;
|
||||
// use crate::upstream::truncated_repr;
|
||||
|
||||
/// Describes a function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Signature {
|
||||
/// A primary function signature.
|
||||
Primary(Arc<PrimarySignature>),
|
||||
/// A partially applied function signature.
|
||||
Partial(Arc<PartialSignature>),
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Returns the primary signature if it is one.
|
||||
pub fn primary(&self) -> &Arc<PrimarySignature> {
|
||||
match self {
|
||||
Signature::Primary(sig) => sig,
|
||||
Signature::Partial(sig) => &sig.signature,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the with bindings of the signature.
|
||||
pub fn bindings(&self) -> &[ArgsInfo] {
|
||||
match self {
|
||||
Signature::Primary(_) => &[],
|
||||
Signature::Partial(sig) => &sig.with_stack,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the all parameters of the signature.
|
||||
pub fn params(&self) -> impl Iterator<Item = (&Interned<ParamTy>, Option<&Ty>)> {
|
||||
let primary = self.primary().params();
|
||||
// todo: with stack
|
||||
primary
|
||||
}
|
||||
|
||||
/// Returns the type of the signature.
|
||||
pub fn type_sig(&self) -> Interned<SigTy> {
|
||||
let primary = self.primary().sig_ty.clone();
|
||||
// todo: with stack
|
||||
primary
|
||||
}
|
||||
|
||||
/// Returns the shift applied to the signature.
|
||||
pub fn param_shift(&self) -> usize {
|
||||
match self {
|
||||
Signature::Primary(_) => 0,
|
||||
Signature::Partial(sig) => sig
|
||||
.with_stack
|
||||
.iter()
|
||||
.map(|ws| ws.items.len())
|
||||
.sum::<usize>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrimarySignature {
|
||||
/// The documentation of the function
|
||||
pub docs: Option<EcoString>,
|
||||
/// The documentation of the parameter.
|
||||
pub param_specs: Vec<Interned<ParamTy>>,
|
||||
/// Whether the function has fill, stroke, or size parameters.
|
||||
pub has_fill_or_size_or_stroke: bool,
|
||||
/// The associated signature type.
|
||||
pub sig_ty: Interned<SigTy>,
|
||||
/// Whether the signature is broken.
|
||||
pub _broken: bool,
|
||||
}
|
||||
|
||||
impl PrimarySignature {
|
||||
/// Returns the number of positional parameters of the function.
|
||||
pub fn pos_size(&self) -> usize {
|
||||
self.sig_ty.name_started as usize
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn pos(&self) -> &[Interned<ParamTy>] {
|
||||
&self.param_specs[..self.pos_size()]
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn get_pos(&self, offset: usize) -> Option<&Interned<ParamTy>> {
|
||||
self.pos().get(offset)
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn named(&self) -> &[Interned<ParamTy>] {
|
||||
&self.param_specs[self.pos_size()..self.pos_size() + self.sig_ty.names.names.len()]
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn get_named(&self, name: &StrRef) -> Option<&Interned<ParamTy>> {
|
||||
self.named().get(self.sig_ty.names.find(name)?)
|
||||
}
|
||||
|
||||
/// Returns the name of the rest parameter of the function.
|
||||
pub fn has_spread_right(&self) -> bool {
|
||||
self.sig_ty.spread_right
|
||||
}
|
||||
|
||||
/// Returns the rest parameter of the function.
|
||||
pub fn rest(&self) -> Option<&Interned<ParamTy>> {
|
||||
self.has_spread_right()
|
||||
.then(|| &self.param_specs[self.pos_size() + self.sig_ty.names.names.len()])
|
||||
}
|
||||
|
||||
/// Returns the all parameters of the function.
|
||||
pub fn params(&self) -> impl Iterator<Item = (&Interned<ParamTy>, Option<&Ty>)> {
|
||||
let pos = self.pos();
|
||||
let named = self.named();
|
||||
let rest = self.rest();
|
||||
let type_sig = &self.sig_ty;
|
||||
let pos = pos
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, pos)| (pos, type_sig.pos(idx)));
|
||||
let named = named.iter().map(|x| (x, type_sig.named(&x.name)));
|
||||
let rest = rest.into_iter().map(|x| (x, type_sig.rest_param()));
|
||||
|
||||
pos.chain(named).chain(rest)
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a function argument instance
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgInfo {
|
||||
/// The argument's name.
|
||||
pub name: Option<StrRef>,
|
||||
/// The argument's term.
|
||||
pub term: Option<Ty>,
|
||||
}
|
||||
|
||||
/// Describes a function argument list.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgsInfo {
|
||||
/// The arguments.
|
||||
pub items: EcoVec<ArgInfo>,
|
||||
}
|
||||
|
||||
/// Describes a function signature that is already partially applied.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PartialSignature {
|
||||
/// The positional parameters.
|
||||
pub signature: Arc<PrimarySignature>,
|
||||
/// The stack of `fn.with(..)` calls.
|
||||
pub with_stack: EcoVec<ArgsInfo>,
|
||||
}
|
||||
|
||||
/// Gets the signature of a function.
|
||||
#[comemo::memoize]
|
||||
pub fn func_signature(func: Func) -> Signature {
|
||||
use typst::foundations::func::Repr;
|
||||
let mut with_stack = eco_vec![];
|
||||
let mut func = func;
|
||||
while let Repr::With(with) = func.inner() {
|
||||
let (inner, args) = with.as_ref();
|
||||
with_stack.push(ArgsInfo {
|
||||
items: args
|
||||
.items
|
||||
.iter()
|
||||
.map(|arg| ArgInfo {
|
||||
name: arg.name.clone().map(From::from),
|
||||
term: Some(Ty::Value(InsTy::new(arg.value.v.clone()))),
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
func = inner.clone();
|
||||
}
|
||||
|
||||
let mut pos_tys = vec![];
|
||||
let mut named_tys = Vec::new();
|
||||
let mut rest_ty = None;
|
||||
|
||||
let mut named_specs = BTreeMap::new();
|
||||
let mut param_specs = Vec::new();
|
||||
let mut rest_spec = None;
|
||||
|
||||
let mut broken = false;
|
||||
let mut has_fill_or_size_or_stroke = false;
|
||||
|
||||
let mut add_param = |param: Interned<ParamTy>| {
|
||||
let name = param.name.clone();
|
||||
if param.attrs.named {
|
||||
if matches!(name.as_ref(), "fill" | "stroke" | "size") {
|
||||
has_fill_or_size_or_stroke = true;
|
||||
}
|
||||
named_tys.push((name.clone(), param.ty.clone()));
|
||||
named_specs.insert(name.clone(), param.clone());
|
||||
}
|
||||
|
||||
if param.attrs.variadic {
|
||||
if rest_ty.is_some() {
|
||||
broken = true;
|
||||
} else {
|
||||
rest_ty = Some(param.ty.clone());
|
||||
rest_spec = Some(param);
|
||||
}
|
||||
} else if param.attrs.positional {
|
||||
// todo: we have some params that are both positional and named
|
||||
pos_tys.push(param.ty.clone());
|
||||
param_specs.push(param);
|
||||
}
|
||||
};
|
||||
|
||||
let ret_ty = match func.inner() {
|
||||
Repr::With(..) => unreachable!(),
|
||||
Repr::Closure(closure) => {
|
||||
analyze_closure_signature(closure.clone(), &mut add_param);
|
||||
None
|
||||
}
|
||||
Repr::Element(..) | Repr::Native(..) | Repr::Plugin(..) => {
|
||||
for param in func.params().unwrap_or_default() {
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: param.name.into(),
|
||||
docs: Some(param.docs.into()),
|
||||
default: param.default.map(|default| truncated_repr(&default())),
|
||||
ty: Ty::from_param_site(&func, param),
|
||||
attrs: param.into(),
|
||||
}));
|
||||
}
|
||||
|
||||
func.returns().map(|r| Ty::from_return_site(&func, r))
|
||||
}
|
||||
};
|
||||
|
||||
let sig_ty = SigTy::new(pos_tys.into_iter(), named_tys, None, rest_ty, ret_ty);
|
||||
|
||||
for name in &sig_ty.names.names {
|
||||
let Some(param) = named_specs.get(name) else {
|
||||
continue;
|
||||
};
|
||||
param_specs.push(param.clone());
|
||||
}
|
||||
if let Some(doc) = rest_spec {
|
||||
param_specs.push(doc);
|
||||
}
|
||||
|
||||
let signature = Arc::new(PrimarySignature {
|
||||
docs: func.docs().map(From::from),
|
||||
param_specs,
|
||||
has_fill_or_size_or_stroke,
|
||||
sig_ty: sig_ty.into(),
|
||||
_broken: broken,
|
||||
});
|
||||
|
||||
log::trace!("got signature {signature:?}");
|
||||
|
||||
if with_stack.is_empty() {
|
||||
return Signature::Primary(signature);
|
||||
}
|
||||
|
||||
Signature::Partial(Arc::new(PartialSignature {
|
||||
signature,
|
||||
with_stack,
|
||||
}))
|
||||
}
|
||||
|
||||
fn analyze_closure_signature(
|
||||
closure: Arc<LazyHash<Closure>>,
|
||||
add_param: &mut impl FnMut(Interned<ParamTy>),
|
||||
) {
|
||||
log::trace!("closure signature for: {:?}", closure.node.kind());
|
||||
|
||||
let closure = &closure.node;
|
||||
let closure_ast = match closure.kind() {
|
||||
SyntaxKind::Closure => closure.cast::<ast::Closure>().unwrap(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for param in closure_ast.params().children() {
|
||||
match param {
|
||||
ast::Param::Pos(pos) => {
|
||||
let name = format!("{}", PatternDisplay(&pos));
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: name.as_str().into(),
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::positional(),
|
||||
}));
|
||||
}
|
||||
// todo: pattern
|
||||
ast::Param::Named(named) => {
|
||||
let default = unwrap_parens(named.expr()).to_untyped().clone().into_text();
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: named.name().get().into(),
|
||||
docs: Some(eco_format!("Default value: {default}")),
|
||||
default: Some(default),
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::named(),
|
||||
}));
|
||||
}
|
||||
ast::Param::Spread(spread) => {
|
||||
let sink = spread.sink_ident().map(|sink| sink.as_str());
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: sink.unwrap_or_default().into(),
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::variadic(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PatternDisplay<'a>(&'a ast::Pattern<'a>);
|
||||
|
||||
impl fmt::Display for PatternDisplay<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {
|
||||
ast::Pattern::Normal(ast::Expr::Ident(ident)) => f.write_str(ident.as_str()),
|
||||
ast::Pattern::Normal(_) => f.write_str("?"), // unreachable?
|
||||
ast::Pattern::Placeholder(_) => f.write_str("_"),
|
||||
ast::Pattern::Parenthesized(paren_expr) => {
|
||||
write!(f, "{}", PatternDisplay(&paren_expr.pattern()))
|
||||
}
|
||||
ast::Pattern::Destructuring(destructing) => {
|
||||
write!(f, "(")?;
|
||||
let mut first = true;
|
||||
for item in destructing.items() {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
match item {
|
||||
ast::DestructuringItem::Pattern(pos) => {
|
||||
write!(f, "{}", PatternDisplay(&pos))?
|
||||
}
|
||||
ast::DestructuringItem::Named(named) => write!(
|
||||
f,
|
||||
"{}: {}",
|
||||
named.name().as_str(),
|
||||
unwrap_parens(named.expr()).to_untyped().text()
|
||||
)?,
|
||||
ast::DestructuringItem::Spread(spread) => write!(
|
||||
f,
|
||||
"..{}",
|
||||
spread
|
||||
.sink_ident()
|
||||
.map(|sink| sink.as_str())
|
||||
.unwrap_or_default()
|
||||
)?,
|
||||
}
|
||||
}
|
||||
write!(f, ")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_parens(mut expr: ast::Expr) -> ast::Expr {
|
||||
while let ast::Expr::Parenthesized(paren_expr) = expr {
|
||||
expr = paren_expr.expr();
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
80
crates/tinymist-analysis/src/stats.rs
Normal file
80
crates/tinymist-analysis/src/stats.rs
Normal file
|
@ -0,0 +1,80 @@
|
|||
//! Tinymist Analysis Statistics
|
||||
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
/// Statistics about the allocation
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AllocStats {
|
||||
/// The number of allocated objects.
|
||||
pub allocated: AtomicUsize,
|
||||
/// The number of dropped objects.
|
||||
pub dropped: AtomicUsize,
|
||||
}
|
||||
|
||||
impl AllocStats {
|
||||
/// increment the statistics.
|
||||
pub fn increment(&self) {
|
||||
self.allocated.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// decrement the statistics.
|
||||
pub fn decrement(&self) {
|
||||
self.dropped.fetch_add(1, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Report the statistics of the allocation.
|
||||
pub fn report() -> String {
|
||||
let maps = crate::adt::interner::MAPS.lock().clone();
|
||||
let mut data = Vec::new();
|
||||
for (name, sz, map) in maps {
|
||||
let allocated = map.allocated.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let dropped = map.dropped.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let alive = allocated.saturating_sub(dropped);
|
||||
data.push((name, sz * alive, allocated, dropped, alive));
|
||||
}
|
||||
|
||||
// sort by total
|
||||
data.sort_by(|x, y| y.4.cmp(&x.4));
|
||||
|
||||
// format to html
|
||||
|
||||
let mut html = String::new();
|
||||
html.push_str(r#"<div>
|
||||
<style>
|
||||
table.alloc-stats { width: 100%; border-collapse: collapse; }
|
||||
table.alloc-stats th, table.alloc-stats td { border: 1px solid black; padding: 8px; text-align: center; }
|
||||
table.alloc-stats th.name-column, table.alloc-stats td.name-column { text-align: left; }
|
||||
table.alloc-stats tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0.8); }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
table.alloc-stats tr:nth-child(odd) { background-color: rgba(50, 50, 50, 0.8); }
|
||||
}
|
||||
</style>
|
||||
<table class="alloc-stats"><tr><th class="name-column">Name</th><th>Alive</th><th>Allocated</th><th>Dropped</th><th>Size</th></tr>"#);
|
||||
|
||||
for (name, sz, allocated, dropped, alive) in data {
|
||||
html.push_str("<tr>");
|
||||
html.push_str(&format!(r#"<td class="name-column">{name}</td>"#));
|
||||
html.push_str(&format!("<td>{alive}</td>"));
|
||||
html.push_str(&format!("<td>{allocated}</td>"));
|
||||
html.push_str(&format!("<td>{dropped}</td>"));
|
||||
html.push_str(&format!("<td>{}</td>", human_size(sz)));
|
||||
html.push_str("</tr>");
|
||||
}
|
||||
html.push_str("</table>");
|
||||
html.push_str("</div>");
|
||||
|
||||
html
|
||||
}
|
||||
}
|
||||
|
||||
fn human_size(size: usize) -> String {
|
||||
let units = ["B", "KB", "MB", "GB", "TB"];
|
||||
let mut unit = 0;
|
||||
let mut size = size as f64;
|
||||
while size >= 768.0 && unit < units.len() {
|
||||
size /= 1024.0;
|
||||
unit += 1;
|
||||
}
|
||||
format!("{:.2} {}", size, units[unit])
|
||||
}
|
|
@ -2,9 +2,17 @@
|
|||
//!
|
||||
//! This module must hide all **AST details** from the rest of the codebase.
|
||||
|
||||
// todo: remove this
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub mod import;
|
||||
pub use import::*;
|
||||
pub mod comment;
|
||||
pub use comment::*;
|
||||
pub mod matcher;
|
||||
pub use matcher::*;
|
||||
|
||||
pub mod def;
|
||||
pub use def::*;
|
||||
pub(crate) mod repr;
|
||||
use repr::*;
|
||||
|
|
|
@ -3,6 +3,7 @@ use std::{collections::BTreeMap, ops::Range};
|
|||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_derive::DeclEnum;
|
||||
use tinymist_std::DefId;
|
||||
use tinymist_world::package::PackageSpec;
|
||||
use typst::{
|
||||
foundations::{Element, Func, Module, Type, Value},
|
||||
|
@ -11,7 +12,6 @@ use typst::{
|
|||
|
||||
use crate::{
|
||||
adt::interner::impl_internable,
|
||||
analysis::SharedContext,
|
||||
prelude::*,
|
||||
ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
|
||||
};
|
||||
|
@ -73,13 +73,13 @@ pub enum Expr {
|
|||
}
|
||||
|
||||
impl Expr {
|
||||
pub(crate) fn repr(&self) -> EcoString {
|
||||
pub fn repr(&self) -> EcoString {
|
||||
let mut s = EcoString::new();
|
||||
let _ = ExprDescriber::new(&mut s).write_expr(self);
|
||||
s
|
||||
}
|
||||
|
||||
pub(crate) fn span(&self) -> Span {
|
||||
pub fn span(&self) -> Span {
|
||||
match self {
|
||||
Expr::Decl(decl) => decl.span(),
|
||||
Expr::Select(select) => select.span,
|
||||
|
@ -88,7 +88,7 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn file_id(&self) -> Option<TypstFileId> {
|
||||
pub fn file_id(&self) -> Option<TypstFileId> {
|
||||
match self {
|
||||
Expr::Decl(decl) => decl.file_id(),
|
||||
_ => self.span().id(),
|
||||
|
@ -409,7 +409,7 @@ impl Decl {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn is_def(&self) -> bool {
|
||||
pub fn is_def(&self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::Func(..)
|
||||
|
@ -452,25 +452,6 @@ impl Decl {
|
|||
}
|
||||
}
|
||||
|
||||
/// Gets name range of the declaration.
|
||||
pub fn name_range(&self, ctx: &SharedContext) -> Option<Range<usize>> {
|
||||
if let Decl::BibEntry(decl) = self {
|
||||
return Some(decl.at.1.clone());
|
||||
}
|
||||
|
||||
if !self.is_def() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let span = self.span();
|
||||
if let Some(range) = span.range() {
|
||||
return Some(range.clone());
|
||||
}
|
||||
|
||||
let src = ctx.source_by_id(self.file_id()?).ok()?;
|
||||
src.range(span)
|
||||
}
|
||||
|
||||
/// Gets full range of the declaration.
|
||||
pub fn full_range(&self) -> Option<Range<usize>> {
|
||||
if let Decl::BibEntry(decl) = self {
|
||||
|
@ -595,8 +576,8 @@ impl fmt::Debug for SpannedDecl {
|
|||
|
||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||
pub struct NameRangeDecl {
|
||||
name: Interned<str>,
|
||||
at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
|
||||
pub name: Interned<str>,
|
||||
pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
|
||||
}
|
||||
|
||||
impl NameRangeDecl {
|
||||
|
@ -724,7 +705,7 @@ impl fmt::Display for Pattern {
|
|||
}
|
||||
|
||||
impl Pattern {
|
||||
pub(crate) fn repr(&self) -> EcoString {
|
||||
pub fn repr(&self) -> EcoString {
|
||||
let mut s = EcoString::new();
|
||||
let _ = ExprDescriber::new(&mut s).write_pattern(self);
|
||||
s
|
|
@ -109,7 +109,7 @@ impl PathPreference {
|
|||
}
|
||||
|
||||
impl Ty {
|
||||
pub(crate) fn from_cast_info(ty: &CastInfo) -> Ty {
|
||||
pub fn from_cast_info(ty: &CastInfo) -> Ty {
|
||||
match &ty {
|
||||
CastInfo::Any => Ty::Any,
|
||||
CastInfo::Value(val, doc) => Ty::Value(InsTy::new_doc(val.clone(), *doc)),
|
||||
|
@ -120,7 +120,7 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_param_site(func: &Func, param: &ParamInfo) -> Ty {
|
||||
pub fn from_param_site(func: &Func, param: &ParamInfo) -> Ty {
|
||||
use typst::foundations::func::Repr;
|
||||
match func.inner() {
|
||||
Repr::Element(..) | Repr::Native(..) | Repr::Plugin(..) => {
|
|
@ -1,4 +1,6 @@
|
|||
use crate::analysis::func_signature;
|
||||
use typst::syntax::Span;
|
||||
|
||||
use crate::func_signature;
|
||||
|
||||
use super::*;
|
||||
|
|
@ -17,10 +17,9 @@ use typst::{
|
|||
syntax::{ast, FileId, Span, SyntaxKind, SyntaxNode},
|
||||
};
|
||||
|
||||
use super::{BoundPred, PackageId};
|
||||
use super::{BoundPred, BuiltinTy, PackageId};
|
||||
use crate::{
|
||||
adt::{interner::impl_internable, snapshot_map},
|
||||
analysis::BuiltinTy,
|
||||
docs::UntypedDefDocs,
|
||||
syntax::{DeclExpr, UnaryOp},
|
||||
};
|
||||
|
@ -142,7 +141,7 @@ impl Ty {
|
|||
matches!(self, Ty::Dict(..))
|
||||
}
|
||||
|
||||
pub(crate) fn union(lhs: Option<Ty>, rhs: Option<Ty>) -> Option<Ty> {
|
||||
pub fn union(lhs: Option<Ty>, rhs: Option<Ty>) -> Option<Ty> {
|
||||
Some(match (lhs, rhs) {
|
||||
(Some(lhs), Some(rhs)) => Ty::from_types([lhs, rhs].into_iter()),
|
||||
(Some(ty), None) | (None, Some(ty)) => ty,
|
||||
|
@ -231,11 +230,11 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn satisfy<T: TyCtx>(&self, ctx: &T, f: impl FnMut(&Ty, bool)) {
|
||||
pub fn satisfy<T: TyCtx>(&self, ctx: &T, f: impl FnMut(&Ty, bool)) {
|
||||
self.bounds(true, &mut BoundPred::new(ctx, f));
|
||||
}
|
||||
|
||||
pub(crate) fn is_content<T: TyCtx>(&self, ctx: &T) -> bool {
|
||||
pub fn is_content<T: TyCtx>(&self, ctx: &T) -> bool {
|
||||
let mut res = false;
|
||||
self.satisfy(ctx, |ty: &Ty, _pol| {
|
||||
res = res || {
|
||||
|
@ -561,7 +560,7 @@ pub struct ParamAttrs {
|
|||
}
|
||||
|
||||
impl ParamAttrs {
|
||||
pub(crate) fn positional() -> ParamAttrs {
|
||||
pub fn positional() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: true,
|
||||
named: false,
|
||||
|
@ -570,7 +569,7 @@ impl ParamAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn named() -> ParamAttrs {
|
||||
pub fn named() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: false,
|
||||
named: true,
|
||||
|
@ -579,7 +578,7 @@ impl ParamAttrs {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn variadic() -> ParamAttrs {
|
||||
pub fn variadic() -> ParamAttrs {
|
||||
ParamAttrs {
|
||||
positional: true,
|
||||
named: false,
|
||||
|
@ -835,7 +834,7 @@ impl SigTy {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn with_body(mut self, res_ty: Ty) -> Self {
|
||||
pub fn with_body(mut self, res_ty: Ty) -> Self {
|
||||
self.body = Some(res_ty);
|
||||
self
|
||||
}
|
||||
|
@ -964,7 +963,7 @@ impl SigTy {
|
|||
pub fn matches<'a>(
|
||||
&'a self,
|
||||
args: &'a SigTy,
|
||||
with: Option<&'a Vec<Interned<crate::analysis::SigTy>>>,
|
||||
with: Option<&'a Vec<Interned<SigTy>>>,
|
||||
) -> impl Iterator<Item = (&'a Ty, &'a Ty)> + 'a {
|
||||
let with_len = with
|
||||
.map(|w| w.iter().map(|w| w.positional_params().len()).sum::<usize>())
|
|
@ -3,11 +3,8 @@ use tinymist_std::hash::hash128;
|
|||
use tinymist_world::vfs::WorkspaceResolver;
|
||||
use typst::foundations::Repr;
|
||||
|
||||
use crate::{
|
||||
analysis::{is_plain_value, term_value},
|
||||
ty::prelude::*,
|
||||
upstream::truncated_repr_,
|
||||
};
|
||||
use super::{is_plain_value, term_value};
|
||||
use crate::{ty::prelude::*, upstream::truncated_repr_};
|
||||
|
||||
impl Ty {
|
||||
/// Describe the given type.
|
|
@ -1,8 +1,11 @@
|
|||
//! Types and type operations for Typst.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
mod apply;
|
||||
mod bound;
|
||||
mod builtin;
|
||||
mod convert;
|
||||
mod def;
|
||||
mod describe;
|
||||
mod iface;
|
||||
|
@ -13,14 +16,16 @@ mod sig;
|
|||
mod simplify;
|
||||
mod subst;
|
||||
|
||||
pub(crate) use apply::*;
|
||||
pub(crate) use bound::*;
|
||||
pub(crate) use builtin::*;
|
||||
pub use apply::*;
|
||||
pub use bound::*;
|
||||
pub use builtin::*;
|
||||
pub use convert::*;
|
||||
pub use def::*;
|
||||
pub(crate) use iface::*;
|
||||
pub(crate) use mutate::*;
|
||||
pub(crate) use select::*;
|
||||
pub(crate) use sig::*;
|
||||
pub use iface::*;
|
||||
pub use mutate::*;
|
||||
pub use select::*;
|
||||
pub use sig::*;
|
||||
|
||||
use typst::foundations::{self, Func, Module, Value};
|
||||
use typst::syntax::FileId;
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
//! Functions from typst-ide
|
||||
|
||||
use std::{collections::HashMap, fmt::Write, sync::LazyLock};
|
||||
|
||||
use comemo::Tracked;
|
||||
|
@ -354,6 +356,7 @@ pub(crate) fn urlify(title: &str) -> EcoString {
|
|||
.collect()
|
||||
}
|
||||
|
||||
/// Get the route of a value.
|
||||
pub fn route_of_value(val: &Value) -> Option<&'static String> {
|
||||
// ROUTE_MAPS.get(&CatKey::Func(k.clone()))
|
||||
let key = match val {
|
||||
|
@ -396,6 +399,7 @@ pub fn summarize_font_family<'a>(variants: impl Iterator<Item = &'a FontInfo>) -
|
|||
detail
|
||||
}
|
||||
|
||||
/// Get the representation but truncated to a certain size.
|
||||
pub fn truncated_repr_<const SZ_LIMIT: usize>(value: &Value) -> EcoString {
|
||||
use typst::foundations::Repr;
|
||||
|
||||
|
@ -416,6 +420,7 @@ pub fn truncated_repr_<const SZ_LIMIT: usize>(value: &Value) -> EcoString {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the representation but truncated to a certain size.
|
||||
pub fn truncated_repr(value: &Value) -> EcoString {
|
||||
const _10MB: usize = 100 * 1024 * 1024;
|
||||
truncated_repr_::<_10MB>(value)
|
|
@ -12,7 +12,7 @@ use typst_shim::syntax::LinkedNodeExt;
|
|||
use typst_shim::utils::{round_2, Numeric};
|
||||
|
||||
use super::{plain_docs_sentence, summarize_font_family, truncated_repr};
|
||||
use crate::analysis::analyze_expr;
|
||||
use crate::analyze_expr;
|
||||
|
||||
/// Describe the item under the cursor.
|
||||
///
|
|
@ -14,43 +14,33 @@ rust-version.workspace = true
|
|||
[dependencies]
|
||||
|
||||
anyhow.workspace = true
|
||||
comemo.workspace = true
|
||||
dirs.workspace = true
|
||||
regex.workspace = true
|
||||
yaml-rust2.workspace = true
|
||||
base64.workspace = true
|
||||
biblatex.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
itertools.workspace = true
|
||||
strum.workspace = true
|
||||
log.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
parking_lot.workspace = true
|
||||
comemo.workspace = true
|
||||
dashmap.workspace = true
|
||||
dirs.workspace = true
|
||||
ena.workspace = true
|
||||
toml.workspace = true
|
||||
walkdir.workspace = true
|
||||
indexmap.workspace = true
|
||||
ecow.workspace = true
|
||||
siphasher.workspace = true
|
||||
rpds.workspace = true
|
||||
rayon.workspace = true
|
||||
|
||||
typst.workspace = true
|
||||
|
||||
typst-shim.workspace = true
|
||||
|
||||
lsp-types.workspace = true
|
||||
if_chain.workspace = true
|
||||
itertools.workspace = true
|
||||
indexmap.workspace = true
|
||||
log.workspace = true
|
||||
lsp-types.workspace = true
|
||||
parking_lot.workspace = true
|
||||
percent-encoding.workspace = true
|
||||
unscanny.workspace = true
|
||||
ttf-parser.workspace = true
|
||||
rayon.workspace = true
|
||||
regex.workspace = true
|
||||
rpds.workspace = true
|
||||
rust_iso639.workspace = true
|
||||
rust_iso3166.workspace = true
|
||||
dashmap.workspace = true
|
||||
rustc-hash.workspace = true
|
||||
hashbrown.workspace = true
|
||||
triomphe.workspace = true
|
||||
base64.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
serde_yaml.workspace = true
|
||||
siphasher.workspace = true
|
||||
strum.workspace = true
|
||||
toml.workspace = true
|
||||
ttf-parser.workspace = true
|
||||
typlite.workspace = true
|
||||
tinymist-world = { workspace = true }
|
||||
tinymist-project = { workspace = true, features = ["lsp"] }
|
||||
|
@ -58,6 +48,12 @@ tinymist-analysis.workspace = true
|
|||
tinymist-derive.workspace = true
|
||||
tinymist-std.workspace = true
|
||||
tinymist-l10n.workspace = true
|
||||
typst.workspace = true
|
||||
typst-shim.workspace = true
|
||||
unscanny.workspace = true
|
||||
walkdir.workspace = true
|
||||
yaml-rust2.workspace = true
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
insta.workspace = true
|
||||
|
|
|
@ -1,3 +1,2 @@
|
|||
pub mod interner;
|
||||
pub mod revision;
|
||||
pub mod snapshot_map;
|
||||
pub use tinymist_analysis::adt::*;
|
||||
|
|
|
@ -34,8 +34,6 @@ mod tyck;
|
|||
pub(crate) use crate::ty::*;
|
||||
pub(crate) use post_tyck::*;
|
||||
pub(crate) use tyck::*;
|
||||
pub mod track_values;
|
||||
pub use track_values::*;
|
||||
mod prelude;
|
||||
|
||||
mod global;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
//! Hybrid analysis for function calls.
|
||||
|
||||
use super::prelude::*;
|
||||
use super::{Signature, StrRef};
|
||||
use super::Signature;
|
||||
use crate::analysis::{analyze_signature, PrimarySignature, SignatureTarget};
|
||||
|
||||
/// Describes kind of a parameter.
|
||||
|
|
|
@ -10,6 +10,7 @@ use lsp_types::InsertTextFormat;
|
|||
use regex::{Captures, Regex};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_analysis::syntax::{bad_completion_cursor, BadCompletionCursor};
|
||||
use tinymist_analysis::{analyze_labels, func_signature, DynLabel};
|
||||
use tinymist_derive::BindTyCtx;
|
||||
use tinymist_project::LspWorld;
|
||||
use tinymist_std::path::unix_slash;
|
||||
|
@ -27,9 +28,7 @@ use typst_shim::{syntax::LinkedNodeExt, utils::hash128};
|
|||
use unscanny::Scanner;
|
||||
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::analysis::{
|
||||
analyze_labels, func_signature, BuiltinTy, DynLabel, LocalContext, PathPreference, Ty,
|
||||
};
|
||||
use crate::analysis::{BuiltinTy, LocalContext, PathPreference, Ty};
|
||||
use crate::completion::{
|
||||
Completion, CompletionCommand, CompletionContextKey, CompletionItem, CompletionKind,
|
||||
EcoTextEdit, ParsedSnippet, PostfixSnippet, PostfixSnippetScope, PrefixSnippet,
|
||||
|
|
|
@ -55,6 +55,31 @@ impl Definition {
|
|||
}
|
||||
}
|
||||
|
||||
trait HasNameRange {
|
||||
/// Gets name range of the item.
|
||||
fn name_range(&self, ctx: &SharedContext) -> Option<Range<usize>>;
|
||||
}
|
||||
|
||||
impl HasNameRange for Decl {
|
||||
fn name_range(&self, ctx: &SharedContext) -> Option<Range<usize>> {
|
||||
if let Decl::BibEntry(decl) = self {
|
||||
return Some(decl.at.1.clone());
|
||||
}
|
||||
|
||||
if !self.is_def() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let span = self.span();
|
||||
if let Some(range) = span.range() {
|
||||
return Some(range.clone());
|
||||
}
|
||||
|
||||
let src = ctx.source_by_id(self.file_id()?).ok()?;
|
||||
src.range(span)
|
||||
}
|
||||
}
|
||||
|
||||
// todo: field definition
|
||||
/// Finds the definition of a symbol.
|
||||
pub fn definition(
|
||||
|
|
|
@ -8,6 +8,9 @@ use comemo::{Track, Tracked};
|
|||
use lsp_types::Url;
|
||||
use parking_lot::Mutex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use tinymist_analysis::stats::AllocStats;
|
||||
use tinymist_analysis::ty::term_value;
|
||||
use tinymist_analysis::{analyze_expr_, analyze_import_};
|
||||
use tinymist_project::LspWorld;
|
||||
use tinymist_std::hash::{hash128, FxDashMap};
|
||||
use tinymist_std::typst::TypstDocument;
|
||||
|
@ -24,10 +27,9 @@ use typst_shim::eval::{eval_compat, Eval};
|
|||
use crate::adt::revision::{RevisionLock, RevisionManager, RevisionManagerLike, RevisionSlot};
|
||||
use crate::analysis::prelude::*;
|
||||
use crate::analysis::{
|
||||
analyze_expr_, analyze_import_, analyze_signature, bib_info, definition, post_type_check,
|
||||
AllocStats, AnalysisStats, BibInfo, CompletionFeat, Definition, PathPreference, QueryStatGuard,
|
||||
SemanticTokenCache, SemanticTokenContext, SemanticTokens, Signature, SignatureTarget, Ty,
|
||||
TypeInfo,
|
||||
analyze_signature, bib_info, definition, post_type_check, AnalysisStats, BibInfo,
|
||||
CompletionFeat, Definition, PathPreference, QueryStatGuard, SemanticTokenCache,
|
||||
SemanticTokenContext, SemanticTokens, Signature, SignatureTarget, Ty, TypeInfo,
|
||||
};
|
||||
use crate::docs::{DefDocs, TidyModuleDocs};
|
||||
use crate::syntax::{
|
||||
|
@ -147,7 +149,7 @@ impl Analysis {
|
|||
|
||||
/// Report the statistics of the allocation.
|
||||
pub fn report_alloc_stats(&self) -> String {
|
||||
AllocStats::report(self)
|
||||
AllocStats::report()
|
||||
}
|
||||
|
||||
/// Get configured trigger suggest command.
|
||||
|
@ -781,7 +783,7 @@ impl SharedContext {
|
|||
return cached;
|
||||
}
|
||||
|
||||
let res = crate::analysis::term_value(val);
|
||||
let res = term_value(val);
|
||||
|
||||
self.analysis
|
||||
.caches
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Infer more than the principal type of some expression.
|
||||
|
||||
use hashbrown::HashSet;
|
||||
use std::collections::HashSet;
|
||||
use tinymist_derive::BindTyCtx;
|
||||
|
||||
use super::{prelude::*, DynTypeBounds, ParamAttrs, ParamTy, SharedContext};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
pub use core::fmt;
|
||||
pub use std::collections::{BTreeMap, HashMap};
|
||||
pub use std::hash::{Hash, Hasher};
|
||||
pub use std::ops::Range;
|
||||
|
@ -14,7 +13,7 @@ pub use typst::World;
|
|||
pub use typst_shim::syntax::LinkedNodeExt;
|
||||
pub use typst_shim::utils::LazyHash;
|
||||
|
||||
pub(crate) use super::StrRef;
|
||||
pub(crate) use super::{LocalContext, ToFunc};
|
||||
pub(crate) use crate::adt::interner::Interned;
|
||||
pub use crate::ty::Ty;
|
||||
pub(crate) use crate::StrRef;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
//! Semantic tokens (highlighting) support for LSP.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::{
|
||||
num::NonZeroUsize,
|
||||
ops::Range,
|
||||
|
@ -7,7 +8,6 @@ use std::{
|
|||
sync::{Arc, OnceLock},
|
||||
};
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use lsp_types::SemanticToken;
|
||||
use lsp_types::{SemanticTokenModifier, SemanticTokenType};
|
||||
use parking_lot::Mutex;
|
||||
|
|
|
@ -1,163 +1,19 @@
|
|||
//! Analysis of function signatures.
|
||||
|
||||
use itertools::Either;
|
||||
use tinymist_analysis::{func_signature, ArgInfo, ArgsInfo, PartialSignature};
|
||||
use tinymist_derive::BindTyCtx;
|
||||
use typst::foundations::Closure;
|
||||
|
||||
use super::{
|
||||
prelude::*, BoundChecker, Definition, DocSource, ParamTy, SharedContext, SigTy, SigWithTy,
|
||||
TypeInfo, TypeVar,
|
||||
};
|
||||
use super::{prelude::*, Definition, SharedContext};
|
||||
use crate::analysis::PostTypeChecker;
|
||||
use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs};
|
||||
use crate::syntax::classify_def_loosely;
|
||||
use crate::ty::{DynTypeBounds, ParamAttrs};
|
||||
use crate::ty::{InsTy, TyCtx};
|
||||
use crate::upstream::truncated_repr;
|
||||
use crate::ty::{
|
||||
BoundChecker, DocSource, DynTypeBounds, ParamAttrs, ParamTy, SigWithTy, TyCtx, TypeInfo,
|
||||
TypeVar,
|
||||
};
|
||||
|
||||
/// Describes a function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Signature {
|
||||
/// A primary function signature.
|
||||
Primary(Arc<PrimarySignature>),
|
||||
/// A partially applied function signature.
|
||||
Partial(Arc<PartialSignature>),
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
/// Returns the primary signature if it is one.
|
||||
pub fn primary(&self) -> &Arc<PrimarySignature> {
|
||||
match self {
|
||||
Signature::Primary(sig) => sig,
|
||||
Signature::Partial(sig) => &sig.signature,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the with bindings of the signature.
|
||||
pub fn bindings(&self) -> &[ArgsInfo] {
|
||||
match self {
|
||||
Signature::Primary(_) => &[],
|
||||
Signature::Partial(sig) => &sig.with_stack,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the all parameters of the function.
|
||||
pub(crate) fn params(&self) -> impl Iterator<Item = (&Interned<ParamTy>, Option<&Ty>)> {
|
||||
let primary = self.primary().params();
|
||||
// todo: with stack
|
||||
primary
|
||||
}
|
||||
|
||||
pub(crate) fn type_sig(&self) -> Interned<SigTy> {
|
||||
let primary = self.primary().sig_ty.clone();
|
||||
// todo: with stack
|
||||
primary
|
||||
}
|
||||
|
||||
pub(crate) fn param_shift(&self) -> usize {
|
||||
match self {
|
||||
Signature::Primary(_) => 0,
|
||||
Signature::Partial(sig) => sig
|
||||
.with_stack
|
||||
.iter()
|
||||
.map(|ws| ws.items.len())
|
||||
.sum::<usize>(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PrimarySignature {
|
||||
/// The documentation of the function
|
||||
pub docs: Option<EcoString>,
|
||||
/// The documentation of the parameter.
|
||||
pub param_specs: Vec<Interned<ParamTy>>,
|
||||
/// Whether the function has fill, stroke, or size parameters.
|
||||
pub has_fill_or_size_or_stroke: bool,
|
||||
/// The associated signature type.
|
||||
pub(crate) sig_ty: Interned<SigTy>,
|
||||
_broken: bool,
|
||||
}
|
||||
|
||||
impl PrimarySignature {
|
||||
/// Returns the number of positional parameters of the function.
|
||||
pub fn pos_size(&self) -> usize {
|
||||
self.sig_ty.name_started as usize
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn pos(&self) -> &[Interned<ParamTy>] {
|
||||
&self.param_specs[..self.pos_size()]
|
||||
}
|
||||
|
||||
/// Returns the positional parameters of the function.
|
||||
pub fn get_pos(&self, offset: usize) -> Option<&Interned<ParamTy>> {
|
||||
self.pos().get(offset)
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn named(&self) -> &[Interned<ParamTy>] {
|
||||
&self.param_specs[self.pos_size()..self.pos_size() + self.sig_ty.names.names.len()]
|
||||
}
|
||||
|
||||
/// Returns the named parameters of the function.
|
||||
pub fn get_named(&self, name: &StrRef) -> Option<&Interned<ParamTy>> {
|
||||
self.named().get(self.sig_ty.names.find(name)?)
|
||||
}
|
||||
|
||||
/// Returns the name of the rest parameter of the function.
|
||||
pub fn has_spread_right(&self) -> bool {
|
||||
self.sig_ty.spread_right
|
||||
}
|
||||
|
||||
/// Returns the rest parameter of the function.
|
||||
pub fn rest(&self) -> Option<&Interned<ParamTy>> {
|
||||
self.has_spread_right()
|
||||
.then(|| &self.param_specs[self.pos_size() + self.sig_ty.names.names.len()])
|
||||
}
|
||||
|
||||
/// Returns the all parameters of the function.
|
||||
pub fn params(&self) -> impl Iterator<Item = (&Interned<ParamTy>, Option<&Ty>)> {
|
||||
let pos = self.pos();
|
||||
let named = self.named();
|
||||
let rest = self.rest();
|
||||
let type_sig = &self.sig_ty;
|
||||
let pos = pos
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, pos)| (pos, type_sig.pos(idx)));
|
||||
let named = named.iter().map(|x| (x, type_sig.named(&x.name)));
|
||||
let rest = rest.into_iter().map(|x| (x, type_sig.rest_param()));
|
||||
|
||||
pos.chain(named).chain(rest)
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a function argument instance
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgInfo {
|
||||
/// The argument's name.
|
||||
pub name: Option<StrRef>,
|
||||
/// The argument's term.
|
||||
pub term: Option<Ty>,
|
||||
}
|
||||
|
||||
/// Describes a function argument list.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgsInfo {
|
||||
/// The arguments.
|
||||
pub items: EcoVec<ArgInfo>,
|
||||
}
|
||||
|
||||
/// Describes a function signature that is already partially applied.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct PartialSignature {
|
||||
/// The positional parameters.
|
||||
pub signature: Arc<PrimarySignature>,
|
||||
/// The stack of `fn.with(..)` calls.
|
||||
pub with_stack: EcoVec<ArgsInfo>,
|
||||
}
|
||||
pub use tinymist_analysis::{PrimarySignature, Signature};
|
||||
|
||||
/// The language object that the signature is being analyzed for.
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -475,216 +331,3 @@ fn analyze_dyn_signature(
|
|||
|
||||
Some(func_signature(func))
|
||||
}
|
||||
|
||||
/// Gets the signature of a function.
|
||||
#[comemo::memoize]
|
||||
pub fn func_signature(func: Func) -> Signature {
|
||||
use typst::foundations::func::Repr;
|
||||
let mut with_stack = eco_vec![];
|
||||
let mut func = func;
|
||||
while let Repr::With(with) = func.inner() {
|
||||
let (inner, args) = with.as_ref();
|
||||
with_stack.push(ArgsInfo {
|
||||
items: args
|
||||
.items
|
||||
.iter()
|
||||
.map(|arg| ArgInfo {
|
||||
name: arg.name.clone().map(From::from),
|
||||
term: Some(Ty::Value(InsTy::new(arg.value.v.clone()))),
|
||||
})
|
||||
.collect(),
|
||||
});
|
||||
func = inner.clone();
|
||||
}
|
||||
|
||||
let mut pos_tys = vec![];
|
||||
let mut named_tys = Vec::new();
|
||||
let mut rest_ty = None;
|
||||
|
||||
let mut named_specs = BTreeMap::new();
|
||||
let mut param_specs = Vec::new();
|
||||
let mut rest_spec = None;
|
||||
|
||||
let mut broken = false;
|
||||
let mut has_fill_or_size_or_stroke = false;
|
||||
|
||||
let mut add_param = |param: Interned<ParamTy>| {
|
||||
let name = param.name.clone();
|
||||
if param.attrs.named {
|
||||
if matches!(name.as_ref(), "fill" | "stroke" | "size") {
|
||||
has_fill_or_size_or_stroke = true;
|
||||
}
|
||||
named_tys.push((name.clone(), param.ty.clone()));
|
||||
named_specs.insert(name.clone(), param.clone());
|
||||
}
|
||||
|
||||
if param.attrs.variadic {
|
||||
if rest_ty.is_some() {
|
||||
broken = true;
|
||||
} else {
|
||||
rest_ty = Some(param.ty.clone());
|
||||
rest_spec = Some(param);
|
||||
}
|
||||
} else if param.attrs.positional {
|
||||
// todo: we have some params that are both positional and named
|
||||
pos_tys.push(param.ty.clone());
|
||||
param_specs.push(param);
|
||||
}
|
||||
};
|
||||
|
||||
let ret_ty = match func.inner() {
|
||||
Repr::With(..) => unreachable!(),
|
||||
Repr::Closure(closure) => {
|
||||
analyze_closure_signature(closure.clone(), &mut add_param);
|
||||
None
|
||||
}
|
||||
Repr::Element(..) | Repr::Native(..) | Repr::Plugin(..) => {
|
||||
for param in func.params().unwrap_or_default() {
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: param.name.into(),
|
||||
docs: Some(param.docs.into()),
|
||||
default: param.default.map(|default| truncated_repr(&default())),
|
||||
ty: Ty::from_param_site(&func, param),
|
||||
attrs: param.into(),
|
||||
}));
|
||||
}
|
||||
|
||||
func.returns().map(|r| Ty::from_return_site(&func, r))
|
||||
}
|
||||
};
|
||||
|
||||
let sig_ty = SigTy::new(pos_tys.into_iter(), named_tys, None, rest_ty, ret_ty);
|
||||
|
||||
for name in &sig_ty.names.names {
|
||||
let Some(param) = named_specs.get(name) else {
|
||||
continue;
|
||||
};
|
||||
param_specs.push(param.clone());
|
||||
}
|
||||
if let Some(doc) = rest_spec {
|
||||
param_specs.push(doc);
|
||||
}
|
||||
|
||||
let signature = Arc::new(PrimarySignature {
|
||||
docs: func.docs().map(From::from),
|
||||
param_specs,
|
||||
has_fill_or_size_or_stroke,
|
||||
sig_ty: sig_ty.into(),
|
||||
_broken: broken,
|
||||
});
|
||||
|
||||
log::trace!("got signature {signature:?}");
|
||||
|
||||
if with_stack.is_empty() {
|
||||
return Signature::Primary(signature);
|
||||
}
|
||||
|
||||
Signature::Partial(Arc::new(PartialSignature {
|
||||
signature,
|
||||
with_stack,
|
||||
}))
|
||||
}
|
||||
|
||||
fn analyze_closure_signature(
|
||||
closure: Arc<LazyHash<Closure>>,
|
||||
add_param: &mut impl FnMut(Interned<ParamTy>),
|
||||
) {
|
||||
log::trace!("closure signature for: {:?}", closure.node.kind());
|
||||
|
||||
let closure = &closure.node;
|
||||
let closure_ast = match closure.kind() {
|
||||
SyntaxKind::Closure => closure.cast::<ast::Closure>().unwrap(),
|
||||
_ => return,
|
||||
};
|
||||
|
||||
for param in closure_ast.params().children() {
|
||||
match param {
|
||||
ast::Param::Pos(pos) => {
|
||||
let name = format!("{}", PatternDisplay(&pos));
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: name.as_str().into(),
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::positional(),
|
||||
}));
|
||||
}
|
||||
// todo: pattern
|
||||
ast::Param::Named(named) => {
|
||||
let default = unwrap_parens(named.expr()).to_untyped().clone().into_text();
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: named.name().get().into(),
|
||||
docs: Some(eco_format!("Default value: {default}")),
|
||||
default: Some(default),
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::named(),
|
||||
}));
|
||||
}
|
||||
ast::Param::Spread(spread) => {
|
||||
let sink = spread.sink_ident().map(|sink| sink.as_str());
|
||||
add_param(Interned::new(ParamTy {
|
||||
name: sink.unwrap_or_default().into(),
|
||||
docs: None,
|
||||
default: None,
|
||||
ty: Ty::Any,
|
||||
attrs: ParamAttrs::variadic(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct PatternDisplay<'a>(&'a ast::Pattern<'a>);
|
||||
|
||||
impl fmt::Display for PatternDisplay<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.0 {
|
||||
ast::Pattern::Normal(ast::Expr::Ident(ident)) => f.write_str(ident.as_str()),
|
||||
ast::Pattern::Normal(_) => f.write_str("?"), // unreachable?
|
||||
ast::Pattern::Placeholder(_) => f.write_str("_"),
|
||||
ast::Pattern::Parenthesized(paren_expr) => {
|
||||
write!(f, "{}", PatternDisplay(&paren_expr.pattern()))
|
||||
}
|
||||
ast::Pattern::Destructuring(destructing) => {
|
||||
write!(f, "(")?;
|
||||
let mut first = true;
|
||||
for item in destructing.items() {
|
||||
if first {
|
||||
first = false;
|
||||
} else {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
match item {
|
||||
ast::DestructuringItem::Pattern(pos) => {
|
||||
write!(f, "{}", PatternDisplay(&pos))?
|
||||
}
|
||||
ast::DestructuringItem::Named(named) => write!(
|
||||
f,
|
||||
"{}: {}",
|
||||
named.name().as_str(),
|
||||
unwrap_parens(named.expr()).to_untyped().text()
|
||||
)?,
|
||||
ast::DestructuringItem::Spread(spread) => write!(
|
||||
f,
|
||||
"..{}",
|
||||
spread
|
||||
.sink_ident()
|
||||
.map(|sink| sink.as_str())
|
||||
.unwrap_or_default()
|
||||
)?,
|
||||
}
|
||||
}
|
||||
write!(f, ")")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn unwrap_parens(mut expr: ast::Expr) -> ast::Expr {
|
||||
while let ast::Expr::Parenthesized(paren_expr) = expr {
|
||||
expr = paren_expr.expr();
|
||||
}
|
||||
|
||||
expr
|
||||
}
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
//! Statistics about the analyzers
|
||||
|
||||
use std::{
|
||||
sync::{atomic::AtomicUsize, Arc},
|
||||
time::Duration,
|
||||
};
|
||||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use tinymist_std::hash::FxDashMap;
|
||||
use typst::syntax::FileId;
|
||||
|
||||
use super::Analysis;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct QueryStatBucketData {
|
||||
pub query: u64,
|
||||
|
@ -117,84 +112,3 @@ table.analysis-stats tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0
|
|||
html
|
||||
}
|
||||
}
|
||||
|
||||
/// Statistics about the allocation
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct AllocStats {
|
||||
/// The number of allocated objects.
|
||||
pub allocated: AtomicUsize,
|
||||
/// The number of dropped objects.
|
||||
pub dropped: AtomicUsize,
|
||||
}
|
||||
|
||||
impl AllocStats {
|
||||
/// increment the statistics.
|
||||
pub fn increment(&self) {
|
||||
self.allocated
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// decrement the statistics.
|
||||
pub fn decrement(&self) {
|
||||
self.dropped
|
||||
.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
impl AllocStats {
|
||||
/// Report the statistics of the allocation.
|
||||
pub fn report(_a: &Analysis) -> String {
|
||||
let maps = crate::adt::interner::MAPS.lock().clone();
|
||||
let mut data = Vec::new();
|
||||
for (name, sz, map) in maps {
|
||||
let allocated = map.allocated.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let dropped = map.dropped.load(std::sync::atomic::Ordering::Relaxed);
|
||||
let alive = allocated.saturating_sub(dropped);
|
||||
data.push((name, sz * alive, allocated, dropped, alive));
|
||||
}
|
||||
|
||||
// sort by total
|
||||
data.sort_by(|x, y| y.4.cmp(&x.4));
|
||||
|
||||
// format to html
|
||||
|
||||
let mut html = String::new();
|
||||
html.push_str(r#"<div>
|
||||
<style>
|
||||
table.alloc-stats { width: 100%; border-collapse: collapse; }
|
||||
table.alloc-stats th, table.alloc-stats td { border: 1px solid black; padding: 8px; text-align: center; }
|
||||
table.alloc-stats th.name-column, table.alloc-stats td.name-column { text-align: left; }
|
||||
table.alloc-stats tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0.8); }
|
||||
@media (prefers-color-scheme: dark) {
|
||||
table.alloc-stats tr:nth-child(odd) { background-color: rgba(50, 50, 50, 0.8); }
|
||||
}
|
||||
</style>
|
||||
<table class="alloc-stats"><tr><th class="name-column">Name</th><th>Alive</th><th>Allocated</th><th>Dropped</th><th>Size</th></tr>"#);
|
||||
|
||||
for (name, sz, allocated, dropped, alive) in data {
|
||||
html.push_str("<tr>");
|
||||
html.push_str(&format!(r#"<td class="name-column">{name}</td>"#));
|
||||
html.push_str(&format!("<td>{alive}</td>"));
|
||||
html.push_str(&format!("<td>{allocated}</td>"));
|
||||
html.push_str(&format!("<td>{dropped}</td>"));
|
||||
html.push_str(&format!("<td>{}</td>", human_size(sz)));
|
||||
html.push_str("</tr>");
|
||||
}
|
||||
html.push_str("</table>");
|
||||
html.push_str("</div>");
|
||||
|
||||
html
|
||||
}
|
||||
}
|
||||
|
||||
fn human_size(size: usize) -> String {
|
||||
let units = ["B", "KB", "MB", "GB", "TB"];
|
||||
let mut unit = 0;
|
||||
let mut size = size as f64;
|
||||
while size >= 768.0 && unit < units.len() {
|
||||
size /= 1024.0;
|
||||
unit += 1;
|
||||
}
|
||||
format!("{:.2} {}", size, units[unit])
|
||||
}
|
||||
|
|
|
@ -15,13 +15,11 @@ use crate::{
|
|||
};
|
||||
|
||||
mod apply;
|
||||
mod convert;
|
||||
mod docs;
|
||||
mod select;
|
||||
mod syntax;
|
||||
|
||||
pub(crate) use apply::*;
|
||||
pub(crate) use convert::*;
|
||||
pub(crate) use select::*;
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_analysis::analyze_expr;
|
||||
use tinymist_world::ShadowApi;
|
||||
use typst::foundations::{Bytes, IntoValue, StyleChain};
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
|
||||
use crate::{
|
||||
analysis::analyze_expr,
|
||||
prelude::*,
|
||||
syntax::{interpret_mode_at, InterpretMode},
|
||||
};
|
||||
|
|
|
@ -2,7 +2,7 @@ use ecow::EcoString;
|
|||
use lsp_types::InsertTextFormat;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::ty::Interned;
|
||||
use crate::StrRef;
|
||||
|
||||
use super::LspRange;
|
||||
|
||||
|
@ -284,11 +284,11 @@ pub struct LspCompletionCommand {
|
|||
/// The title of command.
|
||||
pub title: EcoString,
|
||||
/// The identifier of the actual command handler.
|
||||
pub command: Interned<str>,
|
||||
pub command: StrRef,
|
||||
}
|
||||
|
||||
impl From<Interned<str>> for LspCompletionCommand {
|
||||
fn from(command: Interned<str>) -> Self {
|
||||
impl From<StrRef> for LspCompletionCommand {
|
||||
fn from(command: StrRef) -> Self {
|
||||
Self {
|
||||
title: EcoString::default(),
|
||||
command,
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
use std::collections::HashSet;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use hashbrown::HashSet;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::{Deserialize, Deserializer, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::prelude::*;
|
||||
use crate::syntax::{InterpretMode, SurroundingSyntax};
|
||||
use crate::ty::Interned;
|
||||
|
||||
/// This is the poorman's type filter, which is less powerful but more steady.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
|
|
|
@ -1,303 +1,11 @@
|
|||
use core::fmt;
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::OnceLock;
|
||||
|
||||
use ecow::{eco_format, EcoString};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_analysis::docs::{format_ty, ParamDocs, SignatureDocs, VarDocs};
|
||||
use tinymist_analysis::ty::DocSource;
|
||||
use tinymist_analysis::Signature;
|
||||
use typst::syntax::Span;
|
||||
|
||||
use super::tidy::*;
|
||||
use crate::analysis::{ParamAttrs, ParamTy, Signature};
|
||||
use crate::prelude::*;
|
||||
use crate::ty::Ty;
|
||||
use crate::ty::{DocSource, Interned};
|
||||
use crate::upstream::plain_docs_sentence;
|
||||
|
||||
type TypeRepr = Option<(
|
||||
/* short */ EcoString,
|
||||
/* long */ EcoString,
|
||||
/* value */ EcoString,
|
||||
)>;
|
||||
|
||||
/// Documentation about a definition (without type information).
|
||||
pub type UntypedDefDocs = DefDocsT<()>;
|
||||
/// Documentation about a definition.
|
||||
pub type DefDocs = DefDocsT<TypeRepr>;
|
||||
|
||||
/// Documentation about a definition.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum DefDocsT<T> {
|
||||
/// Documentation about a function.
|
||||
#[serde(rename = "func")]
|
||||
Function(Box<SignatureDocsT<T>>),
|
||||
/// Documentation about a variable.
|
||||
#[serde(rename = "var")]
|
||||
Variable(VarDocsT<T>),
|
||||
/// Documentation about a module.
|
||||
#[serde(rename = "module")]
|
||||
Module(TidyModuleDocs),
|
||||
/// Other kinds of documentation.
|
||||
#[serde(rename = "plain")]
|
||||
Plain {
|
||||
/// The content of the documentation.
|
||||
docs: EcoString,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> DefDocsT<T> {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn docs(&self) -> &EcoString {
|
||||
match self {
|
||||
Self::Function(docs) => &docs.docs,
|
||||
Self::Variable(docs) => &docs.docs,
|
||||
Self::Module(docs) => &docs.docs,
|
||||
Self::Plain { docs } => docs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DefDocs {
|
||||
/// Get full documentation for the signature.
|
||||
pub fn hover_docs(&self) -> EcoString {
|
||||
match self {
|
||||
DefDocs::Function(docs) => docs.hover_docs().clone(),
|
||||
_ => plain_docs_sentence(self.docs()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a primary function signature.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SignatureDocsT<T> {
|
||||
/// Documentation for the function.
|
||||
pub docs: EcoString,
|
||||
/// The positional parameters.
|
||||
pub pos: Vec<ParamDocsT<T>>,
|
||||
/// The named parameters.
|
||||
pub named: BTreeMap<Interned<str>, ParamDocsT<T>>,
|
||||
/// The rest parameter.
|
||||
pub rest: Option<ParamDocsT<T>>,
|
||||
/// The return type.
|
||||
pub ret_ty: T,
|
||||
/// The full documentation for the signature.
|
||||
#[serde(skip)]
|
||||
pub hover_docs: OnceLock<EcoString>,
|
||||
}
|
||||
|
||||
impl SignatureDocsT<TypeRepr> {
|
||||
/// Get full documentation for the signature.
|
||||
pub fn hover_docs(&self) -> &EcoString {
|
||||
self.hover_docs
|
||||
.get_or_init(|| plain_docs_sentence(&format!("{}", SigHoverDocs(self))))
|
||||
}
|
||||
}
|
||||
|
||||
struct SigHoverDocs<'a>(&'a SignatureDocs);
|
||||
|
||||
impl fmt::Display for SigHoverDocs<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let docs = self.0;
|
||||
let base_docs = docs.docs.trim();
|
||||
|
||||
if !base_docs.is_empty() {
|
||||
f.write_str(base_docs)?;
|
||||
}
|
||||
|
||||
fn write_param_docs(
|
||||
f: &mut fmt::Formatter<'_>,
|
||||
docs: &ParamDocsT<TypeRepr>,
|
||||
kind: &str,
|
||||
is_first: &mut bool,
|
||||
) -> fmt::Result {
|
||||
if *is_first {
|
||||
*is_first = false;
|
||||
write!(f, "\n\n## {}\n\n", docs.name)?;
|
||||
} else {
|
||||
write!(f, "\n\n## {} ({kind})\n\n", docs.name)?;
|
||||
}
|
||||
|
||||
// p.cano_type.0
|
||||
if let Some(t) = &docs.cano_type {
|
||||
write!(f, "```typc\ntype: {}\n```\n\n", t.2)?;
|
||||
}
|
||||
|
||||
f.write_str(docs.docs.trim())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
if !docs.pos.is_empty() {
|
||||
f.write_str("\n\n# Positional Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
for pos_docs in &docs.pos {
|
||||
write_param_docs(f, pos_docs, "positional", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
if docs.rest.is_some() {
|
||||
f.write_str("\n\n# Rest Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
if let Some(rest) = &docs.rest {
|
||||
write_param_docs(f, rest, "spread right", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !docs.named.is_empty() {
|
||||
f.write_str("\n\n# Named Parameters")?;
|
||||
|
||||
let mut is_first = true;
|
||||
for named_docs in docs.named.values() {
|
||||
write_param_docs(f, named_docs, "named", &mut is_first)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a signature.
|
||||
pub type UntypedSignatureDocs = SignatureDocsT<()>;
|
||||
/// Documentation about a signature.
|
||||
pub type SignatureDocs = SignatureDocsT<TypeRepr>;
|
||||
|
||||
impl SignatureDocs {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn print(&self, f: &mut impl std::fmt::Write) -> fmt::Result {
|
||||
let mut is_first = true;
|
||||
let mut write_sep = |f: &mut dyn std::fmt::Write| {
|
||||
if is_first {
|
||||
is_first = false;
|
||||
return f.write_str("\n ");
|
||||
}
|
||||
f.write_str(",\n ")
|
||||
};
|
||||
|
||||
f.write_char('(')?;
|
||||
for pos_docs in &self.pos {
|
||||
write_sep(f)?;
|
||||
f.write_str(&pos_docs.name)?;
|
||||
if let Some(t) = &pos_docs.cano_type {
|
||||
write!(f, ": {}", t.0)?;
|
||||
}
|
||||
}
|
||||
if let Some(rest) = &self.rest {
|
||||
write_sep(f)?;
|
||||
f.write_str("..")?;
|
||||
f.write_str(&rest.name)?;
|
||||
if let Some(t) = &rest.cano_type {
|
||||
write!(f, ": {}", t.0)?;
|
||||
}
|
||||
}
|
||||
|
||||
if !self.named.is_empty() {
|
||||
let mut name_prints = vec![];
|
||||
for v in self.named.values() {
|
||||
let ty = v.cano_type.as_ref().map(|t| &t.0);
|
||||
name_prints.push((v.name.clone(), ty, v.default.clone()))
|
||||
}
|
||||
name_prints.sort();
|
||||
for (name, ty, val) in name_prints {
|
||||
write_sep(f)?;
|
||||
let val = val.as_deref().unwrap_or("any");
|
||||
let mut default = val.trim();
|
||||
if default.starts_with('{') && default.ends_with('}') && default.len() > 30 {
|
||||
default = "{ .. }"
|
||||
}
|
||||
if default.starts_with('`') && default.ends_with('`') && default.len() > 30 {
|
||||
default = "raw"
|
||||
}
|
||||
if default.starts_with('[') && default.ends_with(']') && default.len() > 30 {
|
||||
default = "content"
|
||||
}
|
||||
f.write_str(&name)?;
|
||||
if let Some(ty) = ty {
|
||||
write!(f, ": {ty}")?;
|
||||
}
|
||||
if default.contains('\n') {
|
||||
write!(f, " = {}", default.replace("\n", "\n "))?;
|
||||
} else {
|
||||
write!(f, " = {default}")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
if !is_first {
|
||||
f.write_str(",\n")?;
|
||||
}
|
||||
f.write_char(')')?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a variable (without type information).
|
||||
pub type UntypedVarDocs = VarDocsT<()>;
|
||||
/// Documentation about a variable.
|
||||
pub type VarDocs = VarDocsT<Option<(EcoString, EcoString, EcoString)>>;
|
||||
|
||||
/// Describes a primary pattern binding.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct VarDocsT<T> {
|
||||
/// Documentation for the pattern binding.
|
||||
pub docs: EcoString,
|
||||
/// The inferred type of the pattern binding source.
|
||||
pub return_ty: T,
|
||||
/// Cached documentation for the definition.
|
||||
#[serde(skip)]
|
||||
pub def_docs: OnceLock<String>,
|
||||
}
|
||||
|
||||
impl VarDocs {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn def_docs(&self) -> &String {
|
||||
self.def_docs
|
||||
.get_or_init(|| plain_docs_sentence(&self.docs).into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a parameter (without type information).
|
||||
pub type TypelessParamDocs = ParamDocsT<()>;
|
||||
/// Documentation about a parameter.
|
||||
pub type ParamDocs = ParamDocsT<TypeRepr>;
|
||||
|
||||
/// Describes a function parameter.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct ParamDocsT<T> {
|
||||
/// The parameter's name.
|
||||
pub name: Interned<str>,
|
||||
/// Documentation for the parameter.
|
||||
pub docs: EcoString,
|
||||
/// Inferred type of the parameter.
|
||||
pub cano_type: T,
|
||||
/// The parameter's default name as value.
|
||||
pub default: Option<EcoString>,
|
||||
/// The attribute of the parameter.
|
||||
#[serde(flatten)]
|
||||
pub attrs: ParamAttrs,
|
||||
}
|
||||
|
||||
impl ParamDocs {
|
||||
fn new(param: &ParamTy, ty: Option<&Ty>) -> Self {
|
||||
Self {
|
||||
name: param.name.as_ref().into(),
|
||||
docs: param.docs.clone().unwrap_or_default(),
|
||||
cano_type: format_ty(ty.or(Some(¶m.ty))),
|
||||
default: param.default.clone(),
|
||||
attrs: param.attrs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn format_ty(ty: Option<&Ty>) -> TypeRepr {
|
||||
let ty = ty?;
|
||||
let short = ty.repr().unwrap_or_else(|| "any".into());
|
||||
let long = eco_format!("{ty:?}");
|
||||
let value = ty.value_repr().unwrap_or_else(|| "".into());
|
||||
|
||||
Some((short, long, value))
|
||||
}
|
||||
use crate::LocalContext;
|
||||
|
||||
pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option<VarDocs> {
|
||||
let source = ctx.source_by_id(pos.id()?).ok()?;
|
||||
|
|
|
@ -4,16 +4,15 @@ mod convert;
|
|||
mod def;
|
||||
mod module;
|
||||
mod package;
|
||||
mod tidy;
|
||||
|
||||
use tinymist_std::path::unix_slash;
|
||||
use typst::syntax::FileId;
|
||||
|
||||
pub(crate) use convert::convert_docs;
|
||||
pub use def::*;
|
||||
pub(crate) use def::*;
|
||||
pub use module::*;
|
||||
pub use package::*;
|
||||
pub(crate) use tidy::*;
|
||||
pub use tinymist_analysis::docs::*;
|
||||
|
||||
fn file_id_repr(fid: FileId) -> String {
|
||||
if let Some(spec) = fid.package() {
|
||||
|
|
|
@ -10,10 +10,10 @@ use typst::diag::StrResult;
|
|||
use typst::syntax::package::PackageSpec;
|
||||
use typst::syntax::FileId;
|
||||
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::docs::file_id_repr;
|
||||
use crate::package::{get_manifest_id, PackageInfo};
|
||||
use crate::syntax::{Decl, DefKind, Expr, ExprInfo};
|
||||
use crate::ty::Interned;
|
||||
use crate::LocalContext;
|
||||
|
||||
use super::DefDocs;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use hashbrown::HashSet;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
|
|
|
@ -46,7 +46,7 @@ pub mod docs;
|
|||
pub mod package;
|
||||
pub mod syntax;
|
||||
pub mod testing;
|
||||
pub mod ty;
|
||||
pub use tinymist_analysis::{ty, upstream};
|
||||
|
||||
/// The physical position in a document.
|
||||
pub type FramePosition = typst::layout::Position;
|
||||
|
@ -81,15 +81,17 @@ mod semantic_tokens_delta;
|
|||
mod semantic_tokens_full;
|
||||
mod signature_help;
|
||||
mod symbol;
|
||||
mod upstream;
|
||||
mod will_rename_files;
|
||||
mod workspace_label;
|
||||
|
||||
use typst::syntax::Source;
|
||||
|
||||
use tinymist_analysis::log_debug_ct;
|
||||
use tinymist_analysis::{adt::interner::Interned, log_debug_ct};
|
||||
use tinymist_project::LspComputeGraph;
|
||||
|
||||
/// A reference to the interned string
|
||||
pub(crate) type StrRef = Interned<str>;
|
||||
|
||||
/// A request handler with given syntax information.
|
||||
pub trait SyntaxRequest {
|
||||
/// The response type of the request.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::sync::OnceLock;
|
||||
|
||||
use tinymist_analysis::adt::interner::Interned;
|
||||
use tinymist_std::typst::TypstDocument;
|
||||
use typst::syntax::Span;
|
||||
|
||||
|
@ -7,7 +8,7 @@ use crate::{
|
|||
analysis::{Definition, SearchCtx},
|
||||
prelude::*,
|
||||
syntax::{get_index_info, RefExpr, SyntaxClass},
|
||||
ty::Interned,
|
||||
StrRef,
|
||||
};
|
||||
|
||||
/// The [`textDocument/references`] request is sent from the client to the
|
||||
|
@ -73,7 +74,7 @@ struct ReferencesWorker<'a> {
|
|||
ctx: SearchCtx<'a>,
|
||||
references: Vec<LspLocation>,
|
||||
def: Definition,
|
||||
module_path: OnceLock<Interned<str>>,
|
||||
module_path: OnceLock<StrRef>,
|
||||
}
|
||||
|
||||
impl ReferencesWorker<'_> {
|
||||
|
@ -148,7 +149,7 @@ impl ReferencesWorker<'_> {
|
|||
}
|
||||
|
||||
// todo: references of package
|
||||
fn module_path(&self) -> &Interned<str> {
|
||||
fn module_path(&self) -> &StrRef {
|
||||
self.module_path.get_or_init(|| {
|
||||
self.def
|
||||
.decl
|
||||
|
|
|
@ -9,13 +9,13 @@ use typst::{
|
|||
syntax::Span,
|
||||
};
|
||||
|
||||
use crate::adt::interner::Interned;
|
||||
use crate::{
|
||||
analysis::{get_link_exprs, LinkObject, LinkTarget},
|
||||
find_references,
|
||||
prelude::*,
|
||||
prepare_renaming,
|
||||
syntax::{first_ancestor_expr, get_index_info, node_ancestors, Decl, RefExpr, SyntaxClass},
|
||||
ty::Interned,
|
||||
};
|
||||
|
||||
/// The [`textDocument/rename`] request is sent from the client to the server to
|
||||
|
|
|
@ -7,16 +7,13 @@ use std::{
|
|||
use ecow::eco_format;
|
||||
use typst::foundations::{IntoValue, Module, Str, Type};
|
||||
|
||||
use crate::{adt::interner::Interned, StrRef};
|
||||
use crate::{adt::snapshot_map::SnapshotMap, analysis::SharedContext};
|
||||
use crate::{
|
||||
adt::snapshot_map::SnapshotMap,
|
||||
analysis::SharedContext,
|
||||
docs::{convert_docs, identify_pat_docs, identify_tidy_module_docs, UntypedDefDocs, VarDocsT},
|
||||
prelude::*,
|
||||
syntax::{Decl, DefKind},
|
||||
ty::{
|
||||
BuiltinTy, DynTypeBounds, InsTy, Interned, PackageId, SigTy, StrRef, Ty, TypeVar,
|
||||
TypeVarBounds,
|
||||
},
|
||||
ty::{BuiltinTy, DynTypeBounds, InsTy, PackageId, SigTy, Ty, TypeVar, TypeVarBounds},
|
||||
};
|
||||
|
||||
use super::DeclExpr;
|
||||
|
@ -35,6 +32,7 @@ pub struct DocString {
|
|||
}
|
||||
|
||||
impl DocString {
|
||||
/// Gets the docstring as a variable doc
|
||||
pub fn as_var(&self) -> VarDoc {
|
||||
VarDoc {
|
||||
docs: self.docs.clone().unwrap_or_default(),
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#![allow(missing_docs)]
|
||||
|
||||
use std::ops::DerefMut;
|
||||
|
||||
use parking_lot::Mutex;
|
||||
use rpds::RedBlackTreeMapSync;
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::ops::Deref;
|
||||
use tinymist_analysis::adt::interner::Interned;
|
||||
use tinymist_std::hash::hash128;
|
||||
use typst::{
|
||||
foundations::{Element, NativeElement, Type, Value},
|
||||
|
@ -17,7 +20,7 @@ use crate::{
|
|||
analysis::{QueryStatGuard, SharedContext},
|
||||
prelude::*,
|
||||
syntax::{find_module_level_docs, resolve_id_by_path, DefKind},
|
||||
ty::{BuiltinTy, InsTy, Interned, Ty},
|
||||
ty::{BuiltinTy, InsTy, Ty},
|
||||
};
|
||||
|
||||
use super::{compute_docstring, def::*, DocCommentMatcher, DocString, InterpretMode};
|
||||
|
|
|
@ -2,12 +2,8 @@
|
|||
//!
|
||||
//! This module must hide all **AST details** from the rest of the codebase.
|
||||
|
||||
// todo: remove this
|
||||
#![allow(missing_docs)]
|
||||
|
||||
pub use tinymist_analysis::syntax::comment::*;
|
||||
pub use tinymist_analysis::syntax::import::*;
|
||||
pub use tinymist_analysis::syntax::matcher::*;
|
||||
pub(crate) mod lexical_hierarchy;
|
||||
pub use lexical_hierarchy::*;
|
||||
pub(crate) mod module;
|
||||
|
@ -16,9 +12,6 @@ pub(crate) mod expr;
|
|||
pub use expr::*;
|
||||
pub(crate) mod docs;
|
||||
pub use docs::*;
|
||||
pub(crate) mod def;
|
||||
pub use def::*;
|
||||
pub(crate) mod repr;
|
||||
use repr::*;
|
||||
pub(crate) mod index;
|
||||
pub use index::*;
|
||||
pub use tinymist_analysis::syntax::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue