1use wasm_bindgen::prelude::*;
2use lsp_types::{MarkupKind as MK, Position as Pos, TextDocumentItem as TDI, Url};
3use serde_wasm_bindgen::{to_value as to_js_value, from_value as from_js_value};
4use dotrain::{js_api::MetaStore, RainDocument, Rebind};
5use super::{RainLanguageServices, LanguageServiceParams};
6
7#[wasm_bindgen]
8extern "C" {
9 #[wasm_bindgen(typescript_type = "Position")]
12 pub type Position;
13 #[wasm_bindgen(typescript_type = "TextDocumentItem")]
16 pub type TextDocumentItem;
17 #[wasm_bindgen(typescript_type = "MarkupKind")]
20 pub type MarkupKind;
21 #[wasm_bindgen(typescript_type = "Diagnostic")]
24 pub type Diagnostic;
25 #[wasm_bindgen(typescript_type = "Hover")]
28 pub type Hover;
29 #[wasm_bindgen(typescript_type = "CompletionItem")]
32 pub type CompletionItem;
33 #[wasm_bindgen(typescript_type = "SemanticTokensPartialResult")]
36 pub type SemanticTokensPartialResult;
37}
38
39#[wasm_bindgen(typescript_custom_section)]
40const LSP_TS_IMPORTS: &'static str = r#"
41import { SemanticTokensPartialResult } from "vscode-languageserver-protocol";
42import { Hover, Position, MarkupKind, Diagnostic, CompletionItem, TextDocumentItem } from "vscode-languageserver-types";
43"#;
44
45#[wasm_bindgen]
46impl RainLanguageServices {
47 #[wasm_bindgen(getter, js_name = "metaStore")]
49 pub fn js_meta_store(&self) -> MetaStore {
50 self.meta_store.clone().into()
51 }
52
53 #[wasm_bindgen(constructor)]
55 pub fn js_new(meta_store: &MetaStore) -> RainLanguageServices {
56 RainLanguageServices::new(&LanguageServiceParams {
57 meta_store: Some(meta_store.into()),
58 })
59 }
60
61 #[wasm_bindgen(js_name = "newRainDocument")]
63 pub fn js_new_rain_document(
64 &self,
65 text_document: TextDocumentItem,
66 rebinds: Option<Vec<Rebind>>,
67 ) -> RainDocument {
68 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
69 self.new_rain_document(&tdi, rebinds)
70 }
71
72 #[wasm_bindgen(js_name = "newRainDocumentAsync")]
74 pub async fn js_new_rain_document_async(
75 &self,
76 text_document: TextDocumentItem,
77 rebinds: Option<Vec<Rebind>>,
78 ) -> RainDocument {
79 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
80 self.new_rain_document_async(&tdi, rebinds).await
81 }
82
83 #[wasm_bindgen(js_name = "doValidate")]
85 pub fn js_do_validate(
86 &self,
87 text_document: TextDocumentItem,
88 related_information: bool,
89 rebinds: Option<Vec<Rebind>>,
90 ) -> Vec<Diagnostic> {
91 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
92 self.do_validate(&tdi, related_information, rebinds)
93 .iter()
94 .map(|v| Diagnostic {
95 obj: to_js_value(v).unwrap_or(JsValue::NULL),
96 })
97 .collect()
98 }
99
100 #[wasm_bindgen(js_name = "doValidateRainDocument")]
102 pub fn js_do_validate_rain_document(
103 &self,
104 rain_document: &RainDocument,
105 uri: &str,
106 related_information: bool,
107 ) -> Vec<Diagnostic> {
108 self.do_validate_rain_document(
109 rain_document,
110 &Url::parse(uri).unwrap_throw(),
111 related_information,
112 )
113 .iter()
114 .map(|v| Diagnostic {
115 obj: to_js_value(v).unwrap_or(JsValue::NULL),
116 })
117 .collect()
118 }
119
120 #[wasm_bindgen(js_name = "doValidateAsync")]
122 pub async fn js_do_validate_async(
123 &self,
124 text_document: TextDocumentItem,
125 related_information: bool,
126 rebinds: Option<Vec<Rebind>>,
127 ) -> JsValue {
128 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
129 to_js_value(
130 &self
131 .do_validate_async(&tdi, related_information, rebinds)
132 .await,
133 )
134 .unwrap_or(JsValue::NULL)
135 }
136
137 #[wasm_bindgen(js_name = "doComplete")]
139 pub fn js_do_complete(
140 &self,
141 text_document: TextDocumentItem,
142 position: Position,
143 documentation_format: Option<MarkupKind>,
144 rebinds: Option<Vec<Rebind>>,
145 ) -> Option<Vec<CompletionItem>> {
146 let pos = from_js_value::<Pos>(position.obj).unwrap_throw();
147 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
148 self.do_complete(
149 &tdi,
150 pos,
151 documentation_format.and_then(|v| from_js_value::<MK>(v.obj).ok()),
152 rebinds,
153 )
154 .map(|c| {
155 c.iter()
156 .map(|v| CompletionItem {
157 obj: to_js_value(v).unwrap_or(JsValue::NULL),
158 })
159 .collect()
160 })
161 }
162
163 #[wasm_bindgen(js_name = "doCompleteRainDocument")]
165 pub fn js_do_complete_rain_document(
166 &self,
167 rain_document: &RainDocument,
168 uri: &str,
169 position: Position,
170 documentation_format: Option<MarkupKind>,
171 ) -> Option<Vec<CompletionItem>> {
172 let pos = from_js_value::<Pos>(position.obj).unwrap_throw();
173 self.do_complete_rain_document(
174 rain_document,
175 &Url::parse(uri).unwrap_throw(),
176 pos,
177 documentation_format.and_then(|v| from_js_value::<MK>(v.obj).ok()),
178 )
179 .map(|c| {
180 c.iter()
181 .map(|v| CompletionItem {
182 obj: to_js_value(v).unwrap_or(JsValue::NULL),
183 })
184 .collect()
185 })
186 }
187
188 #[wasm_bindgen(js_name = "doHover")]
190 pub fn js_do_hover(
191 &self,
192 text_document: TextDocumentItem,
193 position: Position,
194 content_format: Option<MarkupKind>,
195 rebinds: Option<Vec<Rebind>>,
196 ) -> Option<Hover> {
197 let pos = from_js_value::<Pos>(position.obj).unwrap_throw();
198 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
199 self.do_hover(
200 &tdi,
201 pos,
202 content_format.and_then(|v| from_js_value::<MK>(v.obj).ok()),
203 rebinds,
204 )
205 .map(|v| Hover {
206 obj: to_js_value(&v).unwrap_or(JsValue::NULL),
207 })
208 }
209
210 #[wasm_bindgen(js_name = "doHoverRainDocument")]
212 pub fn js_do_hover_rain_document(
213 &self,
214 rain_document: &RainDocument,
215 position: Position,
216 content_format: Option<MarkupKind>,
217 ) -> Option<Hover> {
218 let pos = from_js_value::<Pos>(position.obj).unwrap_throw();
219 self.do_hover_rain_document(
220 rain_document,
221 pos,
222 content_format.and_then(|v| from_js_value::<MK>(v.obj).ok()),
223 )
224 .map(|v| Hover {
225 obj: to_js_value(&v).unwrap_or(JsValue::NULL),
226 })
227 }
228
229 #[wasm_bindgen(js_name = "semanticTokens")]
231 pub fn js_semantic_tokens(
232 &self,
233 text_document: TextDocumentItem,
234 semantic_token_types_index: u32,
235 semantic_token_modifiers_len: usize,
236 rebinds: Option<Vec<Rebind>>,
237 ) -> SemanticTokensPartialResult {
238 let tdi = from_js_value::<TDI>(text_document.obj).unwrap_throw();
239 SemanticTokensPartialResult {
240 obj: to_js_value(&self.semantic_tokens(
241 &tdi,
242 semantic_token_types_index,
243 semantic_token_modifiers_len,
244 rebinds,
245 ))
246 .unwrap_or(JsValue::NULL),
247 }
248 }
249
250 #[wasm_bindgen(js_name = "rainDocumentSemanticTokens")]
252 pub fn js_rain_document_semantic_tokens(
253 &self,
254 rain_document: &RainDocument,
255 semantic_token_types_index: u32,
256 semantic_token_modifiers_len: usize,
257 ) -> SemanticTokensPartialResult {
258 SemanticTokensPartialResult {
259 obj: to_js_value(&self.rain_document_semantic_tokens(
260 rain_document,
261 semantic_token_types_index,
262 semantic_token_modifiers_len,
263 ))
264 .unwrap_or(JsValue::NULL),
265 }
266 }
267}