tinymist_query/completion/
proto.rs

1use ecow::EcoString;
2use lsp_types::InsertTextFormat;
3use serde::{Deserialize, Serialize};
4
5use crate::StrRef;
6
7use super::LspRange;
8
9/// A kind of item that can be completed.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum CompletionKind {
12    /// A syntactical structure.
13    Syntax,
14    /// A function.
15    Func,
16    /// A type.
17    Type,
18    /// A function parameter.
19    Param,
20    /// A field.
21    Field,
22    /// A constant.
23    #[default]
24    Constant,
25    /// A reference.
26    Reference,
27    /// A symbol.
28    Symbol(char),
29    /// A variable.
30    Variable,
31    /// A module.
32    Module,
33    /// A file.
34    File,
35    /// A folder.
36    Folder,
37}
38
39impl From<CompletionKind> for lsp_types::CompletionItemKind {
40    fn from(value: CompletionKind) -> Self {
41        match value {
42            CompletionKind::Syntax => Self::SNIPPET,
43            CompletionKind::Func => Self::FUNCTION,
44            CompletionKind::Param => Self::VARIABLE,
45            CompletionKind::Field => Self::FIELD,
46            CompletionKind::Variable => Self::VARIABLE,
47            CompletionKind::Constant => Self::CONSTANT,
48            CompletionKind::Reference => Self::REFERENCE,
49            CompletionKind::Symbol(_) => Self::FIELD,
50            CompletionKind::Type => Self::CLASS,
51            CompletionKind::Module => Self::MODULE,
52            CompletionKind::File => Self::FILE,
53            CompletionKind::Folder => Self::FOLDER,
54        }
55    }
56}
57
58impl serde::Serialize for CompletionKind {
59    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
60    where
61        S: serde::Serializer,
62    {
63        <Self as Into<lsp_types::CompletionItemKind>>::into(*self).serialize(serializer)
64    }
65}
66
67impl<'de> serde::Deserialize<'de> for CompletionKind {
68    fn deserialize<D>(deserializer: D) -> Result<CompletionKind, D::Error>
69    where
70        D: serde::Deserializer<'de>,
71    {
72        let kind = lsp_types::CompletionItemKind::deserialize(deserializer)?;
73        Ok(match kind {
74            lsp_types::CompletionItemKind::SNIPPET => CompletionKind::Syntax,
75            lsp_types::CompletionItemKind::FUNCTION => CompletionKind::Func,
76            lsp_types::CompletionItemKind::VARIABLE => CompletionKind::Param,
77            lsp_types::CompletionItemKind::FIELD => CompletionKind::Field,
78            lsp_types::CompletionItemKind::CONSTANT => CompletionKind::Constant,
79            lsp_types::CompletionItemKind::REFERENCE => CompletionKind::Reference,
80            lsp_types::CompletionItemKind::CLASS => CompletionKind::Type,
81            lsp_types::CompletionItemKind::MODULE => CompletionKind::Module,
82            lsp_types::CompletionItemKind::FILE => CompletionKind::File,
83            lsp_types::CompletionItemKind::FOLDER => CompletionKind::Folder,
84            _ => CompletionKind::Variable,
85        })
86    }
87}
88
89/// An autocompletion option.
90#[derive(Debug, Clone, Serialize, Deserialize, Default)]
91pub struct Completion {
92    /// The kind of item this completes to.
93    pub kind: CompletionKind,
94    /// The label the completion is shown with.
95    pub label: EcoString,
96    /// The label the completion is shown with.
97    pub label_details: Option<EcoString>,
98    /// The label the completion is shown with.
99    pub sort_text: Option<EcoString>,
100    /// The composed text used for filtering.
101    pub filter_text: Option<EcoString>,
102    /// The completed version of the input, possibly described with snippet
103    /// syntax like `${lhs} + ${rhs}`.
104    ///
105    /// Should default to the `label` if `None`.
106    pub apply: Option<EcoString>,
107    /// An optional short description, at most one sentence.
108    pub detail: Option<EcoString>,
109    /// An optional array of additional text edits that are applied when
110    /// selecting this completion. Edits must not overlap with the main edit
111    /// nor with themselves.
112    pub additional_text_edits: Option<Vec<EcoTextEdit>>,
113    /// An optional command to run when the completion is selected.
114    pub command: Option<LspCompletionCommand>,
115}
116
117/// Represents a collection of [completion items](#CompletionItem) to be
118/// presented in the editor.
119#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
120#[serde(rename_all = "camelCase")]
121pub struct CompletionList {
122    /// This list it not complete. Further typing should result in recomputing
123    /// this list.
124    pub is_incomplete: bool,
125
126    /// The completion items.
127    pub items: Vec<CompletionItem>,
128}
129
130/// Additional details for a completion item label.
131///
132/// @since 3.17.0
133#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
134#[serde(rename_all = "camelCase")]
135pub struct CompletionItemLabelDetails {
136    /// An optional string which is rendered less prominently directly after
137    /// {@link CompletionItemLabel.label label}, without any spacing. Should be
138    /// used for function signatures or type annotations.
139    #[serde(skip_serializing_if = "Option::is_none")]
140    pub detail: Option<EcoString>,
141
142    /// An optional string which is rendered less prominently after
143    /// {@link CompletionItemLabel.detail}. Should be used for fully qualified
144    /// names or file path.
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub description: Option<EcoString>,
147}
148
149impl From<EcoString> for CompletionItemLabelDetails {
150    fn from(description: EcoString) -> Self {
151        Self {
152            detail: None,
153            description: Some(description),
154        }
155    }
156}
157
158/// A textual edit applicable to a text document.
159///
160/// If n `EcoTextEdit`s are applied to a text document all text edits describe
161/// changes to the initial document version. Execution wise text edits should
162/// applied from the bottom to the top of the text document. Overlapping text
163/// edits are not supported.
164#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
165#[serde(rename_all = "camelCase")]
166pub struct EcoTextEdit {
167    /// The range of the text document to be manipulated. To insert
168    /// text into a document create a range where start === end.
169    pub range: LspRange,
170    /// The string to be inserted. For delete operations use an
171    /// empty string.
172    pub new_text: EcoString,
173}
174
175impl EcoTextEdit {
176    pub fn new(range: LspRange, new_text: EcoString) -> EcoTextEdit {
177        EcoTextEdit { range, new_text }
178    }
179}
180
181/// Represents a completion item.
182#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
183#[serde(rename_all = "camelCase")]
184pub struct CompletionItem {
185    /// The label of this completion item. By default
186    /// also the text that is inserted when selecting
187    /// this completion.
188    pub label: EcoString,
189
190    /// Additional details for the label
191    ///
192    /// @since 3.17.0
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub label_details: Option<CompletionItemLabelDetails>,
195
196    /// The kind of this completion item. Based of the kind
197    /// an icon is chosen by the editor.
198    pub kind: CompletionKind,
199
200    /// A human-readable string with additional information
201    /// about this item, like type or symbol information.
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub detail: Option<EcoString>,
204
205    /// A string that should be used when comparing this item
206    /// with other items. When `falsy` the label is used
207    /// as the sort text for this item.
208    #[serde(skip_serializing_if = "Option::is_none")]
209    pub sort_text: Option<EcoString>,
210
211    /// A string that should be used when filtering a set of
212    /// completion items. When `falsy` the label is used as the
213    /// filter text for this item.
214    #[serde(skip_serializing_if = "Option::is_none")]
215    pub filter_text: Option<EcoString>,
216
217    /// A string that should be inserted into a document when selecting
218    /// this completion. When `falsy` the label is used as the insert text
219    /// for this item.
220    ///
221    /// The `insertText` is subject to interpretation by the client side.
222    /// Some tools might not take the string literally. For example
223    /// VS Code when code complete is requested in this example
224    /// `con<cursor position>` and a completion item with an `insertText` of
225    /// `console` is provided it will only insert `sole`. Therefore it is
226    /// recommended to use `textEdit` instead since it avoids additional client
227    /// side interpretation.
228    #[serde(skip_serializing_if = "Option::is_none")]
229    pub insert_text: Option<EcoString>,
230
231    /// The format of the insert text. The format applies to both the
232    /// `insertText` property and the `newText` property of a provided
233    /// `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
234    ///
235    /// @since 3.16.0
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub insert_text_format: Option<InsertTextFormat>,
238
239    /// An edit which is applied to a document when selecting
240    /// this completion. When an edit is provided the value of
241    /// insertText is ignored.
242    ///
243    /// Most editors support two different operation when accepting a completion
244    /// item. One is to insert a completion text and the other is to replace an
245    /// existing text with a completion text. Since this can usually not
246    /// predetermined by a server it can report both ranges. Clients need to
247    /// signal support for `InsertReplaceEdits` via the
248    /// `textDocument.completion.insertReplaceSupport` client capability
249    /// property.
250    ///
251    /// *Note 1:* The text edit's range as well as both ranges from a insert
252    /// replace edit must be a [single line] and they must contain the
253    /// position at which completion has been requested. *Note 2:* If an
254    /// `InsertReplaceEdit` is returned the edit's insert range must be a prefix
255    /// of the edit's replace range, that means it must be contained and
256    /// starting at the same position.
257    ///
258    /// @since 3.16.0 additional type `InsertReplaceEdit`
259    #[serde(skip_serializing_if = "Option::is_none")]
260    pub text_edit: Option<EcoTextEdit>,
261
262    /// An optional array of additional text edits that are applied when
263    /// selecting this completion. Edits must not overlap with the main edit
264    /// nor with themselves.
265    #[serde(skip_serializing_if = "Option::is_none")]
266    pub additional_text_edits: Option<Vec<EcoTextEdit>>,
267
268    /// An optional command that is executed *after* inserting this completion.
269    /// *Note* that additional modifications to the current document should
270    /// be described with the additionalTextEdits-property.
271    #[serde(skip_serializing_if = "Option::is_none")]
272    pub command: Option<LspCompletionCommand>,
273}
274
275/// Represents a reference to a command. Provides a title which will be used to
276/// represent a command in the UI. Commands are identified by a string
277/// identifier. The recommended way to handle commands is to implement
278/// their execution on the server side if the client and server provides the
279/// corresponding capabilities. Alternatively the tool extension code could
280/// handle the command. The protocol currently doesn’t specify a set of
281/// well-known commands.
282#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
283pub struct LspCompletionCommand {
284    /// The title of command.
285    pub title: EcoString,
286    /// The identifier of the actual command handler.
287    pub command: StrRef,
288}
289
290impl From<StrRef> for LspCompletionCommand {
291    fn from(command: StrRef) -> Self {
292        Self {
293            title: EcoString::default(),
294            command,
295        }
296    }
297}