1 //! See `CompletionItem` structure.
5 use hir::{Documentation, Mutability};
7 use text_edit::TextEdit;
9 use crate::config::SnippetCap;
11 /// `CompletionItem` describes a single completion variant in the editor pop-up.
12 /// It is basically a POD with various properties. To construct a
13 /// `CompletionItem`, use `new` method and the `Builder` struct.
14 pub struct CompletionItem {
15 /// Used only internally in tests, to check only specific kind of
16 /// completion (postfix, keyword, reference, etc).
18 pub(crate) completion_kind: CompletionKind,
19 /// Label in the completion pop up which identifies completion.
21 /// Range of identifier that is being completed.
23 /// It should be used primarily for UI, but we also use this to convert
24 /// genetic TextEdit into LSP's completion edit (see conv.rs).
26 /// `source_range` must contain the completion offset. `insert_text` should
27 /// start with what `source_range` points to, or VSCode will filter out the
28 /// completion silently.
29 source_range: TextRange,
30 /// What happens when user selects this item.
32 /// Typically, replaces `source_range` with new identifier.
34 insert_text_format: InsertTextFormat,
36 /// What item (struct, function, etc) are we completing.
37 kind: Option<CompletionItemKind>,
39 /// Lookup is used to check if completion item indeed can complete current
42 /// That is, in `foo.bar<|>` lookup of `abracadabra` will be accepted (it
43 /// contains `bar` sub sequence), and `quux` will rejected.
44 lookup: Option<String>,
46 /// Additional info to show in the UI pop up.
47 detail: Option<String>,
48 documentation: Option<Documentation>,
50 /// Whether this item is marked as deprecated
53 /// If completing a function call, ask the editor to show parameter popup
55 trigger_call_info: bool,
57 /// Score is useful to pre select or display in better order completion items
58 score: Option<CompletionScore>,
60 /// Indicates that a reference or mutable reference to this variable is a
62 ref_match: Option<(Mutability, CompletionScore)>,
65 // We use custom debug for CompletionItem to make snapshot tests more readable.
66 impl fmt::Debug for CompletionItem {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 let mut s = f.debug_struct("CompletionItem");
69 s.field("label", &self.label()).field("source_range", &self.source_range());
70 if self.text_edit().len() == 1 {
71 let atom = &self.text_edit().iter().next().unwrap();
72 s.field("delete", &atom.delete);
73 s.field("insert", &atom.insert);
75 s.field("text_edit", &self.text_edit);
77 if let Some(kind) = self.kind().as_ref() {
78 s.field("kind", kind);
80 if self.lookup() != self.label() {
81 s.field("lookup", &self.lookup());
83 if let Some(detail) = self.detail() {
84 s.field("detail", &detail);
86 if let Some(documentation) = self.documentation() {
87 s.field("documentation", &documentation);
90 s.field("deprecated", &true);
92 if let Some(score) = &self.score {
93 s.field("score", score);
95 if self.trigger_call_info {
96 s.field("trigger_call_info", &true);
102 #[derive(Debug, Clone, Copy, Ord, PartialOrd, Eq, PartialEq)]
103 pub enum CompletionScore {
104 /// If only type match
106 /// If type and name match
110 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
111 pub enum CompletionItemKind {
133 impl CompletionItemKind {
135 pub(crate) fn tag(&self) -> &'static str {
137 CompletionItemKind::Attribute => "at",
138 CompletionItemKind::Binding => "bn",
139 CompletionItemKind::BuiltinType => "bt",
140 CompletionItemKind::Const => "ct",
141 CompletionItemKind::Enum => "en",
142 CompletionItemKind::EnumVariant => "ev",
143 CompletionItemKind::Field => "fd",
144 CompletionItemKind::Function => "fn",
145 CompletionItemKind::Keyword => "kw",
146 CompletionItemKind::Macro => "ma",
147 CompletionItemKind::Method => "me",
148 CompletionItemKind::Module => "md",
149 CompletionItemKind::Snippet => "sn",
150 CompletionItemKind::Static => "sc",
151 CompletionItemKind::Struct => "st",
152 CompletionItemKind::Trait => "tt",
153 CompletionItemKind::TypeAlias => "ta",
154 CompletionItemKind::TypeParam => "tp",
155 CompletionItemKind::UnresolvedReference => "??",
160 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
161 pub(crate) enum CompletionKind {
162 /// Parser-based keyword completion.
164 /// Your usual "complete all valid identifiers".
166 /// "Secret sauce" completions.
174 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
175 pub enum InsertTextFormat {
180 impl CompletionItem {
182 completion_kind: CompletionKind,
183 source_range: TextRange,
184 label: impl Into<String>,
186 let label = label.into();
192 insert_text_format: InsertTextFormat::PlainText,
199 trigger_call_info: None,
204 /// What user sees in pop-up in the UI.
205 pub fn label(&self) -> &str {
208 pub fn source_range(&self) -> TextRange {
212 pub fn insert_text_format(&self) -> InsertTextFormat {
213 self.insert_text_format
216 pub fn text_edit(&self) -> &TextEdit {
220 /// Short one-line additional information, like a type
221 pub fn detail(&self) -> Option<&str> {
222 self.detail.as_deref()
225 pub fn documentation(&self) -> Option<Documentation> {
226 self.documentation.clone()
228 /// What string is used for filtering.
229 pub fn lookup(&self) -> &str {
230 self.lookup.as_deref().unwrap_or(&self.label)
233 pub fn kind(&self) -> Option<CompletionItemKind> {
237 pub fn deprecated(&self) -> bool {
241 pub fn score(&self) -> Option<CompletionScore> {
245 pub fn trigger_call_info(&self) -> bool {
246 self.trigger_call_info
249 pub fn ref_match(&self) -> Option<(Mutability, CompletionScore)> {
254 /// A helper to make `CompletionItem`s.
257 pub(crate) struct Builder {
258 source_range: TextRange,
259 completion_kind: CompletionKind,
261 insert_text: Option<String>,
262 insert_text_format: InsertTextFormat,
263 detail: Option<String>,
264 documentation: Option<Documentation>,
265 lookup: Option<String>,
266 kind: Option<CompletionItemKind>,
267 text_edit: Option<TextEdit>,
268 deprecated: Option<bool>,
269 trigger_call_info: Option<bool>,
270 score: Option<CompletionScore>,
271 ref_match: Option<(Mutability, CompletionScore)>,
275 pub(crate) fn add_to(self, acc: &mut Completions) {
276 acc.add(self.build())
279 pub(crate) fn build(self) -> CompletionItem {
280 let label = self.label;
281 let text_edit = match self.text_edit {
283 None => TextEdit::replace(
285 self.insert_text.unwrap_or_else(|| label.clone()),
290 source_range: self.source_range,
292 insert_text_format: self.insert_text_format,
295 documentation: self.documentation,
298 completion_kind: self.completion_kind,
299 deprecated: self.deprecated.unwrap_or(false),
300 trigger_call_info: self.trigger_call_info.unwrap_or(false),
302 ref_match: self.ref_match,
305 pub(crate) fn lookup_by(mut self, lookup: impl Into<String>) -> Builder {
306 self.lookup = Some(lookup.into());
309 pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
310 self.label = label.into();
313 pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
314 self.insert_text = Some(insert_text.into());
317 pub(crate) fn insert_snippet(
320 snippet: impl Into<String>,
322 self.insert_text_format = InsertTextFormat::Snippet;
323 self.insert_text(snippet)
325 pub(crate) fn kind(mut self, kind: CompletionItemKind) -> Builder {
326 self.kind = Some(kind);
329 pub(crate) fn text_edit(mut self, edit: TextEdit) -> Builder {
330 self.text_edit = Some(edit);
333 pub(crate) fn snippet_edit(mut self, _cap: SnippetCap, edit: TextEdit) -> Builder {
334 self.insert_text_format = InsertTextFormat::Snippet;
338 pub(crate) fn detail(self, detail: impl Into<String>) -> Builder {
339 self.set_detail(Some(detail))
341 pub(crate) fn set_detail(mut self, detail: Option<impl Into<String>>) -> Builder {
342 self.detail = detail.map(Into::into);
346 pub(crate) fn documentation(self, docs: Documentation) -> Builder {
347 self.set_documentation(Some(docs))
349 pub(crate) fn set_documentation(mut self, docs: Option<Documentation>) -> Builder {
350 self.documentation = docs.map(Into::into);
353 pub(crate) fn set_deprecated(mut self, deprecated: bool) -> Builder {
354 self.deprecated = Some(deprecated);
357 pub(crate) fn set_score(mut self, score: CompletionScore) -> Builder {
358 self.score = Some(score);
361 pub(crate) fn trigger_call_info(mut self) -> Builder {
362 self.trigger_call_info = Some(true);
365 pub(crate) fn set_ref_match(
367 ref_match: Option<(Mutability, CompletionScore)>,
369 self.ref_match = ref_match;
374 impl<'a> Into<CompletionItem> for Builder {
375 fn into(self) -> CompletionItem {
380 /// Represents an in-progress set of completions being built.
381 #[derive(Debug, Default)]
382 pub struct Completions {
383 buf: Vec<CompletionItem>,
387 pub fn add(&mut self, item: impl Into<CompletionItem>) {
388 self.buf.push(item.into())
390 pub fn add_all<I>(&mut self, items: I)
393 I::Item: Into<CompletionItem>,
395 items.into_iter().for_each(|item| self.add(item.into()))
399 impl Into<Vec<CompletionItem>> for Completions {
400 fn into(self) -> Vec<CompletionItem> {