use super::TextModel;
use crate::sys::{
editor::{
self,
BuiltinTheme,
ConfigurationChangedEvent,
EditorLayoutInfo,
IContentSizeChangedEvent,
ICursorPositionChangedEvent,
ICursorSelectionChangedEvent,
IDimension,
IEditorMouseEvent,
IModelChangedEvent,
IModelContentChangedEvent,
IModelLanguageChangedEvent,
IModelOptionsChangedEvent,
IPasteEvent,
IStandaloneCodeEditor,
IStandaloneEditorConstructionOptions,
},
IKeyboardEvent,
IScrollEvent,
};
use std::borrow::Borrow;
use wasm_bindgen::JsValue;
use web_sys::HtmlElement;
pub fn set_global_theme(theme: &str) {
editor::set_theme(theme);
}
pub fn set_global_builtin_theme(theme: BuiltinTheme) {
set_global_theme(theme.to_value())
}
macro_rules! simple_setters {
($target:ident => ) => {};
($target:ident => ref $key:ident, $($tail:tt)*) => {
::paste::paste! {
$target.[<set_ $key>]($key.as_ref().map(|v| v.as_ref()));
}
simple_setters!($target => $($tail)*);
};
($target:ident => $key:ident, $($tail:tt)*) => {
::paste::paste! {
$target.[<set_ $key>](*$key);
}
simple_setters!($target => $($tail)*);
};
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct CodeEditorOptions {
pub dimension: Option<IDimension>,
pub theme: Option<String>,
pub model: Option<TextModel>,
pub language: Option<String>,
pub value: Option<String>,
pub scroll_beyond_last_line: Option<bool>,
pub automatic_layout: Option<bool>,
}
impl CodeEditorOptions {
builder_methods! {
pub with dimension(IDimension);
pub with theme(String);
pub with model(TextModel);
pub with language(String);
pub with value(String);
pub with scroll_beyond_last_line(bool);
pub with automatic_layout(bool);
}
pub fn with_builtin_theme(self, theme: BuiltinTheme) -> Self {
self.with_theme(theme.to_value().to_owned())
}
pub fn with_new_dimension(self, width: impl Into<f64>, height: impl Into<f64>) -> Self {
self.with_dimension(IDimension::new(width, height))
}
pub fn to_sys_options(&self) -> IStandaloneEditorConstructionOptions {
let options = IStandaloneEditorConstructionOptions::default();
let CodeEditorOptions {
dimension,
theme,
model,
language,
value,
scroll_beyond_last_line,
automatic_layout,
} = self;
simple_setters! {
options =>
ref language,
ref dimension,
ref theme,
ref model,
ref value,
scroll_beyond_last_line,
automatic_layout,
}
options
}
}
impl From<CodeEditorOptions> for IStandaloneEditorConstructionOptions {
fn from(options: CodeEditorOptions) -> Self {
options.to_sys_options()
}
}
#[must_use = "editor is disposed when dropped"]
#[derive(Debug)]
pub struct CodeEditor {
js_editor: IStandaloneCodeEditor,
}
impl CodeEditor {
event_methods! {
pub on_context_menu(FnMut(IEditorMouseEvent));
pub on_did_blur_editor_text(FnMut());
pub on_did_blur_editor_widget(FnMut());
pub on_did_change_configuration(FnMut(ConfigurationChangedEvent));
pub on_did_change_cursor_position(FnMut(ICursorPositionChangedEvent));
pub on_did_change_cursor_selection(FnMut(ICursorSelectionChangedEvent));
pub on_did_change_model(FnMut(IModelChangedEvent));
pub on_did_change_model_content(FnMut(IModelContentChangedEvent));
pub on_did_change_model_decorations(FnMut(JsValue));
pub on_did_change_model_language(FnMut(IModelLanguageChangedEvent));
pub on_did_change_model_language_configuration(FnMut(JsValue));
pub on_did_change_model_options(FnMut(IModelOptionsChangedEvent));
pub on_did_content_size_change(FnMut(IContentSizeChangedEvent));
pub on_did_dispose(FnMut());
pub on_did_focus_editor_text(FnMut());
pub on_did_focus_editor_widget(FnMut());
pub on_did_layout_change(FnMut(EditorLayoutInfo));
pub on_did_paste(FnMut(IPasteEvent));
pub on_did_scroll_change(FnMut(IScrollEvent));
pub on_key_down(FnMut(IKeyboardEvent));
pub on_key_up(FnMut(IKeyboardEvent));
pub on_mouse_down(FnMut(IEditorMouseEvent));
pub on_mouse_leave(FnMut(IEditorMouseEvent));
pub on_mouse_move(FnMut(IEditorMouseEvent));
pub on_mouse_up(FnMut(IEditorMouseEvent));
}
pub fn create<OPT>(element: &HtmlElement, options: Option<OPT>) -> Self
where
OPT: Into<IStandaloneEditorConstructionOptions>,
{
#[cfg(feature = "workers")]
crate::workers::ensure_environment_set();
let ioptions = options.map(|x| x.into());
let options = ioptions.as_ref().map(Borrow::borrow);
let js_editor = editor::create(element, options, None);
Self::from(js_editor)
}
#[deprecated(since = "0.3.0", note = "Use `create` instead")]
pub fn create_with_sys_options(
element: &HtmlElement,
options: Option<IStandaloneEditorConstructionOptions>,
) -> Self {
Self::create(element, options)
}
pub fn get_model(&self) -> Option<TextModel> {
self.js_editor.get_model().map(TextModel::from)
}
pub fn set_model(&self, model: &TextModel) {
self.js_editor.set_model(Some(model.as_ref()))
}
pub fn detach_model(&self) -> Option<TextModel> {
let model = self.get_model();
self.js_editor.set_model(None);
model
}
}
impl Drop for CodeEditor {
fn drop(&mut self) {
self.js_editor.dispose();
}
}
impl AsRef<IStandaloneCodeEditor> for CodeEditor {
fn as_ref(&self) -> &IStandaloneCodeEditor {
&self.js_editor
}
}
impl From<IStandaloneCodeEditor> for CodeEditor {
fn from(js_editor: IStandaloneCodeEditor) -> Self {
Self { js_editor }
}
}