1use super::TextModel;
2use crate::sys::{
3 editor::{
4 self,
5 BuiltinTheme,
6 ConfigurationChangedEvent,
7 EditorLayoutInfo,
8 IContentSizeChangedEvent,
9 ICursorPositionChangedEvent,
10 ICursorSelectionChangedEvent,
11 IDimension,
12 IEditorMouseEvent,
13 IModelChangedEvent,
14 IModelContentChangedEvent,
15 IModelLanguageChangedEvent,
16 IModelOptionsChangedEvent,
17 IPasteEvent,
18 IStandaloneCodeEditor,
19 IStandaloneEditorConstructionOptions,
20 },
21 IKeyboardEvent,
22 IScrollEvent,
23};
24use std::borrow::Borrow;
25use wasm_bindgen::JsValue;
26use web_sys::HtmlElement;
27
28pub fn set_global_theme(theme: &str) {
30 editor::set_theme(theme);
31}
32
33pub fn set_global_builtin_theme(theme: BuiltinTheme) {
35 set_global_theme(theme.to_value())
36}
37
38macro_rules! simple_setters {
39 ($target:ident => ) => {};
40 ($target:ident => ref $key:ident, $($tail:tt)*) => {
41 ::paste::paste! {
42 $target.[<set_ $key>]($key.as_ref().map(|v| v.as_ref()));
43 }
44 simple_setters!($target => $($tail)*);
45 };
46 ($target:ident => $key:ident, $($tail:tt)*) => {
47 ::paste::paste! {
48 $target.[<set_ $key>](*$key);
49 }
50 simple_setters!($target => $($tail)*);
51 };
52}
53
54#[derive(Clone, Debug, Default, Eq, PartialEq)]
61pub struct CodeEditorOptions {
62 pub dimension: Option<IDimension>,
63 pub theme: Option<String>,
64 pub model: Option<TextModel>,
65 pub language: Option<String>,
66 pub value: Option<String>,
67 pub scroll_beyond_last_line: Option<bool>,
68 pub automatic_layout: Option<bool>,
69}
70impl CodeEditorOptions {
71 builder_methods! {
72 pub with dimension(IDimension);
73 pub with theme(String);
74 pub with model(TextModel);
75 pub with language(String);
76 pub with value(String);
77 pub with scroll_beyond_last_line(bool);
78 pub with automatic_layout(bool);
79 }
80
81 pub fn with_builtin_theme(self, theme: BuiltinTheme) -> Self {
82 self.with_theme(theme.to_value().to_owned())
83 }
84
85 pub fn with_new_dimension(self, width: impl Into<f64>, height: impl Into<f64>) -> Self {
86 self.with_dimension(IDimension::new(width, height))
87 }
88
89 pub fn to_sys_options(&self) -> IStandaloneEditorConstructionOptions {
91 let options = IStandaloneEditorConstructionOptions::default();
92
93 let CodeEditorOptions {
95 dimension,
96 theme,
97 model,
98 language,
99 value,
100 scroll_beyond_last_line,
101 automatic_layout,
102 } = self;
103
104 simple_setters! {
105 options =>
106 ref language,
107 ref dimension,
108 ref theme,
109 ref model,
110 ref value,
111 scroll_beyond_last_line,
112 automatic_layout,
113 }
114
115 options
116 }
117}
118
119impl From<CodeEditorOptions> for IStandaloneEditorConstructionOptions {
120 fn from(options: CodeEditorOptions) -> Self {
121 options.to_sys_options()
122 }
123}
124
125#[must_use = "editor is disposed when dropped"]
132#[derive(Debug)]
133pub struct CodeEditor {
134 js_editor: IStandaloneCodeEditor,
135}
136impl CodeEditor {
137 event_methods! {
138 pub on_context_menu(FnMut(IEditorMouseEvent));
140 pub on_did_blur_editor_text(FnMut());
142 pub on_did_blur_editor_widget(FnMut());
144 pub on_did_change_configuration(FnMut(ConfigurationChangedEvent));
146 pub on_did_change_cursor_position(FnMut(ICursorPositionChangedEvent));
148 pub on_did_change_cursor_selection(FnMut(ICursorSelectionChangedEvent));
150 pub on_did_change_model(FnMut(IModelChangedEvent));
152 pub on_did_change_model_content(FnMut(IModelContentChangedEvent));
154 pub on_did_change_model_decorations(FnMut(JsValue));
156 pub on_did_change_model_language(FnMut(IModelLanguageChangedEvent));
158 pub on_did_change_model_language_configuration(FnMut(JsValue));
160 pub on_did_change_model_options(FnMut(IModelOptionsChangedEvent));
162 pub on_did_content_size_change(FnMut(IContentSizeChangedEvent));
164 pub on_did_dispose(FnMut());
166 pub on_did_focus_editor_text(FnMut());
168 pub on_did_focus_editor_widget(FnMut());
170 pub on_did_layout_change(FnMut(EditorLayoutInfo));
172 pub on_did_paste(FnMut(IPasteEvent));
174 pub on_did_scroll_change(FnMut(IScrollEvent));
176 pub on_key_down(FnMut(IKeyboardEvent));
178 pub on_key_up(FnMut(IKeyboardEvent));
180 pub on_mouse_down(FnMut(IEditorMouseEvent));
182 pub on_mouse_leave(FnMut(IEditorMouseEvent));
184 pub on_mouse_move(FnMut(IEditorMouseEvent));
186 pub on_mouse_up(FnMut(IEditorMouseEvent));
188 }
189
190 pub fn create<OPT>(element: &HtmlElement, options: Option<OPT>) -> Self
194 where
195 OPT: Into<IStandaloneEditorConstructionOptions>,
196 {
197 #[cfg(feature = "workers")]
198 crate::workers::ensure_environment_set();
199
200 let ioptions = options.map(|x| x.into());
201 let options = ioptions.as_ref().map(Borrow::borrow);
202 let js_editor = editor::create(element, options, None);
203 Self::from(js_editor)
204 }
205
206 #[deprecated(since = "0.3.0", note = "Use `create` instead")]
210 pub fn create_with_sys_options(
211 element: &HtmlElement,
212 options: Option<IStandaloneEditorConstructionOptions>,
213 ) -> Self {
214 Self::create(element, options)
215 }
216
217 pub fn get_model(&self) -> Option<TextModel> {
219 self.js_editor.get_model().map(TextModel::from)
220 }
221
222 pub fn set_model(&self, model: &TextModel) {
228 self.js_editor.set_model(Some(model.as_ref()))
229 }
230
231 pub fn detach_model(&self) -> Option<TextModel> {
236 let model = self.get_model();
237 self.js_editor.set_model(None);
238 model
239 }
240}
241impl Drop for CodeEditor {
242 fn drop(&mut self) {
243 self.js_editor.dispose();
244 }
245}
246
247impl AsRef<IStandaloneCodeEditor> for CodeEditor {
248 fn as_ref(&self) -> &IStandaloneCodeEditor {
249 &self.js_editor
250 }
251}
252impl From<IStandaloneCodeEditor> for CodeEditor {
253 fn from(js_editor: IStandaloneCodeEditor) -> Self {
254 Self { js_editor }
255 }
256}