Skip to main content

swls_core/feature/
completion.rs

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