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, 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(EcoString),
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 /// Whether the completion may capture the right-side identifier suffix as
108 /// the first snippet argument.
109 #[serde(skip)]
110 pub capture_suffix: bool,
111 /// An optional short description, at most one sentence.
112 pub detail: Option<EcoString>,
113 /// An optional array of additional text edits that are applied when
114 /// selecting this completion. Edits must not overlap with the main edit
115 /// nor with themselves.
116 pub additional_text_edits: Option<Vec<EcoTextEdit>>,
117 /// An optional command to run when the completion is selected.
118 pub command: Option<LspCompletionCommand>,
119}
120
121/// Represents a collection of [completion items](#CompletionItem) to be
122/// presented in the editor.
123#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
124#[serde(rename_all = "camelCase")]
125pub struct CompletionList {
126 /// This list it not complete. Further typing should result in recomputing
127 /// this list.
128 pub is_incomplete: bool,
129
130 /// The completion items.
131 pub items: Vec<CompletionItem>,
132}
133
134/// Additional details for a completion item label.
135///
136/// @since 3.17.0
137#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
138#[serde(rename_all = "camelCase")]
139pub struct CompletionItemLabelDetails {
140 /// An optional string which is rendered less prominently directly after
141 /// {@link CompletionItemLabel.label label}, without any spacing. Should be
142 /// used for function signatures or type annotations.
143 #[serde(skip_serializing_if = "Option::is_none")]
144 pub detail: Option<EcoString>,
145
146 /// An optional string which is rendered less prominently after
147 /// {@link CompletionItemLabel.detail}. Should be used for fully qualified
148 /// names or file path.
149 #[serde(skip_serializing_if = "Option::is_none")]
150 pub description: Option<EcoString>,
151}
152
153impl From<EcoString> for CompletionItemLabelDetails {
154 fn from(description: EcoString) -> Self {
155 Self {
156 detail: None,
157 description: Some(description),
158 }
159 }
160}
161
162/// A textual edit applicable to a text document.
163///
164/// If n `EcoTextEdit`s are applied to a text document all text edits describe
165/// changes to the initial document version. Execution wise text edits should
166/// applied from the bottom to the top of the text document. Overlapping text
167/// edits are not supported.
168#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
169#[serde(rename_all = "camelCase")]
170pub struct EcoTextEdit {
171 /// The range of the text document to be manipulated. To insert
172 /// text into a document create a range where start === end.
173 pub range: LspRange,
174 /// The string to be inserted. For delete operations use an
175 /// empty string.
176 pub new_text: EcoString,
177}
178
179impl EcoTextEdit {
180 pub fn new(range: LspRange, new_text: EcoString) -> EcoTextEdit {
181 EcoTextEdit { range, new_text }
182 }
183}
184
185/// A textual edit with separate insert and replace ranges.
186#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
187#[serde(rename_all = "camelCase")]
188pub struct EcoInsertReplaceEdit {
189 /// The string to be inserted.
190 pub new_text: EcoString,
191 /// The range if insert mode is requested.
192 pub insert: LspRange,
193 /// The range if replace mode is requested.
194 pub replace: LspRange,
195}
196
197impl EcoInsertReplaceEdit {
198 pub fn new(insert: LspRange, replace: LspRange, new_text: EcoString) -> EcoInsertReplaceEdit {
199 EcoInsertReplaceEdit {
200 new_text,
201 insert,
202 replace,
203 }
204 }
205}
206
207/// The main edit for a completion item.
208#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
209#[serde(untagged)]
210pub enum EcoCompletionTextEdit {
211 Edit(EcoTextEdit),
212 InsertAndReplace(EcoInsertReplaceEdit),
213}
214
215impl EcoCompletionTextEdit {
216 pub fn new_text(&self) -> &EcoString {
217 match self {
218 EcoCompletionTextEdit::Edit(edit) => &edit.new_text,
219 EcoCompletionTextEdit::InsertAndReplace(edit) => &edit.new_text,
220 }
221 }
222
223 pub fn new_text_mut(&mut self) -> &mut EcoString {
224 match self {
225 EcoCompletionTextEdit::Edit(edit) => &mut edit.new_text,
226 EcoCompletionTextEdit::InsertAndReplace(edit) => &mut edit.new_text,
227 }
228 }
229}
230
231impl From<EcoTextEdit> for EcoCompletionTextEdit {
232 fn from(edit: EcoTextEdit) -> Self {
233 EcoCompletionTextEdit::Edit(edit)
234 }
235}
236
237impl From<EcoInsertReplaceEdit> for EcoCompletionTextEdit {
238 fn from(edit: EcoInsertReplaceEdit) -> Self {
239 EcoCompletionTextEdit::InsertAndReplace(edit)
240 }
241}
242
243/// Represents a completion item.
244#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)]
245#[serde(rename_all = "camelCase")]
246pub struct CompletionItem {
247 /// The label of this completion item. By default
248 /// also the text that is inserted when selecting
249 /// this completion.
250 pub label: EcoString,
251
252 /// Additional details for the label
253 ///
254 /// @since 3.17.0
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub label_details: Option<CompletionItemLabelDetails>,
257
258 /// The kind of this completion item. Based of the kind
259 /// an icon is chosen by the editor.
260 pub kind: CompletionKind,
261
262 /// A human-readable string with additional information
263 /// about this item, like type or symbol information.
264 #[serde(skip_serializing_if = "Option::is_none")]
265 pub detail: Option<EcoString>,
266
267 /// A string that should be used when comparing this item
268 /// with other items. When `falsy` the label is used
269 /// as the sort text for this item.
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub sort_text: Option<EcoString>,
272
273 /// A string that should be used when filtering a set of
274 /// completion items. When `falsy` the label is used as the
275 /// filter text for this item.
276 #[serde(skip_serializing_if = "Option::is_none")]
277 pub filter_text: Option<EcoString>,
278
279 /// A string that should be inserted into a document when selecting
280 /// this completion. When `falsy` the label is used as the insert text
281 /// for this item.
282 ///
283 /// The `insertText` is subject to interpretation by the client side.
284 /// Some tools might not take the string literally. For example
285 /// VS Code when code complete is requested in this example
286 /// `con<cursor position>` and a completion item with an `insertText` of
287 /// `console` is provided it will only insert `sole`. Therefore it is
288 /// recommended to use `textEdit` instead since it avoids additional client
289 /// side interpretation.
290 #[serde(skip_serializing_if = "Option::is_none")]
291 pub insert_text: Option<EcoString>,
292
293 /// The format of the insert text. The format applies to both the
294 /// `insertText` property and the `newText` property of a provided
295 /// `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
296 ///
297 /// @since 3.16.0
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub insert_text_format: Option<InsertTextFormat>,
300
301 /// An edit which is applied to a document when selecting
302 /// this completion. When an edit is provided the value of
303 /// insertText is ignored.
304 ///
305 /// Most editors support two different operation when accepting a completion
306 /// item. One is to insert a completion text and the other is to replace an
307 /// existing text with a completion text. Since this can usually not
308 /// predetermined by a server it can report both ranges. Clients need to
309 /// signal support for `InsertReplaceEdits` via the
310 /// `textDocument.completion.insertReplaceSupport` client capability
311 /// property.
312 ///
313 /// *Note 1:* The text edit's range as well as both ranges from a insert
314 /// replace edit must be a [single line] and they must contain the
315 /// position at which completion has been requested. *Note 2:* If an
316 /// `InsertReplaceEdit` is returned the edit's insert range must be a prefix
317 /// of the edit's replace range, that means it must be contained and
318 /// starting at the same position.
319 ///
320 /// @since 3.16.0 additional type `InsertReplaceEdit`
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub text_edit: Option<EcoCompletionTextEdit>,
323
324 /// An optional array of additional text edits that are applied when
325 /// selecting this completion. Edits must not overlap with the main edit
326 /// nor with themselves.
327 #[serde(skip_serializing_if = "Option::is_none")]
328 pub additional_text_edits: Option<Vec<EcoTextEdit>>,
329
330 /// An optional command that is executed *after* inserting this completion.
331 /// *Note* that additional modifications to the current document should
332 /// be described with the additionalTextEdits-property.
333 #[serde(skip_serializing_if = "Option::is_none")]
334 pub command: Option<LspCompletionCommand>,
335}
336
337/// Represents a reference to a command. Provides a title which will be used to
338/// represent a command in the UI. Commands are identified by a string
339/// identifier. The recommended way to handle commands is to implement
340/// their execution on the server side if the client and server provides the
341/// corresponding capabilities. Alternatively the tool extension code could
342/// handle the command. The protocol currently doesn’t specify a set of
343/// well-known commands.
344#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)]
345pub struct LspCompletionCommand {
346 /// The title of command.
347 pub title: EcoString,
348 /// The identifier of the actual command handler.
349 pub command: StrRef,
350}
351
352impl From<StrRef> for LspCompletionCommand {
353 fn from(command: StrRef) -> Self {
354 Self {
355 title: EcoString::default(),
356 command,
357 }
358 }
359}