Checkpoint, alt-n l is very broken. Bisecting.

Mikayla Maki created

Change summary

crates/gpui/src/platform/mac/window.rs | 86 ++++++++++++++++++++++++++-
1 file changed, 82 insertions(+), 4 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/window.rs 🔗

@@ -313,8 +313,8 @@ struct WindowState {
     previous_modifiers_changed_event: Option<Event>,
     //State tracking what the IME did after the last request
     ime_state: ImeState,
-    //Retains the last IME keystroke that was in the 'Acted' state
-    last_ime_key: Option<Keystroke>,
+    //Retains the last IME Text
+    ime_text: Option<String>,
 }
 
 struct InsertText {
@@ -411,6 +411,8 @@ impl Window {
                 layer,
                 traffic_light_position: options.traffic_light_position,
                 previous_modifiers_changed_event: None,
+                ime_state: ImeState::None,
+                ime_text: None,
             })));
 
             (*native_window).set_ivar(
@@ -774,6 +776,9 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
     let mut window_state_borrow = window_state.as_ref().borrow_mut();
 
     let event = unsafe { Event::from_native(native_event, Some(window_state_borrow.size().y())) };
+
+    println!("Handle key event! {:?}", event);
+
     if let Some(event) = event {
         if key_equivalent {
             window_state_borrow.performed_key_equivalent = true;
@@ -811,7 +816,9 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
 
         let mut handled = false;
         let mut window_state_borrow = window_state.borrow_mut();
+        let ime_text = window_state_borrow.ime_text.clone();
         if let Some((event, insert_text)) = window_state_borrow.pending_key_down.take() {
+            let is_held = event.is_held;
             if let Some(mut callback) = window_state_borrow.event_callback.take() {
                 drop(window_state_borrow);
 
@@ -830,6 +837,18 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
                             input_handler
                                 .replace_text_in_range(insert.replacement_range, &insert.text)
                         });
+                    } else if !is_composing && is_held {
+                        if let Some(last_insert_text) = ime_text {
+                            //MacOS IME is a bit funky, and even when you've told it there's nothing to
+                            //inter it will still swallow certain keys (e.g. 'f', 'j') and not others
+                            //(e.g. 'n'). This is a problem for certain kinds of views, like the terminal
+                            with_input_handler(this, |input_handler| {
+                                if input_handler.selected_text_range().is_none() {
+                                    handled = true;
+                                    input_handler.replace_text_in_range(None, &last_insert_text)
+                                }
+                            });
+                        }
                     }
                 }
 
@@ -1180,11 +1199,24 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
             .unwrap();
         let replacement_range = replacement_range.to_range();
 
+        window_state.borrow_mut().ime_text = Some(text.to_string());
+        window_state.borrow_mut().ime_state = ImeState::Acted;
+
+        //Conceptually incorrect
         let is_composing =
             with_input_handler(this, |input_handler| input_handler.marked_text_range())
                 .flatten()
                 .is_some();
 
+        println!(
+            "Insert text, is_composing {}, text {}, have pending key down? {:?}",
+            is_composing,
+            &text,
+            &pending_key_down.is_some()
+        );
+
+        //Handle key event is going to be returned to soon! Make sure it
+        //has the new text from the IME
         match pending_key_down {
             None | Some(_) if is_composing || text.chars().count() > 1 => {
                 with_input_handler(this, |input_handler| {
@@ -1202,6 +1234,30 @@ extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NS
 
             _ => unreachable!(),
         }
+
+        // if let Some(mut pending_key_down) = pending_key_down {
+        //     pending_key_down.1 = Some(InsertText {
+        //         replacement_range,
+        //         text: text.to_string(),
+        //     });
+        //     window_state.borrow_mut().pending_key_down = Some(pending_key_down);
+
+        //     //Modifier key combos (˜ˆ) (success / failure)
+        //     //Press-and-hold replacements ((hold i) 1 -> î) (success / failure)
+        //     //Pop down chinese composition menu
+        //     //Handwriting menu
+        //     //Emoji Picker (😤)
+
+        //     //Regression -> alt-i l only causes 'l' to be placed, instead of ˆl
+        //     //
+        // }
+        // //If no pending key down, then handle_key_event isn't going to
+        // //insert the text for us. Do it ourselves
+        // else {
+        //     with_input_handler(this, |input_handler| {
+        //         input_handler.replace_text_in_range(replacement_range, text)
+        //     });
+        // }
     }
 }
 
@@ -1213,7 +1269,8 @@ extern "C" fn set_marked_text(
     replacement_range: NSRange,
 ) {
     unsafe {
-        get_window_state(this).borrow_mut().pending_key_down.take();
+        let window_state = get_window_state(this);
+        window_state.borrow_mut().pending_key_down.take();
 
         let is_attributed_string: BOOL =
             msg_send![text, isKindOfClass: [class!(NSAttributedString)]];
@@ -1228,6 +1285,11 @@ extern "C" fn set_marked_text(
             .to_str()
             .unwrap();
 
+        window_state.borrow_mut().ime_state = ImeState::Acted;
+        window_state.borrow_mut().ime_text = Some(text.to_string());
+
+        println!("set_marked_text({selected_range:?}, {replacement_range:?}, {text:?})");
+
         with_input_handler(this, |input_handler| {
             input_handler.replace_and_mark_text_in_range(replacement_range, text, selected_range);
         });
@@ -1235,6 +1297,15 @@ extern "C" fn set_marked_text(
 }
 
 extern "C" fn unmark_text(this: &Object, _: Sel) {
+    unsafe {
+        let state = get_window_state(this);
+        let mut borrow = state.borrow_mut();
+        borrow.ime_state = ImeState::Acted;
+        borrow.ime_text.take();
+    }
+
+    println!("unmark_text()");
+
     with_input_handler(this, |input_handler| input_handler.unmark_text());
 }
 
@@ -1261,7 +1332,14 @@ extern "C" fn attributed_substring_for_proposed_range(
     .unwrap_or(nil)
 }
 
-extern "C" fn do_command_by_selector(_: &Object, _: Sel, _: Sel) {}
+extern "C" fn do_command_by_selector(this: &Object, _: Sel, _: Sel) {
+    unsafe {
+        let state = get_window_state(this);
+        let mut borrow = state.borrow_mut();
+        borrow.ime_state = ImeState::Continue;
+        borrow.ime_text.take();
+    }
+}
 
 async fn synthetic_drag(
     window_state: Weak<RefCell<WindowState>>,