Quellcode durchsuchen

app: various cleanups to Editor used by BaseEdit with main one being moving from async to purely sync. other changes:

* Removed `Option` wrapper from editor
* Removed `EditorHandle` wrapper
* Changed all editor locks to synchronous
* Made all Editor methods synchronous
* Created `ParleyDriverWrapper`. This makes using the driver much easier.
darkfi vor 7 Monaten
Ursprung
Commit
38e5829196

+ 8 - 8
bin/app/src/text/editor/android.rs

@@ -73,16 +73,16 @@ impl Editor {
         }
     }
 
-    pub async fn on_text_prop_changed(&mut self) {
+    pub fn on_text_prop_changed(&mut self) {
         // Update GameTextInput state
         self.state.text = self.text.get();
         self.state.select = (0, 0);
         self.state.compose = None;
         self.input.set_state(self.state.clone());
         // Refresh our layout
-        self.refresh().await;
+        self.refresh();
     }
-    pub async fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
+    pub fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
         // Only refresh layout if text content actually changed
         // Avoid triggering expensive recomputes of layout and property tree.
         let old_text = self.text.get();
@@ -90,7 +90,7 @@ impl Editor {
             return
         }
 
-        self.refresh().await;
+        self.refresh();
         // Update the text attribute
         self.text.set(atom, &self.state.text);
     }
@@ -102,7 +102,7 @@ impl Editor {
         self.input.hide();
     }
 
-    pub async fn refresh(&mut self) {
+    pub fn refresh(&mut self) {
         let font_size = self.font_size.get();
         let text_color = self.text_color.get();
         let window_scale = self.window_scale.get();
@@ -139,7 +139,7 @@ impl Editor {
         self.input.set_select(cursor_idx, cursor_idx);
     }
 
-    pub async fn select_word_at_point(&mut self, pos: Point) {
+    pub fn select_word_at_point(&mut self, pos: Point) {
         let select = parley::Selection::word_from_point(&self.layout, pos.x, pos.y);
         assert!(!select.is_collapsed());
         let select = select.text_range();
@@ -163,7 +163,7 @@ impl Editor {
         Point::new(cursor_rect.x0 as f32, cursor_rect.y0 as f32)
     }
 
-    pub async fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
+    pub fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
         // TODO: need to verify this is correct
         // Insert text by updating the state
         self.state.text.push_str(txt);
@@ -214,7 +214,7 @@ impl Editor {
 
         parley::Selection::new(anchor, focus)
     }
-    pub async fn set_selection(&mut self, select_start: usize, select_end: usize) {
+    pub fn set_selection(&mut self, select_start: usize, select_end: usize) {
         assert!(select_start <= self.state.text.len());
         assert!(select_end <= self.state.text.len());
         assert_eq!(self.state.text, self.text.get());

+ 1 - 0
bin/app/src/text/editor/mod.rs

@@ -21,6 +21,7 @@ mod android;
 mod driver;
 #[cfg(target_os = "android")]
 pub use android::Editor;
+pub use driver::ParleyDriverWrapper;
 
 #[cfg(not(target_os = "android"))]
 mod parley;

+ 8 - 8
bin/app/src/text/editor/parley.rs

@@ -57,19 +57,19 @@ impl Editor {
     pub fn focus(&self) {}
     pub fn unfocus(&self) {}
 
-    pub async fn on_text_prop_changed(&mut self) {
+    pub fn on_text_prop_changed(&mut self) {
         // Get modified text property
         let txt = self.text.get();
         // Update Parley text buffer
         self.editor.set_text(&txt);
         // Refresh our layout
-        self.refresh().await;
+        self.refresh();
     }
-    pub async fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
+    pub fn on_buffer_changed(&mut self, atom: &mut PropertyAtomicGuard) {
         self.text.set(atom, self.editor.raw_text());
     }
 
-    pub async fn refresh(&mut self) {
+    pub fn refresh(&mut self) {
         let font_size = self.font_size.get();
         let text_color = self.text_color.get();
         let window_scale = self.window_scale.get();
@@ -99,7 +99,7 @@ impl Editor {
     pub fn move_to_pos(&self, _pos: Point) {
         unimplemented!()
     }
-    pub async fn select_word_at_point(&mut self, _pos: Point) {
+    pub fn select_word_at_point(&mut self, _pos: Point) {
         unimplemented!()
     }
 
@@ -109,9 +109,9 @@ impl Editor {
         cursor_pos
     }
 
-    pub async fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
+    pub fn insert(&mut self, txt: &str, atom: &mut PropertyAtomicGuard) {
         self.driver().insert_or_replace_selection(&txt);
-        self.on_buffer_changed(atom).await;
+        self.on_buffer_changed(atom);
     }
 
     pub fn driver(&mut self) -> ParleyDriverWrapper {
@@ -137,7 +137,7 @@ impl Editor {
     }
     /// Android uses byte indexes whereas parley has its own things. So this API is a compromise
     /// between them both.
-    pub async fn set_selection(&mut self, select_start: usize, select_end: usize) {
+    pub fn set_selection(&mut self, select_start: usize, select_end: usize) {
         self.driver().select_byte_range(select_start, select_end);
     }
 

+ 6 - 2
bin/app/src/text/mod.rs

@@ -16,14 +16,18 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use std::{cell::RefCell, ops::Range, sync::{Arc, LazyLock}};
 use parley::fontique::{Collection, CollectionOptions, SourceCache, SourceCacheOptions};
+use std::{
+    cell::RefCell,
+    ops::Range,
+    sync::{Arc, LazyLock},
+};
 
 use crate::{mesh::Color, util::spawn_thread};
 
 pub mod atlas;
 mod editor;
-pub use editor::Editor;
+pub use editor::{Editor, ParleyDriverWrapper};
 mod render;
 pub use render::{render_layout, render_layout_with_opts, DebugRenderOptions};
 

+ 9 - 24
bin/app/src/ui/edit/behave.rs

@@ -15,7 +15,6 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use async_lock::Mutex as AsyncMutex;
 use async_trait::async_trait;
 use atomic_float::AtomicF32;
 use parking_lot::Mutex as SyncMutex;
@@ -27,8 +26,6 @@ use crate::{
     text::Editor,
 };
 
-use super::EditorHandle;
-
 //macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::edit::behave", $($arg)*); } }
 
 pub enum BaseEditType {
@@ -87,17 +84,12 @@ pub(super) struct MultiLine {
     pub padding: PropertyPtr,
     pub cursor_descent: PropertyFloat32,
     pub parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
-    pub editor: Arc<AsyncMutex<Option<Editor>>>,
+    pub editor: Arc<SyncMutex<Editor>>,
     pub content_height: AtomicF32,
     pub scroll: Arc<AtomicF32>,
 }
 
 impl MultiLine {
-    /// Lazy-initializes the editor and returns a handle to it
-    async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
-        EditorHandle { guard: self.editor.lock().await }
-    }
-
     fn bounded_height(&self, height: f32) -> f32 {
         height.clamp(self.min_height.get(), self.max_height.get())
     }
@@ -112,7 +104,7 @@ impl MultiLine {
     /// Gets the real cursor pos within the rect.
     async fn get_cursor_pos(&self) -> Point {
         // This is the position within the content.
-        let cursor_pos = self.lock_editor().await.get_cursor_pos();
+        let cursor_pos = self.editor.lock().get_cursor_pos();
         // Apply the inner padding
         cursor_pos + self.inner_pos()
     }
@@ -140,9 +132,9 @@ impl EditorBehavior for MultiLine {
         // Use the width to adjust the height calcs
         let rect_w = self.rect.get_width() - pad_left - pad_right;
         let content_height = {
-            let mut editor = self.lock_editor().await;
+            let mut editor = self.editor.lock();
             editor.set_width(rect_w);
-            editor.refresh().await;
+            editor.refresh();
             editor.height()
         };
         self.content_height.store(content_height, Ordering::Relaxed);
@@ -242,24 +234,17 @@ pub(super) struct SingleLine {
     pub padding: PropertyPtr,
     pub cursor_width: PropertyFloat32,
     pub parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
-    pub editor: Arc<AsyncMutex<Option<Editor>>>,
+    pub editor: Arc<SyncMutex<Editor>>,
     pub content_height: AtomicF32,
     pub scroll: Arc<AtomicF32>,
 }
 
-impl SingleLine {
-    /// Lazy-initializes the editor and returns a handle to it
-    async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
-        EditorHandle { guard: self.editor.lock().await }
-    }
-}
-
 #[async_trait]
 impl EditorBehavior for SingleLine {
     async fn eval_rect(&self, atom: &mut PropertyAtomicGuard) {
         let content_height = {
-            let mut editor = self.lock_editor().await;
-            editor.refresh().await;
+            let mut editor = self.editor.lock();
+            editor.refresh();
             editor.height()
         };
         self.content_height.store(content_height, Ordering::Relaxed);
@@ -283,7 +268,7 @@ impl EditorBehavior for SingleLine {
         let pad_left = self.padding.get_f32(3).unwrap();
         let scroll = self.scroll.load(Ordering::Relaxed);
         let rect_w = self.rect.get_width() - pad_right;
-        let cursor_x0 = self.lock_editor().await.get_cursor_pos().x + pad_left;
+        let cursor_x0 = self.editor.lock().get_cursor_pos().x + pad_left;
         let cursor_x1 = cursor_x0 + self.cursor_width.get();
 
         if cursor_x0 < scroll {
@@ -304,7 +289,7 @@ impl EditorBehavior for SingleLine {
         let pad_right = self.padding.get_f32(1).unwrap();
         let pad_left = self.padding.get_f32(3).unwrap();
         let rect_w = self.rect.get_width();
-        let content_w = self.lock_editor().await.width() + self.cursor_width.get();
+        let content_w = self.editor.lock().width() + self.cursor_width.get();
         (pad_left + pad_right + content_w - rect_w).max(0.)
     }
 

+ 123 - 169
bin/app/src/ui/edit/mod.rs

@@ -16,7 +16,6 @@
  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  */
 
-use async_lock::Mutex as AsyncMutex;
 use async_trait::async_trait;
 use atomic_float::AtomicF32;
 use darkfi::system::msleep;
@@ -179,23 +178,6 @@ impl std::fmt::Debug for Editor {
 }
 */
 
-struct EditorHandle<'a> {
-    guard: async_lock::MutexGuard<'a, Option<Editor>>,
-}
-
-impl<'a> Deref for EditorHandle<'a> {
-    type Target = Editor;
-
-    fn deref(&self) -> &Self::Target {
-        self.guard.as_ref().unwrap()
-    }
-}
-impl<'a> DerefMut for EditorHandle<'a> {
-    fn deref_mut(&mut self) -> &mut Self::Target {
-        self.guard.as_mut().unwrap()
-    }
-}
-
 pub type BaseEditPtr = Arc<BaseEdit>;
 
 pub struct BaseEdit {
@@ -258,7 +240,7 @@ pub struct BaseEdit {
     parent_rect: Arc<SyncMutex<Option<Rectangle>>>,
     is_mouse_hover: AtomicBool,
 
-    editor: Arc<AsyncMutex<Option<Editor>>>,
+    editor: Arc<SyncMutex<Editor>>,
     behave: Box<dyn EditorBehavior>,
 }
 
@@ -309,8 +291,16 @@ impl BaseEdit {
         let debug = PropertyBool::wrap(node_ref, Role::Internal, "debug", 0).unwrap();
 
         let parent_rect = Arc::new(SyncMutex::new(None));
-        let editor = Arc::new(AsyncMutex::new(None));
         let scroll = Arc::new(AtomicF32::new(0.));
+
+        let editor = Arc::new(SyncMutex::new(Editor::new(
+            text.clone(),
+            font_size.clone(),
+            text_color.clone(),
+            window_scale.clone(),
+            lineheight.clone(),
+        )));
+
         let behave: Box<dyn EditorBehavior> = match edit_type {
             BaseEditType::SingleLine => Box::new(SingleLine {
                 rect: rect.clone(),
@@ -420,16 +410,11 @@ impl BaseEdit {
     /// Gets the real cursor pos within the rect.
     async fn get_cursor_pos(&self) -> Point {
         // This is the position within the content.
-        let cursor_pos = self.lock_editor().await.get_cursor_pos();
+        let cursor_pos = self.editor.lock().get_cursor_pos();
         // Apply the inner padding
         cursor_pos + self.behave.inner_pos()
     }
 
-    /// Lazy-initializes the editor and returns a handle to it
-    async fn lock_editor<'a>(&'a self) -> EditorHandle<'a> {
-        EditorHandle { guard: self.editor.lock().await }
-    }
-
     fn regen_cursor_mesh(&self) -> DrawMesh {
         let cursor_width = self.cursor_width.get();
         let cursor_ascent = self.cursor_ascent.get();
@@ -516,7 +501,7 @@ impl BaseEdit {
         match key {
             'a' => {
                 if action_mod {
-                    let mut editor = self.lock_editor().await;
+                    let mut editor = self.editor.lock();
                     editor.driver().select_all();
                     if let Some(seltext) = editor.selected_text() {
                         self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
@@ -525,7 +510,7 @@ impl BaseEdit {
             }
             'c' => {
                 if action_mod {
-                    let editor = self.lock_editor().await;
+                    let editor = self.editor.lock();
                     if let Some(txt) = editor.selected_text() {
                         miniquad::window::clipboard_set(&txt);
                     }
@@ -534,7 +519,7 @@ impl BaseEdit {
             'v' => {
                 if action_mod {
                     if let Some(txt) = miniquad::window::clipboard_get() {
-                        self.insert(&txt, atom).await;
+                        self.editor.lock().insert(&txt, atom);
                         // Maybe insert should call this?
                         self.behave.apply_cursor_scroll().await;
                     }
@@ -556,135 +541,132 @@ impl BaseEdit {
     ) -> bool {
         #[cfg(not(target_os = "macos"))]
         let action_mod = mods.ctrl;
-
         #[cfg(target_os = "macos")]
         let action_mod = mods.logo;
 
         t!("handle_key({:?}, {:?}) action_mod={action_mod}", key, mods);
-
-        let mut editor = self.lock_editor().await;
-
-        match key {
-            KeyCode::Left => {
-                if action_mod {
-                    if mods.shift {
-                        editor.driver().select_word_left();
+        {
+            let mut editor = self.editor.lock();
+            match key {
+                KeyCode::Left => {
+                    if action_mod {
+                        if mods.shift {
+                            editor.driver().select_word_left();
+                        } else {
+                            editor.driver().move_word_left();
+                        }
+                    } else if mods.shift {
+                        editor.driver().select_left();
                     } else {
-                        editor.driver().move_word_left();
+                        editor.driver().move_left();
                     }
-                } else if mods.shift {
-                    editor.driver().select_left();
-                } else {
-                    editor.driver().move_left();
                 }
-            }
-            KeyCode::Right => {
-                if action_mod {
-                    if mods.shift {
-                        editor.driver().select_word_right();
+                KeyCode::Right => {
+                    if action_mod {
+                        if mods.shift {
+                            editor.driver().select_word_right();
+                        } else {
+                            editor.driver().move_word_right();
+                        }
+                    } else if mods.shift {
+                        editor.driver().select_right();
                     } else {
-                        editor.driver().move_word_right();
+                        editor.driver().move_right();
                     }
-                } else if mods.shift {
-                    editor.driver().select_right();
-                } else {
-                    editor.driver().move_right();
                 }
-            }
-            KeyCode::Up => {
-                if mods.shift {
-                    editor.driver().select_up();
-                } else {
-                    editor.driver().move_up();
+                KeyCode::Up => {
+                    if mods.shift {
+                        editor.driver().select_up();
+                    } else {
+                        editor.driver().move_up();
+                    }
                 }
-            }
-            KeyCode::Down => {
-                if mods.shift {
-                    editor.driver().select_down();
-                } else {
-                    editor.driver().move_down();
+                KeyCode::Down => {
+                    if mods.shift {
+                        editor.driver().select_down();
+                    } else {
+                        editor.driver().move_down();
+                    }
                 }
-            }
-            KeyCode::Enter | KeyCode::KpEnter => {
-                if mods.shift {
-                    if self.behave.allow_endl() {
-                        editor.driver().insert_or_replace_selection("\n");
-                        editor.on_buffer_changed(atom).await;
+                KeyCode::Enter | KeyCode::KpEnter => {
+                    if mods.shift {
+                        if self.behave.allow_endl() {
+                            editor.driver().insert_or_replace_selection("\n");
+                            editor.on_buffer_changed(atom);
+                        }
+                    } else {
+                        //let node = self.node.upgrade().unwrap();
+                        //node.trigger("enter_pressed", vec![]).await.unwrap();
+                        return false;
                     }
-                } else {
-                    //let node = self.node.upgrade().unwrap();
-                    //node.trigger("enter_pressed", vec![]).await.unwrap();
-                    return false;
                 }
-            }
-            KeyCode::Delete => {
-                if action_mod {
-                    editor.driver().delete_word();
-                } else {
-                    editor.driver().delete();
+                KeyCode::Delete => {
+                    if action_mod {
+                        editor.driver().delete_word();
+                    } else {
+                        editor.driver().delete();
+                    }
+                    editor.on_buffer_changed(atom);
                 }
-                editor.on_buffer_changed(atom).await;
-            }
-            KeyCode::Backspace => {
-                if action_mod {
-                    editor.driver().backdelete_word();
-                } else {
-                    editor.driver().backdelete();
+                KeyCode::Backspace => {
+                    if action_mod {
+                        editor.driver().backdelete_word();
+                    } else {
+                        editor.driver().backdelete();
+                    }
+                    editor.on_buffer_changed(atom);
                 }
-                editor.on_buffer_changed(atom).await;
-            }
-            KeyCode::Home => {
-                if action_mod {
-                    if mods.shift {
-                        editor.driver().select_to_text_start();
+                KeyCode::Home => {
+                    if action_mod {
+                        if mods.shift {
+                            editor.driver().select_to_text_start();
+                        } else {
+                            editor.driver().move_to_text_start();
+                        }
+                    } else if mods.shift {
+                        editor.driver().select_to_line_start();
                     } else {
-                        editor.driver().move_to_text_start();
+                        editor.driver().move_to_line_start();
                     }
-                } else if mods.shift {
-                    editor.driver().select_to_line_start();
-                } else {
-                    editor.driver().move_to_line_start();
                 }
-            }
-            KeyCode::End => {
-                if action_mod {
-                    if mods.shift {
-                        editor.driver().select_to_text_end();
+                KeyCode::End => {
+                    if action_mod {
+                        if mods.shift {
+                            editor.driver().select_to_text_end();
+                        } else {
+                            editor.driver().move_to_text_end();
+                        }
+                    } else if mods.shift {
+                        editor.driver().select_to_line_end();
                     } else {
-                        editor.driver().move_to_text_end();
+                        editor.driver().move_to_line_end();
                     }
-                } else if mods.shift {
-                    editor.driver().select_to_line_end();
-                } else {
-                    editor.driver().move_to_line_end();
                 }
+                _ => return false,
             }
-            _ => return false,
-        }
 
-        if let Some(seltext) = editor.selected_text() {
-            self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
-        } else {
-            self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
+            if let Some(seltext) = editor.selected_text() {
+                self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
+            } else {
+                self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
+            }
         }
 
-        drop(editor);
-
         self.eval_rect().await;
         self.behave.apply_cursor_scroll().await;
         self.pause_blinking();
         self.redraw(atom).await;
 
-        return true
+        true
     }
 
     /// This will select the entire word rather than move the cursor to that location
     async fn start_touch_select(&self, touch_pos: Point, atom: &mut PropertyAtomicGuard) {
         t!("start_touch_select({touch_pos:?})");
 
-        let mut editor = self.lock_editor().await;
-        editor.select_word_at_point(touch_pos).await;
-        editor.refresh().await;
+        let mut editor = self.editor.lock();
+        editor.select_word_at_point(touch_pos);
+        editor.refresh();
 
         let seltext = editor.selected_text().unwrap();
         d!("Selected {seltext:?} from {touch_pos:?}");
@@ -717,7 +699,7 @@ impl BaseEdit {
         true
     }
 
-    async fn get_select_handles(&self, editor: &Editor) -> Option<(Point, Point)> {
+    fn get_select_handles(&self, editor: &Editor) -> Option<(Point, Point)> {
         let layout = editor.layout();
 
         let sel = editor.selection(1);
@@ -732,10 +714,8 @@ impl BaseEdit {
     }
 
     async fn try_handle_drag(&self, mut touch_pos: Point) -> bool {
-        let editor = self.lock_editor().await;
-        let Some((mut first, mut last)) = self.get_select_handles(&editor).await else {
-            return false
-        };
+        let editor = self.editor.lock();
+        let Some((mut first, mut last)) = self.get_select_handles(&editor) else { return false };
 
         self.abs_to_local(&mut touch_pos);
         t!("localize touch_pos = {touch_pos:?}");
@@ -878,9 +858,9 @@ impl BaseEdit {
     async fn touch_set_cursor_pos(&self, atom: &mut PropertyAtomicGuard, touch_pos: Point) {
         t!("touch_set_cursor_pos({touch_pos:?})");
 
-        let mut editor = self.lock_editor().await;
+        let mut editor = self.editor.lock();
         editor.move_to_pos(touch_pos);
-        editor.refresh().await;
+        editor.refresh();
         drop(editor);
 
         self.pause_blinking();
@@ -926,7 +906,7 @@ impl BaseEdit {
         }
 
         let seltext = {
-            let mut editor = self.lock_editor().await;
+            let mut editor = self.editor.lock();
 
             // The below lines rely on parley driver which android does not use
             //let mut txt_ctx = text::TEXT_CTX.get().await;
@@ -970,8 +950,8 @@ impl BaseEdit {
             assert!(start < end);
 
             //t!("handle_select(): set_selection({start}, {end})");
-            editor.set_selection(start, end).await;
-            editor.refresh().await;
+            editor.set_selection(start, end);
+            editor.refresh();
 
             editor.selected_text()
         };
@@ -1096,7 +1076,7 @@ impl BaseEdit {
     async fn regen_txt_mesh(&self) -> Vec<DrawInstruction> {
         let mut instrs = vec![DrawInstruction::Move(self.behave.inner_pos())];
 
-        let editor = self.lock_editor().await;
+        let editor = self.editor.lock();
         let layout = editor.layout();
 
         let mut render_instrs =
@@ -1109,7 +1089,7 @@ impl BaseEdit {
     async fn regen_select_mesh(&self) -> Vec<DrawInstruction> {
         let mut instrs = vec![DrawInstruction::Move(self.behave.inner_pos())];
 
-        let editor = self.lock_editor().await;
+        let editor = self.editor.lock();
         let layout = editor.layout();
 
         let sel = editor.selection(1);
@@ -1131,8 +1111,8 @@ impl BaseEdit {
             //t!("regen_phone_select_handle_mesh() [DISABLED]");
             return vec![]
         }
-        let editor = self.lock_editor().await;
-        let (first, last) = self.get_select_handles(&editor).await.unwrap();
+        let editor = self.editor.lock();
+        let (first, last) = self.get_select_handles(&editor).unwrap();
 
         let sel = editor.selection(1);
         assert!(!sel.is_collapsed());
@@ -1214,11 +1194,6 @@ impl BaseEdit {
         }
     }
 
-    async fn insert(&self, txt: &str, atom: &mut PropertyAtomicGuard) {
-        let mut editor = self.lock_editor().await;
-        editor.insert(txt, atom).await;
-    }
-
     async fn process_insert_text_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
         let Ok(method_call) = sub.receive().await else {
             debug!(target: "ui::chatedit", "Event relayer closed");
@@ -1246,7 +1221,7 @@ impl BaseEdit {
 
         let atom =
             &mut self_.render_api.make_guard(gfxtag!("BaseEdit::process_insert_text_method"));
-        self_.insert(&text, atom).await;
+        self_.editor.lock().insert(&text, atom);
         self_.eval_rect().await;
         self_.redraw(atom).await;
         true
@@ -1267,8 +1242,7 @@ impl BaseEdit {
             panic!("self destroyed before insert_text_method_task was stopped!");
         };
 
-        let mut editor = self_.lock_editor().await;
-        editor.focus();
+        self_.editor.lock().focus();
         true
     }
     async fn process_unfocus_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
@@ -1286,8 +1260,7 @@ impl BaseEdit {
             panic!("self destroyed before insert_text_method_task was stopped!");
         };
 
-        let mut editor = self_.lock_editor().await;
-        editor.unfocus();
+        self_.editor.lock().unfocus();
         true
     }
 
@@ -1300,7 +1273,7 @@ impl BaseEdit {
         t!("handle_android_event({state:?})");
         let atom = &mut self.render_api.make_guard(gfxtag!("BaseEdit::handle_android_event"));
 
-        let mut editor = self.lock_editor().await;
+        let mut editor = self.editor.lock();
         // Diff old and new state so we know what changed
         let is_text_changed = editor.state.text != state.text;
         let is_select_changed = editor.state.select != state.select;
@@ -1357,22 +1330,7 @@ impl UIObject for BaseEdit {
         self.priority.get()
     }
 
-    fn init(&self) {
-        let mut guard = self.editor.lock_blocking();
-        assert!(guard.is_none());
-        let editor = Editor::new(
-            self.text.clone(),
-            self.font_size.clone(),
-            self.text_color.clone(),
-            self.window_scale.clone(),
-            self.lineheight.clone(),
-        );
-        // For Android you can do this:
-        //let atom = &mut PropertyAtomicGuard::none();
-        //self.text.set(atom, "the quick brown fox jumped over the");
-        //smol::block_on(editor.on_text_prop_changed());
-        *guard = Some(editor);
-    }
+    fn init(&self) {}
 
     async fn start(self: Arc<Self>, ex: ExecutorPtr) {
         let me = Arc::downgrade(&self);
@@ -1414,7 +1372,7 @@ impl UIObject for BaseEdit {
             self_.redraw(atom).await;
         }
         async fn set_text(self_: Arc<BaseEdit>, batch: BatchGuardPtr) {
-            self_.lock_editor().await.on_text_prop_changed().await;
+            self_.editor.lock().on_text_prop_changed();
             let atom = &mut batch.spawn();
             self_.eval_rect().await;
             self_.redraw(atom).await;
@@ -1549,7 +1507,6 @@ impl UIObject for BaseEdit {
         *self.parent_rect.lock() = None;
         self.key_repeat.lock().clear();
         *self.cursor_mesh.lock() = None;
-        *self.editor.lock_blocking() = None;
     }
 
     #[instrument(target = "ui::edit")]
@@ -1598,7 +1555,7 @@ impl UIObject for BaseEdit {
 
         t!("Key {:?} has {} actions", key, actions);
         let key_str = key.to_string().repeat(actions as usize);
-        self.insert(&key_str, atom).await;
+        self.editor.lock().insert(&key_str, atom);
         self.eval_rect().await;
         self.behave.apply_cursor_scroll().await;
         self.redraw(atom).await;
@@ -1672,10 +1629,7 @@ impl UIObject for BaseEdit {
         // Move mouse pos within this widget
         self.abs_to_local(&mut mouse_pos);
 
-        {
-            let mut editor = self.lock_editor().await;
-            editor.driver().move_to_point(mouse_pos.x, mouse_pos.y);
-        }
+        self.editor.lock().driver().move_to_point(mouse_pos.x, mouse_pos.y);
 
         if !self.select_text.is_null(0).unwrap() {
             self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();