ls_types/
completion.rs

1use serde::{Deserialize, Serialize};
2
3use crate::macros::lsp_enum;
4use crate::{
5    Command, Documentation, MarkupKind, PartialResultParams, TagSupport,
6    TextDocumentPositionParams, TextDocumentRegistrationOptions, TextEdit, WorkDoneProgressOptions,
7    WorkDoneProgressParams,
8};
9
10use crate::Range;
11use serde_json::Value;
12use std::fmt::Debug;
13
14/// Defines how to interpret the insert text in a completion item
15#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
16#[serde(transparent)]
17pub struct InsertTextFormat(i32);
18
19lsp_enum! {
20    impl InsertTextFormat {
21        const PLAIN_TEXT = 1;
22        const SNIPPET = 2;
23    }
24}
25
26/// The kind of a completion entry.
27#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
28#[serde(transparent)]
29pub struct CompletionItemKind(i32);
30
31lsp_enum! {
32    impl CompletionItemKind {
33        const TEXT = 1;
34        const METHOD = 2;
35        const FUNCTION = 3;
36        const CONSTRUCTOR = 4;
37        const FIELD = 5;
38        const VARIABLE = 6;
39        const CLASS = 7;
40        const INTERFACE = 8;
41        const MODULE = 9;
42        const PROPERTY = 10;
43        const UNIT = 11;
44        const VALUE = 12;
45        const ENUM = 13;
46        const KEYWORD = 14;
47        const SNIPPET = 15;
48        const COLOR = 16;
49        const FILE = 17;
50        const REFERENCE = 18;
51        const FOLDER = 19;
52        const ENUM_MEMBER = 20;
53        const CONSTANT = 21;
54        const STRUCT = 22;
55        const EVENT = 23;
56        const OPERATOR = 24;
57        const TYPE_PARAMETER = 25;
58    }
59}
60
61#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
62#[serde(rename_all = "camelCase")]
63pub struct CompletionItemCapability {
64    /// Client supports snippets as insert text.
65    ///
66    /// A snippet can define tab stops and placeholders with `$1`, `$2`
67    /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to
68    /// the end of the snippet. Placeholders with equal identifiers are linked,
69    /// that is typing in one will update others too.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub snippet_support: Option<bool>,
72
73    /// Client supports commit characters on a completion item.
74    #[serde(skip_serializing_if = "Option::is_none")]
75    pub commit_characters_support: Option<bool>,
76
77    /// Client supports the follow content formats for the documentation
78    /// property. The order describes the preferred format of the client.
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub documentation_format: Option<Vec<MarkupKind>>,
81
82    /// Client supports the deprecated property on a completion item.
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub deprecated_support: Option<bool>,
85
86    /// Client supports the preselect property on a completion item.
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub preselect_support: Option<bool>,
89
90    /// Client supports the tag property on a completion item. Clients supporting
91    /// tags have to handle unknown tags gracefully. Clients especially need to
92    /// preserve unknown tags when sending a completion item back to the server in
93    /// a resolve call.
94    #[serde(
95        default,
96        skip_serializing_if = "Option::is_none",
97        deserialize_with = "TagSupport::deserialize_compat"
98    )]
99    pub tag_support: Option<TagSupport<CompletionItemTag>>,
100
101    /// Client support insert replace edit to control different behavior if a
102    /// completion item is inserted in the text or should replace text.
103    ///
104    /// @since 3.16.0
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub insert_replace_support: Option<bool>,
107
108    /// Indicates which properties a client can resolve lazily on a completion
109    /// item. Before version 3.16.0 only the predefined properties `documentation`
110    /// and `details` could be resolved lazily.
111    ///
112    /// @since 3.16.0
113    #[serde(skip_serializing_if = "Option::is_none")]
114    pub resolve_support: Option<CompletionItemCapabilityResolveSupport>,
115
116    /// The client supports the `insertTextMode` property on
117    /// a completion item to override the whitespace handling mode
118    /// as defined by the client.
119    ///
120    /// @since 3.16.0
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub insert_text_mode_support: Option<InsertTextModeSupport>,
123
124    /// The client has support for completion item label
125    /// details (see also `CompletionItemLabelDetails`).
126    ///
127    /// @since 3.17.0
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub label_details_support: Option<bool>,
130}
131
132#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
133#[serde(rename_all = "camelCase")]
134pub struct CompletionItemCapabilityResolveSupport {
135    /// The properties that a client can resolve lazily.
136    pub properties: Vec<String>,
137}
138
139#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
140#[serde(rename_all = "camelCase")]
141pub struct InsertTextModeSupport {
142    pub value_set: Vec<InsertTextMode>,
143}
144
145/// How whitespace and indentation is handled during completion
146/// item insertion.
147///
148/// @since 3.16.0
149#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
150#[serde(transparent)]
151pub struct InsertTextMode(i32);
152
153lsp_enum! {
154    impl InsertTextMode {
155        /// The insertion or replace strings is taken as it is. If the
156        /// value is multi line the lines below the cursor will be
157        /// inserted using the indentation defined in the string value.
158        /// The client will not apply any kind of adjustments to the
159        /// string.
160        const AS_IS = 1;
161
162        /// The editor adjusts leading whitespace of new lines so that
163        /// they match the indentation up to the cursor of the line for
164        /// which the item is accepted.
165        ///
166        /// Consider a line like this: `<2tabs><cursor><3tabs>foo`. Accepting a
167        /// multi line completion item is indented using 2 tabs all
168        /// following lines inserted will be indented using 2 tabs as well.
169        const ADJUST_INDENTATION = 2;
170    }
171}
172
173#[derive(Clone, PartialEq, Eq, Deserialize, Serialize)]
174#[serde(transparent)]
175pub struct CompletionItemTag(i32);
176
177lsp_enum! {
178    impl CompletionItemTag {
179        const DEPRECATED = 1;
180    }
181}
182
183#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
184#[serde(rename_all = "camelCase")]
185pub struct CompletionItemKindCapability {
186    /// The completion item kind values the client supports. When this
187    /// property exists the client also guarantees that it will
188    /// handle values outside its set gracefully and falls back
189    /// to a default value when unknown.
190    ///
191    /// If this property is not present the client only supports
192    /// the completion items kinds from `Text` to `Reference` as defined in
193    /// the initial version of the protocol.
194    #[serde(skip_serializing_if = "Option::is_none")]
195    pub value_set: Option<Vec<CompletionItemKind>>,
196}
197
198#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
199#[serde(rename_all = "camelCase")]
200pub struct CompletionListCapability {
201    /// The client supports the following itemDefaults on
202    /// a completion list.
203    ///
204    /// The value lists the supported property names of the
205    /// `CompletionList.itemDefaults` object. If omitted
206    /// no properties are supported.
207    ///
208    /// @since 3.17.0
209    #[serde(skip_serializing_if = "Option::is_none")]
210    pub item_defaults: Option<Vec<String>>,
211}
212
213#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
214#[serde(rename_all = "camelCase")]
215pub struct CompletionClientCapabilities {
216    /// Whether completion supports dynamic registration.
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub dynamic_registration: Option<bool>,
219
220    /// The client supports the following `CompletionItem` specific
221    /// capabilities.
222    #[serde(skip_serializing_if = "Option::is_none")]
223    pub completion_item: Option<CompletionItemCapability>,
224
225    #[serde(skip_serializing_if = "Option::is_none")]
226    pub completion_item_kind: Option<CompletionItemKindCapability>,
227
228    /// The client supports to send additional context information for a
229    /// `textDocument/completion` request.
230    #[serde(skip_serializing_if = "Option::is_none")]
231    pub context_support: Option<bool>,
232
233    /// The client's default when the completion item doesn't provide a
234    /// `insertTextMode` property.
235    ///
236    /// @since 3.17.0
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub insert_text_mode: Option<InsertTextMode>,
239
240    /// The client supports the following `CompletionList` specific
241    /// capabilities.
242    ///
243    /// @since 3.17.0
244    #[serde(skip_serializing_if = "Option::is_none")]
245    pub completion_list: Option<CompletionListCapability>,
246}
247
248/// A special text edit to provide an insert and a replace operation.
249///
250/// @since 3.16.0
251#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
252#[serde(rename_all = "camelCase")]
253pub struct InsertReplaceEdit {
254    /// The string to be inserted.
255    pub new_text: String,
256
257    /// The range if the insert is requested
258    pub insert: Range,
259
260    /// The range if the replace is requested.
261    pub replace: Range,
262}
263
264#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
265#[serde(untagged)]
266pub enum CompletionTextEdit {
267    Edit(TextEdit),
268    InsertAndReplace(InsertReplaceEdit),
269}
270
271impl From<TextEdit> for CompletionTextEdit {
272    fn from(edit: TextEdit) -> Self {
273        Self::Edit(edit)
274    }
275}
276
277impl From<InsertReplaceEdit> for CompletionTextEdit {
278    fn from(edit: InsertReplaceEdit) -> Self {
279        Self::InsertAndReplace(edit)
280    }
281}
282
283/// Completion options.
284#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
285#[serde(rename_all = "camelCase")]
286pub struct CompletionOptions {
287    /// The server provides support to resolve additional information for a completion item.
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub resolve_provider: Option<bool>,
290
291    /// Most tools trigger completion request automatically without explicitly
292    /// requesting it using a keyboard shortcut (e.g. Ctrl+Space). Typically they
293    /// do so when the user starts to type an identifier. For example if the user
294    /// types `c` in a JavaScript file code complete will automatically pop up
295    /// present `console` besides others as a completion item. Characters that
296    /// make up identifiers don't need to be listed here.
297    ///
298    /// If code complete should automatically be trigger on characters not being
299    /// valid inside an identifier (for example `.` in JavaScript) list them in
300    /// `triggerCharacters`.
301    #[serde(skip_serializing_if = "Option::is_none")]
302    pub trigger_characters: Option<Vec<String>>,
303
304    /// The list of all possible characters that commit a completion. This field
305    /// can be used if clients don't support individual commit characters per
306    /// completion item. See client capability
307    /// `completion.completionItem.commitCharactersSupport`.
308    ///
309    /// If a server provides both `allCommitCharacters` and commit characters on
310    /// an individual completion item the ones on the completion item win.
311    ///
312    /// @since 3.2.0
313    #[serde(skip_serializing_if = "Option::is_none")]
314    pub all_commit_characters: Option<Vec<String>>,
315
316    #[serde(flatten)]
317    pub work_done_progress_options: WorkDoneProgressOptions,
318
319    /// The server supports the following `CompletionItem` specific
320    /// capabilities.
321    ///
322    /// @since 3.17.0
323    #[serde(skip_serializing_if = "Option::is_none")]
324    pub completion_item: Option<CompletionOptionsCompletionItem>,
325}
326
327#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
328#[serde(rename_all = "camelCase")]
329pub struct CompletionOptionsCompletionItem {
330    /// The server has support for completion item label
331    /// details (see also `CompletionItemLabelDetails`) when receiving
332    /// a completion item in a resolve call.
333    ///
334    /// @since 3.17.0
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub label_details_support: Option<bool>,
337}
338
339#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
340pub struct CompletionRegistrationOptions {
341    #[serde(flatten)]
342    pub text_document_registration_options: TextDocumentRegistrationOptions,
343
344    #[serde(flatten)]
345    pub completion_options: CompletionOptions,
346}
347
348#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)]
349#[serde(untagged)]
350pub enum CompletionResponse {
351    Array(Vec<CompletionItem>),
352    List(CompletionList),
353}
354
355impl From<Vec<CompletionItem>> for CompletionResponse {
356    fn from(items: Vec<CompletionItem>) -> Self {
357        Self::Array(items)
358    }
359}
360
361impl From<CompletionList> for CompletionResponse {
362    fn from(list: CompletionList) -> Self {
363        Self::List(list)
364    }
365}
366
367#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
368#[serde(rename_all = "camelCase")]
369pub struct CompletionParams {
370    // This field was "mixed-in" from TextDocumentPositionParams
371    #[serde(flatten)]
372    pub text_document_position: TextDocumentPositionParams,
373
374    #[serde(flatten)]
375    pub work_done_progress_params: WorkDoneProgressParams,
376
377    #[serde(flatten)]
378    pub partial_result_params: PartialResultParams,
379
380    // CompletionParams properties:
381    #[serde(skip_serializing_if = "Option::is_none")]
382    pub context: Option<CompletionContext>,
383}
384
385#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
386#[serde(rename_all = "camelCase")]
387pub struct CompletionContext {
388    /// How the completion was triggered.
389    pub trigger_kind: CompletionTriggerKind,
390
391    /// The trigger character (a single character) that has trigger code complete.
392    /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
393    #[serde(skip_serializing_if = "Option::is_none")]
394    pub trigger_character: Option<String>,
395}
396
397/// How a completion was triggered.
398#[derive(Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
399#[serde(transparent)]
400pub struct CompletionTriggerKind(i32);
401
402lsp_enum! {
403    impl CompletionTriggerKind {
404        const INVOKED = 1;
405        const TRIGGER_CHARACTER = 2;
406        const TRIGGER_FOR_INCOMPLETE_COMPLETIONS = 3;
407    }
408}
409
410/// Represents a collection of [completion items](#CompletionItem) to be presented
411/// in the editor.
412#[derive(Debug, PartialEq, Eq, Clone, Default, Deserialize, Serialize)]
413#[serde(rename_all = "camelCase")]
414pub struct CompletionList {
415    /// This list it not complete. Further typing should result in recomputing
416    /// this list.
417    pub is_incomplete: bool,
418
419    /// The completion items.
420    pub items: Vec<CompletionItem>,
421}
422
423#[derive(Debug, PartialEq, Eq, Default, Deserialize, Serialize, Clone)]
424#[serde(rename_all = "camelCase")]
425pub struct CompletionItem {
426    /// The label of this completion item. By default
427    /// also the text that is inserted when selecting
428    /// this completion.
429    pub label: String,
430
431    /// Additional details for the label
432    ///
433    /// @since 3.17.0
434    #[serde(skip_serializing_if = "Option::is_none")]
435    pub label_details: Option<CompletionItemLabelDetails>,
436
437    /// The kind of this completion item. Based of the kind
438    /// an icon is chosen by the editor.
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub kind: Option<CompletionItemKind>,
441
442    /// A human-readable string with additional information
443    /// about this item, like type or symbol information.
444    #[serde(skip_serializing_if = "Option::is_none")]
445    pub detail: Option<String>,
446
447    /// A human-readable string that represents a doc-comment.
448    #[serde(skip_serializing_if = "Option::is_none")]
449    pub documentation: Option<Documentation>,
450
451    /// Indicates if this item is deprecated.
452    #[serde(skip_serializing_if = "Option::is_none")]
453    pub deprecated: Option<bool>,
454
455    /// Select this item when showing.
456    #[serde(skip_serializing_if = "Option::is_none")]
457    pub preselect: Option<bool>,
458
459    /// A string that should be used when comparing this item
460    /// with other items. When `falsy` the label is used
461    /// as the sort text for this item.
462    #[serde(skip_serializing_if = "Option::is_none")]
463    pub sort_text: Option<String>,
464
465    /// A string that should be used when filtering a set of
466    /// completion items. When `falsy` the label is used as the
467    /// filter text for this item.
468    #[serde(skip_serializing_if = "Option::is_none")]
469    pub filter_text: Option<String>,
470
471    /// A string that should be inserted into a document when selecting
472    /// this completion. When `falsy` the label is used as the insert text
473    /// for this item.
474    ///
475    /// The `insertText` is subject to interpretation by the client side.
476    /// Some tools might not take the string literally. For example
477    /// VS Code when code complete is requested in this example
478    /// `con<cursor position>` and a completion item with an `insertText` of
479    /// `console` is provided it will only insert `sole`. Therefore it is
480    /// recommended to use `textEdit` instead since it avoids additional client
481    /// side interpretation.
482    #[serde(skip_serializing_if = "Option::is_none")]
483    pub insert_text: Option<String>,
484
485    /// The format of the insert text. The format applies to both the `insertText` property
486    /// and the `newText` property of a provided `textEdit`. If omitted defaults to `InsertTextFormat.PlainText`.
487    ///
488    /// @since 3.16.0
489    #[serde(skip_serializing_if = "Option::is_none")]
490    pub insert_text_format: Option<InsertTextFormat>,
491
492    /// How whitespace and indentation is handled during completion
493    /// item insertion. If not provided the client's default value depends on
494    /// the `textDocument.completion.insertTextMode` client capability.
495    ///
496    /// @since 3.16.0
497    /// @since 3.17.0 - support for `textDocument.completion.insertTextMode`
498    #[serde(skip_serializing_if = "Option::is_none")]
499    pub insert_text_mode: Option<InsertTextMode>,
500
501    /// An edit which is applied to a document when selecting
502    /// this completion. When an edit is provided the value of
503    /// insertText is ignored.
504    ///
505    /// Most editors support two different operation when accepting a completion item. One is to insert a
506
507    /// completion text and the other is to replace an existing text with a completion text. Since this can
508    /// usually not predetermined by a server it can report both ranges. Clients need to signal support for
509    /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability
510    /// property.
511    ///
512    /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a
513    /// [single line] and they must contain the position at which completion has been requested.
514    /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of
515    /// the edit's replace range, that means it must be contained and starting at the same position.
516    ///
517    /// @since 3.16.0 additional type `InsertReplaceEdit`
518    #[serde(skip_serializing_if = "Option::is_none")]
519    pub text_edit: Option<CompletionTextEdit>,
520
521    /// An optional array of additional text edits that are applied when
522    /// selecting this completion. Edits must not overlap with the main edit
523    /// nor with themselves.
524    #[serde(skip_serializing_if = "Option::is_none")]
525    pub additional_text_edits: Option<Vec<TextEdit>>,
526
527    /// An optional command that is executed *after* inserting this completion. *Note* that
528    /// additional modifications to the current document should be described with the
529    /// additionalTextEdits-property.
530    #[serde(skip_serializing_if = "Option::is_none")]
531    pub command: Option<Command>,
532
533    /// An optional set of characters that when pressed while this completion is
534    /// active will accept it first and then type that character. *Note* that all
535    /// commit characters should have `length=1` and that superfluous characters
536    /// will be ignored.
537    #[serde(skip_serializing_if = "Option::is_none")]
538    pub commit_characters: Option<Vec<String>>,
539
540    /// An data entry field that is preserved on a completion item between
541    /// a completion and a completion resolve request.
542    #[serde(skip_serializing_if = "Option::is_none")]
543    pub data: Option<Value>,
544
545    /// Tags for this completion item.
546    #[serde(skip_serializing_if = "Option::is_none")]
547    pub tags: Option<Vec<CompletionItemTag>>,
548}
549
550impl CompletionItem {
551    /// Create a `CompletionItem` with the minimum possible info (label and detail).
552    #[must_use]
553    pub fn new_simple(label: String, detail: String) -> Self {
554        Self {
555            label,
556            detail: Some(detail),
557            ..Self::default()
558        }
559    }
560}
561
562/// Additional details for a completion item label.
563///
564/// @since 3.17.0
565#[derive(Debug, PartialEq, Eq, Default, Deserialize, Serialize, Clone)]
566#[serde(rename_all = "camelCase")]
567pub struct CompletionItemLabelDetails {
568    /// An optional string which is rendered less prominently directly after
569    /// {@link CompletionItemLabel.label label}, without any spacing. Should be
570    /// used for function signatures or type annotations.
571    #[serde(skip_serializing_if = "Option::is_none")]
572    pub detail: Option<String>,
573
574    /// An optional string which is rendered less prominently after
575    /// {@link CompletionItemLabel.detail}. Should be used for fully qualified
576    /// names or file path.
577    #[serde(skip_serializing_if = "Option::is_none")]
578    pub description: Option<String>,
579}
580
581#[cfg(test)]
582mod tests {
583    use super::*;
584    use crate::tests::test_deserialization;
585
586    #[test]
587    fn test_tag_support_deserialization() {
588        let empty = CompletionItemCapability {
589            tag_support: None,
590            ..Default::default()
591        };
592        test_deserialization(r"{}", &empty);
593        test_deserialization(r#"{"tagSupport": false}"#, &empty);
594
595        let t = CompletionItemCapability {
596            tag_support: Some(TagSupport { value_set: vec![] }),
597            ..Default::default()
598        };
599        test_deserialization(r#"{"tagSupport": true}"#, &t);
600
601        let t = CompletionItemCapability {
602            tag_support: Some(TagSupport {
603                value_set: vec![CompletionItemTag::DEPRECATED],
604            }),
605            ..Default::default()
606        };
607        test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t);
608    }
609
610    #[test]
611    fn test_debug_enum() {
612        assert_eq!(format!("{:?}", CompletionItemKind::TEXT), "Text");
613        assert_eq!(
614            format!("{:?}", CompletionItemKind::TYPE_PARAMETER),
615            "TypeParameter"
616        );
617    }
618
619    #[test]
620    fn test_try_from_enum() {
621        use std::convert::TryInto;
622        assert_eq!("Text".try_into(), Ok(CompletionItemKind::TEXT));
623        assert_eq!(
624            "TypeParameter".try_into(),
625            Ok(CompletionItemKind::TYPE_PARAMETER)
626        );
627    }
628}