diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index 7beab3b7c5..3e916ccd1b 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -735,7 +735,7 @@ mod tests { .map_or(5, |o| o.parse().expect("invalid OPERATIONS variable")); for seed in starting_seed..(starting_seed + num_iterations) { - dbg!(seed); + eprintln!("seed = {}", seed); let mut rng = StdRng::seed_from_u64(seed); let rng = &mut rng; diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index 658f80f323..81fb03ea76 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -1,5 +1,5 @@ use editor::{EditorBlurred, EditorFocused, EditorMode, EditorReleased, Event}; -use gpui::AppContext; +use gpui::{AppContext, WindowContext}; use crate::{state::Mode, Vim}; @@ -10,65 +10,71 @@ pub fn init(cx: &mut AppContext) { } fn focused(EditorFocused(editor): &EditorFocused, cx: &mut AppContext) { - Vim::update(cx, |vim, cx| { - vim.update_active_editor(cx, |previously_active_editor, cx| { - Vim::unhook_vim_settings(previously_active_editor, cx); - }); + cx.update_window(editor.window_id(), |cx| { + Vim::update(cx, |vim, cx| { + vim.update_active_editor(cx, |previously_active_editor, cx| { + Vim::unhook_vim_settings(previously_active_editor, cx); + }); - vim.active_editor = Some(editor.downgrade()); - vim.editor_subscription = Some(cx.subscribe(editor, |editor, event, cx| match event { - Event::SelectionsChanged { local: true } => { + vim.active_editor = Some(editor.downgrade()); + vim.editor_subscription = Some(cx.subscribe(editor, |editor, event, cx| match event { + Event::SelectionsChanged { local: true } => { + let editor = editor.read(cx); + if editor.leader_replica_id().is_none() { + let newest_empty = editor.selections.newest::(cx).is_empty(); + local_selections_changed(newest_empty, cx); + } + } + Event::InputIgnored { text } => { + Vim::active_editor_input_ignored(text.clone(), cx); + } + _ => {} + })); + + if vim.enabled { let editor = editor.read(cx); - if editor.leader_replica_id().is_none() { - let newest_empty = editor.selections.newest::(cx).is_empty(); - local_selections_changed(newest_empty, cx); + let editor_mode = editor.mode(); + let newest_selection_empty = editor.selections.newest::(cx).is_empty(); + + if editor_mode == EditorMode::Full && !newest_selection_empty { + vim.switch_mode(Mode::Visual { line: false }, true, cx); } } - Event::InputIgnored { text } => { - Vim::active_editor_input_ignored(text.clone(), cx); - } - _ => {} - })); - if vim.enabled { - let editor = editor.read(cx); - let editor_mode = editor.mode(); - let newest_selection_empty = editor.selections.newest::(cx).is_empty(); - - if editor_mode == EditorMode::Full && !newest_selection_empty { - vim.switch_mode(Mode::Visual { line: false }, true, cx); - } - } - - vim.sync_vim_settings(cx); + vim.sync_vim_settings(cx); + }); }); } fn blurred(EditorBlurred(editor): &EditorBlurred, cx: &mut AppContext) { - Vim::update(cx, |vim, cx| { - if let Some(previous_editor) = vim.active_editor.clone() { - if previous_editor == editor.clone() { - vim.active_editor = None; + cx.update_window(editor.window_id(), |cx| { + Vim::update(cx, |vim, cx| { + if let Some(previous_editor) = vim.active_editor.clone() { + if previous_editor == editor.clone() { + vim.active_editor = None; + } } - } - cx.update_window(editor.window_id(), |cx| { - editor.update(cx, |editor, cx| Vim::unhook_vim_settings(editor, cx)) + cx.update_window(editor.window_id(), |cx| { + editor.update(cx, |editor, cx| Vim::unhook_vim_settings(editor, cx)) + }); }); - }) -} - -fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) { - cx.update_default_global(|vim: &mut Vim, _| { - if let Some(previous_editor) = vim.active_editor.clone() { - if previous_editor == editor.clone() { - vim.active_editor = None; - } - } }); } -fn local_selections_changed(newest_empty: bool, cx: &mut AppContext) { +fn released(EditorReleased(editor): &EditorReleased, cx: &mut AppContext) { + cx.update_window(editor.window_id(), |cx| { + cx.update_default_global(|vim: &mut Vim, _| { + if let Some(previous_editor) = vim.active_editor.clone() { + if previous_editor == editor.clone() { + vim.active_editor = None; + } + } + }); + }); +} + +fn local_selections_changed(newest_empty: bool, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { if vim.enabled && vim.state.mode == Mode::Normal && !newest_empty { vim.switch_mode(Mode::Visual { line: false }, false, cx) diff --git a/crates/vim/src/motion.rs b/crates/vim/src/motion.rs index e919cf8096..cc3ec06c47 100644 --- a/crates/vim/src/motion.rs +++ b/crates/vim/src/motion.rs @@ -5,7 +5,7 @@ use editor::{ display_map::{DisplaySnapshot, ToDisplayPoint}, movement, Bias, CharKind, DisplayPoint, ToOffset, }; -use gpui::{actions, impl_actions, AppContext}; +use gpui::{actions, impl_actions, AppContext, WindowContext}; use language::{Point, Selection, SelectionGoal}; use serde::Deserialize; use workspace::Workspace; @@ -116,7 +116,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(|_: &mut Workspace, &NextLineStart, cx: _| motion(Motion::NextLineStart, cx)) } -pub(crate) fn motion(motion: Motion, cx: &mut AppContext) { +pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) { if let Some(Operator::Namespace(_)) | Some(Operator::FindForward { .. }) | Some(Operator::FindBackward { .. }) = Vim::read(cx).active_operator() diff --git a/crates/vim/src/normal.rs b/crates/vim/src/normal.rs index 3147fb6cf9..9f4cf449bd 100644 --- a/crates/vim/src/normal.rs +++ b/crates/vim/src/normal.rs @@ -16,7 +16,7 @@ use editor::{ scroll::{autoscroll::Autoscroll, scroll_amount::ScrollAmount}, Anchor, Bias, ClipboardSelection, DisplayPoint, Editor, }; -use gpui::{actions, impl_actions, AppContext, ViewContext}; +use gpui::{actions, impl_actions, AppContext, ViewContext, WindowContext}; use language::{AutoindentMode, Point, SelectionGoal}; use log::error; use serde::Deserialize; @@ -94,7 +94,7 @@ pub fn normal_motion( motion: Motion, operator: Option, times: usize, - cx: &mut AppContext, + cx: &mut WindowContext, ) { Vim::update(cx, |vim, cx| { match operator { @@ -110,7 +110,7 @@ pub fn normal_motion( }); } -pub fn normal_object(object: Object, cx: &mut AppContext) { +pub fn normal_object(object: Object, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { match vim.state.operator_stack.pop() { Some(Operator::Object { around }) => match vim.state.operator_stack.pop() { @@ -129,7 +129,7 @@ pub fn normal_object(object: Object, cx: &mut AppContext) { }) } -fn move_cursor(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) { +fn move_cursor(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::fit()), cx, |s| { s.move_cursors_with(|map, cursor, goal| { @@ -424,7 +424,7 @@ fn scroll(editor: &mut Editor, amount: &ScrollAmount, cx: &mut ViewContext, cx: &mut AppContext) { +pub(crate) fn normal_replace(text: Arc, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { diff --git a/crates/vim/src/normal/change.rs b/crates/vim/src/normal/change.rs index 899fea8b73..350ffdbb8f 100644 --- a/crates/vim/src/normal/change.rs +++ b/crates/vim/src/normal/change.rs @@ -3,10 +3,10 @@ use editor::{ char_kind, display_map::DisplaySnapshot, movement, scroll::autoscroll::Autoscroll, CharKind, DisplayPoint, }; -use gpui::AppContext; +use gpui::WindowContext; use language::Selection; -pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) { +pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) { // Some motions ignore failure when switching to normal mode let mut motion_succeeded = matches!( motion, @@ -38,7 +38,7 @@ pub fn change_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppCo } } -pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) { +pub fn change_object(vim: &mut Vim, object: Object, around: bool, cx: &mut WindowContext) { let mut objects_found = false; vim.update_active_editor(cx, |editor, cx| { // We are swapping to insert mode anyway. Just set the line end clipping behavior now diff --git a/crates/vim/src/normal/delete.rs b/crates/vim/src/normal/delete.rs index 1be264b7fd..cbea65ddaf 100644 --- a/crates/vim/src/normal/delete.rs +++ b/crates/vim/src/normal/delete.rs @@ -1,9 +1,9 @@ use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim}; use collections::{HashMap, HashSet}; use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Bias}; -use gpui::AppContext; +use gpui::WindowContext; -pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) { +pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.set_clip_at_line_ends(false, cx); @@ -36,7 +36,7 @@ pub fn delete_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppCo }); } -pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) { +pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.set_clip_at_line_ends(false, cx); diff --git a/crates/vim/src/normal/yank.rs b/crates/vim/src/normal/yank.rs index 610b137d49..aeef333127 100644 --- a/crates/vim/src/normal/yank.rs +++ b/crates/vim/src/normal/yank.rs @@ -1,8 +1,8 @@ use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim}; use collections::HashMap; -use gpui::AppContext; +use gpui::WindowContext; -pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppContext) { +pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.set_clip_at_line_ends(false, cx); @@ -25,7 +25,7 @@ pub fn yank_motion(vim: &mut Vim, motion: Motion, times: usize, cx: &mut AppCont }); } -pub fn yank_object(vim: &mut Vim, object: Object, around: bool, cx: &mut AppContext) { +pub fn yank_object(vim: &mut Vim, object: Object, around: bool, cx: &mut WindowContext) { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| { editor.set_clip_at_line_ends(false, cx); diff --git a/crates/vim/src/object.rs b/crates/vim/src/object.rs index c7ad577d55..fb09d7141f 100644 --- a/crates/vim/src/object.rs +++ b/crates/vim/src/object.rs @@ -1,7 +1,7 @@ use std::ops::Range; use editor::{char_kind, display_map::DisplaySnapshot, movement, Bias, CharKind, DisplayPoint}; -use gpui::{actions, impl_actions, AppContext}; +use gpui::{actions, impl_actions, AppContext, WindowContext}; use language::Selection; use serde::Deserialize; use workspace::Workspace; @@ -61,7 +61,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(|_: &mut Workspace, _: &AngleBrackets, cx: _| object(Object::AngleBrackets, cx)); } -fn object(object: Object, cx: &mut AppContext) { +fn object(object: Object, cx: &mut WindowContext) { match Vim::read(cx).state.mode { Mode::Normal => normal_object(object, cx), Mode::Visual { .. } => visual_object(object, cx), @@ -434,17 +434,17 @@ mod test { use crate::test::{ExemptionFeatures, NeovimBackedTestContext}; const WORD_LOCATIONS: &'static str = indoc! {" - The quick ˇbrowˇnˇ + The quick ˇbrowˇnˇ fox ˇjuˇmpsˇ over - the lazy dogˇ + the lazy dogˇ ˇ ˇ ˇ - Thˇeˇ-ˇquˇickˇ ˇbrownˇ - ˇ - ˇ + Thˇeˇ-ˇquˇickˇ ˇbrownˇ + ˇ + ˇ ˇ fox-jumpˇs over - the lazy dogˇ + the lazy dogˇ ˇ "}; @@ -527,7 +527,7 @@ mod test { const SENTENCE_EXAMPLES: &[&'static str] = &[ "ˇThe quick ˇbrownˇ?ˇ ˇFox Jˇumpsˇ!ˇ Ovˇer theˇ lazyˇ.", indoc! {" - ˇThe quick ˇbrownˇ + ˇThe quick ˇbrownˇ fox jumps over the lazy doˇgˇ.ˇ ˇThe quick ˇ brown fox jumps over diff --git a/crates/vim/src/test/vim_test_context.rs b/crates/vim/src/test/vim_test_context.rs index 2e668292e8..577f8c8bd4 100644 --- a/crates/vim/src/test/vim_test_context.rs +++ b/crates/vim/src/test/vim_test_context.rs @@ -16,19 +16,15 @@ pub struct VimTestContext<'a> { impl<'a> VimTestContext<'a> { pub async fn new(cx: &'a mut gpui::TestAppContext, enabled: bool) -> VimTestContext<'a> { - cx.update(|cx| { - search::init(cx); - crate::init(cx); - - settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap(); - }); - let mut cx = EditorLspTestContext::new_rust(Default::default(), cx).await; - cx.update(|cx| { cx.update_global(|settings: &mut Settings, _| { settings.vim_mode = enabled; }); + search::init(cx); + crate::init(cx); + + settings::KeymapFileContent::load("keymaps/vim.json", cx).unwrap(); }); // Setup search toolbars and keypress hook @@ -80,7 +76,8 @@ impl<'a> VimTestContext<'a> { } pub fn set_state(&mut self, text: &str, mode: Mode) -> ContextHandle { - self.cx.update(|cx| { + let window_id = self.window_id; + self.update_window(window_id, |cx| { Vim::update(cx, |vim, cx| { vim.switch_mode(mode, false, cx); }) diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index f9f72b7c37..32a3f6e3ea 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -65,7 +65,7 @@ pub fn init(cx: &mut AppContext) { // Otherwise forward cancel on to the editor let vim = Vim::read(cx); if vim.state.mode != Mode::Normal || vim.active_operator().is_some() { - AppContext::defer(cx, |cx| { + WindowContext::defer(cx, |cx| { Vim::update(cx, |state, cx| { state.switch_mode(Mode::Normal, false, cx); }); @@ -83,14 +83,14 @@ pub fn init(cx: &mut AppContext) { Vim::active_editor_input_ignored("\n".into(), cx) }); - // Sync initial settings with the rest of the app - Vim::update(cx, |vim, cx| vim.sync_vim_settings(cx)); - - // Any time settings change, update vim mode to match + // Any time settings change, update vim mode to match. + cx.update_default_global(|vim: &mut Vim, cx: &mut AppContext| { + vim.set_enabled(cx.global::().vim_mode, cx) + }); cx.observe_global::(|cx| { - Vim::update(cx, |state, cx| { - state.set_enabled(cx.global::().vim_mode, cx) - }) + cx.update_default_global(|vim: &mut Vim, cx: &mut AppContext| { + vim.set_enabled(cx.global::().vim_mode, cx) + }); }) .detach(); } @@ -135,23 +135,23 @@ impl Vim { cx.default_global() } - fn update(cx: &mut AppContext, update: F) -> S + fn update(cx: &mut WindowContext, update: F) -> S where - F: FnOnce(&mut Self, &mut AppContext) -> S, + F: FnOnce(&mut Self, &mut WindowContext) -> S, { cx.update_default_global(update) } fn update_active_editor( &self, - cx: &mut AppContext, + cx: &mut WindowContext, update: impl FnOnce(&mut Editor, &mut ViewContext) -> S, ) -> Option { let editor = self.active_editor.clone()?.upgrade(cx)?; - cx.update_window(editor.window_id(), |cx| editor.update(cx, update)) + Some(editor.update(cx, update)) } - fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut AppContext) { + fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut WindowContext) { self.state.mode = mode; self.state.operator_stack.clear(); @@ -178,12 +178,12 @@ impl Vim { }); } - fn push_operator(&mut self, operator: Operator, cx: &mut AppContext) { + fn push_operator(&mut self, operator: Operator, cx: &mut WindowContext) { self.state.operator_stack.push(operator); self.sync_vim_settings(cx); } - fn push_number(&mut self, Number(number): &Number, cx: &mut AppContext) { + fn push_number(&mut self, Number(number): &Number, cx: &mut WindowContext) { if let Some(Operator::Number(current_number)) = self.active_operator() { self.pop_operator(cx); self.push_operator(Operator::Number(current_number * 10 + *number as usize), cx); @@ -192,14 +192,14 @@ impl Vim { } } - fn pop_operator(&mut self, cx: &mut AppContext) -> Operator { + fn pop_operator(&mut self, cx: &mut WindowContext) -> Operator { let popped_operator = self.state.operator_stack.pop() .expect("Operator popped when no operator was on the stack. This likely means there is an invalid keymap config"); self.sync_vim_settings(cx); popped_operator } - fn pop_number_operator(&mut self, cx: &mut AppContext) -> usize { + fn pop_number_operator(&mut self, cx: &mut WindowContext) -> usize { let mut times = 1; if let Some(Operator::Number(number)) = self.active_operator() { times = number; @@ -208,7 +208,7 @@ impl Vim { times } - fn clear_operator(&mut self, cx: &mut AppContext) { + fn clear_operator(&mut self, cx: &mut WindowContext) { self.state.operator_stack.clear(); self.sync_vim_settings(cx); } @@ -217,7 +217,7 @@ impl Vim { self.state.operator_stack.last().copied() } - fn active_editor_input_ignored(text: Arc, cx: &mut AppContext) { + fn active_editor_input_ignored(text: Arc, cx: &mut WindowContext) { if text.is_empty() { return; } @@ -242,25 +242,33 @@ impl Vim { if self.enabled != enabled { self.enabled = enabled; self.state = Default::default(); - if enabled { - self.switch_mode(Mode::Normal, false, cx); - } - self.sync_vim_settings(cx); + + cx.update_default_global::(|filter, _| { + if self.enabled { + filter.filtered_namespaces.remove("vim"); + } else { + filter.filtered_namespaces.insert("vim"); + } + }); + + cx.update_active_window(|cx| { + if self.enabled { + self.active_editor = cx + .root_view() + .downcast_ref::() + .and_then(|workspace| workspace.read(cx).active_item(cx)) + .and_then(|item| item.downcast::().map(|h| h.downgrade())); + self.switch_mode(Mode::Normal, false, cx); + } + self.sync_vim_settings(cx); + }); } } - fn sync_vim_settings(&self, cx: &mut AppContext) { + fn sync_vim_settings(&self, cx: &mut WindowContext) { let state = &self.state; let cursor_shape = state.cursor_shape(); - cx.update_default_global::(|filter, _| { - if self.enabled { - filter.filtered_namespaces.remove("vim"); - } else { - filter.filtered_namespaces.insert("vim"); - } - }); - self.update_active_editor(cx, |editor, cx| { if self.enabled && editor.mode() == EditorMode::Full { editor.set_cursor_shape(cursor_shape, cx); diff --git a/crates/vim/src/visual.rs b/crates/vim/src/visual.rs index 1e8d02e063..c3728db222 100644 --- a/crates/vim/src/visual.rs +++ b/crates/vim/src/visual.rs @@ -4,7 +4,7 @@ use collections::HashMap; use editor::{ display_map::ToDisplayPoint, movement, scroll::autoscroll::Autoscroll, Bias, ClipboardSelection, }; -use gpui::{actions, AppContext, ViewContext}; +use gpui::{actions, AppContext, ViewContext, WindowContext}; use language::{AutoindentMode, SelectionGoal}; use workspace::Workspace; @@ -25,7 +25,7 @@ pub fn init(cx: &mut AppContext) { cx.add_action(paste); } -pub fn visual_motion(motion: Motion, times: usize, cx: &mut AppContext) { +pub fn visual_motion(motion: Motion, times: usize, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { vim.update_active_editor(cx, |editor, cx| { editor.change_selections(Some(Autoscroll::fit()), cx, |s| { @@ -56,7 +56,7 @@ pub fn visual_motion(motion: Motion, times: usize, cx: &mut AppContext) { }); } -pub fn visual_object(object: Object, cx: &mut AppContext) { +pub fn visual_object(object: Object, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { if let Operator::Object { around } = vim.pop_operator(cx) { vim.update_active_editor(cx, |editor, cx| { @@ -313,7 +313,7 @@ pub fn paste(_: &mut Workspace, _: &VisualPaste, cx: &mut ViewContext }); } -pub(crate) fn visual_replace(text: Arc, line: bool, cx: &mut AppContext) { +pub(crate) fn visual_replace(text: Arc, line: bool, cx: &mut WindowContext) { Vim::update(cx, |vim, cx| { vim.update_active_editor(cx, |editor, cx| { editor.transact(cx, |editor, cx| {