1use nifty_check::elements::{self, ParamKind};
5use nifty_check::functions;
6use nifty_syntax::ast::{Item, TypedName};
7
8use crate::document::to_u32;
9use crate::project::Project;
10
11#[derive(Debug)]
12pub(crate) struct Signature {
13 pub name: String,
14 pub params: Vec<Param>,
15 pub summary: Option<&'static str>,
16}
17
18#[derive(Debug)]
19pub(crate) struct Param {
20 pub name: String,
21 pub detail: String,
23 pub positional: bool,
26 pub named: bool,
27 pub kind: Option<ParamKind>,
29}
30
31impl Signature {
32 pub(crate) fn label(&self) -> (String, Vec<[u32; 2]>) {
34 let mut label = format!("{}(", self.name);
35 let mut offsets = Vec::with_capacity(self.params.len());
36 for (index, param) in self.params.iter().enumerate() {
37 if index > 0 {
38 label.push_str(", ");
39 }
40 let start = label.encode_utf16().count();
41 label.push_str(¶m.name);
42 label.push_str(": ");
43 label.push_str(¶m.detail);
44 offsets.push([to_u32(start), to_u32(label.encode_utf16().count())]);
45 }
46 label.push(')');
47 (label, offsets)
48 }
49
50 pub(crate) fn active(&self, label: Option<&str>, positional: usize) -> Option<usize> {
53 match label {
54 Some(label) => self.params.iter().position(|param| param.name == label),
55 None => self
56 .params
57 .iter()
58 .enumerate()
59 .filter(|(_, param)| param.positional)
60 .nth(positional)
61 .map(|(index, _)| index),
62 }
63 }
64}
65
66pub(crate) fn of(project: &Project, callee: &str) -> Option<Signature> {
67 if let Some(element) = elements::element(callee) {
68 return Some(built_in(element.name, element.params, element.summary));
69 }
70 if let Some(function) = functions::function(callee) {
71 return Some(built_in(function.name, function.params, function.summary));
72 }
73 let params = project.items().find_map(|item| match item {
74 Item::Fn(decl) if decl.name.name == callee => Some(&decl.params),
75 Item::View(decl) if decl.name.name == callee => Some(&decl.params),
76 Item::Struct(decl) if decl.name.name == callee => Some(&decl.fields),
77 _ => None,
78 })?;
79 Some(Signature {
80 name: callee.to_owned(),
81 params: params
82 .iter()
83 .map(|param| declared(project, param))
84 .collect(),
85 summary: None,
86 })
87}
88
89fn built_in(name: &str, params: &[elements::Param], summary: &'static str) -> Signature {
90 Signature {
91 name: name.to_owned(),
92 params: params
93 .iter()
94 .map(|param| Param {
95 name: param.name.to_owned(),
96 detail: param.kind.describe().into_owned(),
97 positional: param.positional,
98 named: !param.positional,
99 kind: Some(param.kind),
100 })
101 .collect(),
102 summary: Some(summary),
103 }
104}
105
106fn declared(project: &Project, param: &TypedName) -> Param {
107 Param {
108 name: param.name.name.clone(),
109 detail: project.text(param.ty.span).to_owned(),
110 positional: true,
111 named: true,
112 kind: None,
113 }
114}