Skip to main content

swls_core/feature/
completion.rs

1use bevy_ecs::{prelude::*, schedule::ScheduleLabel};
2use derive_more::{AsMut, AsRef, Deref, DerefMut};
3use tower_lsp::lsp_types::{MarkupContent, MarkupKind};
4
5use crate::lsp_types::{
6    CompletionItem, CompletionItemKind, CompletionItemLabelDetails, CompletionTextEdit,
7    Documentation, InsertTextFormat, TextEdit,
8};
9pub use crate::{
10    systems::{
11        complete_class, complete_properties, keyword_complete, prefix::defined_prefix_completion,
12    },
13    util::{token::get_current_cst_token, triple::get_current_triple},
14};
15
16/// [`ScheduleLabel`] related to the Completion schedule
17#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
18pub struct Label;
19
20/// [`Component`] indicating that the current document is handling a Completion request.
21#[derive(Component, AsRef, Deref, AsMut, DerefMut, Debug)]
22pub struct CompletionRequest(pub Vec<SimpleCompletion>);
23
24pub fn setup_schedule(world: &mut World) {
25    let mut completion = Schedule::new(Label);
26    completion.add_systems((
27        get_current_cst_token,
28        get_current_triple
29            .after(get_current_cst_token)
30            .before(generate_completions),
31        keyword_complete.after(generate_completions),
32        complete_class.after(generate_completions),
33        complete_properties.after(generate_completions),
34        // defined_prefix_completion.after(generate_completions),
35    ));
36    world.add_schedule(completion);
37}
38
39pub fn generate_completions() {}
40
41#[derive(Debug)]
42pub struct SimpleCompletion {
43    pub kind: CompletionItemKind,
44    pub label: String,
45    pub _is_snippet: bool,
46    pub _label_details: Option<CompletionItemLabelDetails>,
47    pub _documentation: Option<String>,
48    pub _sort_text: Option<String>,
49    pub _filter_text: Option<String>,
50    pub edits: Vec<TextEdit>,
51    pub _commit_char: Option<String>,
52}
53
54impl SimpleCompletion {
55    pub fn new(kind: CompletionItemKind, label: String, edit: TextEdit) -> Self {
56        Self {
57            kind,
58            label,
59            edits: vec![edit],
60            _is_snippet: false,
61            _label_details: None,
62            _documentation: None,
63            _sort_text: None,
64            _filter_text: None,
65            _commit_char: None,
66        }
67    }
68    pub fn as_snippet(mut self) -> Self {
69        self._is_snippet = true;
70        self
71    }
72
73    pub fn label_detail(mut self, detail: impl Into<String>) -> Self {
74        if let Some(ref mut t) = self._label_details {
75            t.detail = Some(detail.into());
76        } else {
77            self._label_details = Some(CompletionItemLabelDetails {
78                detail: Some(detail.into()),
79                description: None,
80            });
81        }
82        self
83    }
84
85    pub fn label_description(mut self, description: impl Into<String>) -> Self {
86        if let Some(ref mut t) = self._label_details {
87            t.description = Some(description.into());
88        } else {
89            self._label_details = Some(CompletionItemLabelDetails {
90                description: Some(description.into()),
91                detail: None,
92            });
93        }
94        self
95    }
96
97    pub fn text_edit(mut self, edit: TextEdit) -> Self {
98        self.edits.push(edit);
99        self
100    }
101
102    pub fn documentation(mut self, documentation: impl Into<String>) -> Self {
103        self._documentation = Some(documentation.into());
104        self
105    }
106
107    pub fn m_documentation<S: Into<String>>(mut self, documentation: Option<S>) -> Self {
108        self._documentation = documentation.map(|x| x.into());
109        self
110    }
111
112    pub fn sort_text(mut self, sort_text: impl Into<String>) -> Self {
113        self._sort_text = Some(sort_text.into());
114        self
115    }
116
117    pub fn filter_text(mut self, filter_text: impl Into<String>) -> Self {
118        self._filter_text = Some(filter_text.into());
119        self
120    }
121
122    pub fn commit_char(mut self, commit_char: impl Into<String>) -> Self {
123        self._commit_char = Some(commit_char.into());
124        self
125    }
126}
127
128impl Into<CompletionItem> for SimpleCompletion {
129    fn into(self) -> CompletionItem {
130        let SimpleCompletion {
131            _is_snippet: is_snippet,
132            _filter_text: filter_text,
133            _sort_text: sort_text,
134            label,
135            _label_details,
136            _documentation: documentation,
137            kind,
138            edits,
139            _commit_char: commit_char,
140        } = self;
141
142        let text_edit = edits
143            .iter()
144            .next()
145            .map(|x| CompletionTextEdit::Edit(x.clone()));
146
147        let additional_text_edits = edits.into_iter().skip(1).collect();
148
149        CompletionItem {
150            label,
151            kind: Some(kind),
152            sort_text,
153            insert_text_format: (kind == CompletionItemKind::SNIPPET || is_snippet)
154                .then_some(InsertTextFormat::SNIPPET),
155            filter_text,
156            label_details: _label_details,
157            documentation: documentation.map(|st| {
158                Documentation::MarkupContent(MarkupContent {
159                    kind: MarkupKind::Markdown,
160                    value: st,
161                })
162            }),
163            text_edit,
164            additional_text_edits: Some(additional_text_edits),
165            commit_characters: commit_char.map(|x| vec![String::from(x)]),
166            ..Default::default()
167        }
168    }
169}