Просмотр исходного кода

app/edit: optional enhanced logging

darkfi 1 неделя назад
Родитель
Сommit
0ce9360453
1 измененных файлов с 107 добавлено и 7 удалено
  1. 107 7
      bin/app/src/ui/edit/mod.rs

+ 107 - 7
bin/app/src/ui/edit/mod.rs

@@ -84,6 +84,20 @@ const SELECT_SCROLL_TRAVEL_SPEED: f32 = 1.;
 macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui::edit", $($arg)*); } }
 macro_rules! d { ($($arg:tt)*) => { debug!(target: "ui::edit", $($arg)*); } }
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::edit", $($arg)*); } }
 macro_rules! t { ($($arg:tt)*) => { trace!(target: "ui::edit", $($arg)*); } }
 
 
+/// Master switch for verbose edit/IME debugging.
+/// When true, detailed diagnostics about text content, selection range,
+/// compose region, focus state, and touch/keyboard events are emitted to
+/// the `ui::edit` log target. Set to false to silence them.
+const ENABLE_DEBUG: bool = true;
+
+macro_rules! ed {
+    ($($arg:tt)*) => {
+        if ENABLE_DEBUG {
+            debug!(target: "ui::edit", $($arg)*);
+        }
+    };
+}
+
 #[derive(Debug, Clone)]
 #[derive(Debug, Clone)]
 enum TouchStateAction {
 enum TouchStateAction {
     Inactive,
     Inactive,
@@ -413,6 +427,41 @@ impl BaseEdit {
         self.node.upgrade().unwrap()
         self.node.upgrade().unwrap()
     }
     }
 
 
+    /// Snapshot of the editor state useful for debugging editing bugs.
+    fn dbg_state(&self) -> String {
+        let focused = self.is_focused.get();
+        let active = self.is_active.get();
+        let phone_select = self.is_phone_select.load(Ordering::Relaxed);
+        let editor = self.editor.lock();
+        let selected = editor.selected_text();
+
+        #[cfg(target_os = "android")]
+        {
+            format!(
+                "text={:?} select={:?} compose={:?} selected={:?} focused={} active={} phone_select={}",
+                editor.state.text,
+                editor.state.select,
+                editor.state.compose,
+                selected,
+                focused,
+                active,
+                phone_select,
+            )
+        }
+
+        #[cfg(not(target_os = "android"))]
+        {
+            format!(
+                "text={:?} selected={:?} focused={} active={} phone_select={}",
+                self.text.get(),
+                selected,
+                focused,
+                active,
+                phone_select,
+            )
+        }
+    }
+
     /// Reset the horizontal scroll to 0.
     /// Reset the horizontal scroll to 0.
     /// Useful when the input width is dynamically changed and scrolling is not desired.
     /// Useful when the input width is dynamically changed and scrolling is not desired.
     pub fn reset_scroll(&self) {
     pub fn reset_scroll(&self) {
@@ -500,8 +549,10 @@ impl BaseEdit {
 
 
     async fn change_focus(self: Arc<Self>, batch: BatchGuardPtr) {
     async fn change_focus(self: Arc<Self>, batch: BatchGuardPtr) {
         if !self.is_active.get() {
         if !self.is_active.get() {
+            ed!("change_focus: not active, skipping");
             return
             return
         }
         }
+        ed!("change_focus: focused={} -> [{}]", self.is_focused.get(), self.dbg_state());
         t!("Focus changed");
         t!("Focus changed");
 
 
         let atom = &mut batch.spawn();
         let atom = &mut batch.spawn();
@@ -510,6 +561,7 @@ impl BaseEdit {
     }
     }
 
 
     fn handle_shortcut(&self, key: char, mods: &KeyMods, atom: &mut PropertyAtomicGuard) -> bool {
     fn handle_shortcut(&self, key: char, mods: &KeyMods, atom: &mut PropertyAtomicGuard) -> bool {
+        ed!("handle_shortcut({key:?}, {mods:?}) before=[{}]", self.dbg_state());
         t!("handle_shortcut({:?}, {:?})", key, mods);
         t!("handle_shortcut({:?}, {:?})", key, mods);
 
 
         #[cfg(not(target_os = "macos"))]
         #[cfg(not(target_os = "macos"))]
@@ -550,6 +602,7 @@ impl BaseEdit {
 
 
         self.eval_rect();
         self.eval_rect();
         self.redraw(atom);
         self.redraw(atom);
+        ed!("handle_shortcut: handled key={key:?} after=[{}]", self.dbg_state());
         true
         true
     }
     }
 
 
@@ -672,11 +725,13 @@ impl BaseEdit {
         self.pause_blinking();
         self.pause_blinking();
         self.redraw(atom);
         self.redraw(atom);
 
 
+        ed!("handle_key: handled {key:?} after=[{}]", self.dbg_state());
         true
         true
     }
     }
 
 
     /// This will select the entire word rather than move the cursor to that location
     /// This will select the entire word rather than move the cursor to that location
     fn start_touch_select(&self, touch_pos: Point, atom: &mut PropertyAtomicGuard) {
     fn start_touch_select(&self, touch_pos: Point, atom: &mut PropertyAtomicGuard) {
+        ed!("start_touch_select({touch_pos:?}) before=[{}]", self.dbg_state());
         t!("start_touch_select({touch_pos:?})");
         t!("start_touch_select({touch_pos:?})");
 
 
         let mut editor = self.editor.lock();
         let mut editor = self.editor.lock();
@@ -684,7 +739,7 @@ impl BaseEdit {
         editor.refresh();
         editor.refresh();
 
 
         let seltext = editor.selected_text().unwrap();
         let seltext = editor.selected_text().unwrap();
-        d!("Selected {seltext:?} from {touch_pos:?}");
+        ed!("start_touch_select: word selected text={seltext:?} after=[{}]", self.dbg_state());
         self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
         self.select_text.clone().set_str(atom, Role::Internal, 0, seltext).unwrap();
 
 
         drop(editor);
         drop(editor);
@@ -697,7 +752,7 @@ impl BaseEdit {
     }
     }
 
 
     fn handle_touch_start(&self, touch_pos: Point) -> bool {
     fn handle_touch_start(&self, touch_pos: Point) -> bool {
-        t!("handle_touch_start({touch_pos:?})");
+        ed!("handle_touch_start({touch_pos:?}) before=[{}]", self.dbg_state());
 
 
         let rect = self.rect.get();
         let rect = self.rect.get();
         let local_pos = touch_pos - rect.pos();
         let local_pos = touch_pos - rect.pos();
@@ -735,16 +790,19 @@ impl BaseEdit {
         }
         }
 
 
         if !rect.contains(touch_pos) {
         if !rect.contains(touch_pos) {
+            ed!("handle_touch_start: outside rect={rect:?}, ignoring");
             t!("rect!cont rect={rect:?}, touch_pos={touch_pos:?}");
             t!("rect!cont rect={rect:?}, touch_pos={touch_pos:?}");
             return false
             return false
         }
         }
 
 
         if self.try_handle_drag(touch_pos) {
         if self.try_handle_drag(touch_pos) {
+            ed!("handle_touch_start: handled by drag handle");
             return true
             return true
         }
         }
 
 
         let mut touch_info = self.touch_info.lock();
         let mut touch_info = self.touch_info.lock();
         touch_info.start(touch_pos);
         touch_info.start(touch_pos);
+        ed!("handle_touch_start: touch started, waiting for move/end");
         true
         true
     }
     }
 
 
@@ -806,9 +864,11 @@ impl BaseEdit {
             // Set touch_state status to enable begin dragging them
             // Set touch_state status to enable begin dragging them
             let mut touch_info = self.touch_info.lock();
             let mut touch_info = self.touch_info.lock();
             touch_info.state = TouchStateAction::DragSelectHandle { side };
             touch_info.state = TouchStateAction::DragSelectHandle { side };
+            ed!("try_handle_drag: grabbing select handle side={side}");
             return true
             return true
         }
         }
 
 
+        ed!("try_handle_drag: no handle grabbed");
         false
         false
     }
     }
 
 
@@ -826,6 +886,7 @@ impl BaseEdit {
             touch_info.update(&touch_pos);
             touch_info.update(&touch_pos);
             touch_info.state.clone()
             touch_info.state.clone()
         };
         };
+        ed!("handle_touch_move({touch_pos:?}) touch_state={touch_state:?}");
         //t!("handle_touch_move({touch_pos:?})  touch_state={touch_state:?}");
         //t!("handle_touch_move({touch_pos:?})  touch_state={touch_state:?}");
         match &touch_state {
         match &touch_state {
             TouchStateAction::Inactive => return false,
             TouchStateAction::Inactive => return false,
@@ -876,6 +937,7 @@ impl BaseEdit {
                 }
                 }
                 self.action_mode.set(menu);
                 self.action_mode.set(menu);
                 self.action_mode.redraw(atom.batch_id);
                 self.action_mode.redraw(atom.batch_id);
+                ed!("handle_touch_move: StartSelect handled");
             }
             }
             TouchStateAction::DragSelectHandle { side } => {
             TouchStateAction::DragSelectHandle { side } => {
                 let rect = self.rect.get();
                 let rect = self.rect.get();
@@ -920,6 +982,7 @@ impl BaseEdit {
         self.abs_to_local(&mut touch_pos);
         self.abs_to_local(&mut touch_pos);
 
 
         let state = self.touch_info.lock().stop();
         let state = self.touch_info.lock().stop();
+        ed!("handle_touch_end({touch_pos:?}) final_state={state:?}");
         match state {
         match state {
             TouchStateAction::Inactive => return false,
             TouchStateAction::Inactive => return false,
             TouchStateAction::Started { pos: _, instant: _ } | TouchStateAction::SetCursorPos => {
             TouchStateAction::Started { pos: _, instant: _ } | TouchStateAction::SetCursorPos => {
@@ -941,18 +1004,20 @@ impl BaseEdit {
     }
     }
 
 
     fn touch_set_cursor_pos(&self, atom: &mut PropertyAtomicGuard, touch_pos: Point) {
     fn touch_set_cursor_pos(&self, atom: &mut PropertyAtomicGuard, touch_pos: Point) {
-        t!("touch_set_cursor_pos({touch_pos:?})");
+        ed!("touch_set_cursor_pos({touch_pos:?}) before=[{}]", self.dbg_state());
 
 
         let mut editor = self.editor.lock();
         let mut editor = self.editor.lock();
         editor.move_to_pos(touch_pos);
         editor.move_to_pos(touch_pos);
         editor.refresh();
         editor.refresh();
         drop(editor);
         drop(editor);
+        ed!("touch_set_cursor_pos: moved cursor after=[{}]", self.dbg_state());
 
 
         self.pause_blinking();
         self.pause_blinking();
         self.finish_select(atom);
         self.finish_select(atom);
     }
     }
 
 
     fn finish_select(&self, atom: &mut PropertyAtomicGuard) {
     fn finish_select(&self, atom: &mut PropertyAtomicGuard) {
+        ed!("finish_select: phone_select={} -> false", self.is_phone_select.load(Ordering::Relaxed));
         self.is_phone_select.store(false, Ordering::Release);
         self.is_phone_select.store(false, Ordering::Release);
         self.hide_cursor.store(false, Ordering::Release);
         self.hide_cursor.store(false, Ordering::Release);
         self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
         self.select_text.clone().set_null(atom, Role::Internal, 0).unwrap();
@@ -1035,10 +1100,11 @@ impl BaseEdit {
             assert!(start < end);
             assert!(start < end);
 
 
             //t!("handle_select(): set_selection({start}, {end})");
             //t!("handle_select(): set_selection({start}, {end})");
+            ed!("handle_select: set_selection({start}, {end}) side={side:?} prev=({prev_start}, {prev_end})");
             editor.set_selection(start, end);
             editor.set_selection(start, end);
             editor.selected_text()
             editor.selected_text()
         };
         };
-        //d!("Select {seltext:?} from {clip_mouse_pos:?} (unclipped: {mouse_pos:?})");
+        ed!("handle_select: seltext={seltext:?} clip_pos={clip_mouse_pos:?}");
 
 
         // Android editor impl detail: selection disappears when anchor == index
         // Android editor impl detail: selection disappears when anchor == index
         // But we disallow this so it should never happen. Just making a note of it here.
         // But we disallow this so it should never happen. Just making a note of it here.
@@ -1379,6 +1445,7 @@ impl BaseEdit {
         self_.editor.lock().insert(&text, atom);
         self_.editor.lock().insert(&text, atom);
         self_.eval_rect();
         self_.eval_rect();
         self_.redraw(atom);
         self_.redraw(atom);
+        ed!("insert_text method: inserted {text:?} after=[{}]", self_.dbg_state());
         true
         true
     }
     }
 
 
@@ -1401,6 +1468,7 @@ impl BaseEdit {
         #[cfg(target_os = "android")]
         #[cfg(target_os = "android")]
         {
         {
             let input_type = self_.android_input_type.get();
             let input_type = self_.android_input_type.get();
+            ed!("focus method: setting android input_type={input_type}");
             self_.editor.lock().set_input_type(input_type);
             self_.editor.lock().set_input_type(input_type);
         }
         }
 
 
@@ -1408,6 +1476,7 @@ impl BaseEdit {
         let atom = &mut self_.renderer.make_guard(gfxtag!("BaseEdit::process_focus_method"));
         let atom = &mut self_.renderer.make_guard(gfxtag!("BaseEdit::process_focus_method"));
         self_.is_focused.set(atom, true);
         self_.is_focused.set(atom, true);
         self_.redraw(atom);
         self_.redraw(atom);
+        ed!("focus method: done after=[{}]", self_.dbg_state());
         true
         true
     }
     }
     async fn process_unfocus_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
     async fn process_unfocus_method(me: &Weak<Self>, sub: &MethodCallSub) -> bool {
@@ -1429,27 +1498,38 @@ impl BaseEdit {
         let atom = &mut self_.renderer.make_guard(gfxtag!("BaseEdit::process_unfocus_method"));
         let atom = &mut self_.renderer.make_guard(gfxtag!("BaseEdit::process_unfocus_method"));
         self_.is_focused.set(atom, false);
         self_.is_focused.set(atom, false);
         self_.redraw(atom);
         self_.redraw(atom);
+        ed!("unfocus method: done after=[{}]", self_.dbg_state());
         true
         true
     }
     }
 
 
     #[cfg(target_os = "android")]
     #[cfg(target_os = "android")]
     fn handle_android_event(&self, state: AndroidTextInputState) {
     fn handle_android_event(&self, state: AndroidTextInputState) {
         if !self.is_active.get() {
         if !self.is_active.get() {
+            ed!("handle_android_event: DROP inactive state={state:?}");
             return
             return
         }
         }
 
 
-        t!("handle_android_event({state:?})");
+        ed!("handle_android_event: ENTER incoming={state:?} before=[{}]", self.dbg_state());
         let atom = &mut self.renderer.make_guard(gfxtag!("BaseEdit::handle_android_event"));
         let atom = &mut self.renderer.make_guard(gfxtag!("BaseEdit::handle_android_event"));
 
 
         let is_new_select_collapsed = state.select.0 == state.select.1;
         let is_new_select_collapsed = state.select.0 == state.select.1;
         let (is_text_changed, is_select_changed, is_compose_changed) = {
         let (is_text_changed, is_select_changed, is_compose_changed) = {
             let mut editor = self.editor.lock();
             let mut editor = self.editor.lock();
             // Diff old and new state so we know what changed
             // Diff old and new state so we know what changed
+            let old_text = editor.state.text.clone();
+            let old_select = editor.state.select;
+            let old_compose = editor.state.compose;
             let diff = (
             let diff = (
                 editor.state.text != state.text,
                 editor.state.text != state.text,
                 editor.state.select != state.select,
                 editor.state.select != state.select,
                 editor.state.compose != state.compose,
                 editor.state.compose != state.compose,
             );
             );
+            ed!(
+                "handle_android_event: diff text_changed={} (old={:?} new={:?}) select_changed={} (old={:?} new={:?}) compose_changed={} (old={:?} new={:?})",
+                diff.0, old_text, state.text,
+                diff.1, old_select, state.select,
+                diff.2, old_compose, state.compose,
+            );
             editor.state = state;
             editor.state = state;
             editor.on_buffer_changed(atom);
             editor.on_buffer_changed(atom);
             diff
             diff
@@ -1457,14 +1537,19 @@ impl BaseEdit {
 
 
         // Nothing changed. Just return.
         // Nothing changed. Just return.
         if !is_text_changed && !is_select_changed && !is_compose_changed {
         if !is_text_changed && !is_select_changed && !is_compose_changed {
-            //t!("Skipping update since nothing changed");
+            ed!("handle_android_event: no-op (nothing changed), after=[{}]", self.dbg_state());
             return
             return
         }
         }
 
 
-        //t!("is_text_changed={is_text_changed}, is_select_changed={is_select_changed}, is_compose_changed={is_compose_changed}");
+        ed!(
+            "handle_android_event: applying text_changed={} select_changed={} compose_changed={} collapsed={}",
+            is_text_changed, is_select_changed, is_compose_changed, is_new_select_collapsed
+        );
+
         // Only redraw once we have the parent_rect
         // Only redraw once we have the parent_rect
         // Can happen when we receive an Android event before the canvas is ready
         // Can happen when we receive an Android event before the canvas is ready
         if self.parent_rect.lock().is_none() {
         if self.parent_rect.lock().is_none() {
+            ed!("handle_android_event: parent_rect not ready yet, bailing before redraw");
             return
             return
         }
         }
 
 
@@ -1482,6 +1567,7 @@ impl BaseEdit {
             //assert!(state.text != self.text.get());
             //assert!(state.text != self.text.get());
             self.finish_select(atom);
             self.finish_select(atom);
             self.redraw(atom);
             self.redraw(atom);
+            ed!("handle_android_event: handled text change, after=[{}]", self.dbg_state());
         } else if is_select_changed {
         } else if is_select_changed {
             // The IME can collapse a phone-style word selection out from under
             // The IME can collapse a phone-style word selection out from under
             // us (e.g. it repositions the cursor when the keyboard is shown).
             // us (e.g. it repositions the cursor when the keyboard is shown).
@@ -1489,6 +1575,7 @@ impl BaseEdit {
             // A handle drag always maintains a range, so its IME echoes are
             // A handle drag always maintains a range, so its IME echoes are
             // unaffected.
             // unaffected.
             if is_new_select_collapsed && self.is_phone_select.load(Ordering::Relaxed) {
             if is_new_select_collapsed && self.is_phone_select.load(Ordering::Relaxed) {
+                ed!("handle_android_event: IME collapsed the phone selection, finishing select");
                 d!("IME has collapsed selection!");
                 d!("IME has collapsed selection!");
                 self.finish_select(atom);
                 self.finish_select(atom);
             }
             }
@@ -1496,6 +1583,9 @@ impl BaseEdit {
             self.redraw_cursor(&self.renderer);
             self.redraw_cursor(&self.renderer);
             //t!("handle_android_event calling redraw_select");
             //t!("handle_android_event calling redraw_select");
             self.redraw_select(&self.renderer, atom.batch_id);
             self.redraw_select(&self.renderer, atom.batch_id);
+            ed!("handle_android_event: handled select change, after=[{}]", self.dbg_state());
+        } else if is_compose_changed {
+            ed!("handle_android_event: compose-only change ignored, after=[{}]", self.dbg_state());
         }
         }
     }
     }
 }
 }
@@ -1700,13 +1790,16 @@ impl UIObject for BaseEdit {
     }
     }
 
 
     async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool {
     async fn handle_char(&self, key: char, mods: KeyMods, repeat: bool) -> bool {
+        ed!("handle_char({key}, {mods:?}, repeat={repeat}) before=[{}]", self.dbg_state());
         t!("handle_char({key}, {mods:?}, {repeat})");
         t!("handle_char({key}, {mods:?}, {repeat})");
         // First filter for only single digit keys
         // First filter for only single digit keys
         if DISALLOWED_CHARS.contains(&key) {
         if DISALLOWED_CHARS.contains(&key) {
+            ed!("handle_char: {key:?} disallowed, ignoring");
             return false
             return false
         }
         }
 
 
         if !self.is_focused.get() {
         if !self.is_focused.get() {
+            ed!("handle_char: not focused, ignoring");
             return false
             return false
         }
         }
 
 
@@ -1739,18 +1832,22 @@ impl UIObject for BaseEdit {
         self.behave.apply_cursor_scroll();
         self.behave.apply_cursor_scroll();
         self.pause_blinking();
         self.pause_blinking();
         self.redraw(atom);
         self.redraw(atom);
+        ed!("handle_char: inserted {key_str:?} after=[{}]", self.dbg_state());
         true
         true
     }
     }
 
 
     async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool {
     async fn handle_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) -> bool {
+        ed!("handle_key_down({key:?}, {mods:?}, repeat={repeat}) before=[{}]", self.dbg_state());
         t!("handle_key_down({key:?}, {mods:?}, {repeat})");
         t!("handle_key_down({key:?}, {mods:?}, {repeat})");
         // First filter for only single digit keys
         // First filter for only single digit keys
         // Avoid processing events handled by handle_char()
         // Avoid processing events handled by handle_char()
         if !ALLOWED_KEYCODES.contains(&key) {
         if !ALLOWED_KEYCODES.contains(&key) {
+            ed!("handle_key_down: {key:?} not in ALLOWED_KEYCODES, ignoring");
             return false
             return false
         }
         }
 
 
         if !self.is_focused.get() {
         if !self.is_focused.get() {
+            ed!("handle_key_down: not focused, ignoring");
             return false
             return false
         }
         }
 
 
@@ -1770,6 +1867,7 @@ impl UIObject for BaseEdit {
         for _ in 0..actions {
         for _ in 0..actions {
             is_handled = self.handle_key(&key, &mods, atom);
             is_handled = self.handle_key(&key, &mods, atom);
         }
         }
+        ed!("handle_key_down: {key:?} handled={is_handled} after=[{}]", self.dbg_state());
         is_handled
         is_handled
     }
     }
 
 
@@ -1822,8 +1920,10 @@ impl UIObject for BaseEdit {
         // 1. make it active
         // 1. make it active
         // 2. begin selection
         // 2. begin selection
         if self.is_focused.get() {
         if self.is_focused.get() {
+            ed!("handle_mouse_btn_down({btn:?}, {mouse_pos:?}): already focused click");
             d!("BaseEdit clicked");
             d!("BaseEdit clicked");
         } else {
         } else {
+            ed!("handle_mouse_btn_down({btn:?}, {mouse_pos:?}): focusing widget");
             d!("BaseEdit focused");
             d!("BaseEdit focused");
             self.is_focused.set(atom, true);
             self.is_focused.set(atom, true);