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"
|
name = "tinymist-analysis"
|
||||||
version = "0.13.10"
|
version = "0.13.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"comemo",
|
||||||
|
"dashmap",
|
||||||
"ecow",
|
"ecow",
|
||||||
|
"ena",
|
||||||
|
"hashbrown 0.14.5",
|
||||||
|
"if_chain",
|
||||||
"insta",
|
"insta",
|
||||||
|
"itertools 0.13.0",
|
||||||
"log",
|
"log",
|
||||||
|
"lsp-types",
|
||||||
|
"parking_lot",
|
||||||
"regex",
|
"regex",
|
||||||
|
"rpds",
|
||||||
|
"rustc-hash 2.1.1",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
"strum",
|
"strum",
|
||||||
|
"tinymist-derive",
|
||||||
|
"tinymist-std",
|
||||||
"tinymist-world",
|
"tinymist-world",
|
||||||
"toml",
|
"toml",
|
||||||
|
"triomphe",
|
||||||
"typst",
|
"typst",
|
||||||
|
"typst-shim",
|
||||||
|
"unscanny",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -4226,7 +4242,6 @@ dependencies = [
|
||||||
"dirs",
|
"dirs",
|
||||||
"ecow",
|
"ecow",
|
||||||
"ena",
|
"ena",
|
||||||
"hashbrown 0.14.5",
|
|
||||||
"hex",
|
"hex",
|
||||||
"if_chain",
|
"if_chain",
|
||||||
"indexmap 2.8.0",
|
"indexmap 2.8.0",
|
||||||
|
@ -4255,7 +4270,6 @@ dependencies = [
|
||||||
"tinymist-std",
|
"tinymist-std",
|
||||||
"tinymist-world",
|
"tinymist-world",
|
||||||
"toml",
|
"toml",
|
||||||
"triomphe",
|
|
||||||
"ttf-parser",
|
"ttf-parser",
|
||||||
"typlite",
|
"typlite",
|
||||||
"typst",
|
"typst",
|
||||||
|
|
|
@ -13,13 +13,30 @@ repository.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
comemo.workspace = true
|
||||||
|
dashmap.workspace = true
|
||||||
ecow.workspace = true
|
ecow.workspace = true
|
||||||
|
ena.workspace = true
|
||||||
|
hashbrown.workspace = true
|
||||||
|
if_chain.workspace = true
|
||||||
|
itertools.workspace = true
|
||||||
log.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.workspace = true
|
||||||
|
serde_yaml.workspace = true
|
||||||
strum.workspace = true
|
strum.workspace = true
|
||||||
toml.workspace = true
|
tinymist-derive.workspace = true
|
||||||
|
tinymist-std.workspace = true
|
||||||
tinymist-world.workspace = true
|
tinymist-world.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
|
triomphe.workspace = true
|
||||||
typst.workspace = true
|
typst.workspace = true
|
||||||
|
typst-shim.workspace = true
|
||||||
|
unscanny.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
insta.workspace = true
|
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>)>> =
|
pub static MAPS: Mutex<EcoVec<(&'static str, usize, Arc<AllocStats>)>> = Mutex::new(EcoVec::new());
|
||||||
Mutex::new(EcoVec::new());
|
|
||||||
|
|
||||||
pub struct InternStorage<T: ?Sized> {
|
pub struct InternStorage<T: ?Sized> {
|
||||||
alloc: OnceLock<Arc<AllocStats>>,
|
alloc: OnceLock<Arc<AllocStats>>,
|
||||||
|
@ -407,6 +406,6 @@ macro_rules! _impl_internable {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub use crate::_impl_internable as impl_internable;
|
pub use crate::_impl_internable as impl_internable;
|
||||||
use crate::analysis::AllocStats;
|
use crate::stats::AllocStats;
|
||||||
|
|
||||||
impl_internable!(str,);
|
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
|
//! Tinymist Analysis
|
||||||
|
|
||||||
|
pub mod adt;
|
||||||
|
pub mod docs;
|
||||||
pub mod location;
|
pub mod location;
|
||||||
mod prelude;
|
mod sig;
|
||||||
|
pub mod stats;
|
||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
|
pub mod ty;
|
||||||
|
pub mod upstream;
|
||||||
|
|
||||||
|
pub use sig::*;
|
||||||
|
pub use track_values::*;
|
||||||
|
|
||||||
|
mod prelude;
|
||||||
|
mod track_values;
|
||||||
|
|
||||||
/// Completely disabled log
|
/// Completely disabled log
|
||||||
#[macro_export]
|
#[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.
|
//! This module must hide all **AST details** from the rest of the codebase.
|
||||||
|
|
||||||
|
// todo: remove this
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub use import::*;
|
pub use import::*;
|
||||||
pub mod comment;
|
pub mod comment;
|
||||||
pub use comment::*;
|
pub use comment::*;
|
||||||
pub mod matcher;
|
pub mod matcher;
|
||||||
pub use 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 serde::{Deserialize, Serialize};
|
||||||
use tinymist_derive::DeclEnum;
|
use tinymist_derive::DeclEnum;
|
||||||
|
use tinymist_std::DefId;
|
||||||
use tinymist_world::package::PackageSpec;
|
use tinymist_world::package::PackageSpec;
|
||||||
use typst::{
|
use typst::{
|
||||||
foundations::{Element, Func, Module, Type, Value},
|
foundations::{Element, Func, Module, Type, Value},
|
||||||
|
@ -11,7 +12,6 @@ use typst::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::interner::impl_internable,
|
adt::interner::impl_internable,
|
||||||
analysis::SharedContext,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
|
ty::{InsTy, Interned, SelectTy, Ty, TypeVar},
|
||||||
};
|
};
|
||||||
|
@ -73,13 +73,13 @@ pub enum Expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expr {
|
impl Expr {
|
||||||
pub(crate) fn repr(&self) -> EcoString {
|
pub fn repr(&self) -> EcoString {
|
||||||
let mut s = EcoString::new();
|
let mut s = EcoString::new();
|
||||||
let _ = ExprDescriber::new(&mut s).write_expr(self);
|
let _ = ExprDescriber::new(&mut s).write_expr(self);
|
||||||
s
|
s
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn span(&self) -> Span {
|
pub fn span(&self) -> Span {
|
||||||
match self {
|
match self {
|
||||||
Expr::Decl(decl) => decl.span(),
|
Expr::Decl(decl) => decl.span(),
|
||||||
Expr::Select(select) => select.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 {
|
match self {
|
||||||
Expr::Decl(decl) => decl.file_id(),
|
Expr::Decl(decl) => decl.file_id(),
|
||||||
_ => self.span().id(),
|
_ => self.span().id(),
|
||||||
|
@ -409,7 +409,7 @@ impl Decl {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_def(&self) -> bool {
|
pub fn is_def(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
Self::Func(..)
|
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.
|
/// Gets full range of the declaration.
|
||||||
pub fn full_range(&self) -> Option<Range<usize>> {
|
pub fn full_range(&self) -> Option<Range<usize>> {
|
||||||
if let Decl::BibEntry(decl) = self {
|
if let Decl::BibEntry(decl) = self {
|
||||||
|
@ -595,8 +576,8 @@ impl fmt::Debug for SpannedDecl {
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq, Hash)]
|
#[derive(Clone, PartialEq, Eq, Hash)]
|
||||||
pub struct NameRangeDecl {
|
pub struct NameRangeDecl {
|
||||||
name: Interned<str>,
|
pub name: Interned<str>,
|
||||||
at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
|
pub at: Box<(TypstFileId, Range<usize>, Option<Range<usize>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NameRangeDecl {
|
impl NameRangeDecl {
|
||||||
|
@ -724,7 +705,7 @@ impl fmt::Display for Pattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pattern {
|
impl Pattern {
|
||||||
pub(crate) fn repr(&self) -> EcoString {
|
pub fn repr(&self) -> EcoString {
|
||||||
let mut s = EcoString::new();
|
let mut s = EcoString::new();
|
||||||
let _ = ExprDescriber::new(&mut s).write_pattern(self);
|
let _ = ExprDescriber::new(&mut s).write_pattern(self);
|
||||||
s
|
s
|
|
@ -109,7 +109,7 @@ impl PathPreference {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ty {
|
impl Ty {
|
||||||
pub(crate) fn from_cast_info(ty: &CastInfo) -> Ty {
|
pub fn from_cast_info(ty: &CastInfo) -> Ty {
|
||||||
match &ty {
|
match &ty {
|
||||||
CastInfo::Any => Ty::Any,
|
CastInfo::Any => Ty::Any,
|
||||||
CastInfo::Value(val, doc) => Ty::Value(InsTy::new_doc(val.clone(), *doc)),
|
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;
|
use typst::foundations::func::Repr;
|
||||||
match func.inner() {
|
match func.inner() {
|
||||||
Repr::Element(..) | Repr::Native(..) | Repr::Plugin(..) => {
|
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::*;
|
use super::*;
|
||||||
|
|
|
@ -17,10 +17,9 @@ use typst::{
|
||||||
syntax::{ast, FileId, Span, SyntaxKind, SyntaxNode},
|
syntax::{ast, FileId, Span, SyntaxKind, SyntaxNode},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{BoundPred, PackageId};
|
use super::{BoundPred, BuiltinTy, PackageId};
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::{interner::impl_internable, snapshot_map},
|
adt::{interner::impl_internable, snapshot_map},
|
||||||
analysis::BuiltinTy,
|
|
||||||
docs::UntypedDefDocs,
|
docs::UntypedDefDocs,
|
||||||
syntax::{DeclExpr, UnaryOp},
|
syntax::{DeclExpr, UnaryOp},
|
||||||
};
|
};
|
||||||
|
@ -142,7 +141,7 @@ impl Ty {
|
||||||
matches!(self, Ty::Dict(..))
|
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(match (lhs, rhs) {
|
||||||
(Some(lhs), Some(rhs)) => Ty::from_types([lhs, rhs].into_iter()),
|
(Some(lhs), Some(rhs)) => Ty::from_types([lhs, rhs].into_iter()),
|
||||||
(Some(ty), None) | (None, Some(ty)) => ty,
|
(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));
|
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;
|
let mut res = false;
|
||||||
self.satisfy(ctx, |ty: &Ty, _pol| {
|
self.satisfy(ctx, |ty: &Ty, _pol| {
|
||||||
res = res || {
|
res = res || {
|
||||||
|
@ -561,7 +560,7 @@ pub struct ParamAttrs {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParamAttrs {
|
impl ParamAttrs {
|
||||||
pub(crate) fn positional() -> ParamAttrs {
|
pub fn positional() -> ParamAttrs {
|
||||||
ParamAttrs {
|
ParamAttrs {
|
||||||
positional: true,
|
positional: true,
|
||||||
named: false,
|
named: false,
|
||||||
|
@ -570,7 +569,7 @@ impl ParamAttrs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn named() -> ParamAttrs {
|
pub fn named() -> ParamAttrs {
|
||||||
ParamAttrs {
|
ParamAttrs {
|
||||||
positional: false,
|
positional: false,
|
||||||
named: true,
|
named: true,
|
||||||
|
@ -579,7 +578,7 @@ impl ParamAttrs {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn variadic() -> ParamAttrs {
|
pub fn variadic() -> ParamAttrs {
|
||||||
ParamAttrs {
|
ParamAttrs {
|
||||||
positional: true,
|
positional: true,
|
||||||
named: false,
|
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.body = Some(res_ty);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -964,7 +963,7 @@ impl SigTy {
|
||||||
pub fn matches<'a>(
|
pub fn matches<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
args: &'a SigTy,
|
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 {
|
) -> impl Iterator<Item = (&'a Ty, &'a Ty)> + 'a {
|
||||||
let with_len = with
|
let with_len = with
|
||||||
.map(|w| w.iter().map(|w| w.positional_params().len()).sum::<usize>())
|
.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 tinymist_world::vfs::WorkspaceResolver;
|
||||||
use typst::foundations::Repr;
|
use typst::foundations::Repr;
|
||||||
|
|
||||||
use crate::{
|
use super::{is_plain_value, term_value};
|
||||||
analysis::{is_plain_value, term_value},
|
use crate::{ty::prelude::*, upstream::truncated_repr_};
|
||||||
ty::prelude::*,
|
|
||||||
upstream::truncated_repr_,
|
|
||||||
};
|
|
||||||
|
|
||||||
impl Ty {
|
impl Ty {
|
||||||
/// Describe the given type.
|
/// Describe the given type.
|
|
@ -1,8 +1,11 @@
|
||||||
//! Types and type operations for Typst.
|
//! Types and type operations for Typst.
|
||||||
|
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
mod apply;
|
mod apply;
|
||||||
mod bound;
|
mod bound;
|
||||||
mod builtin;
|
mod builtin;
|
||||||
|
mod convert;
|
||||||
mod def;
|
mod def;
|
||||||
mod describe;
|
mod describe;
|
||||||
mod iface;
|
mod iface;
|
||||||
|
@ -13,14 +16,16 @@ mod sig;
|
||||||
mod simplify;
|
mod simplify;
|
||||||
mod subst;
|
mod subst;
|
||||||
|
|
||||||
pub(crate) use apply::*;
|
pub use apply::*;
|
||||||
pub(crate) use bound::*;
|
pub use bound::*;
|
||||||
pub(crate) use builtin::*;
|
pub use builtin::*;
|
||||||
|
pub use convert::*;
|
||||||
pub use def::*;
|
pub use def::*;
|
||||||
pub(crate) use iface::*;
|
pub use iface::*;
|
||||||
pub(crate) use mutate::*;
|
pub use mutate::*;
|
||||||
pub(crate) use select::*;
|
pub use select::*;
|
||||||
pub(crate) use sig::*;
|
pub use sig::*;
|
||||||
|
|
||||||
use typst::foundations::{self, Func, Module, Value};
|
use typst::foundations::{self, Func, Module, Value};
|
||||||
use typst::syntax::FileId;
|
use typst::syntax::FileId;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Functions from typst-ide
|
||||||
|
|
||||||
use std::{collections::HashMap, fmt::Write, sync::LazyLock};
|
use std::{collections::HashMap, fmt::Write, sync::LazyLock};
|
||||||
|
|
||||||
use comemo::Tracked;
|
use comemo::Tracked;
|
||||||
|
@ -354,6 +356,7 @@ pub(crate) fn urlify(title: &str) -> EcoString {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the route of a value.
|
||||||
pub fn route_of_value(val: &Value) -> Option<&'static String> {
|
pub fn route_of_value(val: &Value) -> Option<&'static String> {
|
||||||
// ROUTE_MAPS.get(&CatKey::Func(k.clone()))
|
// ROUTE_MAPS.get(&CatKey::Func(k.clone()))
|
||||||
let key = match val {
|
let key = match val {
|
||||||
|
@ -396,6 +399,7 @@ pub fn summarize_font_family<'a>(variants: impl Iterator<Item = &'a FontInfo>) -
|
||||||
detail
|
detail
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the representation but truncated to a certain size.
|
||||||
pub fn truncated_repr_<const SZ_LIMIT: usize>(value: &Value) -> EcoString {
|
pub fn truncated_repr_<const SZ_LIMIT: usize>(value: &Value) -> EcoString {
|
||||||
use typst::foundations::Repr;
|
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 {
|
pub fn truncated_repr(value: &Value) -> EcoString {
|
||||||
const _10MB: usize = 100 * 1024 * 1024;
|
const _10MB: usize = 100 * 1024 * 1024;
|
||||||
truncated_repr_::<_10MB>(value)
|
truncated_repr_::<_10MB>(value)
|
|
@ -12,7 +12,7 @@ use typst_shim::syntax::LinkedNodeExt;
|
||||||
use typst_shim::utils::{round_2, Numeric};
|
use typst_shim::utils::{round_2, Numeric};
|
||||||
|
|
||||||
use super::{plain_docs_sentence, summarize_font_family, truncated_repr};
|
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.
|
/// Describe the item under the cursor.
|
||||||
///
|
///
|
|
@ -14,43 +14,33 @@ rust-version.workspace = true
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
anyhow.workspace = true
|
anyhow.workspace = true
|
||||||
comemo.workspace = true
|
base64.workspace = true
|
||||||
dirs.workspace = true
|
|
||||||
regex.workspace = true
|
|
||||||
yaml-rust2.workspace = true
|
|
||||||
biblatex.workspace = true
|
biblatex.workspace = true
|
||||||
serde_yaml.workspace = true
|
comemo.workspace = true
|
||||||
itertools.workspace = true
|
dashmap.workspace = true
|
||||||
strum.workspace = true
|
dirs.workspace = true
|
||||||
log.workspace = true
|
|
||||||
serde.workspace = true
|
|
||||||
serde_json.workspace = true
|
|
||||||
parking_lot.workspace = true
|
|
||||||
ena.workspace = true
|
ena.workspace = true
|
||||||
toml.workspace = true
|
|
||||||
walkdir.workspace = true
|
|
||||||
indexmap.workspace = true
|
|
||||||
ecow.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
|
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
|
percent-encoding.workspace = true
|
||||||
unscanny.workspace = true
|
rayon.workspace = true
|
||||||
ttf-parser.workspace = true
|
regex.workspace = true
|
||||||
|
rpds.workspace = true
|
||||||
rust_iso639.workspace = true
|
rust_iso639.workspace = true
|
||||||
rust_iso3166.workspace = true
|
rust_iso3166.workspace = true
|
||||||
dashmap.workspace = true
|
|
||||||
rustc-hash.workspace = true
|
rustc-hash.workspace = true
|
||||||
hashbrown.workspace = true
|
serde.workspace = true
|
||||||
triomphe.workspace = true
|
serde_json.workspace = true
|
||||||
base64.workspace = true
|
serde_yaml.workspace = true
|
||||||
|
siphasher.workspace = true
|
||||||
|
strum.workspace = true
|
||||||
|
toml.workspace = true
|
||||||
|
ttf-parser.workspace = true
|
||||||
typlite.workspace = true
|
typlite.workspace = true
|
||||||
tinymist-world = { workspace = true }
|
tinymist-world = { workspace = true }
|
||||||
tinymist-project = { workspace = true, features = ["lsp"] }
|
tinymist-project = { workspace = true, features = ["lsp"] }
|
||||||
|
@ -58,6 +48,12 @@ tinymist-analysis.workspace = true
|
||||||
tinymist-derive.workspace = true
|
tinymist-derive.workspace = true
|
||||||
tinymist-std.workspace = true
|
tinymist-std.workspace = true
|
||||||
tinymist-l10n.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]
|
[dev-dependencies]
|
||||||
insta.workspace = true
|
insta.workspace = true
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
pub mod interner;
|
|
||||||
pub mod revision;
|
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 crate::ty::*;
|
||||||
pub(crate) use post_tyck::*;
|
pub(crate) use post_tyck::*;
|
||||||
pub(crate) use tyck::*;
|
pub(crate) use tyck::*;
|
||||||
pub mod track_values;
|
|
||||||
pub use track_values::*;
|
|
||||||
mod prelude;
|
mod prelude;
|
||||||
|
|
||||||
mod global;
|
mod global;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//! Hybrid analysis for function calls.
|
//! Hybrid analysis for function calls.
|
||||||
|
|
||||||
use super::prelude::*;
|
use super::prelude::*;
|
||||||
use super::{Signature, StrRef};
|
use super::Signature;
|
||||||
use crate::analysis::{analyze_signature, PrimarySignature, SignatureTarget};
|
use crate::analysis::{analyze_signature, PrimarySignature, SignatureTarget};
|
||||||
|
|
||||||
/// Describes kind of a parameter.
|
/// Describes kind of a parameter.
|
||||||
|
|
|
@ -10,6 +10,7 @@ use lsp_types::InsertTextFormat;
|
||||||
use regex::{Captures, Regex};
|
use regex::{Captures, Regex};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use tinymist_analysis::syntax::{bad_completion_cursor, BadCompletionCursor};
|
use tinymist_analysis::syntax::{bad_completion_cursor, BadCompletionCursor};
|
||||||
|
use tinymist_analysis::{analyze_labels, func_signature, DynLabel};
|
||||||
use tinymist_derive::BindTyCtx;
|
use tinymist_derive::BindTyCtx;
|
||||||
use tinymist_project::LspWorld;
|
use tinymist_project::LspWorld;
|
||||||
use tinymist_std::path::unix_slash;
|
use tinymist_std::path::unix_slash;
|
||||||
|
@ -27,9 +28,7 @@ use typst_shim::{syntax::LinkedNodeExt, utils::hash128};
|
||||||
use unscanny::Scanner;
|
use unscanny::Scanner;
|
||||||
|
|
||||||
use crate::adt::interner::Interned;
|
use crate::adt::interner::Interned;
|
||||||
use crate::analysis::{
|
use crate::analysis::{BuiltinTy, LocalContext, PathPreference, Ty};
|
||||||
analyze_labels, func_signature, BuiltinTy, DynLabel, LocalContext, PathPreference, Ty,
|
|
||||||
};
|
|
||||||
use crate::completion::{
|
use crate::completion::{
|
||||||
Completion, CompletionCommand, CompletionContextKey, CompletionItem, CompletionKind,
|
Completion, CompletionCommand, CompletionContextKey, CompletionItem, CompletionKind,
|
||||||
EcoTextEdit, ParsedSnippet, PostfixSnippet, PostfixSnippetScope, PrefixSnippet,
|
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
|
// todo: field definition
|
||||||
/// Finds the definition of a symbol.
|
/// Finds the definition of a symbol.
|
||||||
pub fn definition(
|
pub fn definition(
|
||||||
|
|
|
@ -8,6 +8,9 @@ use comemo::{Track, Tracked};
|
||||||
use lsp_types::Url;
|
use lsp_types::Url;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rustc_hash::FxHashMap;
|
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_project::LspWorld;
|
||||||
use tinymist_std::hash::{hash128, FxDashMap};
|
use tinymist_std::hash::{hash128, FxDashMap};
|
||||||
use tinymist_std::typst::TypstDocument;
|
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::adt::revision::{RevisionLock, RevisionManager, RevisionManagerLike, RevisionSlot};
|
||||||
use crate::analysis::prelude::*;
|
use crate::analysis::prelude::*;
|
||||||
use crate::analysis::{
|
use crate::analysis::{
|
||||||
analyze_expr_, analyze_import_, analyze_signature, bib_info, definition, post_type_check,
|
analyze_signature, bib_info, definition, post_type_check, AnalysisStats, BibInfo,
|
||||||
AllocStats, AnalysisStats, BibInfo, CompletionFeat, Definition, PathPreference, QueryStatGuard,
|
CompletionFeat, Definition, PathPreference, QueryStatGuard, SemanticTokenCache,
|
||||||
SemanticTokenCache, SemanticTokenContext, SemanticTokens, Signature, SignatureTarget, Ty,
|
SemanticTokenContext, SemanticTokens, Signature, SignatureTarget, Ty, TypeInfo,
|
||||||
TypeInfo,
|
|
||||||
};
|
};
|
||||||
use crate::docs::{DefDocs, TidyModuleDocs};
|
use crate::docs::{DefDocs, TidyModuleDocs};
|
||||||
use crate::syntax::{
|
use crate::syntax::{
|
||||||
|
@ -147,7 +149,7 @@ impl Analysis {
|
||||||
|
|
||||||
/// Report the statistics of the allocation.
|
/// Report the statistics of the allocation.
|
||||||
pub fn report_alloc_stats(&self) -> String {
|
pub fn report_alloc_stats(&self) -> String {
|
||||||
AllocStats::report(self)
|
AllocStats::report()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get configured trigger suggest command.
|
/// Get configured trigger suggest command.
|
||||||
|
@ -781,7 +783,7 @@ impl SharedContext {
|
||||||
return cached;
|
return cached;
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = crate::analysis::term_value(val);
|
let res = term_value(val);
|
||||||
|
|
||||||
self.analysis
|
self.analysis
|
||||||
.caches
|
.caches
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Infer more than the principal type of some expression.
|
//! Infer more than the principal type of some expression.
|
||||||
|
|
||||||
use hashbrown::HashSet;
|
use std::collections::HashSet;
|
||||||
use tinymist_derive::BindTyCtx;
|
use tinymist_derive::BindTyCtx;
|
||||||
|
|
||||||
use super::{prelude::*, DynTypeBounds, ParamAttrs, ParamTy, SharedContext};
|
use super::{prelude::*, DynTypeBounds, ParamAttrs, ParamTy, SharedContext};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
pub use core::fmt;
|
|
||||||
pub use std::collections::{BTreeMap, HashMap};
|
pub use std::collections::{BTreeMap, HashMap};
|
||||||
pub use std::hash::{Hash, Hasher};
|
pub use std::hash::{Hash, Hasher};
|
||||||
pub use std::ops::Range;
|
pub use std::ops::Range;
|
||||||
|
@ -14,7 +13,7 @@ pub use typst::World;
|
||||||
pub use typst_shim::syntax::LinkedNodeExt;
|
pub use typst_shim::syntax::LinkedNodeExt;
|
||||||
pub use typst_shim::utils::LazyHash;
|
pub use typst_shim::utils::LazyHash;
|
||||||
|
|
||||||
pub(crate) use super::StrRef;
|
|
||||||
pub(crate) use super::{LocalContext, ToFunc};
|
pub(crate) use super::{LocalContext, ToFunc};
|
||||||
pub(crate) use crate::adt::interner::Interned;
|
pub(crate) use crate::adt::interner::Interned;
|
||||||
pub use crate::ty::Ty;
|
pub use crate::ty::Ty;
|
||||||
|
pub(crate) use crate::StrRef;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Semantic tokens (highlighting) support for LSP.
|
//! Semantic tokens (highlighting) support for LSP.
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::{
|
use std::{
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::Range,
|
ops::Range,
|
||||||
|
@ -7,7 +8,6 @@ use std::{
|
||||||
sync::{Arc, OnceLock},
|
sync::{Arc, OnceLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
use lsp_types::SemanticToken;
|
use lsp_types::SemanticToken;
|
||||||
use lsp_types::{SemanticTokenModifier, SemanticTokenType};
|
use lsp_types::{SemanticTokenModifier, SemanticTokenType};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
|
|
@ -1,163 +1,19 @@
|
||||||
//! Analysis of function signatures.
|
//! Analysis of function signatures.
|
||||||
|
|
||||||
use itertools::Either;
|
use itertools::Either;
|
||||||
|
use tinymist_analysis::{func_signature, ArgInfo, ArgsInfo, PartialSignature};
|
||||||
use tinymist_derive::BindTyCtx;
|
use tinymist_derive::BindTyCtx;
|
||||||
use typst::foundations::Closure;
|
|
||||||
|
|
||||||
use super::{
|
use super::{prelude::*, Definition, SharedContext};
|
||||||
prelude::*, BoundChecker, Definition, DocSource, ParamTy, SharedContext, SigTy, SigWithTy,
|
|
||||||
TypeInfo, TypeVar,
|
|
||||||
};
|
|
||||||
use crate::analysis::PostTypeChecker;
|
use crate::analysis::PostTypeChecker;
|
||||||
use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs};
|
use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs};
|
||||||
use crate::syntax::classify_def_loosely;
|
use crate::syntax::classify_def_loosely;
|
||||||
use crate::ty::{DynTypeBounds, ParamAttrs};
|
use crate::ty::{
|
||||||
use crate::ty::{InsTy, TyCtx};
|
BoundChecker, DocSource, DynTypeBounds, ParamAttrs, ParamTy, SigWithTy, TyCtx, TypeInfo,
|
||||||
use crate::upstream::truncated_repr;
|
TypeVar,
|
||||||
|
};
|
||||||
|
|
||||||
/// Describes a function signature.
|
pub use tinymist_analysis::{PrimarySignature, 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>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The language object that the signature is being analyzed for.
|
/// The language object that the signature is being analyzed for.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -475,216 +331,3 @@ fn analyze_dyn_signature(
|
||||||
|
|
||||||
Some(func_signature(func))
|
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
|
//! Statistics about the analyzers
|
||||||
|
|
||||||
use std::{
|
use std::{sync::Arc, time::Duration};
|
||||||
sync::{atomic::AtomicUsize, Arc},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use tinymist_std::hash::FxDashMap;
|
use tinymist_std::hash::FxDashMap;
|
||||||
use typst::syntax::FileId;
|
use typst::syntax::FileId;
|
||||||
|
|
||||||
use super::Analysis;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct QueryStatBucketData {
|
pub(crate) struct QueryStatBucketData {
|
||||||
pub query: u64,
|
pub query: u64,
|
||||||
|
@ -117,84 +112,3 @@ table.analysis-stats tr:nth-child(odd) { background-color: rgba(242, 242, 242, 0
|
||||||
html
|
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 apply;
|
||||||
mod convert;
|
|
||||||
mod docs;
|
mod docs;
|
||||||
mod select;
|
mod select;
|
||||||
mod syntax;
|
mod syntax;
|
||||||
|
|
||||||
pub(crate) use apply::*;
|
pub(crate) use apply::*;
|
||||||
pub(crate) use convert::*;
|
|
||||||
pub(crate) use select::*;
|
pub(crate) use select::*;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use tinymist_analysis::analyze_expr;
|
||||||
use tinymist_world::ShadowApi;
|
use tinymist_world::ShadowApi;
|
||||||
use typst::foundations::{Bytes, IntoValue, StyleChain};
|
use typst::foundations::{Bytes, IntoValue, StyleChain};
|
||||||
use typst_shim::syntax::LinkedNodeExt;
|
use typst_shim::syntax::LinkedNodeExt;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::analyze_expr,
|
|
||||||
prelude::*,
|
prelude::*,
|
||||||
syntax::{interpret_mode_at, InterpretMode},
|
syntax::{interpret_mode_at, InterpretMode},
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ use ecow::EcoString;
|
||||||
use lsp_types::InsertTextFormat;
|
use lsp_types::InsertTextFormat;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::ty::Interned;
|
use crate::StrRef;
|
||||||
|
|
||||||
use super::LspRange;
|
use super::LspRange;
|
||||||
|
|
||||||
|
@ -284,11 +284,11 @@ pub struct LspCompletionCommand {
|
||||||
/// The title of command.
|
/// The title of command.
|
||||||
pub title: EcoString,
|
pub title: EcoString,
|
||||||
/// The identifier of the actual command handler.
|
/// The identifier of the actual command handler.
|
||||||
pub command: Interned<str>,
|
pub command: StrRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Interned<str>> for LspCompletionCommand {
|
impl From<StrRef> for LspCompletionCommand {
|
||||||
fn from(command: Interned<str>) -> Self {
|
fn from(command: StrRef) -> Self {
|
||||||
Self {
|
Self {
|
||||||
title: EcoString::default(),
|
title: EcoString::default(),
|
||||||
command,
|
command,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoString};
|
use ecow::{eco_format, EcoString};
|
||||||
use hashbrown::HashSet;
|
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::adt::interner::Interned;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::syntax::{InterpretMode, SurroundingSyntax};
|
use crate::syntax::{InterpretMode, SurroundingSyntax};
|
||||||
use crate::ty::Interned;
|
|
||||||
|
|
||||||
/// This is the poorman's type filter, which is less powerful but more steady.
|
/// This is the poorman's type filter, which is less powerful but more steady.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
|
|
@ -1,303 +1,11 @@
|
||||||
use core::fmt;
|
|
||||||
use std::collections::BTreeMap;
|
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
use ecow::{eco_format, EcoString};
|
use tinymist_analysis::docs::{format_ty, ParamDocs, SignatureDocs, VarDocs};
|
||||||
use serde::{Deserialize, Serialize};
|
use tinymist_analysis::ty::DocSource;
|
||||||
|
use tinymist_analysis::Signature;
|
||||||
use typst::syntax::Span;
|
use typst::syntax::Span;
|
||||||
|
|
||||||
use super::tidy::*;
|
use crate::LocalContext;
|
||||||
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))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option<VarDocs> {
|
pub(crate) fn var_docs(ctx: &mut LocalContext, pos: Span) -> Option<VarDocs> {
|
||||||
let source = ctx.source_by_id(pos.id()?).ok()?;
|
let source = ctx.source_by_id(pos.id()?).ok()?;
|
||||||
|
|
|
@ -4,16 +4,15 @@ mod convert;
|
||||||
mod def;
|
mod def;
|
||||||
mod module;
|
mod module;
|
||||||
mod package;
|
mod package;
|
||||||
mod tidy;
|
|
||||||
|
|
||||||
use tinymist_std::path::unix_slash;
|
use tinymist_std::path::unix_slash;
|
||||||
use typst::syntax::FileId;
|
use typst::syntax::FileId;
|
||||||
|
|
||||||
pub(crate) use convert::convert_docs;
|
pub(crate) use convert::convert_docs;
|
||||||
pub use def::*;
|
pub(crate) use def::*;
|
||||||
pub use module::*;
|
pub use module::*;
|
||||||
pub use package::*;
|
pub use package::*;
|
||||||
pub(crate) use tidy::*;
|
pub use tinymist_analysis::docs::*;
|
||||||
|
|
||||||
fn file_id_repr(fid: FileId) -> String {
|
fn file_id_repr(fid: FileId) -> String {
|
||||||
if let Some(spec) = fid.package() {
|
if let Some(spec) = fid.package() {
|
||||||
|
|
|
@ -10,10 +10,10 @@ use typst::diag::StrResult;
|
||||||
use typst::syntax::package::PackageSpec;
|
use typst::syntax::package::PackageSpec;
|
||||||
use typst::syntax::FileId;
|
use typst::syntax::FileId;
|
||||||
|
|
||||||
|
use crate::adt::interner::Interned;
|
||||||
use crate::docs::file_id_repr;
|
use crate::docs::file_id_repr;
|
||||||
use crate::package::{get_manifest_id, PackageInfo};
|
use crate::package::{get_manifest_id, PackageInfo};
|
||||||
use crate::syntax::{Decl, DefKind, Expr, ExprInfo};
|
use crate::syntax::{Decl, DefKind, Expr, ExprInfo};
|
||||||
use crate::ty::Interned;
|
|
||||||
use crate::LocalContext;
|
use crate::LocalContext;
|
||||||
|
|
||||||
use super::DefDocs;
|
use super::DefDocs;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use hashbrown::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
|
|
|
@ -46,7 +46,7 @@ pub mod docs;
|
||||||
pub mod package;
|
pub mod package;
|
||||||
pub mod syntax;
|
pub mod syntax;
|
||||||
pub mod testing;
|
pub mod testing;
|
||||||
pub mod ty;
|
pub use tinymist_analysis::{ty, upstream};
|
||||||
|
|
||||||
/// The physical position in a document.
|
/// The physical position in a document.
|
||||||
pub type FramePosition = typst::layout::Position;
|
pub type FramePosition = typst::layout::Position;
|
||||||
|
@ -81,15 +81,17 @@ mod semantic_tokens_delta;
|
||||||
mod semantic_tokens_full;
|
mod semantic_tokens_full;
|
||||||
mod signature_help;
|
mod signature_help;
|
||||||
mod symbol;
|
mod symbol;
|
||||||
mod upstream;
|
|
||||||
mod will_rename_files;
|
mod will_rename_files;
|
||||||
mod workspace_label;
|
mod workspace_label;
|
||||||
|
|
||||||
use typst::syntax::Source;
|
use typst::syntax::Source;
|
||||||
|
|
||||||
use tinymist_analysis::log_debug_ct;
|
use tinymist_analysis::{adt::interner::Interned, log_debug_ct};
|
||||||
use tinymist_project::LspComputeGraph;
|
use tinymist_project::LspComputeGraph;
|
||||||
|
|
||||||
|
/// A reference to the interned string
|
||||||
|
pub(crate) type StrRef = Interned<str>;
|
||||||
|
|
||||||
/// A request handler with given syntax information.
|
/// A request handler with given syntax information.
|
||||||
pub trait SyntaxRequest {
|
pub trait SyntaxRequest {
|
||||||
/// The response type of the request.
|
/// The response type of the request.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use tinymist_analysis::adt::interner::Interned;
|
||||||
use tinymist_std::typst::TypstDocument;
|
use tinymist_std::typst::TypstDocument;
|
||||||
use typst::syntax::Span;
|
use typst::syntax::Span;
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ use crate::{
|
||||||
analysis::{Definition, SearchCtx},
|
analysis::{Definition, SearchCtx},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
syntax::{get_index_info, RefExpr, SyntaxClass},
|
syntax::{get_index_info, RefExpr, SyntaxClass},
|
||||||
ty::Interned,
|
StrRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The [`textDocument/references`] request is sent from the client to the
|
/// The [`textDocument/references`] request is sent from the client to the
|
||||||
|
@ -73,7 +74,7 @@ struct ReferencesWorker<'a> {
|
||||||
ctx: SearchCtx<'a>,
|
ctx: SearchCtx<'a>,
|
||||||
references: Vec<LspLocation>,
|
references: Vec<LspLocation>,
|
||||||
def: Definition,
|
def: Definition,
|
||||||
module_path: OnceLock<Interned<str>>,
|
module_path: OnceLock<StrRef>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReferencesWorker<'_> {
|
impl ReferencesWorker<'_> {
|
||||||
|
@ -148,7 +149,7 @@ impl ReferencesWorker<'_> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: references of package
|
// todo: references of package
|
||||||
fn module_path(&self) -> &Interned<str> {
|
fn module_path(&self) -> &StrRef {
|
||||||
self.module_path.get_or_init(|| {
|
self.module_path.get_or_init(|| {
|
||||||
self.def
|
self.def
|
||||||
.decl
|
.decl
|
||||||
|
|
|
@ -9,13 +9,13 @@ use typst::{
|
||||||
syntax::Span,
|
syntax::Span,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use crate::adt::interner::Interned;
|
||||||
use crate::{
|
use crate::{
|
||||||
analysis::{get_link_exprs, LinkObject, LinkTarget},
|
analysis::{get_link_exprs, LinkObject, LinkTarget},
|
||||||
find_references,
|
find_references,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
prepare_renaming,
|
prepare_renaming,
|
||||||
syntax::{first_ancestor_expr, get_index_info, node_ancestors, Decl, RefExpr, SyntaxClass},
|
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
|
/// The [`textDocument/rename`] request is sent from the client to the server to
|
||||||
|
|
|
@ -7,16 +7,13 @@ use std::{
|
||||||
use ecow::eco_format;
|
use ecow::eco_format;
|
||||||
use typst::foundations::{IntoValue, Module, Str, Type};
|
use typst::foundations::{IntoValue, Module, Str, Type};
|
||||||
|
|
||||||
|
use crate::{adt::interner::Interned, StrRef};
|
||||||
|
use crate::{adt::snapshot_map::SnapshotMap, analysis::SharedContext};
|
||||||
use crate::{
|
use crate::{
|
||||||
adt::snapshot_map::SnapshotMap,
|
|
||||||
analysis::SharedContext,
|
|
||||||
docs::{convert_docs, identify_pat_docs, identify_tidy_module_docs, UntypedDefDocs, VarDocsT},
|
docs::{convert_docs, identify_pat_docs, identify_tidy_module_docs, UntypedDefDocs, VarDocsT},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
syntax::{Decl, DefKind},
|
syntax::{Decl, DefKind},
|
||||||
ty::{
|
ty::{BuiltinTy, DynTypeBounds, InsTy, PackageId, SigTy, Ty, TypeVar, TypeVarBounds},
|
||||||
BuiltinTy, DynTypeBounds, InsTy, Interned, PackageId, SigTy, StrRef, Ty, TypeVar,
|
|
||||||
TypeVarBounds,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::DeclExpr;
|
use super::DeclExpr;
|
||||||
|
@ -35,6 +32,7 @@ pub struct DocString {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DocString {
|
impl DocString {
|
||||||
|
/// Gets the docstring as a variable doc
|
||||||
pub fn as_var(&self) -> VarDoc {
|
pub fn as_var(&self) -> VarDoc {
|
||||||
VarDoc {
|
VarDoc {
|
||||||
docs: self.docs.clone().unwrap_or_default(),
|
docs: self.docs.clone().unwrap_or_default(),
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
#![allow(missing_docs)]
|
||||||
|
|
||||||
use std::ops::DerefMut;
|
use std::ops::DerefMut;
|
||||||
|
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use rpds::RedBlackTreeMapSync;
|
use rpds::RedBlackTreeMapSync;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
use tinymist_analysis::adt::interner::Interned;
|
||||||
use tinymist_std::hash::hash128;
|
use tinymist_std::hash::hash128;
|
||||||
use typst::{
|
use typst::{
|
||||||
foundations::{Element, NativeElement, Type, Value},
|
foundations::{Element, NativeElement, Type, Value},
|
||||||
|
@ -17,7 +20,7 @@ use crate::{
|
||||||
analysis::{QueryStatGuard, SharedContext},
|
analysis::{QueryStatGuard, SharedContext},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
syntax::{find_module_level_docs, resolve_id_by_path, DefKind},
|
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};
|
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.
|
//! This module must hide all **AST details** from the rest of the codebase.
|
||||||
|
|
||||||
// todo: remove this
|
|
||||||
#![allow(missing_docs)]
|
#![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(crate) mod lexical_hierarchy;
|
||||||
pub use lexical_hierarchy::*;
|
pub use lexical_hierarchy::*;
|
||||||
pub(crate) mod module;
|
pub(crate) mod module;
|
||||||
|
@ -16,9 +12,6 @@ pub(crate) mod expr;
|
||||||
pub use expr::*;
|
pub use expr::*;
|
||||||
pub(crate) mod docs;
|
pub(crate) mod docs;
|
||||||
pub use docs::*;
|
pub use docs::*;
|
||||||
pub(crate) mod def;
|
|
||||||
pub use def::*;
|
|
||||||
pub(crate) mod repr;
|
|
||||||
use repr::*;
|
|
||||||
pub(crate) mod index;
|
pub(crate) mod index;
|
||||||
pub use index::*;
|
pub use index::*;
|
||||||
|
pub use tinymist_analysis::syntax::*;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue