From a4ea7bf92867b3502c5fb6f56c9f36c76f8da20c Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 8 Dec 2023 17:45:17 -0700 Subject: [PATCH] More code written, similar lack of workingness so far --- 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 | 154 +++++++++++++------------- crates/vim2/src/vim.rs | 75 +++++++------ crates/workspace2/src/workspace2.rs | 1 + 7 files changed, 188 insertions(+), 190 deletions(-) diff --git a/crates/editor2/src/element.rs b/crates/editor2/src/element.rs index ad66ed8090..810dd44cd0 100644 --- a/crates/editor2/src/element.rs +++ b/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( diff --git a/crates/settings2/src/settings_file.rs b/crates/settings2/src/settings_file.rs index 46450a9c28..590079c51b 100644 --- a/crates/settings2/src/settings_file.rs +++ b/crates/settings2/src/settings_file.rs @@ -124,17 +124,6 @@ pub fn update_settings_file( 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(); } diff --git a/crates/vim2/src/editor_events.rs b/crates/vim2/src/editor_events.rs index e4eb9047ab..6211bbe1e7 100644 --- a/crates/vim2/src/editor_events.rs +++ b/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| { + 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, 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, 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)] diff --git a/crates/vim2/src/mode_indicator.rs b/crates/vim2/src/mode_indicator.rs index 9a59aa3f37..9da542ec7e 100644 --- a/crates/vim2/src/mode_indicator.rs +++ b/crates/vim2/src/mode_indicator.rs @@ -11,21 +11,8 @@ pub struct ModeIndicator { impl ModeIndicator { pub fn new(cx: &mut ViewContext) -> Self { - let handle = cx.view().downgrade(); - - // let _subscription = cx.subscribe_global::(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::(|this, cx| this.set_mode(Vim::read(cx).state().mode, cx)) + .detach(); cx.observe_global::(move |mode_indicator, cx| { if VimModeSetting::get_global(cx).0 { diff --git a/crates/vim2/src/normal.rs b/crates/vim2/src/normal.rs index cba5dadb3f..64eecd00e5 100644 --- a/crates/vim2/src/normal.rs +++ b/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); +pub(crate) fn register(workspace: &mut Workspace, cx: &mut ViewContext) { + 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); - // 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); + 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; + } - // 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) + } + }) + }) + }); + }); - // 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) { + dbg!("insert before!"); Vim::update(cx, |vim, cx| { vim.start_recording(cx); vim.switch_mode(Mode::Insert, false, cx); diff --git a/crates/vim2/src/vim.rs b/crates/vim2/src/vim.rs index 4403a8e881..e3b3a3c2be 100644 --- a/crates/vim2/src/vim.rs +++ b/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::(cx).0; - // update_settings_file::(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.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::(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::() } fn update(cx: &mut WindowContext, update: F) -> S diff --git a/crates/workspace2/src/workspace2.rs b/crates/workspace2/src/workspace2.rs index 251f0685b0..742dd01fe4 100644 --- a/crates/workspace2/src/workspace2.rs +++ b/crates/workspace2/src/workspace2.rs @@ -114,6 +114,7 @@ actions!( ToggleLeftDock, ToggleRightDock, ToggleBottomDock, + ToggleVimMode, CloseAllDocks, );