mirror of
https://github.com/Myriad-Dreamin/tinymist.git
synced 2025-08-03 17:58:17 +00:00
dev: more consistent way to get docs of decls (#752)
* dev: more consistent way to get docs of decls * test: update snapshot
This commit is contained in:
parent
8129c6741e
commit
1c1bc19caf
23 changed files with 462 additions and 451 deletions
|
@ -5,7 +5,7 @@ use typst::introspection::Introspector;
|
|||
use typst::model::BibliographyElem;
|
||||
|
||||
use super::{prelude::*, BuiltinTy, InsTy, SharedContext};
|
||||
use crate::syntax::{get_deref_target, Decl, DeclExpr, DerefTarget, Expr, ExprInfo};
|
||||
use crate::syntax::{Decl, DeclExpr, DerefTarget, Expr, ExprInfo};
|
||||
use crate::VersionedDocument;
|
||||
|
||||
/// A linked definition in the source code
|
||||
|
@ -59,7 +59,7 @@ pub fn definition(
|
|||
ctx: &Arc<SharedContext>,
|
||||
source: &Source,
|
||||
document: Option<&VersionedDocument>,
|
||||
deref_target: DerefTarget<'_>,
|
||||
deref_target: DerefTarget,
|
||||
) -> Option<Definition> {
|
||||
match deref_target {
|
||||
// todi: field access
|
||||
|
@ -249,10 +249,7 @@ impl CallConvention {
|
|||
pub fn resolve_call_target(ctx: &Arc<SharedContext>, node: &SyntaxNode) -> Option<CallConvention> {
|
||||
let callee = (|| {
|
||||
let source = ctx.source_by_id(node.span().id()?).ok()?;
|
||||
let node = source.find(node.span())?;
|
||||
let cursor = node.offset();
|
||||
let deref_target = get_deref_target(node, cursor)?;
|
||||
let def = ctx.definition(&source, None, deref_target)?;
|
||||
let def = ctx.def_of_span(&source, None, node.span())?;
|
||||
let func_ptr = match def.term.and_then(|val| val.value()) {
|
||||
Some(Value::Func(f)) => Some(f),
|
||||
Some(Value::Type(ty)) => ty.constructor().ok(),
|
||||
|
|
|
@ -13,12 +13,13 @@ use reflexo_typst::{EntryReader, WorldDeps};
|
|||
use rustc_hash::FxHashMap;
|
||||
use tinymist_world::LspWorld;
|
||||
use tinymist_world::DETACHED_ENTRY;
|
||||
use typst::diag::{eco_format, At, FileError, FileResult, SourceResult};
|
||||
use typst::diag::{eco_format, At, FileError, FileResult, SourceResult, StrResult};
|
||||
use typst::engine::{Route, Sink, Traced};
|
||||
use typst::eval::Eval;
|
||||
use typst::foundations::{Bytes, Module, Styles};
|
||||
use typst::layout::Position;
|
||||
use typst::model::Document;
|
||||
use typst::syntax::package::PackageManifest;
|
||||
use typst::syntax::{package::PackageSpec, Span, VirtualPath};
|
||||
|
||||
use crate::analysis::prelude::*;
|
||||
|
@ -26,10 +27,11 @@ use crate::analysis::{
|
|||
analyze_bib, analyze_import_, analyze_signature, post_type_check, BibInfo, PathPreference,
|
||||
Signature, SignatureTarget, Ty, TypeScheme,
|
||||
};
|
||||
use crate::docs::{SignatureDocs, VarDocs};
|
||||
use crate::docs::{DefDocs, TidyModuleDocs};
|
||||
use crate::syntax::{
|
||||
construct_module_dependencies, find_expr_in_import, get_deref_target, resolve_id_by_path,
|
||||
scan_workspace_files, DerefTarget, ExprInfo, LexicalScope, ModuleDependency, Processing,
|
||||
scan_workspace_files, Decl, DefKind, DerefTarget, ExprInfo, LexicalScope, ModuleDependency,
|
||||
Processing,
|
||||
};
|
||||
use crate::upstream::{tooltip_, Tooltip};
|
||||
use crate::{
|
||||
|
@ -200,10 +202,6 @@ impl<'w> AnalysisContext<'w> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn variable_docs(&mut self, pos: &LinkedNode) -> Option<VarDocs> {
|
||||
crate::docs::variable_docs(self, pos)
|
||||
}
|
||||
|
||||
pub(crate) fn preload_package(&self, entry_point: TypstFileId) {
|
||||
self.shared_().preload_package(entry_point);
|
||||
}
|
||||
|
@ -376,6 +374,11 @@ impl LocalContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the expression information of a source file.
|
||||
pub(crate) fn expr_stage_by_id(&mut self, fid: TypstFileId) -> Option<Arc<ExprInfo>> {
|
||||
Some(self.expr_stage(&self.source_by_id(fid).ok()?))
|
||||
}
|
||||
|
||||
/// Get the expression information of a source file.
|
||||
pub(crate) fn expr_stage(&mut self, source: &Source) -> Arc<ExprInfo> {
|
||||
let id = source.id();
|
||||
|
@ -389,6 +392,29 @@ impl LocalContext {
|
|||
let cache = &self.caches.modules.entry(id).or_default().type_check;
|
||||
cache.get_or_init(|| self.shared.type_check(source)).clone()
|
||||
}
|
||||
|
||||
pub(crate) fn def_docs(&mut self, def: &Definition) -> Option<DefDocs> {
|
||||
// let plain_docs = sym.head.docs.as_deref();
|
||||
// let plain_docs = plain_docs.or(sym.head.oneliner.as_deref());
|
||||
match def.decl.kind() {
|
||||
DefKind::Function => {
|
||||
let sig = self.sig_of_def(def.clone())?;
|
||||
let docs = crate::docs::signature_docs(&sig, None)?;
|
||||
Some(DefDocs::Function(Box::new(docs)))
|
||||
}
|
||||
DefKind::Struct | DefKind::Constant | DefKind::Variable => {
|
||||
let docs = crate::docs::variable_docs(self, def.decl.span())?;
|
||||
Some(DefDocs::Variable(docs))
|
||||
}
|
||||
DefKind::Module => {
|
||||
let ei = self.expr_stage_by_id(def.decl.file_id()?)?;
|
||||
Some(DefDocs::Module(TidyModuleDocs {
|
||||
docs: ei.module_docstring.docs.clone().unwrap_or_default(),
|
||||
}))
|
||||
}
|
||||
DefKind::Reference => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The shared analysis context for analyzers.
|
||||
|
@ -594,6 +620,11 @@ impl SharedContext {
|
|||
res
|
||||
}
|
||||
|
||||
/// Get the expression information of a source file.
|
||||
pub(crate) fn expr_stage_by_id(self: &Arc<Self>, fid: TypstFileId) -> Option<Arc<ExprInfo>> {
|
||||
Some(self.expr_stage(&self.source_by_id(fid).ok()?))
|
||||
}
|
||||
|
||||
/// Get the expression information of a source file.
|
||||
pub(crate) fn expr_stage(self: &Arc<Self>, source: &Source) -> Arc<ExprInfo> {
|
||||
let mut route = Processing::default();
|
||||
|
@ -660,7 +691,25 @@ impl SharedContext {
|
|||
})
|
||||
}
|
||||
|
||||
pub(crate) fn definition(
|
||||
pub(crate) fn def_of_span(
|
||||
self: &Arc<Self>,
|
||||
source: &Source,
|
||||
doc: Option<&VersionedDocument>,
|
||||
span: Span,
|
||||
) -> Option<Definition> {
|
||||
let target = self.deref_syntax(source, span)?;
|
||||
definition(self, source, doc, target)
|
||||
}
|
||||
|
||||
pub(crate) fn def_of_decl(&self, decl: &Interned<Decl>) -> Option<Definition> {
|
||||
match decl.as_ref() {
|
||||
Decl::Func(..) => Some(Definition::new(decl.clone(), None)),
|
||||
Decl::Module(..) => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn def_of_syntax(
|
||||
self: &Arc<Self>,
|
||||
source: &Source,
|
||||
doc: Option<&VersionedDocument>,
|
||||
|
@ -669,22 +718,17 @@ impl SharedContext {
|
|||
definition(self, source, doc, deref_target)
|
||||
}
|
||||
|
||||
pub(crate) fn signature_def(self: &Arc<Self>, def: Definition) -> Option<Signature> {
|
||||
pub(crate) fn sig_of_def(self: &Arc<Self>, def: Definition) -> Option<Signature> {
|
||||
log::debug!("check definition func {def:?}");
|
||||
let source = def.decl.file_id().and_then(|f| self.source_by_id(f).ok());
|
||||
analyze_signature(self, SignatureTarget::Def(source, def))
|
||||
}
|
||||
|
||||
pub(crate) fn signature_dyn(self: &Arc<Self>, func: Func) -> Signature {
|
||||
pub(crate) fn sig_of_func(self: &Arc<Self>, func: Func) -> Signature {
|
||||
log::debug!("check runtime func {func:?}");
|
||||
analyze_signature(self, SignatureTarget::Runtime(func)).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn signature_docs(self: &Arc<Self>, def: &Definition) -> Option<SignatureDocs> {
|
||||
let sig = self.signature_def(def.clone())?;
|
||||
crate::docs::signature_docs(&sig, None)
|
||||
}
|
||||
|
||||
/// Try to find imported target from the current source file.
|
||||
/// This function will try to resolves target statically.
|
||||
///
|
||||
|
@ -789,6 +833,11 @@ impl SharedContext {
|
|||
}
|
||||
}
|
||||
|
||||
/// Get the manifest of a package by file id.
|
||||
pub fn get_manifest(&self, toml_id: TypstFileId) -> StrResult<PackageManifest> {
|
||||
crate::docs::get_manifest(&self.world, toml_id)
|
||||
}
|
||||
|
||||
/// Compute the signature of a function.
|
||||
pub fn compute_signature(
|
||||
self: &Arc<Self>,
|
||||
|
|
|
@ -6,7 +6,7 @@ use typst::foundations::{Closure, ParamInfo};
|
|||
|
||||
use super::{prelude::*, BoundChecker, Definition, DocSource, SharedContext, SigTy, TypeVar};
|
||||
use crate::analysis::PostTypeChecker;
|
||||
use crate::docs::{UntypedSignatureDocs, UntypedSymbolDocs, UntypedVarDocs};
|
||||
use crate::docs::{UntypedDefDocs, UntypedSignatureDocs, UntypedVarDocs};
|
||||
use crate::syntax::get_non_strict_def_target;
|
||||
use crate::ty::TyCtx;
|
||||
use crate::ty::TypeBounds;
|
||||
|
@ -290,8 +290,8 @@ fn analyze_type_signature(
|
|||
|
||||
// todo: this will affect inlay hint: _var_with
|
||||
let (_var_with, docstring) = match type_info.var_docs.get(&v.def).map(|x| x.as_ref()) {
|
||||
Some(UntypedSymbolDocs::Function(sig)) => (vec![], Either::Left(sig.as_ref())),
|
||||
Some(UntypedSymbolDocs::Variable(d)) => find_alias_stack(&mut ty_ctx, &v, d)?,
|
||||
Some(UntypedDefDocs::Function(sig)) => (vec![], Either::Left(sig.as_ref())),
|
||||
Some(UntypedDefDocs::Variable(d)) => find_alias_stack(&mut ty_ctx, &v, d)?,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
|
@ -415,10 +415,10 @@ impl<'a, 'b> BoundChecker for AliasStackChecker<'a, 'b> {
|
|||
log::debug!("collecting var {u:?} {pol:?} => {docs:?}");
|
||||
// todo: bind builtin functions
|
||||
match docs {
|
||||
Some(UntypedSymbolDocs::Function(sig)) => {
|
||||
Some(UntypedDefDocs::Function(sig)) => {
|
||||
self.res = Some(Either::Left(sig));
|
||||
}
|
||||
Some(UntypedSymbolDocs::Variable(d)) => {
|
||||
Some(UntypedDefDocs::Variable(d)) => {
|
||||
self.checking_with = true;
|
||||
self.stack.push(d);
|
||||
self.check_var_rec(u, pol);
|
||||
|
@ -468,8 +468,7 @@ fn analyze_dyn_signature(
|
|||
SignatureTarget::Def(_source, def) => def.value()?.to_func()?,
|
||||
SignatureTarget::SyntaxFast(..) => return None,
|
||||
SignatureTarget::Syntax(source, span) => {
|
||||
let target = ctx.deref_syntax(source, *span)?;
|
||||
let def = ctx.definition(source, None, target)?;
|
||||
let def = ctx.def_of_span(source, None, *span)?;
|
||||
def.value()?.to_func()?
|
||||
}
|
||||
SignatureTarget::Convert(func) | SignatureTarget::Runtime(func) => func.clone(),
|
||||
|
|
|
@ -121,13 +121,13 @@ impl<'a> TypeChecker<'a> {
|
|||
|
||||
log::debug!("import_ty {name} from {fid:?}");
|
||||
|
||||
let source = self.ctx.source_by_id(fid).ok()?;
|
||||
let ext_def_use_info = self.ctx.expr_stage(&source);
|
||||
let ext_def_use_info = self.ctx.expr_stage_by_id(fid)?;
|
||||
let source = &ext_def_use_info.source;
|
||||
// todo: check types in cycle
|
||||
let ext_type_info = if let Some(route) = self.route.get(&source.id()) {
|
||||
route.clone()
|
||||
} else {
|
||||
self.ctx.type_check_(&source, self.route)
|
||||
self.ctx.type_check_(source, self.route)
|
||||
};
|
||||
let ext_def = ext_def_use_info.exports.get(&name)?;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use super::*;
|
||||
use crate::analysis::ParamAttrs;
|
||||
use crate::docs::{SignatureDocsT, TypelessParamDocs, UntypedSymbolDocs};
|
||||
use crate::docs::{SignatureDocsT, TypelessParamDocs, UntypedDefDocs};
|
||||
use crate::syntax::{def::*, DocString, VarDoc};
|
||||
use crate::ty::*;
|
||||
|
||||
|
@ -261,13 +261,13 @@ impl<'a> TypeChecker<'a> {
|
|||
if let Some(base) = base {
|
||||
self.info.var_docs.insert(
|
||||
base.clone(),
|
||||
Arc::new(UntypedSymbolDocs::Function(Box::new(SignatureDocsT {
|
||||
Arc::new(UntypedDefDocs::Function(Box::new(SignatureDocsT {
|
||||
docs: docstring.docs.clone().unwrap_or_default(),
|
||||
pos: pos_docs,
|
||||
named: named_docs,
|
||||
rest: rest_docs,
|
||||
ret_ty: (),
|
||||
def_docs: Default::default(),
|
||||
hover_docs: Default::default(),
|
||||
}))),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ mod symbol;
|
|||
mod tidy;
|
||||
|
||||
use reflexo::path::unix_slash;
|
||||
use typst::{foundations::Value, syntax::FileId};
|
||||
use typst::syntax::FileId;
|
||||
|
||||
pub use module::*;
|
||||
pub use package::*;
|
||||
|
@ -21,13 +21,3 @@ fn file_id_repr(k: FileId) -> String {
|
|||
unix_slash(k.vpath().as_rooted_path())
|
||||
}
|
||||
}
|
||||
|
||||
fn kind_of(val: &Value) -> DocStringKind {
|
||||
match val {
|
||||
Value::Module(_) => DocStringKind::Module,
|
||||
Value::Type(_) => DocStringKind::Struct,
|
||||
Value::Func(_) => DocStringKind::Function,
|
||||
Value::Label(_) => DocStringKind::Reference,
|
||||
_ => DocStringKind::Constant,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,27 +1,26 @@
|
|||
//! Module documentation.
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::ops::Range;
|
||||
use std::sync::Arc;
|
||||
|
||||
use ecow::{eco_vec, EcoString, EcoVec};
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use typst::diag::{eco_format, StrResult};
|
||||
use typst::foundations::{Module, Value};
|
||||
use typst::diag::StrResult;
|
||||
use typst::syntax::package::PackageSpec;
|
||||
use typst::syntax::{FileId, Span};
|
||||
use typst::syntax::FileId;
|
||||
|
||||
use crate::docs::file_id_repr;
|
||||
use crate::syntax::{find_docs_of, get_non_strict_def_target};
|
||||
use crate::upstream::truncated_doc_repr;
|
||||
use crate::syntax::{Decl, DefKind, Expr, ExprInfo};
|
||||
use crate::ty::Interned;
|
||||
use crate::AnalysisContext;
|
||||
|
||||
use super::{get_manifest, get_manifest_id, kind_of, DocStringKind, PackageInfo, SymbolDocs};
|
||||
use super::{get_manifest_id, DefDocs, PackageInfo};
|
||||
|
||||
/// Get documentation of symbols in a package.
|
||||
pub fn package_module_docs(ctx: &mut AnalysisContext, pkg: &PackageInfo) -> StrResult<SymbolsInfo> {
|
||||
let toml_id = get_manifest_id(pkg)?;
|
||||
let manifest = get_manifest(ctx.world(), toml_id)?;
|
||||
let manifest = ctx.get_manifest(toml_id)?;
|
||||
|
||||
let entry_point = toml_id.join(&manifest.package.entrypoint);
|
||||
module_docs(ctx, entry_point)
|
||||
|
@ -40,11 +39,11 @@ pub fn module_docs(ctx: &mut AnalysisContext, entry_point: FileId) -> StrResult<
|
|||
extras: &mut extras,
|
||||
};
|
||||
|
||||
let src = scan_ctx
|
||||
let ei = scan_ctx
|
||||
.ctx
|
||||
.module_by_id(entry_point)
|
||||
.map_err(|e| eco_format!("failed to get module by id {entry_point:?}: {e:?}"))?;
|
||||
let mut symbols = scan_ctx.module_sym(eco_vec![], src);
|
||||
.expr_stage_by_id(entry_point)
|
||||
.ok_or("entry point not found")?;
|
||||
let mut symbols = scan_ctx.module_sym(eco_vec![], ei);
|
||||
|
||||
let module_uses = aliases
|
||||
.into_iter()
|
||||
|
@ -70,7 +69,7 @@ pub struct SymbolInfoHead {
|
|||
/// The name of the symbol.
|
||||
pub name: EcoString,
|
||||
/// The kind of the symbol.
|
||||
pub kind: DocStringKind,
|
||||
pub kind: DefKind,
|
||||
/// The location (file, start, end) of the symbol.
|
||||
pub loc: Option<(usize, usize, usize)>,
|
||||
/// Is the symbol reexport
|
||||
|
@ -80,24 +79,16 @@ pub struct SymbolInfoHead {
|
|||
/// The one-line documentation of the symbol.
|
||||
pub oneliner: Option<String>,
|
||||
/// The raw documentation of the symbol.
|
||||
pub docs: Option<String>,
|
||||
pub docs: Option<EcoString>,
|
||||
/// The parsed documentation of the symbol.
|
||||
pub parsed_docs: Option<SymbolDocs>,
|
||||
pub parsed_docs: Option<DefDocs>,
|
||||
/// The value of the symbol.
|
||||
#[serde(skip)]
|
||||
pub constant: Option<EcoString>,
|
||||
/// The file owning the symbol.
|
||||
#[serde(skip)]
|
||||
pub fid: Option<FileId>,
|
||||
/// The span of the symbol.
|
||||
#[serde(skip)]
|
||||
pub span: Option<Span>,
|
||||
/// The name range of the symbol.
|
||||
#[serde(skip)]
|
||||
pub name_range: Option<Range<usize>>,
|
||||
/// The value of the symbol.
|
||||
#[serde(skip)]
|
||||
pub value: Option<Value>,
|
||||
pub decl: Option<Interned<Decl>>,
|
||||
}
|
||||
|
||||
/// Information about a symbol.
|
||||
|
@ -129,11 +120,59 @@ struct ScanSymbolCtx<'a, 'w> {
|
|||
}
|
||||
|
||||
impl ScanSymbolCtx<'_, '_> {
|
||||
fn module_sym(&mut self, path: EcoVec<&str>, module: Module) -> SymbolInfo {
|
||||
let key = module.name().to_owned();
|
||||
fn module_sym(&mut self, path: EcoVec<&str>, ei: Arc<ExprInfo>) -> SymbolInfo {
|
||||
let name = {
|
||||
let stem = ei.fid.vpath().as_rooted_path().file_stem();
|
||||
stem.and_then(|s| Some(Interned::new_str(s.to_str()?)))
|
||||
.unwrap_or_default()
|
||||
};
|
||||
let module_decl = Decl::module(name.clone(), ei.fid).into();
|
||||
let site = Some(self.root);
|
||||
let p = path.clone();
|
||||
self.sym(&key, p, site.as_ref(), &Value::Module(module))
|
||||
self.sym(&name, p, site.as_ref(), &module_decl, None)
|
||||
}
|
||||
|
||||
fn expr(
|
||||
&mut self,
|
||||
key: &str,
|
||||
path: EcoVec<&str>,
|
||||
site: Option<&FileId>,
|
||||
val: &Expr,
|
||||
) -> SymbolInfo {
|
||||
match val {
|
||||
Expr::Decl(d) => self.sym(key, path, site, d, Some(val)),
|
||||
Expr::Ref(r) if r.root.is_some() => {
|
||||
self.expr(key, path, site, r.root.as_ref().unwrap())
|
||||
}
|
||||
// todo: select
|
||||
Expr::Select(..) => {
|
||||
let mut path = path.clone();
|
||||
path.push(key);
|
||||
let head = SymbolInfoHead {
|
||||
name: key.to_string().into(),
|
||||
kind: DefKind::Module,
|
||||
..Default::default()
|
||||
};
|
||||
SymbolInfo {
|
||||
head,
|
||||
children: eco_vec![],
|
||||
}
|
||||
}
|
||||
// v => panic!("unexpected export: {key} -> {v}"),
|
||||
_ => {
|
||||
let mut path = path.clone();
|
||||
path.push(key);
|
||||
let head = SymbolInfoHead {
|
||||
name: key.to_string().into(),
|
||||
kind: DefKind::Constant,
|
||||
..Default::default()
|
||||
};
|
||||
SymbolInfo {
|
||||
head,
|
||||
children: eco_vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sym(
|
||||
|
@ -141,12 +180,13 @@ impl ScanSymbolCtx<'_, '_> {
|
|||
key: &str,
|
||||
path: EcoVec<&str>,
|
||||
site: Option<&FileId>,
|
||||
val: &Value,
|
||||
val: &Interned<Decl>,
|
||||
expr: Option<&Expr>,
|
||||
) -> SymbolInfo {
|
||||
let mut head = create_head(self.ctx, key, val);
|
||||
let mut head = create_head(self.ctx, key, val, expr);
|
||||
|
||||
if !matches!(&val, Value::Module(..)) {
|
||||
if let Some((span, mod_fid)) = head.span.and_then(Span::id).zip(site) {
|
||||
if !matches!(val.as_ref(), Decl::Module(..)) {
|
||||
if let Some((span, mod_fid)) = head.decl.as_ref().and_then(|d| d.file_id()).zip(site) {
|
||||
if span != *mod_fid {
|
||||
head.export_again = true;
|
||||
head.oneliner = head.docs.as_deref().map(oneliner).map(|e| e.to_owned());
|
||||
|
@ -155,8 +195,8 @@ impl ScanSymbolCtx<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
let children = match val {
|
||||
Value::Module(module) => module.file_id().and_then(|fid| {
|
||||
let children = match val.as_ref() {
|
||||
Decl::Module(..) => val.file_id().and_then(|fid| {
|
||||
// only generate docs for the same package
|
||||
if fid.package() != self.for_spec {
|
||||
return None;
|
||||
|
@ -174,12 +214,15 @@ impl ScanSymbolCtx<'_, '_> {
|
|||
|
||||
log::debug!("found module: {path:?}");
|
||||
|
||||
let symbols = module.scope().iter();
|
||||
let symbols = symbols
|
||||
.map(|(k, v, _)| {
|
||||
let ei = self.ctx.expr_stage_by_id(fid)?;
|
||||
|
||||
let symbols = ei
|
||||
.exports
|
||||
.iter()
|
||||
.map(|(k, v)| {
|
||||
let mut path = path.clone();
|
||||
path.push(k);
|
||||
self.sym(k, path.clone(), Some(&fid), v)
|
||||
self.expr(k, path.clone(), Some(&fid), v)
|
||||
})
|
||||
.collect();
|
||||
Some(symbols)
|
||||
|
@ -188,18 +231,18 @@ impl ScanSymbolCtx<'_, '_> {
|
|||
};
|
||||
|
||||
// Insert module that is not exported
|
||||
if let Some(fid) = head.fid {
|
||||
if let Some(fid) = head.decl.as_ref().and_then(|d| d.file_id()) {
|
||||
// only generate docs for the same package
|
||||
if fid.package() == self.for_spec {
|
||||
let av = self.aliases.entry(fid).or_default();
|
||||
if av.is_empty() {
|
||||
let m = self.ctx.module_by_id(fid);
|
||||
let src = self.ctx.expr_stage_by_id(fid);
|
||||
let mut path = path.clone();
|
||||
path.push("-");
|
||||
path.push(key);
|
||||
|
||||
log::debug!("found internal module: {path:?}");
|
||||
if let Ok(m) = m {
|
||||
if let Some(m) = src {
|
||||
let msym = self.module_sym(path, m);
|
||||
self.extras.push(msym)
|
||||
}
|
||||
|
@ -212,44 +255,24 @@ impl ScanSymbolCtx<'_, '_> {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_head(world: &mut AnalysisContext, k: &str, v: &Value) -> SymbolInfoHead {
|
||||
let kind = kind_of(v);
|
||||
let (docs, name_range, fid, span) = match v {
|
||||
Value::Func(f) => {
|
||||
let mut span = None;
|
||||
let mut name_range = None;
|
||||
let docs = None.or_else(|| {
|
||||
let source = world.source_by_id(f.span().id()?).ok()?;
|
||||
let node = source.find(f.span())?;
|
||||
log::debug!("node: {k} -> {:?}", node.parent());
|
||||
// use parent of params, todo: reliable way to get the def target
|
||||
let def = get_non_strict_def_target(node.parent()?.clone())?;
|
||||
span = Some(def.node().span());
|
||||
name_range = def.name_range();
|
||||
fn create_head(
|
||||
ctx: &mut AnalysisContext,
|
||||
k: &str,
|
||||
decl: &Interned<Decl>,
|
||||
expr: Option<&Expr>,
|
||||
) -> SymbolInfoHead {
|
||||
let kind = decl.kind();
|
||||
|
||||
find_docs_of(&source, def)
|
||||
});
|
||||
|
||||
let s = span.or(Some(f.span()));
|
||||
|
||||
(docs, name_range, s.and_then(Span::id), s)
|
||||
}
|
||||
Value::Module(m) => (None, None, m.file_id(), None),
|
||||
_ => Default::default(),
|
||||
};
|
||||
let parsed_docs = ctx.def_of_decl(decl).and_then(|def| ctx.def_docs(&def));
|
||||
let docs = parsed_docs.as_ref().map(|d| d.docs().clone());
|
||||
|
||||
SymbolInfoHead {
|
||||
name: k.to_string().into(),
|
||||
kind,
|
||||
constant: None.or_else(|| match v {
|
||||
Value::Func(_) => None,
|
||||
t => Some(truncated_doc_repr(t)),
|
||||
}),
|
||||
constant: expr.map(|e| e.repr()),
|
||||
docs,
|
||||
name_range,
|
||||
fid,
|
||||
span,
|
||||
value: Some(v.clone()),
|
||||
parsed_docs,
|
||||
decl: Some(decl.clone()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,21 +5,18 @@ use std::path::PathBuf;
|
|||
use ecow::{EcoString, EcoVec};
|
||||
use indexmap::IndexSet;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_world::LspWorld;
|
||||
use typst::diag::{eco_format, StrResult};
|
||||
use typst::foundations::Value;
|
||||
use typst::syntax::package::{PackageManifest, PackageSpec};
|
||||
use typst::syntax::{FileId, Span, VirtualPath};
|
||||
use typst::World;
|
||||
|
||||
use crate::docs::{file_id_repr, module_docs, symbol_docs, SymbolDocs, SymbolsInfo};
|
||||
use crate::ty::Ty;
|
||||
use crate::docs::{file_id_repr, module_docs, DefDocs, SymbolsInfo};
|
||||
use crate::AnalysisContext;
|
||||
|
||||
/// Check Package.
|
||||
pub fn check_package(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<()> {
|
||||
let toml_id = get_manifest_id(spec)?;
|
||||
let manifest = get_manifest(ctx.world(), toml_id)?;
|
||||
let manifest = ctx.get_manifest(toml_id)?;
|
||||
|
||||
let entry_point = toml_id.join(&manifest.package.entrypoint);
|
||||
|
||||
|
@ -33,7 +30,7 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
|
||||
let mut md = String::new();
|
||||
let toml_id = get_manifest_id(spec)?;
|
||||
let manifest = get_manifest(ctx.world(), toml_id)?;
|
||||
let manifest = ctx.get_manifest(toml_id)?;
|
||||
|
||||
let for_spec = toml_id.package().unwrap();
|
||||
let entry_point = toml_id.join(&manifest.package.entrypoint);
|
||||
|
@ -54,7 +51,7 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
md.push('\n');
|
||||
md.push('\n');
|
||||
|
||||
let manifest = get_manifest(&ctx.world, toml_id)?;
|
||||
let manifest = ctx.get_manifest(toml_id)?;
|
||||
|
||||
let meta = PackageMeta {
|
||||
namespace: spec.namespace.clone(),
|
||||
|
@ -84,32 +81,13 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
.clone()
|
||||
};
|
||||
|
||||
// todo: extend this cache idea for all crate?
|
||||
#[allow(clippy::mutable_key_type)]
|
||||
let mut describe_cache = HashMap::<Ty, String>::new();
|
||||
let mut doc_ty = |ty: Option<&Ty>| {
|
||||
let ty = ty?;
|
||||
let short = {
|
||||
describe_cache
|
||||
.entry(ty.clone())
|
||||
.or_insert_with(|| ty.describe().unwrap_or_else(|| "unknown".to_string()))
|
||||
.clone()
|
||||
};
|
||||
|
||||
Some((short, format!("{ty:?}")))
|
||||
};
|
||||
|
||||
while !modules_to_generate.is_empty() {
|
||||
for (parent_ident, sym) in std::mem::take(&mut modules_to_generate) {
|
||||
// parent_ident, symbols
|
||||
let symbols = sym.children;
|
||||
|
||||
let module_val = sym.head.value.as_ref().unwrap();
|
||||
let module = match module_val {
|
||||
Value::Module(m) => m,
|
||||
_ => todo!(),
|
||||
};
|
||||
let fid = module.file_id();
|
||||
let module_val = sym.head.decl.as_ref().unwrap();
|
||||
let fid = module_val.file_id();
|
||||
let aka = fid.map(&mut akas).unwrap_or_default();
|
||||
|
||||
// It is (primary) known to safe as a part of HTML string, so we don't have to
|
||||
|
@ -141,7 +119,8 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
let _ = writeln!(md, "<!-- begin:module {primary} {m} -->");
|
||||
|
||||
for mut sym in symbols {
|
||||
let span = sym.head.span.and_then(|v| {
|
||||
let span = sym.head.decl.as_ref().map(|d| d.span());
|
||||
let fid_range = span.and_then(|v| {
|
||||
v.id().and_then(|e| {
|
||||
let fid = file_ids.insert_full(e).0;
|
||||
let src = ctx.source_by_id(e).ok()?;
|
||||
|
@ -149,34 +128,42 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
Some((fid, rng.start, rng.end))
|
||||
})
|
||||
});
|
||||
let sym_fid = sym.head.fid;
|
||||
let sym_fid = sym_fid.or_else(|| sym.head.span.and_then(Span::id)).or(fid);
|
||||
let span = span.or_else(|| {
|
||||
let sym_fid = sym.head.decl.as_ref().and_then(|d| d.file_id());
|
||||
let sym_fid = sym_fid.or_else(|| span.and_then(Span::id)).or(fid);
|
||||
let span = fid_range.or_else(|| {
|
||||
let fid = sym_fid?;
|
||||
Some((file_ids.insert_full(fid).0, 0, 0))
|
||||
});
|
||||
sym.head.loc = span;
|
||||
// .ok_or_else(|| {
|
||||
// let err = format!("failed to convert docs in {title}").replace(
|
||||
// "-->", "—>", // avoid markdown comment
|
||||
// );
|
||||
// log::error!("{err}");
|
||||
// err
|
||||
// })
|
||||
let docs = sym.head.parsed_docs.clone();
|
||||
// Err(e) => {
|
||||
// let err = format!("failed to convert docs: {e}").replace(
|
||||
// "-->", "—>", // avoid markdown comment
|
||||
// );
|
||||
// log::error!("{err}");
|
||||
// return Err(err);
|
||||
// }
|
||||
|
||||
let docs = symbol_docs(
|
||||
ctx,
|
||||
sym.head.kind,
|
||||
sym.head.value.as_ref(),
|
||||
sym.head.docs.as_deref(),
|
||||
Some(&mut doc_ty),
|
||||
);
|
||||
|
||||
let mut convert_err = None;
|
||||
let convert_err = None::<EcoString>;
|
||||
match &docs {
|
||||
Ok(docs) => {
|
||||
Some(docs) => {
|
||||
sym.head.parsed_docs = Some(docs.clone());
|
||||
sym.head.docs = None;
|
||||
}
|
||||
Err(e) => {
|
||||
let err = format!("failed to convert docs in {title}: {e}").replace(
|
||||
"-->", "—>", // avoid markdown comment
|
||||
);
|
||||
log::error!("{err}");
|
||||
convert_err = Some(err);
|
||||
None => {
|
||||
// let err = format!("failed to convert docs in {title}:
|
||||
// {e}").replace( "-->",
|
||||
// "—>", // avoid markdown comment
|
||||
// );
|
||||
// log::error!("{err}");
|
||||
// convert_err = Some(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,8 +175,7 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
let _ = writeln!(md, "### {}: {} in {primary}", sym.head.kind, sym.head.name);
|
||||
|
||||
if sym.head.export_again {
|
||||
let sub_fid = sym.head.fid;
|
||||
if let Some(fid) = sub_fid {
|
||||
if let Some(fid) = sym_fid {
|
||||
let lnk = if fid.package() == Some(for_spec) {
|
||||
let sub_aka = akas(fid);
|
||||
let sub_primary = sub_aka.first().cloned().unwrap_or_default();
|
||||
|
@ -218,7 +204,7 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
let head = jbase64(&sym.head);
|
||||
let _ = writeln!(md, "<!-- begin:symbol {ident} {head} -->");
|
||||
|
||||
if let Some(SymbolDocs::Function(sig)) = &sym.head.parsed_docs {
|
||||
if let Some(DefDocs::Function(sig)) = &sym.head.parsed_docs {
|
||||
let _ = writeln!(md, "<!-- begin:sig -->");
|
||||
let _ = writeln!(md, "```typc");
|
||||
let _ = write!(md, "let {}", sym.head.name);
|
||||
|
@ -238,7 +224,7 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
}
|
||||
(Some(docs), _) => {
|
||||
let _ = writeln!(md, "{}", remove_list_annotations(docs.docs()));
|
||||
if let SymbolDocs::Function(f) = docs {
|
||||
if let DefDocs::Function(f) = docs {
|
||||
for param in f.pos.iter().chain(f.named.values()).chain(f.rest.as_ref())
|
||||
{
|
||||
let _ = writeln!(md, "<!-- begin:param {} -->", param.name);
|
||||
|
@ -273,9 +259,8 @@ pub fn package_docs(ctx: &mut AnalysisContext, spec: &PackageInfo) -> StrResult<
|
|||
}
|
||||
|
||||
if !sym.children.is_empty() {
|
||||
let sub_fid = sym.head.fid;
|
||||
log::debug!("sub_fid: {sub_fid:?}");
|
||||
match sub_fid {
|
||||
log::debug!("sub_fid: {sym_fid:?}");
|
||||
match sym_fid {
|
||||
Some(fid) => {
|
||||
let aka = akas(fid);
|
||||
let primary = aka.first().cloned().unwrap_or_default();
|
||||
|
@ -352,7 +337,7 @@ pub fn get_manifest_id(spec: &PackageInfo) -> StrResult<FileId> {
|
|||
}
|
||||
|
||||
/// Parses the manifest of the package located at `package_path`.
|
||||
pub fn get_manifest(world: &LspWorld, toml_id: FileId) -> StrResult<PackageManifest> {
|
||||
pub fn get_manifest(world: &dyn World, toml_id: FileId) -> StrResult<PackageManifest> {
|
||||
let toml_data = world
|
||||
.file(toml_id)
|
||||
.map_err(|err| eco_format!("failed to read package manifest ({})", err))?;
|
||||
|
|
|
@ -7,64 +7,32 @@ use parking_lot::Mutex;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_world::base::{EntryState, ShadowApi, TaskInputs};
|
||||
use tinymist_world::LspWorld;
|
||||
use typst::foundations::{Bytes, Value};
|
||||
use typst::syntax::LinkedNode;
|
||||
use typst::foundations::Bytes;
|
||||
use typst::{
|
||||
diag::StrResult,
|
||||
syntax::{FileId, VirtualPath},
|
||||
syntax::{FileId, Span, VirtualPath},
|
||||
};
|
||||
|
||||
use super::tidy::*;
|
||||
use crate::analysis::{ParamAttrs, ParamSpec, Signature, ToFunc};
|
||||
use crate::analysis::{ParamAttrs, ParamSpec, Signature};
|
||||
use crate::docs::library;
|
||||
use crate::prelude::*;
|
||||
use crate::ty::Ty;
|
||||
use crate::ty::{DocSource, Interned};
|
||||
use crate::upstream::plain_docs_sentence;
|
||||
use crate::{ty::Ty, AnalysisContext};
|
||||
|
||||
type TypeRepr = Option<(/* short */ String, /* long */ String)>;
|
||||
type ShowTypeRepr<'a> = &'a mut dyn FnMut(Option<&Ty>) -> TypeRepr;
|
||||
|
||||
/// Kind of a docstring.
|
||||
#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum DocStringKind {
|
||||
/// A docstring for a any constant.
|
||||
#[default]
|
||||
Constant,
|
||||
/// A docstring for a function.
|
||||
Function,
|
||||
/// A docstring for a variable.
|
||||
Variable,
|
||||
/// A docstring for a module.
|
||||
Module,
|
||||
/// A docstring for a struct.
|
||||
Struct,
|
||||
/// A docstring for a reference.
|
||||
Reference,
|
||||
}
|
||||
|
||||
impl fmt::Display for DocStringKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Constant => write!(f, "constant"),
|
||||
Self::Function => write!(f, "function"),
|
||||
Self::Variable => write!(f, "variable"),
|
||||
Self::Module => write!(f, "module"),
|
||||
Self::Struct => write!(f, "struct"),
|
||||
Self::Reference => write!(f, "reference"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Documentation about a symbol (without type information).
|
||||
pub type UntypedSymbolDocs = SymbolDocsT<()>;
|
||||
pub type UntypedDefDocs = DefDocsT<()>;
|
||||
/// Documentation about a symbol.
|
||||
pub type SymbolDocs = SymbolDocsT<TypeRepr>;
|
||||
pub type DefDocs = DefDocsT<TypeRepr>;
|
||||
|
||||
/// Documentation about a symbol.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(tag = "kind")]
|
||||
pub enum SymbolDocsT<T> {
|
||||
pub enum DefDocsT<T> {
|
||||
/// Documentation about a function.
|
||||
#[serde(rename = "func")]
|
||||
Function(Box<SignatureDocsT<T>>),
|
||||
|
@ -82,7 +50,7 @@ pub enum SymbolDocsT<T> {
|
|||
},
|
||||
}
|
||||
|
||||
impl<T> SymbolDocsT<T> {
|
||||
impl<T> DefDocsT<T> {
|
||||
/// Get the markdown representation of the documentation.
|
||||
pub fn docs(&self) -> &EcoString {
|
||||
match self {
|
||||
|
@ -94,37 +62,14 @@ impl<T> SymbolDocsT<T> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn symbol_docs(
|
||||
ctx: &mut AnalysisContext,
|
||||
kind: DocStringKind,
|
||||
sym_value: Option<&Value>,
|
||||
docs: Option<&str>,
|
||||
doc_ty: Option<ShowTypeRepr>,
|
||||
) -> Result<SymbolDocs, String> {
|
||||
let signature =
|
||||
sym_value.and_then(|e| signature_docs(&ctx.signature_dyn(e.to_func()?), doc_ty));
|
||||
if let Some(signature) = signature {
|
||||
return Ok(SymbolDocs::Function(Box::new(signature)));
|
||||
}
|
||||
|
||||
if let Some(docs) = &docs {
|
||||
match convert_docs(ctx.world(), docs) {
|
||||
Ok(content) => {
|
||||
let docs = identify_docs(kind, content.clone())
|
||||
.unwrap_or(SymbolDocs::Plain { docs: content });
|
||||
return Ok(docs);
|
||||
}
|
||||
Err(e) => {
|
||||
let err = format!("failed to convert docs: {e}").replace(
|
||||
"-->", "—>", // avoid markdown comment
|
||||
);
|
||||
log::error!("{err}");
|
||||
return Err(err);
|
||||
}
|
||||
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()),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(SymbolDocs::Plain { docs: "".into() })
|
||||
}
|
||||
|
||||
/// Describes a primary function signature.
|
||||
|
@ -142,20 +87,20 @@ pub struct SignatureDocsT<T> {
|
|||
pub ret_ty: T,
|
||||
/// The full documentation for the signature.
|
||||
#[serde(skip)]
|
||||
pub def_docs: OnceLock<String>,
|
||||
pub hover_docs: OnceLock<EcoString>,
|
||||
}
|
||||
|
||||
impl SignatureDocsT<TypeRepr> {
|
||||
/// Get full documentation for the signature.
|
||||
pub fn def_docs(&self) -> &String {
|
||||
self.def_docs
|
||||
.get_or_init(|| plain_docs_sentence(&format!("{}", DefDocs(self))).into())
|
||||
pub fn hover_docs(&self) -> &EcoString {
|
||||
self.hover_docs
|
||||
.get_or_init(|| plain_docs_sentence(&format!("{}", SigDefDocs(self))))
|
||||
}
|
||||
}
|
||||
|
||||
struct DefDocs<'a>(&'a SignatureDocs);
|
||||
struct SigDefDocs<'a>(&'a SignatureDocs);
|
||||
|
||||
impl fmt::Display for DefDocs<'_> {
|
||||
impl fmt::Display for SigDefDocs<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let docs = self.0;
|
||||
let base_docs = docs.docs.trim();
|
||||
|
@ -318,10 +263,10 @@ fn format_ty(ty: Option<&Ty>, doc_ty: Option<&mut ShowTypeRepr>) -> TypeRepr {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn variable_docs(ctx: &mut AnalysisContext, pos: &LinkedNode) -> Option<VarDocs> {
|
||||
let source = ctx.source_by_id(pos.span().id()?).ok()?;
|
||||
pub(crate) fn variable_docs(ctx: &mut LocalContext, pos: Span) -> Option<VarDocs> {
|
||||
let source = ctx.source_by_id(pos.id()?).ok()?;
|
||||
let type_info = ctx.type_check(&source);
|
||||
let ty = type_info.type_of_span(pos.span())?;
|
||||
let ty = type_info.type_of_span(pos)?;
|
||||
|
||||
// todo multiple sources
|
||||
let mut srcs = ty.sources();
|
||||
|
@ -396,7 +341,7 @@ pub(crate) fn signature_docs(
|
|||
named,
|
||||
rest,
|
||||
ret_ty,
|
||||
def_docs: OnceLock::new(),
|
||||
hover_docs: OnceLock::new(),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -430,14 +375,3 @@ pub(crate) fn convert_docs(world: &LspWorld, content: &str) -> StrResult<EcoStri
|
|||
|
||||
Ok(conv.replace("```example", "```typ"))
|
||||
}
|
||||
|
||||
pub(crate) fn identify_docs(kind: DocStringKind, docs: EcoString) -> StrResult<SymbolDocs> {
|
||||
match kind {
|
||||
DocStringKind::Function => Err(eco_format!("must be already handled")),
|
||||
DocStringKind::Variable => identify_var_docs(docs).map(SymbolDocs::Variable),
|
||||
DocStringKind::Constant => identify_var_docs(docs).map(SymbolDocs::Variable),
|
||||
DocStringKind::Module => identify_tidy_module_docs(docs).map(SymbolDocs::Module),
|
||||
DocStringKind::Struct => Ok(SymbolDocs::Plain { docs }),
|
||||
DocStringKind::Reference => Ok(SymbolDocs::Plain { docs }),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ impl StatefulRequest for GotoDefinitionRequest {
|
|||
let deref_target = ctx.deref_syntax_at(&source, self.position, 1)?;
|
||||
let origin_selection_range = ctx.to_lsp_range(deref_target.node().range(), &source);
|
||||
|
||||
let def = ctx.definition(&source, doc.as_ref(), deref_target)?;
|
||||
let def = ctx.def_of_syntax(&source, doc.as_ref(), deref_target)?;
|
||||
|
||||
let (fid, def_range) = def.def_at(ctx.shared())?;
|
||||
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
use core::fmt;
|
||||
use core::fmt::Write;
|
||||
|
||||
use typst_shim::syntax::LinkedNodeExt;
|
||||
|
||||
use crate::{
|
||||
analysis::{get_link_exprs_in, Definition},
|
||||
docs::SignatureDocs,
|
||||
docs::DefDocs,
|
||||
jump_from_cursor,
|
||||
prelude::*,
|
||||
syntax::{find_docs_before, get_deref_target, Decl},
|
||||
syntax::{get_deref_target, Decl, DefKind},
|
||||
ty::PathPreference,
|
||||
upstream::{expr_tooltip, plain_docs_sentence, route_of_value, truncated_repr, Tooltip},
|
||||
upstream::{expr_tooltip, route_of_value, truncated_repr, Tooltip},
|
||||
LspHoverContents, StatefulRequest,
|
||||
};
|
||||
|
||||
|
@ -223,10 +223,8 @@ fn def_tooltip(
|
|||
cursor: usize,
|
||||
) -> Option<LspHoverContents> {
|
||||
let leaf = LinkedNode::new(source.root()).leaf_at_compat(cursor)?;
|
||||
|
||||
let deref_target = get_deref_target(leaf.clone(), cursor)?;
|
||||
|
||||
let def = ctx.definition(source, document, deref_target.clone())?;
|
||||
let def = ctx.def_of_syntax(source, document, deref_target.clone())?;
|
||||
|
||||
let mut results = vec![];
|
||||
let mut actions = vec![];
|
||||
|
@ -250,76 +248,66 @@ fn def_tooltip(
|
|||
|
||||
Some(LspHoverContents::Array(results))
|
||||
}
|
||||
Func(..) | Closure(..) => {
|
||||
let sig = ctx.signature_docs(&def);
|
||||
_ => {
|
||||
let sym_docs = ctx.def_docs(&def);
|
||||
|
||||
results.push(MarkedString::LanguageString(LanguageString {
|
||||
language: "typc".to_owned(),
|
||||
value: format!(
|
||||
"let {name}{params}{result};",
|
||||
name = def.name(),
|
||||
params = ParamTooltip(sig.as_ref()),
|
||||
result =
|
||||
ResultTooltip(def.name(), sig.as_ref().and_then(|sig| sig.ret_ty.as_ref()))
|
||||
),
|
||||
}));
|
||||
|
||||
if let Some(doc) = sig {
|
||||
results.push(MarkedString::String(doc.def_docs().into()));
|
||||
}
|
||||
|
||||
if let Some(link) = ExternalDocLink::get(ctx, &def) {
|
||||
actions.push(link);
|
||||
}
|
||||
|
||||
render_actions(&mut results, actions);
|
||||
Some(LspHoverContents::Array(results))
|
||||
}
|
||||
ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
|
||||
let id = def.decl.file_id()?;
|
||||
let src = ctx.source_by_id(id).ok()?;
|
||||
let ei = ctx.expr_stage(&src);
|
||||
let docs = ei.module_docstring.docs.clone()?;
|
||||
results.push(MarkedString::String(docs.as_str().into()));
|
||||
Some(LspHoverContents::Array(results))
|
||||
}
|
||||
IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => {
|
||||
let deref_node = deref_target.node();
|
||||
let sig = ctx.variable_docs(deref_target.node());
|
||||
|
||||
// todo: check sensible length, value highlighting
|
||||
if let Some(values) = expr_tooltip(ctx.world(), deref_node) {
|
||||
match values {
|
||||
Tooltip::Text(values) => {
|
||||
results.push(MarkedString::String(values.into()));
|
||||
}
|
||||
Tooltip::Code(values) => {
|
||||
results.push(MarkedString::LanguageString(LanguageString {
|
||||
language: "typc".to_owned(),
|
||||
value: values.into(),
|
||||
}));
|
||||
if matches!(def.decl.kind(), DefKind::Variable | DefKind::Constant) {
|
||||
// todo: check sensible length, value highlighting
|
||||
if let Some(values) = expr_tooltip(ctx.world(), deref_target.node()) {
|
||||
match values {
|
||||
Tooltip::Text(values) => {
|
||||
results.push(MarkedString::String(values.into()));
|
||||
}
|
||||
Tooltip::Code(values) => {
|
||||
results.push(MarkedString::LanguageString(LanguageString {
|
||||
language: "typc".to_owned(),
|
||||
value: values.into(),
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
results.push(MarkedString::LanguageString(LanguageString {
|
||||
language: "typc".to_owned(),
|
||||
value: format!(
|
||||
"let {name}{result};",
|
||||
name = def.name(),
|
||||
result = ResultTooltip(
|
||||
def.name(),
|
||||
sig.as_ref().and_then(|sig| sig.return_ty.as_ref())
|
||||
)
|
||||
),
|
||||
}));
|
||||
// todo: hover with `with_stack`
|
||||
|
||||
if let Some(doc) = sig {
|
||||
results.push(MarkedString::String(doc.def_docs().clone()));
|
||||
} else if let Some(doc) = DocTooltip::get(ctx, &def) {
|
||||
results.push(MarkedString::String(doc));
|
||||
if matches!(
|
||||
def.decl.kind(),
|
||||
DefKind::Function | DefKind::Variable | DefKind::Constant
|
||||
) && !def.name().is_empty()
|
||||
{
|
||||
results.push(MarkedString::LanguageString(LanguageString {
|
||||
language: "typc".to_owned(),
|
||||
value: {
|
||||
let mut type_doc = String::new();
|
||||
type_doc.push_str("let ");
|
||||
type_doc.push_str(def.name());
|
||||
|
||||
match &sym_docs {
|
||||
Some(DefDocs::Variable(docs)) => {
|
||||
push_result_ty(def.name(), docs.return_ty.as_ref(), &mut type_doc);
|
||||
}
|
||||
Some(DefDocs::Function(docs)) => {
|
||||
let _ = docs.print(&mut type_doc);
|
||||
push_result_ty(def.name(), docs.ret_ty.as_ref(), &mut type_doc);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
type_doc.push(';');
|
||||
type_doc
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
if let Some(doc) = sym_docs {
|
||||
results.push(MarkedString::String(doc.hover_docs().into()));
|
||||
}
|
||||
|
||||
// if let Some(doc) = sig {
|
||||
// results.push(MarkedString::String(doc.def_docs().clone()));
|
||||
// } else if let Some(doc) = DocTooltip::get(ctx, &def) {
|
||||
// results.push(MarkedString::String(doc));
|
||||
// }
|
||||
|
||||
if let Some(link) = ExternalDocLink::get(ctx, &def) {
|
||||
actions.push(link);
|
||||
}
|
||||
|
@ -327,11 +315,20 @@ fn def_tooltip(
|
|||
render_actions(&mut results, actions);
|
||||
Some(LspHoverContents::Array(results))
|
||||
}
|
||||
Pattern(..) | Docs(..) | Generated(..) | Constant(..) | ContentRef(..) | StrName(..)
|
||||
| ModuleImport(..) | Content(..) | Spread(..) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn push_result_ty(name: &str, ty_repr: Option<&(String, String)>, type_doc: &mut String) {
|
||||
let Some((short, _)) = ty_repr else {
|
||||
return;
|
||||
};
|
||||
if short == name {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = write!(type_doc, " = {short}");
|
||||
}
|
||||
|
||||
fn render_actions(results: &mut Vec<MarkedString>, actions: Vec<CommandLink>) {
|
||||
if actions.is_empty() {
|
||||
return;
|
||||
|
@ -371,33 +368,6 @@ fn render_actions(results: &mut Vec<MarkedString>, actions: Vec<CommandLink>) {
|
|||
results.push(MarkedString::String(g));
|
||||
}
|
||||
|
||||
// todo: hover with `with_stack`
|
||||
struct ParamTooltip<'a>(Option<&'a SignatureDocs>);
|
||||
|
||||
impl fmt::Display for ParamTooltip<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Some(sig) = self.0 else {
|
||||
return Ok(());
|
||||
};
|
||||
sig.print(f)
|
||||
}
|
||||
}
|
||||
|
||||
struct ResultTooltip<'a>(&'a str, Option<&'a (String, String)>);
|
||||
|
||||
impl fmt::Display for ResultTooltip<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Some((short, _)) = self.1 else {
|
||||
return Ok(());
|
||||
};
|
||||
if short == self.0 {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
write!(f, " = {short}")
|
||||
}
|
||||
}
|
||||
|
||||
struct ExternalDocLink;
|
||||
|
||||
impl ExternalDocLink {
|
||||
|
@ -452,54 +422,6 @@ impl ExternalDocLink {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DocTooltip;
|
||||
|
||||
impl DocTooltip {
|
||||
pub fn get(ctx: &mut AnalysisContext, def: &Definition) -> Option<String> {
|
||||
self::DocTooltip::get_inner(ctx, def).map(|s| "\n\n".to_owned() + &s)
|
||||
}
|
||||
|
||||
fn get_inner(ctx: &mut AnalysisContext, def: &Definition) -> Option<String> {
|
||||
let value = def.value();
|
||||
if matches!(value, Some(Value::Func(..))) {
|
||||
if let Some(builtin) = Self::builtin_func_tooltip(def) {
|
||||
return Some(plain_docs_sentence(builtin).into());
|
||||
}
|
||||
};
|
||||
|
||||
let (fid, def_range) = def.def_at(ctx.shared()).clone()?;
|
||||
|
||||
let src = ctx.source_by_id(fid).ok()?;
|
||||
find_docs_before(&src, def_range.start)
|
||||
}
|
||||
}
|
||||
|
||||
impl DocTooltip {
|
||||
fn builtin_func_tooltip(def: &Definition) -> Option<&'_ str> {
|
||||
let value = def.value();
|
||||
let Some(Value::Func(func)) = &value else {
|
||||
return None;
|
||||
};
|
||||
|
||||
use typst::foundations::func::Repr;
|
||||
let mut func = func;
|
||||
let docs = 'search: loop {
|
||||
match func.inner() {
|
||||
Repr::Native(n) => break 'search n.docs,
|
||||
Repr::Element(e) => break 'search e.docs(),
|
||||
Repr::With(w) => {
|
||||
func = &w.0;
|
||||
}
|
||||
Repr::Closure(..) => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(docs)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
@ -47,7 +47,7 @@ impl StatefulRequest for PrepareRenameRequest {
|
|||
}
|
||||
|
||||
let origin_selection_range = ctx.to_lsp_range(deref_target.node().range(), &source);
|
||||
let def = ctx.definition(&source, doc.as_ref(), deref_target.clone())?;
|
||||
let def = ctx.def_of_syntax(&source, doc.as_ref(), deref_target.clone())?;
|
||||
|
||||
let (name, range) = prepare_renaming(ctx, &deref_target, &def)?;
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ pub(crate) fn find_references(
|
|||
}
|
||||
};
|
||||
|
||||
let def = ctx.definition(source, doc, target)?;
|
||||
let def = ctx.def_of_syntax(source, doc, target)?;
|
||||
|
||||
let worker = ReferencesWorker {
|
||||
ctx: ctx.fork_for_search(),
|
||||
|
@ -103,14 +103,13 @@ impl<'a, 'w> ReferencesWorker<'a, 'w> {
|
|||
|
||||
fn file(&mut self, ref_fid: TypstFileId) -> Option<()> {
|
||||
log::debug!("references: file: {ref_fid:?}");
|
||||
let ref_source = self.ctx.ctx.source_by_id(ref_fid).ok()?;
|
||||
let expr_info = self.ctx.ctx.expr_stage(&ref_source);
|
||||
let ei = self.ctx.ctx.expr_stage_by_id(ref_fid)?;
|
||||
let uri = self.ctx.ctx.uri_for_id(ref_fid).ok()?;
|
||||
|
||||
let t = expr_info.get_refs(self.def.decl.clone());
|
||||
self.push_idents(&ref_source, &uri, t);
|
||||
let t = ei.get_refs(self.def.decl.clone());
|
||||
self.push_idents(&ei.source, &uri, t);
|
||||
|
||||
if expr_info.is_exported(&self.def.decl) {
|
||||
if ei.is_exported(&self.def.decl) {
|
||||
self.ctx.push_dependents(ref_fid);
|
||||
}
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ impl StatefulRequest for RenameRequest {
|
|||
let source = ctx.source_by_path(&self.path).ok()?;
|
||||
let deref_target = ctx.deref_syntax_at(&source, self.position, 1)?;
|
||||
|
||||
let def = ctx.definition(&source, doc.as_ref(), deref_target.clone())?;
|
||||
let def = ctx.def_of_syntax(&source, doc.as_ref(), deref_target.clone())?;
|
||||
|
||||
prepare_renaming(ctx, &deref_target, &def)?;
|
||||
|
||||
|
|
|
@ -3,9 +3,11 @@ use typst_shim::syntax::LinkedNodeExt;
|
|||
|
||||
use crate::{
|
||||
adt::interner::Interned,
|
||||
analysis::Definition,
|
||||
prelude::*,
|
||||
syntax::{get_check_target, get_deref_target, CheckTarget, ParamTarget},
|
||||
DocTooltip, LspParamInfo, SemanticRequest,
|
||||
syntax::{find_docs_before, get_check_target, get_deref_target, CheckTarget, ParamTarget},
|
||||
upstream::plain_docs_sentence,
|
||||
LspParamInfo, SemanticRequest,
|
||||
};
|
||||
|
||||
/// The [`textDocument/signatureHelp`] request is sent from the client to the
|
||||
|
@ -40,7 +42,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
|
||||
let deref_target = get_deref_target(callee, cursor)?;
|
||||
|
||||
let def_link = ctx.definition(&source, None, deref_target)?;
|
||||
let def_link = ctx.def_of_syntax(&source, None, deref_target)?;
|
||||
|
||||
let documentation = DocTooltip::get(ctx, &def_link)
|
||||
.as_deref()
|
||||
|
@ -59,7 +61,7 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
function = &inner.0;
|
||||
}
|
||||
|
||||
let sig = ctx.signature_dyn(function.clone());
|
||||
let sig = ctx.sig_of_func(function.clone());
|
||||
|
||||
log::debug!("got signature {sig:?}");
|
||||
|
||||
|
@ -145,6 +147,54 @@ impl SemanticRequest for SignatureHelpRequest {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct DocTooltip;
|
||||
|
||||
impl DocTooltip {
|
||||
pub fn get(ctx: &mut AnalysisContext, def: &Definition) -> Option<String> {
|
||||
self::DocTooltip::get_inner(ctx, def).map(|s| "\n\n".to_owned() + &s)
|
||||
}
|
||||
|
||||
fn get_inner(ctx: &mut AnalysisContext, def: &Definition) -> Option<String> {
|
||||
let value = def.value();
|
||||
if matches!(value, Some(Value::Func(..))) {
|
||||
if let Some(builtin) = Self::builtin_func_tooltip(def) {
|
||||
return Some(plain_docs_sentence(builtin).into());
|
||||
}
|
||||
};
|
||||
|
||||
let (fid, def_range) = def.def_at(ctx.shared()).clone()?;
|
||||
|
||||
let src = ctx.source_by_id(fid).ok()?;
|
||||
find_docs_before(&src, def_range.start)
|
||||
}
|
||||
}
|
||||
|
||||
impl DocTooltip {
|
||||
fn builtin_func_tooltip(def: &Definition) -> Option<&'_ str> {
|
||||
let value = def.value();
|
||||
let Some(Value::Func(func)) = &value else {
|
||||
return None;
|
||||
};
|
||||
|
||||
use typst::foundations::func::Repr;
|
||||
let mut func = func;
|
||||
let docs = 'search: loop {
|
||||
match func.inner() {
|
||||
Repr::Native(n) => break 'search n.docs,
|
||||
Repr::Element(e) => break 'search e.docs(),
|
||||
Repr::With(w) => {
|
||||
func = &w.0;
|
||||
}
|
||||
Repr::Closure(..) => {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Some(docs)
|
||||
}
|
||||
}
|
||||
|
||||
fn markdown_docs(docs: &str) -> Documentation {
|
||||
Documentation::MarkupContent(MarkupContent {
|
||||
kind: MarkupKind::Markdown,
|
||||
|
|
|
@ -2,6 +2,7 @@ use core::fmt;
|
|||
use std::{collections::BTreeMap, ops::Range};
|
||||
|
||||
use reflexo_typst::package::PackageSpec;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tinymist_derive::DeclEnum;
|
||||
use typst::{
|
||||
foundations::{Element, Func, Module, Type, Value},
|
||||
|
@ -71,6 +72,12 @@ pub enum Expr {
|
|||
Star,
|
||||
}
|
||||
impl Expr {
|
||||
pub(crate) fn repr(&self) -> EcoString {
|
||||
let mut s = EcoString::new();
|
||||
let _ = ExprFormatter::new(&mut s, true).write_expr(self);
|
||||
s
|
||||
}
|
||||
|
||||
pub(crate) fn span(&self) -> Span {
|
||||
match self {
|
||||
Expr::Decl(d) => d.span(),
|
||||
|
@ -171,6 +178,38 @@ fn select_of(source: Interned<Ty>, name: Interned<str>) -> Expr {
|
|||
Expr::Type(Ty::Select(SelectTy::new(source, name)))
|
||||
}
|
||||
|
||||
/// Kind of a definition.
|
||||
#[derive(Debug, Default, Clone, Copy, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum DefKind {
|
||||
/// A definition for some constant.
|
||||
#[default]
|
||||
Constant,
|
||||
/// A definition for some function.
|
||||
Function,
|
||||
/// A definition for some variable.
|
||||
Variable,
|
||||
/// A definition for some module.
|
||||
Module,
|
||||
/// A definition for some struct.
|
||||
Struct,
|
||||
/// A definition for some reference.
|
||||
Reference,
|
||||
}
|
||||
|
||||
impl fmt::Display for DefKind {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Constant => write!(f, "constant"),
|
||||
Self::Function => write!(f, "function"),
|
||||
Self::Variable => write!(f, "variable"),
|
||||
Self::Module => write!(f, "module"),
|
||||
Self::Struct => write!(f, "struct"),
|
||||
Self::Reference => write!(f, "reference"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type DeclExpr = Interned<Decl>;
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Hash, DeclEnum)]
|
||||
|
@ -369,6 +408,21 @@ impl Decl {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> DefKind {
|
||||
use Decl::*;
|
||||
match self {
|
||||
ModuleAlias(..) | Module(..) | PathStem(..) | ImportPath(..) | IncludePath(..) => {
|
||||
DefKind::Module
|
||||
}
|
||||
// Type(_) => DocStringKind::Struct,
|
||||
Func(..) | Closure(..) => DefKind::Function,
|
||||
Label(..) | BibEntry(..) | ContentRef(..) => DefKind::Reference,
|
||||
IdentRef(..) | ImportAlias(..) | Import(..) | Var(..) => DefKind::Variable,
|
||||
Pattern(..) | Docs(..) | Generated(..) | Constant(..) | StrName(..)
|
||||
| ModuleImport(..) | Content(..) | Spread(..) => DefKind::Constant,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_id(&self) -> Option<TypstFileId> {
|
||||
match self {
|
||||
Self::Module(ModuleDecl { fid, .. }) => Some(*fid),
|
||||
|
|
|
@ -10,10 +10,10 @@ use crate::{
|
|||
analysis::SharedContext,
|
||||
docs::{
|
||||
convert_docs, identify_func_docs, identify_tidy_module_docs, identify_var_docs,
|
||||
DocStringKind, UntypedSymbolDocs, VarDocsT,
|
||||
UntypedDefDocs, VarDocsT,
|
||||
},
|
||||
prelude::*,
|
||||
syntax::Decl,
|
||||
syntax::{Decl, DefKind},
|
||||
ty::{BuiltinTy, Interned, PackageId, SigTy, StrRef, Ty, TypeBounds, TypeVar, TypeVarBounds},
|
||||
};
|
||||
|
||||
|
@ -62,8 +62,8 @@ pub struct VarDoc {
|
|||
|
||||
impl VarDoc {
|
||||
/// Convert the variable doc to an untyped version
|
||||
pub fn to_untyped(&self) -> Arc<UntypedSymbolDocs> {
|
||||
Arc::new(UntypedSymbolDocs::Variable(VarDocsT {
|
||||
pub fn to_untyped(&self) -> Arc<UntypedDefDocs> {
|
||||
Arc::new(UntypedDefDocs::Variable(VarDocsT {
|
||||
docs: self.docs.clone(),
|
||||
return_ty: (),
|
||||
def_docs: OnceLock::new(),
|
||||
|
@ -75,7 +75,7 @@ pub(crate) fn compute_docstring(
|
|||
ctx: &Arc<SharedContext>,
|
||||
fid: TypstFileId,
|
||||
docs: String,
|
||||
kind: DocStringKind,
|
||||
kind: DefKind,
|
||||
) -> Option<DocString> {
|
||||
let checker = DocsChecker {
|
||||
fid,
|
||||
|
@ -86,12 +86,12 @@ pub(crate) fn compute_docstring(
|
|||
next_id: 0,
|
||||
};
|
||||
match kind {
|
||||
DocStringKind::Function => checker.check_func_docs(docs),
|
||||
DocStringKind::Variable => checker.check_var_docs(docs),
|
||||
DocStringKind::Module => checker.check_module_docs(docs),
|
||||
DocStringKind::Constant => None,
|
||||
DocStringKind::Struct => None,
|
||||
DocStringKind::Reference => None,
|
||||
DefKind::Function => checker.check_func_docs(docs),
|
||||
DefKind::Variable => checker.check_var_docs(docs),
|
||||
DefKind::Module => checker.check_module_docs(docs),
|
||||
DefKind::Constant => None,
|
||||
DefKind::Struct => None,
|
||||
DefKind::Reference => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,8 @@ use typst::{
|
|||
|
||||
use crate::{
|
||||
analysis::{QueryStatGuard, SharedContext},
|
||||
docs::DocStringKind,
|
||||
prelude::*,
|
||||
syntax::find_module_level_docs,
|
||||
syntax::{find_module_level_docs, DefKind},
|
||||
ty::{BuiltinTy, InsTy, Interned, Ty},
|
||||
};
|
||||
|
||||
|
@ -82,7 +81,7 @@ pub(crate) fn expr_of(
|
|||
|
||||
let module_docstring = Arc::new(
|
||||
find_module_level_docs(&source)
|
||||
.and_then(|docs| compute_docstring(&ctx, source.id(), docs, DocStringKind::Module))
|
||||
.and_then(|docs| compute_docstring(&ctx, source.id(), docs, DefKind::Module))
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
|
||||
|
@ -275,7 +274,7 @@ impl<'a> ExprWorker<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn check_docstring(&mut self, decl: &DeclExpr, kind: DocStringKind) {
|
||||
fn check_docstring(&mut self, decl: &DeclExpr, kind: DefKind) {
|
||||
if let Some(docs) = self.comment_matcher.collect() {
|
||||
let docstring = compute_docstring(&self.ctx, self.fid, docs, kind);
|
||||
if let Some(docstring) = docstring {
|
||||
|
@ -427,7 +426,7 @@ impl<'a> ExprWorker<'a> {
|
|||
|
||||
let span = p.span();
|
||||
let decl = Decl::pattern(span).into();
|
||||
self.check_docstring(&decl, DocStringKind::Variable);
|
||||
self.check_docstring(&decl, DefKind::Variable);
|
||||
let pattern = self.check_pattern(p);
|
||||
Expr::Let(Interned::new(LetExpr {
|
||||
span,
|
||||
|
@ -443,7 +442,7 @@ impl<'a> ExprWorker<'a> {
|
|||
Some(name) => Decl::func(name).into(),
|
||||
None => Decl::closure(typed.span()).into(),
|
||||
};
|
||||
self.check_docstring(&decl, DocStringKind::Function);
|
||||
self.check_docstring(&decl, DefKind::Function);
|
||||
self.resolve_as(Decl::as_def(&decl, None));
|
||||
|
||||
let (params, body) = self.with_scope(|this| {
|
||||
|
|
|
@ -21,7 +21,7 @@ use super::PackageId;
|
|||
use crate::{
|
||||
adt::{interner::impl_internable, snapshot_map},
|
||||
analysis::BuiltinTy,
|
||||
docs::UntypedSymbolDocs,
|
||||
docs::UntypedDefDocs,
|
||||
syntax::{DeclExpr, UnaryOp},
|
||||
};
|
||||
|
||||
|
@ -962,7 +962,7 @@ pub struct TypeScheme {
|
|||
/// The typing on definitions
|
||||
pub vars: FxHashMap<DeclExpr, TypeVarBounds>,
|
||||
/// The checked documentation of definitions
|
||||
pub var_docs: FxHashMap<DeclExpr, Arc<UntypedSymbolDocs>>,
|
||||
pub var_docs: FxHashMap<DeclExpr, Arc<UntypedDefDocs>>,
|
||||
/// The local binding of the type variable
|
||||
pub local_binds: snapshot_map::SnapshotMap<DeclExpr, Ty>,
|
||||
/// The typing on syntax structures
|
||||
|
|
|
@ -26,6 +26,21 @@ impl Ty {
|
|||
let mut worker = TypeDescriber::default();
|
||||
worker.describe_root(self)
|
||||
}
|
||||
|
||||
// todo: extend this cache idea for all crate?
|
||||
// #[allow(clippy::mutable_key_type)]
|
||||
// let mut describe_cache = HashMap::<Ty, String>::new();
|
||||
// let doc_ty = |ty: Option<&Ty>| {
|
||||
// let ty = ty?;
|
||||
// let short = {
|
||||
// describe_cache
|
||||
// .entry(ty.clone())
|
||||
// .or_insert_with(|| ty.describe().unwrap_or_else(||
|
||||
// "unknown".to_string())) .clone()
|
||||
// };
|
||||
|
||||
// Some((short, format!("{ty:?}")))
|
||||
// };
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -464,7 +464,7 @@ fn describe_value(ctx: &mut AnalysisContext, v: &Value) -> EcoString {
|
|||
f = &with_f.0;
|
||||
}
|
||||
|
||||
let sig = ctx.signature_dyn(f.clone());
|
||||
let sig = ctx.sig_of_func(f.clone());
|
||||
sig.primary()
|
||||
.ty()
|
||||
.describe()
|
||||
|
@ -582,7 +582,7 @@ pub fn param_completions<'a>(
|
|||
let pos_index =
|
||||
param_index_at_leaf(&ctx.leaf, &func, args).map(|i| if this.is_some() { i + 1 } else { i });
|
||||
|
||||
let signature = ctx.ctx.signature_dyn(func.clone());
|
||||
let signature = ctx.ctx.sig_of_func(func.clone());
|
||||
|
||||
let leaf_type = ctx.ctx.literal_type_of_node(ctx.leaf.clone());
|
||||
log::debug!("pos_param_completion_by_type: {:?}", leaf_type);
|
||||
|
@ -998,7 +998,7 @@ pub fn named_param_value_completions<'a>(
|
|||
func = f.0.clone();
|
||||
}
|
||||
|
||||
let signature = ctx.ctx.signature_dyn(func.clone());
|
||||
let signature = ctx.ctx.sig_of_func(func.clone());
|
||||
|
||||
let primary_sig = signature.primary();
|
||||
|
||||
|
|
|
@ -424,11 +424,6 @@ pub fn truncated_repr(value: &Value) -> EcoString {
|
|||
truncated_repr_::<_10MB>(value)
|
||||
}
|
||||
|
||||
pub fn truncated_doc_repr(value: &Value) -> EcoString {
|
||||
const _128B: usize = 128;
|
||||
truncated_repr_::<_128B>(value)
|
||||
}
|
||||
|
||||
/// Run a function with a VM instance in the world
|
||||
pub fn with_vm<T>(world: Tracked<dyn World + '_>, f: impl FnOnce(&mut typst::eval::Vm) -> T) -> T {
|
||||
use comemo::Track;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue