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}