tinymist_query/docs/
def.rs1use std::sync::{Arc, OnceLock};
2
3use ecow::EcoString;
4use tinymist_analysis::Signature;
5use tinymist_analysis::docs::tidy::remove_list_annotations;
6use tinymist_analysis::docs::{
7 DocText, DocTextResolver, ParamDocs, SignatureDocs, VarDocs, format_ty_short,
8};
9use tinymist_analysis::ty::DocSource;
10use typst::syntax::Span;
11
12use crate::analysis::SharedContext;
13
14pub(crate) fn var_docs(ctx: &Arc<SharedContext>, pos: Span) -> Option<VarDocs> {
15 let source = ctx.source_by_id(pos.id()?).ok()?;
16 let type_info = ctx.type_check(&source);
17 let ty = type_info.type_of_span(pos)?;
18
19 let mut srcs = ty.sources();
22 srcs.sort();
23 log::debug!("check variable docs of ty: {ty:?} => {srcs:?}");
24 let doc_source = srcs.into_iter().next()?;
25
26 let simplified_ty = type_info.simplify(ty, false);
31 let return_ty = format_ty_short(Some(&simplified_ty));
32 match doc_source {
33 DocSource::Var(var) => {
34 let docs = type_info
35 .var_docs
36 .get(&var.def)
37 .map(|docstring| docstring.docs().clone());
38 Some(VarDocs {
39 docs: docs.unwrap_or_default(),
40 return_ty,
41 def_docs: OnceLock::new(),
42 })
43 }
44 DocSource::Ins(ins) => ins.syntax.as_ref().map(|src| {
45 let docs = convert_typst_docs_shared(ctx, src.doc.as_ref().into());
46 VarDocs {
47 docs,
48 return_ty,
49 def_docs: OnceLock::new(),
50 }
51 }),
52 _ => None,
53 }
54}
55
56pub(crate) fn sig_docs(ctx: &Arc<SharedContext>, sig: &Signature) -> Option<SignatureDocs> {
57 let type_sig = sig.type_sig().clone();
58 let mut resolver = ctx.as_ref();
59
60 let pos_in = sig
61 .primary()
62 .pos()
63 .iter()
64 .enumerate()
65 .map(|(idx, pos)| (pos, type_sig.pos(idx)));
66 let named_in = sig
67 .primary()
68 .named()
69 .iter()
70 .map(|param| (param, type_sig.named(¶m.name)));
71 let rest_in = sig.primary().rest().map(|x| (x, type_sig.rest_param()));
72
73 let ret_in = type_sig.body.as_ref();
74
75 let pos = pos_in
76 .map(|(param, ty)| ParamDocs::new(&mut resolver, param, ty))
77 .collect::<Vec<_>>();
78 let named = named_in
79 .map(|(param, ty)| (param.name.clone(), ParamDocs::new(&mut resolver, param, ty)))
80 .collect::<std::collections::BTreeMap<_, _>>();
81 let rest = rest_in.map(|(param, ty)| ParamDocs::new(&mut resolver, param, ty));
82
83 let ret_ty = format_ty_short(ret_in);
84
85 let docs = sig
86 .primary()
87 .docs
88 .as_ref()
89 .map(|docs| resolve_doc_text(ctx, docs))
90 .unwrap_or_default();
91
92 Some(SignatureDocs {
93 docs,
94 pos,
95 named,
96 rest,
97 ret_ty,
98 hover_docs: OnceLock::new(),
99 })
100}
101
102pub(crate) fn resolve_doc_text(ctx: &SharedContext, docs: &DocText) -> EcoString {
103 docs.get_or_init(|raw| convert_official_doc(ctx, raw.clone()))
104 .clone()
105}
106
107impl DocTextResolver for &SharedContext {
108 fn resolve_doc_text(&mut self, docs: &DocText) -> EcoString {
109 resolve_doc_text(self, docs)
110 }
111}
112
113fn convert_official_doc(ctx: &SharedContext, docs: EcoString) -> EcoString {
114 if docs.trim().is_empty() {
115 return docs;
116 }
117
118 let docs_text = DocText::official(docs.clone());
119 match crate::docs::convert_docs(ctx, &docs_text, None) {
120 Ok(converted) => {
121 let converted = remove_list_annotations(&converted);
122 ctx.remove_html(converted.trim().into())
123 }
124 Err(err) => {
125 log::warn!("failed to convert official Typst docs to Markdown: {err}");
126 ctx.remove_html(docs)
127 }
128 }
129}
130
131pub(crate) fn convert_typst_docs_shared(ctx: &SharedContext, docs: EcoString) -> EcoString {
132 if docs.trim().is_empty() {
133 return docs;
134 }
135
136 let docs_text = DocText::plain(docs.clone());
137 match crate::docs::convert_docs(ctx, &docs_text, None) {
138 Ok(converted) => {
139 let converted = remove_list_annotations(&converted);
140 ctx.remove_html(converted.trim().into())
141 }
142 Err(err) => {
143 log::warn!("failed to convert Typst docs to Markdown: {err}");
144 ctx.remove_html(docs)
145 }
146 }
147}