sync_lsp/text_document/
completion.rs

1//! implementation of the `textDocument/completion` request
2//! 
3//! # Usage
4//! [`Server::on_completion`] is invoked when completion items are requested for
5//! a cursor position. As the computation of completion items can be expensive
6//! [`Server::on_resolve_completion`] may be used to resolve additional
7//! information for a completion item. Additionally, [`Server::set_completion_trigger_character`]
8//! can be used to set the characters that trigger a completion. If the client
9//! supports snippets, [`Server::snippet_support`] will return true. Otherwise,
10//! [`InsertTextFormat::Snippet`] should not be used.
11
12use crate::workspace::execute_command::{serialize_opt_command, deserialize_opt_command};
13use crate::{Server, TypeProvider};
14use crate::connection::{Callback, Endpoint};
15use serde::{Serialize, Deserialize};
16use serde_repr::{Serialize_repr, Deserialize_repr};
17use super::{TextDocumentIdentifer, TextDocumentPositionParams, Position, TextEdit};
18
19#[derive(Serialize, Clone, Debug)]
20#[serde(rename_all = "camelCase")]
21pub(crate) struct CompletionOptions {
22    resolve_provider: bool,
23    #[serde(skip_serializing_if = "Vec::is_empty")]
24    trigger_characters: Vec<String>
25}
26
27#[derive(Deserialize, Default)]
28#[serde(default, rename_all = "camelCase")]
29pub(super) struct CompletionCapabilities {
30    dynamic_registration: bool,
31    completion_item: ItemCapabilities,
32}
33
34#[derive(Deserialize, Default)]
35#[serde(default, rename_all = "camelCase")]
36struct ItemCapabilities {
37    snippet_support: bool
38}
39
40
41#[derive(Clone, Default)]
42pub(crate) struct ResolveCompletionOptions;
43
44/// A list of completion items.
45#[derive(Serialize)]
46#[serde(rename_all = "camelCase")]
47#[serde(bound = "")]
48pub struct CompletionList<T: TypeProvider> {
49    /// This may cause recomputations if set to `true`.
50    pub is_incomplete: bool,
51    /// The completion items.
52    pub items: Vec<CompletionItem<T>>,
53}
54
55/// Defines different kind of completion items.
56/// Mainly used in the ui to resolve icons.
57#[repr(i32)]
58#[derive(Serialize_repr, Deserialize_repr, Debug)]
59pub enum CompletionItemKind {
60    Text = 1,
61    Method = 2,
62    Function = 3,
63    Constructor = 4,
64    Field = 5,
65    Variable = 6,
66    Class = 7,
67    Interface = 8,
68    Module = 9,
69    Property = 10,
70    Unit = 11,
71    Value = 12,
72    Enum = 13,
73    Keyword = 14,
74    Snippet = 15,
75    Color = 16,
76    File = 17,
77    Reference = 18
78}
79
80/// Defines whether the insert text contains snippets.
81#[repr(i32)]
82#[derive(Serialize_repr, Deserialize_repr, Debug)]
83pub enum InsertTextFormat {
84    /// This completion item is plain text.
85    PlainText = 1,
86    /// **Warning:** This variant should only be used if [`Server::snippet_support`] returns true;
87    /// This completion item is a [snippet](https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md),
88    /// allowing it to define placeholders
89    /// using `$1`, `$2` and `${3:foo}`. `$0` may optionally be used to define
90    /// the final tab stop, if omitted it will default to the end of the snippet.
91    /// Equal identifiers are linked.
92    Snippet = 2
93}
94
95/// The actual completion item.
96#[derive(Serialize, Deserialize, Debug)]
97#[serde(rename_all = "camelCase")]
98pub struct CompletionItem<T: TypeProvider> {
99    /// This is shown in the ui and also applied as the edit, if
100    /// `insert_text` is not set.
101    pub label: String,
102    /// This is used to resolve the icon in the ui.
103    #[serde(default)]
104    #[serde(skip_serializing_if = "Option::is_none")]
105    pub kind: Option<CompletionItemKind>,
106    /// This is used to provide additional information.
107    #[serde(default)]
108    #[serde(skip_serializing_if = "Option::is_none")]
109    pub detail: Option<String>,
110    /// A doc-comment.
111    #[serde(default)]
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub documentation: Option<String>,
114    /// A sort text may be used to alter the sorting of this in relation to others.
115    #[serde(default)]
116    #[serde(skip_serializing_if = "Option::is_none")]
117    pub sort_text: Option<String>,
118    /// This is used to filter the completion items.
119    #[serde(default)]
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub filter_text: Option<String>,
122    /// The text to insert.
123    #[serde(default)]
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub insert_text: Option<String>,
126    /// The format of the insert text.
127    #[serde(default)]
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub insert_text_format: Option<InsertTextFormat>,
130    /// A optional edit to be applied to the document.
131    #[serde(default)]
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub text_edit: Option<TextEdit>,
134    /// An array of additional non overlapping edits.
135    #[serde(default)]
136    #[serde(skip_serializing_if = "Vec::is_empty")]
137    pub additional_text_edits: Vec<TextEdit>,
138    /// This command will be executed after inserting the completion.
139    #[serde(default)]
140    #[serde(skip_serializing_if = "Option::is_none")]
141    #[serde(serialize_with = "serialize_opt_command")]
142    #[serde(deserialize_with = "deserialize_opt_command")]
143    pub command: Option<T::Command>,
144    /// Additional data to identify this completion item.
145    pub data: T::CompletionData
146}
147
148impl CompletionOptions {
149    pub(crate) const METHOD: &'static str = "textDocument/completion";
150    
151    pub(super) fn endpoint<T: TypeProvider>() -> Endpoint<T, CompletionOptions> {
152        Endpoint::new(Callback::request(|_, _: TextDocumentPositionParams| CompletionList::<T>::default()))
153    }
154}
155
156impl ResolveCompletionOptions {
157    pub(crate) const METHOD: &'static str = "completionItem/resolve";
158
159    pub(super) fn endpoint<T: TypeProvider>() -> Endpoint<T, ResolveCompletionOptions> {
160        Endpoint::new(Callback::request(|_, item: CompletionItem<T>| item))
161    }
162}
163
164impl<T: TypeProvider> Server<T> {
165
166    /// Sets the callback that will be called to [compute completion items](self).
167    /// 
168    /// # Argument
169    /// * `callback` - A callback which is called with the following parameters as soon as completion items are requested:
170    ///     * The server instance receiving the response.
171    ///     * The [`TextDocumentIdentifer`] of the document for which completions are requested.
172    ///     * `return` - A list of completions to display.
173
174
175    pub fn on_completion(&mut self, callback: fn(&mut Server<T>, TextDocumentIdentifer, Position) -> CompletionList<T>) {
176        self.text_document.completion.set_callback(Callback::request(move |server, params: TextDocumentPositionParams| {
177            callback(server, params.text_document, params.position)
178        }));
179    }
180
181    /// Sets the callback that will be called to compute missing information on [completion items](self), which were previously returned by [`Server::on_completion`].
182    /// 
183    /// # Argument
184    /// * `callback` - A callback which is called with the following parameters as soon a completion can be resolved:
185    ///     * The server instance receiving the response.
186    ///     * The [`CompletionItem`] to resolve.
187    ///     * `return` - The resolved completion.
188
189    pub fn on_resolve_completion(&mut self, callback: fn(&mut Server<T>, CompletionItem<T>) -> CompletionItem<T>) {
190        self.text_document.resolve_completion.set_callback(Callback::request(move |server, item| {
191            callback(server, item)
192        }));
193    }
194
195    /// The client will request [completions](self) if one of the characters in `trigger_characters` is typed.
196    /// 
197    /// # Argument
198    /// * `trigger_characters` - A list of characters that trigger completion. 
199
200    pub fn set_completion_trigger_character(&mut self, trigger_characters: Vec<String>) {
201        self.text_document.completion.options_mut().trigger_characters = trigger_characters;
202    }
203
204    /// Returns whether the client supports snippets for [completion items](self).
205    /// 
206    /// # Return
207    /// * `true` if the client supports snippets, `false` otherwise.
208
209    pub fn snippet_support(&self) -> bool {
210        self.capabilities.text_document.completion.completion_item.snippet_support
211    }
212}
213
214impl Default for CompletionOptions {
215    fn default() -> Self {
216        CompletionOptions {
217            resolve_provider: true,
218            trigger_characters: Vec::new()
219        }
220    }
221}
222
223
224impl<T: TypeProvider> Default for CompletionList<T> {
225    fn default() -> Self {
226        CompletionList {
227            is_incomplete: false,
228            items: Vec::new()
229        }
230    }
231}