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#[derive(ScheduleLabel, Clone, Eq, PartialEq, Debug, Hash)]
18pub struct Label;
19
20#[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 ));
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}