More code written, similar lack of workingness so far

Conrad Irwin created

Change summary

crates/editor2/src/element.rs         |   7 +
crates/settings2/src/settings_file.rs |  11 -
crates/vim2/src/editor_events.rs      | 113 +++++++++++---------
crates/vim2/src/mode_indicator.rs     |  17 --
crates/vim2/src/normal.rs             | 160 ++++++++++++++--------------
crates/vim2/src/vim.rs                |  75 +++++++------
crates/workspace2/src/workspace2.rs   |   1 
7 files changed, 191 insertions(+), 193 deletions(-)

Detailed changes

crates/editor2/src/element.rs 🔗

@@ -1043,7 +1043,12 @@ impl EditorElement {
                                         .chars_at(cursor_position)
                                         .next()
                                         .and_then(|(character, _)| {
-                                            let text = SharedString::from(character.to_string());
+                                            // todo!() currently shape_line panics if text conatins newlines
+                                            let text = if character == '\n' {
+                                                SharedString::from(" ")
+                                            } else {
+                                                SharedString::from(character.to_string())
+                                            };
                                             let len = text.len();
                                             cx.text_system()
                                                 .shape_line(

crates/settings2/src/settings_file.rs 🔗

@@ -124,17 +124,6 @@ pub fn update_settings_file<T: Settings>(
 
 pub fn load_default_keymap(cx: &mut AppContext) {
     for path in ["keymaps/default.json", "keymaps/vim.json"] {
-        // TODO: Remove this conditional when we're ready to add Vim support.
-        // Right now we're avoiding loading the Vim keymap to silence the warnings
-        // about invalid action bindings.
-        if path.contains("vim") {
-            let _: Option<()> = Err(format!(
-                "TODO: Skipping {path} until we're ready to add Vim support"
-            ))
-            .log_err();
-            continue;
-        }
-
         KeymapFile::load_asset(path, cx).unwrap();
     }
 

crates/vim2/src/editor_events.rs 🔗

@@ -1,70 +1,79 @@
 use crate::{Vim, VimEvent};
-use editor::{EditorBlurred, EditorFocused, EditorReleased};
-use gpui::AppContext;
+use editor::{Editor, EditorBlurred, EditorEvent, EditorFocused, EditorReleased};
+use gpui::{AppContext, Entity, EntityId, View, ViewContext, WindowContext};
+use workspace::item::WeakItemHandle;
 
 pub fn init(cx: &mut AppContext) {
+    cx.observe_new_views(|_, cx: &mut ViewContext<Editor>| {
+        let editor = cx.view().clone();
+        cx.subscribe(&editor, |_, editor, event: &EditorEvent, cx| match event {
+            EditorEvent::Focused => cx.window_context().defer(|cx| focused(editor, cx)),
+            EditorEvent::Blurred => cx.window_context().defer(|cx| blurred(editor, cx)),
+            _ => {}
+        })
+        .detach();
+
+        let id = cx.view().entity_id();
+        cx.on_release(move |_, cx| released(id, cx)).detach();
+    })
+    .detach();
     // todo!()
     // cx.subscribe_global(focused).detach();
     // cx.subscribe_global(blurred).detach();
     // cx.subscribe_global(released).detach();
 }
 
-fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) {
-    todo!();
-    // if let Some(previously_active_editor) = Vim::read(cx).active_editor.clone() {
-    //     previously_active_editor.window_handle().update(cx, |cx| {
-    //         Vim::update(cx, |vim, cx| {
-    //             vim.update_active_editor(cx, |previously_active_editor, cx| {
-    //                 vim.unhook_vim_settings(previously_active_editor, cx)
-    //             });
-    //         });
-    //     });
-    // }
+fn focused(editor: View<Editor>, cx: &mut WindowContext) {
+    if let Some(previously_active_editor) = Vim::read(cx).active_editor.clone() {
+        Vim::update(cx, |vim, cx| {
+            vim.update_active_editor(cx, |previously_active_editor, cx| {
+                vim.unhook_vim_settings(previously_active_editor, cx)
+            });
+        });
+    }
 
-    // editor.window().update(cx, |cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.set_active_editor(editor.clone(), cx);
-    //         if vim.enabled {
-    //             cx.emit_global(VimEvent::ModeChanged {
-    //                 mode: vim.state().mode,
-    //             });
-    //         }
-    //     });
-    // });
+    Vim::update(cx, |vim, cx| {
+        vim.set_active_editor(editor.clone(), cx);
+        if vim.enabled {
+            // todo!()
+            // cx.emit_global(VimEvent::ModeChanged {
+            //     mode: vim.state().mode,
+            // });
+        }
+    });
 }
 
-fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) {
-    todo!();
-    // editor.window().update(cx, |cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.workspace_state.recording = false;
-    //         vim.workspace_state.recorded_actions.clear();
-    //         if let Some(previous_editor) = vim.active_editor.clone() {
-    //             if previous_editor == editor.clone() {
-    //                 vim.clear_operator(cx);
-    //                 vim.active_editor = None;
-    //                 vim.editor_subscription = None;
-    //             }
-    //         }
+fn blurred(editor: View<Editor>, cx: &mut WindowContext) {
+    Vim::update(cx, |vim, cx| {
+        vim.workspace_state.recording = false;
+        vim.workspace_state.recorded_actions.clear();
+        if let Some(previous_editor) = vim.active_editor.clone() {
+            if previous_editor
+                .upgrade()
+                .is_some_and(|previous| previous == editor.clone())
+            {
+                vim.clear_operator(cx);
+                vim.active_editor = None;
+                vim.editor_subscription = None;
+            }
+        }
 
-    //         editor.update(cx, |editor, cx| vim.unhook_vim_settings(editor, cx))
-    //     });
-    // });
+        editor.update(cx, |editor, cx| vim.unhook_vim_settings(editor, cx))
+    });
 }
 
-fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) {
-    todo!();
-    // editor.window().update(cx, |cx| {
-    //     Vim::update(cx, |vim, _| {
-    //         if let Some(previous_editor) = vim.active_editor.clone() {
-    //             if previous_editor == editor.clone() {
-    //                 vim.active_editor = None;
-    //                 vim.editor_subscription = None;
-    //             }
-    //         }
-    //         vim.editor_states.remove(&editor.id())
-    //     });
-    // });
+fn released(entity_id: EntityId, cx: &mut WindowContext) {
+    Vim::update(cx, |vim, _| {
+        if vim
+            .active_editor
+            .as_ref()
+            .is_some_and(|previous| previous.entity_id() == entity_id)
+        {
+            vim.active_editor = None;
+            vim.editor_subscription = None;
+        }
+        vim.editor_states.remove(&entity_id)
+    });
 }
 
 // #[cfg(test)]

crates/vim2/src/mode_indicator.rs 🔗

@@ -11,21 +11,8 @@ pub struct ModeIndicator {
 
 impl ModeIndicator {
     pub fn new(cx: &mut ViewContext<Self>) -> Self {
-        let handle = cx.view().downgrade();
-
-        // let _subscription = cx.subscribe_global::<VimEvent, _>(move |&event, cx| {
-        //     if let Some(mode_indicator) = handle.upgrade(cx) {
-        //         match event {
-        //             VimEvent::ModeChanged { mode } => {
-        //                 mode_indicator.window().update(cx, |cx| {
-        //                     mode_indicator.update(cx, move |mode_indicator, cx| {
-        //                         mode_indicator.set_mode(mode, cx);
-        //                     })
-        //                 });
-        //             }
-        //         }
-        //     }
-        // });
+        cx.observe_global::<Vim>(|this, cx| this.set_mode(Vim::read(cx).state().mode, cx))
+            .detach();
 
         cx.observe_global::<SettingsStore>(move |mode_indicator, cx| {
             if VimModeSetting::get_global(cx).0 {

crates/vim2/src/normal.rs 🔗

@@ -49,85 +49,86 @@ actions!(
     JoinLines,
 );
 
-pub fn init(cx: &mut AppContext) {
-    paste::init(cx);
-    repeat::init(cx);
-    scroll::init(cx);
-    search::init(cx);
-    substitute::init(cx);
-    increment::init(cx);
-
-    // cx.add_action(insert_after);
-    // cx.add_action(insert_before);
-    // cx.add_action(insert_first_non_whitespace);
-    // cx.add_action(insert_end_of_line);
-    // cx.add_action(insert_line_above);
-    // cx.add_action(insert_line_below);
-    // cx.add_action(change_case);
-    // cx.add_action(yank_line);
-
-    // cx.add_action(|_: &mut Workspace, _: &DeleteLeft, cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.record_current_action(cx);
-    //         let times = vim.take_count(cx);
-    //         delete_motion(vim, Motion::Left, times, cx);
-    //     })
-    // });
-    // cx.add_action(|_: &mut Workspace, _: &DeleteRight, cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.record_current_action(cx);
-    //         let times = vim.take_count(cx);
-    //         delete_motion(vim, Motion::Right, times, cx);
-    //     })
-    // });
-    // cx.add_action(|_: &mut Workspace, _: &ChangeToEndOfLine, cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.start_recording(cx);
-    //         let times = vim.take_count(cx);
-    //         change_motion(
-    //             vim,
-    //             Motion::EndOfLine {
-    //                 display_lines: false,
-    //             },
-    //             times,
-    //             cx,
-    //         );
-    //     })
-    // });
-    // cx.add_action(|_: &mut Workspace, _: &DeleteToEndOfLine, cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.record_current_action(cx);
-    //         let times = vim.take_count(cx);
-    //         delete_motion(
-    //             vim,
-    //             Motion::EndOfLine {
-    //                 display_lines: false,
-    //             },
-    //             times,
-    //             cx,
-    //         );
-    //     })
-    // });
-    // cx.add_action(|_: &mut Workspace, _: &JoinLines, cx| {
-    //     Vim::update(cx, |vim, cx| {
-    //         vim.record_current_action(cx);
-    //         let mut times = vim.take_count(cx).unwrap_or(1);
-    //         if vim.state().mode.is_visual() {
-    //             times = 1;
-    //         } else if times > 1 {
-    //             // 2J joins two lines together (same as J or 1J)
-    //             times -= 1;
-    //         }
-
-    //         vim.update_active_editor(cx, |editor, cx| {
-    //             editor.transact(cx, |editor, cx| {
-    //                 for _ in 0..times {
-    //                     editor.join_lines(&Default::default(), cx)
-    //                 }
-    //             })
-    //         })
-    //     })
-    // })
+pub(crate) fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
+    dbg!("registering");
+    workspace.register_action(insert_after);
+    workspace.register_action(insert_before);
+    workspace.register_action(insert_first_non_whitespace);
+    workspace.register_action(insert_end_of_line);
+    workspace.register_action(insert_line_above);
+    workspace.register_action(insert_line_below);
+    workspace.register_action(change_case);
+    workspace.register_action(yank_line);
+
+    workspace.register_action(|_: &mut Workspace, _: &DeleteLeft, cx| {
+        Vim::update(cx, |vim, cx| {
+            vim.record_current_action(cx);
+            let times = vim.take_count(cx);
+            delete_motion(vim, Motion::Left, times, cx);
+        })
+    });
+    workspace.register_action(|_: &mut Workspace, _: &DeleteRight, cx| {
+        Vim::update(cx, |vim, cx| {
+            vim.record_current_action(cx);
+            let times = vim.take_count(cx);
+            delete_motion(vim, Motion::Right, times, cx);
+        })
+    });
+    workspace.register_action(|_: &mut Workspace, _: &ChangeToEndOfLine, cx| {
+        Vim::update(cx, |vim, cx| {
+            vim.start_recording(cx);
+            let times = vim.take_count(cx);
+            change_motion(
+                vim,
+                Motion::EndOfLine {
+                    display_lines: false,
+                },
+                times,
+                cx,
+            );
+        })
+    });
+    workspace.register_action(|_: &mut Workspace, _: &DeleteToEndOfLine, cx| {
+        Vim::update(cx, |vim, cx| {
+            vim.record_current_action(cx);
+            let times = vim.take_count(cx);
+            delete_motion(
+                vim,
+                Motion::EndOfLine {
+                    display_lines: false,
+                },
+                times,
+                cx,
+            );
+        })
+    });
+    workspace.register_action(|_: &mut Workspace, _: &JoinLines, cx| {
+        Vim::update(cx, |vim, cx| {
+            vim.record_current_action(cx);
+            let mut times = vim.take_count(cx).unwrap_or(1);
+            if vim.state().mode.is_visual() {
+                times = 1;
+            } else if times > 1 {
+                // 2J joins two lines together (same as J or 1J)
+                times -= 1;
+            }
+
+            vim.update_active_editor(cx, |editor, cx| {
+                editor.transact(cx, |editor, cx| {
+                    for _ in 0..times {
+                        editor.join_lines(&Default::default(), cx)
+                    }
+                })
+            })
+        });
+    });
+
+    // paste::init(cx);
+    // repeat::init(cx);
+    // scroll::init(cx);
+    // search::init(cx);
+    // substitute::init(cx);
+    // increment::init(cx);
 }
 
 pub fn normal_motion(
@@ -200,6 +201,7 @@ fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext<Workspa
 }
 
 fn insert_before(_: &mut Workspace, _: &InsertBefore, cx: &mut ViewContext<Workspace>) {
+    dbg!("insert before!");
     Vim::update(cx, |vim, cx| {
         vim.start_recording(cx);
         vim.switch_mode(Mode::Insert, false, cx);

crates/vim2/src/vim.rs 🔗

@@ -44,9 +44,7 @@ pub struct PushOperator(pub Operator);
 #[derive(Action, Clone, Deserialize, PartialEq)]
 struct Number(usize);
 
-actions!(Tab, Enter, Object, InnerObject, FindForward, FindBackward);
-// todo!
-// actions!(workspace, [ToggleVimMode]);
+actions!(Tab, Enter, Object, InnerObject, FindForward, FindBackward,);
 
 #[derive(Copy, Clone, Debug)]
 enum VimEvent {
@@ -58,43 +56,16 @@ pub fn init(cx: &mut AppContext) {
     VimModeSetting::register(cx);
 
     editor_events::init(cx);
-    normal::init(cx);
+
+    cx.observe_new_views(|workspace: &mut Workspace, cx| register(workspace, cx))
+        .detach();
+
     visual::init(cx);
     insert::init(cx);
     object::init(cx);
     motion::init(cx);
     command::init(cx);
 
-    // Vim Actions
-    // todo!()
-    // cx.add_action(|_: &mut Workspace, &SwitchMode(mode): &SwitchMode, cx| {
-    //     Vim::update(cx, |vim, cx| vim.switch_mode(mode, false, cx))
-    // });
-    // cx.add_action(
-    //     |_: &mut Workspace, &PushOperator(operator): &PushOperator, cx| {
-    //         Vim::update(cx, |vim, cx| vim.push_operator(operator, cx))
-    //     },
-    // );
-    // cx.add_action(|_: &mut Workspace, n: &Number, cx: _| {
-    //     Vim::update(cx, |vim, cx| vim.push_count_digit(n.0, cx));
-    // });
-
-    // cx.add_action(|_: &mut Workspace, _: &Tab, cx| {
-    //     Vim::active_editor_input_ignored(" ".into(), cx)
-    // });
-
-    // cx.add_action(|_: &mut Workspace, _: &Enter, cx| {
-    //     Vim::active_editor_input_ignored("\n".into(), cx)
-    // });
-
-    // cx.add_action(|workspace: &mut Workspace, _: &ToggleVimMode, cx| {
-    //     let fs = workspace.app_state().fs.clone();
-    //     let currently_enabled = settings::get::<VimModeSetting>(cx).0;
-    //     update_settings_file::<VimModeSetting>(fs, cx, move |setting| {
-    //         *setting = Some(!currently_enabled)
-    //     })
-    // });
-
     // Any time settings change, update vim mode to match. The Vim struct
     // will be initialized as disabled by default, so we filter its commands
     // out when starting up.
@@ -112,6 +83,40 @@ pub fn init(cx: &mut AppContext) {
     .detach();
 }
 
+fn register(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) {
+    workspace.register_action(|_: &mut Workspace, &SwitchMode(mode): &SwitchMode, cx| {
+        Vim::update(cx, |vim, cx| vim.switch_mode(mode, false, cx))
+    });
+    workspace.register_action(
+        |_: &mut Workspace, &PushOperator(operator): &PushOperator, cx| {
+            Vim::update(cx, |vim, cx| vim.push_operator(operator, cx))
+        },
+    );
+    workspace.register_action(|_: &mut Workspace, n: &Number, cx: _| {
+        Vim::update(cx, |vim, cx| vim.push_count_digit(n.0, cx));
+    });
+
+    workspace.register_action(|_: &mut Workspace, _: &Tab, cx| {
+        Vim::active_editor_input_ignored(" ".into(), cx)
+    });
+
+    workspace.register_action(|_: &mut Workspace, _: &Enter, cx| {
+        Vim::active_editor_input_ignored("\n".into(), cx)
+    });
+
+    workspace.register_action(
+        |workspace: &mut Workspace, _: &workspace::ToggleVimMode, cx| {
+            let fs = workspace.app_state().fs.clone();
+            let currently_enabled = VimModeSetting::get_global(cx).0;
+            update_settings_file::<VimModeSetting>(fs, cx, move |setting| {
+                *setting = Some(!currently_enabled)
+            })
+        },
+    );
+
+    normal::register(workspace, cx)
+}
+
 pub fn observe_keystrokes(cx: &mut WindowContext) {
     // todo!()
 
@@ -165,7 +170,7 @@ pub struct Vim {
 
 impl Vim {
     fn read(cx: &mut AppContext) -> &Self {
-        cx.default_global()
+        cx.global::<Self>()
     }
 
     fn update<F, S>(cx: &mut WindowContext, update: F) -> S