use itertools::Itertools;use unindent::Unindent;use warpui::platform::WindowStyle;use warpui::{App, EntityIdSet, ViewHandle}; use super::*;use crate::editor::EditorView; /// Helper function for testing vim mode commands./// This creates an editor with the given content and enters Vim Normal mode,/// as opposed to the default Insert mode.fn add_editor_vim_normal_mode(buffer_content: &str, app: &mut App) -> ViewHandle<EditorView> { let (_, editor) = app.add_window(WindowStyle::NotStealFocus, move |ctx| { let options = EditorOptions { supports_vim_mode: true, ..Default::default() }; let base_text = buffer_content.unindent(); let mut editor = EditorView::new_with_base_text(base_text.as_str(), options, ctx); editor .select_ranges(vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], ctx) .unwrap(); editor.vim_keystroke(&Keystroke::parse("escape").unwrap(), ctx); assert_eq!(editor.vim_mode(ctx), Some(VimMode::Normal)); editor }); editor} #[test]fn test_vim_ctrl_c_normal() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in normal mode should clear the buffer // and stay in normal mode. editor.update(&mut app, |view, view_ctx| { view.handle_action(&EditorAction::CtrlC, view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), ""); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); });} #[test]fn test_vim_ctrl_c_insert() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("", &mut app); // Insert some text. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("i", view_ctx); view.vim_user_insert("add text", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "add text"); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); // Ctrl-c in insert mode should clear the buffer // and stay in insert mode. // // Why not switch to normal mode? // Terminal vi mode implementations typically use insert mode as the default mode, // because inserting text is generally more common in the terminal than editing text. // To be consistent with those, we're not changing to normal mode on ctrl-c. editor.update(&mut app, |view, view_ctx| { view.handle_action(&EditorAction::CtrlC, view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), ""); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); });} #[test]fn test_vim_ctrl_c_replace() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in replace mode should cancel the replacement. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("r", view_ctx); view.handle_action(&EditorAction::CtrlC, view_ctx); view.vim_user_insert("~", view_ctx); }); // Instead of replacing "s" with "~", the "~" should be interpreted // on its own. editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "Some text"); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); });} #[test]fn test_vim_ctrl_c_visual() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in replace mode should exit visual mode. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("vw", view_ctx); view.handle_action(&EditorAction::CtrlC, view_ctx); view.vim_user_insert("d", view_ctx); }); // Instead of deleting the word, the "d" should be a pending operator. editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "some text"); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)); assert_eq!(view.vim_model.as_ref(app_ctx).state().showcmd, "d"); }); });} #[test]fn test_vim_enter() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("letters", &mut app); // Go into insert mode, then enter. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("A", view_ctx); view.enter(view_ctx); }); // Vim FSA should stay in insert mode. editor.read(&app, |view, app_ctx| { assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); // Go into normal mode, then enter. editor.update(&mut app, |view, view_ctx| { view.vim_keystroke(&Keystroke::parse("escape").unwrap(), view_ctx); view.enter(view_ctx); }); // Vim FSA should switch back to insert mode. editor.read(&app, |view, app_ctx| { assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); });} #[test]fn test_vim_number_repeat_action() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "line 1 line 2 line 3 line 4", &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3dd", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.buffer_text(app_ctx), "line 4"); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); });} #[test]fn test_vim_number_repeat_word_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "abc de f gh ijkl m nop" .unindent() .as_str(), &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); }); // Try to go past the end of the buffer. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("4w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 12)..DisplayPoint::new(1, 12)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2b", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 8)..DisplayPoint::new(1, 8)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2b2e", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6)] ); }); });} #[test]fn test_vim_number_repeat_line_motion() { // TODO: make sure to test line motions where number-repeat does nothing App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "aa bbbbb ccc dddd" .unindent() .as_str(), &mut app, ); // Lay out the window so that up and down motions work. // Layout code starts here. let window_id = app.read(|ctx| editor.window_id(ctx)); let mut presenter = warpui::presenter::Presenter::new(window_id); let mut updated = EntityIdSet::default(); updated.insert(app.root_view_id(window_id).unwrap()); let invalidation = warpui::WindowInvalidation { updated, ..Default::default() }; app.update(move |ctx| { presenter.invalidate(invalidation, ctx); presenter.build_scene( pathfinder_geometry::vector::vec2f(1000., 1000.), 1., None, ctx, ); }); // Layout code ends here. // #$ editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("2$", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3$", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3)] ); }); // #^ ignores the repetition count. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3^", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] ); }); });} #[test]fn test_vim_number_repeat_character_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "aa bbbbb ccc dddd" .unindent() .as_str(), &mut app, ); // Lay out the window so that up and down motions work. // Layout code starts here. let window_id = app.read(|ctx| editor.window_id(ctx)); let mut presenter = warpui::presenter::Presenter::new(window_id); let mut updated = EntityIdSet::default(); updated.insert(app.root_view_id(window_id).unwrap()); let invalidation = warpui::WindowInvalidation { updated, ..Default::default() }; app.update(move |ctx| { presenter.invalidate(invalidation, ctx); presenter.build_scene( pathfinder_geometry::vector::vec2f(1000., 1000.), 1., None, ctx, ); }); // Layout code ends here. // #j editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3j", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] ); }); // #l editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3l", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3)] ); }); // #k editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2k", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] ); }); // #h (and attempt to go past the start of the line) editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("4h", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); }); });} #[test]fn test_vim_number_repeat_op_word_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "line 1 line 2 line 3 line 4", &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("d3w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); assert_eq!( view.buffer_text(app_ctx), "line 1 3 line 4" .unindent() .as_str() ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("c2w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(Lines 1–500 of 7864. Load more
use itertools::Itertools; use unindent::Unindent; use warpui::platform::WindowStyle; use warpui::{App, EntityIdSet, ViewHandle}; use super::*; use crate::editor::EditorView; /// Helper function for testing vim mode commands. /// This creates an editor with the given content and enters Vim Normal mode, /// as opposed to the default Insert mode. fn add_editor_vim_normal_mode(buffer_content: &str, app: &mut App) -> ViewHandle<EditorView> { let (_, editor) = app.add_window(WindowStyle::NotStealFocus, move |ctx| { let options = EditorOptions { supports_vim_mode: true, ..Default::default() }; let base_text = buffer_content.unindent(); let mut editor = EditorView::new_with_base_text(base_text.as_str(), options, ctx); editor .select_ranges(vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], ctx) .unwrap(); editor.vim_keystroke(&Keystroke::parse("escape").unwrap(), ctx); assert_eq!(editor.vim_mode(ctx), Some(VimMode::Normal)); editor }); editor } #[test] fn test_vim_ctrl_c_normal() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in normal mode should clear the buffer // and stay in normal mode. editor.update(&mut app, |view, view_ctx| { view.handle_action(&EditorAction::CtrlC, view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), ""); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); }); } #[test] fn test_vim_ctrl_c_insert() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("", &mut app); // Insert some text. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("i", view_ctx); view.vim_user_insert("add text", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "add text"); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 8)..DisplayPoint::new(0, 8)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); // Ctrl-c in insert mode should clear the buffer // and stay in insert mode. // // Why not switch to normal mode? // Terminal vi mode implementations typically use insert mode as the default mode, // because inserting text is generally more common in the terminal than editing text. // To be consistent with those, we're not changing to normal mode on ctrl-c. editor.update(&mut app, |view, view_ctx| { view.handle_action(&EditorAction::CtrlC, view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), ""); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); }); } #[test] fn test_vim_ctrl_c_replace() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in replace mode should cancel the replacement. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("r", view_ctx); view.handle_action(&EditorAction::CtrlC, view_ctx); view.vim_user_insert("~", view_ctx); }); // Instead of replacing "s" with "~", the "~" should be interpreted // on its own. editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "Some text"); assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 1)..DisplayPoint::new(0, 1)] ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); }); } #[test] fn test_vim_ctrl_c_visual() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("some text", &mut app); // Ctrl-c in replace mode should exit visual mode. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("vw", view_ctx); view.handle_action(&EditorAction::CtrlC, view_ctx); view.vim_user_insert("d", view_ctx); }); // Instead of deleting the word, the "d" should be a pending operator. editor.read(&app, |view, app_ctx| { assert_eq!(view.buffer_text(app_ctx), "some text"); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)); assert_eq!(view.vim_model.as_ref(app_ctx).state().showcmd, "d"); }); }); } #[test] fn test_vim_enter() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode("letters", &mut app); // Go into insert mode, then enter. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("A", view_ctx); view.enter(view_ctx); }); // Vim FSA should stay in insert mode. editor.read(&app, |view, app_ctx| { assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); // Go into normal mode, then enter. editor.update(&mut app, |view, view_ctx| { view.vim_keystroke(&Keystroke::parse("escape").unwrap(), view_ctx); view.enter(view_ctx); }); // Vim FSA should switch back to insert mode. editor.read(&app, |view, app_ctx| { assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Insert)) }); }); } #[test] fn test_vim_number_repeat_action() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "line 1 line 2 line 3 line 4", &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3dd", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)] ); assert_eq!(view.buffer_text(app_ctx), "line 4"); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); }); } #[test] fn test_vim_number_repeat_word_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "abc de f gh ijkl m nop" .unindent() .as_str(), &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); }); // Try to go past the end of the buffer. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("4w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 12)..DisplayPoint::new(1, 12)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2b", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 8)..DisplayPoint::new(1, 8)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2b2e", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 6)..DisplayPoint::new(1, 6)] ); }); }); } #[test] fn test_vim_number_repeat_line_motion() { // TODO: make sure to test line motions where number-repeat does nothing App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "aa bbbbb ccc dddd" .unindent() .as_str(), &mut app, ); // Lay out the window so that up and down motions work. // Layout code starts here. let window_id = app.read(|ctx| editor.window_id(ctx)); let mut presenter = warpui::presenter::Presenter::new(window_id); let mut updated = EntityIdSet::default(); updated.insert(app.root_view_id(window_id).unwrap()); let invalidation = warpui::WindowInvalidation { updated, ..Default::default() }; app.update(move |ctx| { presenter.invalidate(invalidation, ctx); presenter.build_scene( pathfinder_geometry::vector::vec2f(1000., 1000.), 1., None, ctx, ); }); // Layout code ends here. // #$ editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("2$", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)] ); }); editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3$", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3)] ); }); // #^ ignores the repetition count. editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3^", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] ); }); }); } #[test] fn test_vim_number_repeat_character_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "aa bbbbb ccc dddd" .unindent() .as_str(), &mut app, ); // Lay out the window so that up and down motions work. // Layout code starts here. let window_id = app.read(|ctx| editor.window_id(ctx)); let mut presenter = warpui::presenter::Presenter::new(window_id); let mut updated = EntityIdSet::default(); updated.insert(app.root_view_id(window_id).unwrap()); let invalidation = warpui::WindowInvalidation { updated, ..Default::default() }; app.update(move |ctx| { presenter.invalidate(invalidation, ctx); presenter.build_scene( pathfinder_geometry::vector::vec2f(1000., 1000.), 1., None, ctx, ); }); // Layout code ends here. // #j editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("3j", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 0)..DisplayPoint::new(3, 0)] ); }); // #l editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("3l", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(3, 3)..DisplayPoint::new(3, 3)] ); }); // #k editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("2k", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 3)..DisplayPoint::new(1, 3)] ); }); // #h (and attempt to go past the start of the line) editor.update(&mut app, |view, view_ctx| { view.vim_user_insert("4h", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); }); }); } #[test] fn test_vim_number_repeat_op_word_motion() { App::test((), |mut app| async move { initialize_app(&mut app); let editor = add_editor_vim_normal_mode( "line 1 line 2 line 3 line 4", &mut app, ); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("d3w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!( view.selected_ranges(app_ctx), vec![DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)] ); assert_eq!( view.buffer_text(app_ctx), "line 1 3 line 4" .unindent() .as_str() ); assert_eq!(view.vim_mode(app_ctx), Some(VimMode::Normal)) }); editor.update(&mut app, |view, view_ctx| { view.select_ranges( vec![DisplayPoint::new(0, 0)..DisplayPoint::new(0, 0)], view_ctx, ) .unwrap(); view.vim_user_insert("c2w", view_ctx); }); editor.read(&app, |view, app_ctx| { assert_eq!(