From 32837d67beb68c96d7fddb20b19ed6eefeaaa99a Mon Sep 17 00:00:00 2001 From: Conrad Irwin Date: Fri, 8 Dec 2023 18:47:14 +0000 Subject: [PATCH] vim2 compiling (but mostly commented out) --- Cargo.lock | 35 + .../command_palette2/src/command_palette.rs | 1 + crates/editor2/src/editor.rs | 8 +- crates/vim/src/editor_events.rs | 3 +- crates/vim/src/vim.rs | 2 + crates/vim2/Cargo.toml | 53 + crates/vim2/src/command.rs | 438 +++ crates/vim2/src/editor_events.rs | 101 + crates/vim2/src/insert.rs | 136 + crates/vim2/src/mode_indicator.rs | 91 + crates/vim2/src/motion.rs | 1072 ++++++++ crates/vim2/src/normal.rs | 903 +++++++ crates/vim2/src/normal/case.rs | 116 + crates/vim2/src/normal/change.rs | 502 ++++ crates/vim2/src/normal/delete.rs | 475 ++++ crates/vim2/src/normal/increment.rs | 277 ++ crates/vim2/src/normal/paste.rs | 475 ++++ crates/vim2/src/normal/repeat.rs | 524 ++++ crates/vim2/src/normal/scroll.rs | 227 ++ crates/vim2/src/normal/search.rs | 492 ++++ crates/vim2/src/normal/substitute.rs | 277 ++ crates/vim2/src/normal/yank.rs | 50 + crates/vim2/src/object.rs | 1009 +++++++ crates/vim2/src/state.rs | 234 ++ crates/vim2/src/test.rs | 759 ++++++ .../neovim_backed_binding_test_context.rs | 95 + .../src/test/neovim_backed_test_context.rs | 427 +++ crates/vim2/src/test/neovim_connection.rs | 591 ++++ crates/vim2/src/test/vim_test_context.rs | 165 ++ crates/vim2/src/utils.rs | 50 + crates/vim2/src/vim.rs | 603 +++++ crates/vim2/src/visual.rs | 1023 +++++++ .../neovim_backed_test_context_works.json | 3 + crates/vim2/test_data/test_a.json | 6 + crates/vim2/test_data/test_b.json | 54 + crates/vim2/test_data/test_backspace.json | 9 + .../test_capital_f_and_capital_t.json | 570 ++++ crates/vim2/test_data/test_cc.json | 24 + crates/vim2/test_data/test_change_0.json | 8 + crates/vim2/test_data/test_change_b.json | 24 + .../vim2/test_data/test_change_backspace.json | 16 + crates/vim2/test_data/test_change_case.json | 23 + crates/vim2/test_data/test_change_e.json | 24 + .../test_change_end_of_document.json | 16 + .../test_data/test_change_end_of_line.json | 8 + crates/vim2/test_data/test_change_gg.json | 20 + crates/vim2/test_data/test_change_h.json | 16 + crates/vim2/test_data/test_change_j.json | 16 + crates/vim2/test_data/test_change_k.json | 16 + crates/vim2/test_data/test_change_l.json | 8 + .../test_change_sentence_object.json | 270 ++ ..._change_surrounding_character_objects.json | 2380 +++++++++++++++++ crates/vim2/test_data/test_change_w.json | 28 + .../test_data/test_change_word_object.json | 460 ++++ crates/vim2/test_data/test_clear_counts.json | 7 + .../vim2/test_data/test_comma_semicolon.json | 17 + .../vim2/test_data/test_command_basics.json | 6 + crates/vim2/test_data/test_command_goto.json | 5 + .../vim2/test_data/test_command_replace.json | 22 + .../vim2/test_data/test_command_search.json | 11 + crates/vim2/test_data/test_ctrl_d_u.json | 22 + crates/vim2/test_data/test_dd.json | 24 + crates/vim2/test_data/test_delete_0.json | 8 + crates/vim2/test_data/test_delete_b.json | 24 + .../test_delete_end_of_document.json | 16 + .../test_data/test_delete_end_of_line.json | 8 + crates/vim2/test_data/test_delete_gg.json | 20 + crates/vim2/test_data/test_delete_h.json | 16 + crates/vim2/test_data/test_delete_j.json | 16 + crates/vim2/test_data/test_delete_k.json | 16 + crates/vim2/test_data/test_delete_l.json | 16 + crates/vim2/test_data/test_delete_left.json | 15 + .../test_data/test_delete_next_word_end.json | 12 + .../test_delete_sentence_object.json | 270 ++ ..._delete_surrounding_character_objects.json | 2372 ++++++++++++++++ .../test_data/test_delete_to_end_of_line.json | 6 + crates/vim2/test_data/test_delete_w.json | 28 + .../test_data/test_delete_with_counts.json | 16 + .../test_data/test_delete_word_object.json | 460 ++++ crates/vim2/test_data/test_dot_repeat.json | 38 + .../vim2/test_data/test_end_of_document.json | 15 + crates/vim2/test_data/test_end_of_word.json | 32 + crates/vim2/test_data/test_enter.json | 11 + .../test_enter_visual_line_mode.json | 15 + .../test_data/test_enter_visual_mode.json | 20 + crates/vim2/test_data/test_f_and_t.json | 557 ++++ crates/vim2/test_data/test_folds.json | 23 + crates/vim2/test_data/test_folds_panic.json | 13 + crates/vim2/test_data/test_gg.json | 21 + crates/vim2/test_data/test_h.json | 9 + .../test_data/test_h_through_unicode.json | 12 + crates/vim2/test_data/test_increment.json | 16 + .../vim2/test_data/test_increment_radix.json | 18 + .../vim2/test_data/test_increment_steps.json | 15 + .../test_data/test_insert_end_of_line.json | 9 + .../test_insert_first_non_whitespace.json | 15 + .../test_data/test_insert_line_above.json | 18 + .../test_data/test_insert_with_counts.json | 36 + .../test_data/test_insert_with_repeat.json | 23 + crates/vim2/test_data/test_j.json | 15 + crates/vim2/test_data/test_join_lines.json | 13 + crates/vim2/test_data/test_jump_to_end.json | 14 + .../test_jump_to_first_non_whitespace.json | 18 + .../test_jump_to_line_boundaries.json | 28 + crates/vim2/test_data/test_k.json | 15 + crates/vim2/test_data/test_l.json | 15 + crates/vim2/test_data/test_matching.json | 17 + ...ltiline_surrounding_character_objects.json | 15 + crates/vim2/test_data/test_neovim.json | 16 + .../vim2/test_data/test_next_line_start.json | 3 + crates/vim2/test_data/test_o.json | 18 + .../test_data/test_paragraphs_dont_wrap.json | 8 + crates/vim2/test_data/test_paste.json | 31 + crates/vim2/test_data/test_paste_visual.json | 42 + .../test_data/test_paste_visual_block.json | 31 + crates/vim2/test_data/test_percent.json | 58 + .../test_data/test_repeat_motion_counts.json | 13 + crates/vim2/test_data/test_repeat_visual.json | 51 + crates/vim2/test_data/test_repeated_cb.json | 275 ++ crates/vim2/test_data/test_repeated_ce.json | 275 ++ crates/vim2/test_data/test_repeated_cj.json | 275 ++ crates/vim2/test_data/test_repeated_cl.json | 275 ++ crates/vim2/test_data/test_repeated_word.json | 214 ++ .../vim2/test_data/test_selection_goal.json | 8 + ...gleline_surrounding_character_objects.json | 27 + .../test_start_end_of_paragraph.json | 13 + .../vim2/test_data/test_substitute_line.json | 29 + .../test_data/test_visual_block_insert.json | 18 + .../test_visual_block_issue_2123.json | 5 + .../test_data/test_visual_block_mode.json | 38 + crates/vim2/test_data/test_visual_change.json | 47 + crates/vim2/test_data/test_visual_delete.json | 48 + .../test_data/test_visual_line_change.json | 35 + .../test_data/test_visual_line_delete.json | 23 + crates/vim2/test_data/test_visual_object.json | 19 + .../test_visual_sentence_object.json | 0 .../test_data/test_visual_word_object.json | 236 ++ crates/vim2/test_data/test_visual_yank.json | 35 + crates/vim2/test_data/test_w.json | 40 + crates/vim2/test_data/test_wrapped_lines.json | 61 + .../vim2/test_data/test_wrapped_motions.json | 15 + crates/vim2/test_data/test_x.json | 12 + crates/vim2/test_data/test_zero.json | 7 + crates/zed2/Cargo.toml | 2 +- crates/zed2/src/main.rs | 2 +- crates/zed2/src/zed2.rs | 6 +- 146 files changed, 22013 insertions(+), 10 deletions(-) create mode 100644 crates/vim2/Cargo.toml create mode 100644 crates/vim2/src/command.rs create mode 100644 crates/vim2/src/editor_events.rs create mode 100644 crates/vim2/src/insert.rs create mode 100644 crates/vim2/src/mode_indicator.rs create mode 100644 crates/vim2/src/motion.rs create mode 100644 crates/vim2/src/normal.rs create mode 100644 crates/vim2/src/normal/case.rs create mode 100644 crates/vim2/src/normal/change.rs create mode 100644 crates/vim2/src/normal/delete.rs create mode 100644 crates/vim2/src/normal/increment.rs create mode 100644 crates/vim2/src/normal/paste.rs create mode 100644 crates/vim2/src/normal/repeat.rs create mode 100644 crates/vim2/src/normal/scroll.rs create mode 100644 crates/vim2/src/normal/search.rs create mode 100644 crates/vim2/src/normal/substitute.rs create mode 100644 crates/vim2/src/normal/yank.rs create mode 100644 crates/vim2/src/object.rs create mode 100644 crates/vim2/src/state.rs create mode 100644 crates/vim2/src/test.rs create mode 100644 crates/vim2/src/test/neovim_backed_binding_test_context.rs create mode 100644 crates/vim2/src/test/neovim_backed_test_context.rs create mode 100644 crates/vim2/src/test/neovim_connection.rs create mode 100644 crates/vim2/src/test/vim_test_context.rs create mode 100644 crates/vim2/src/utils.rs create mode 100644 crates/vim2/src/vim.rs create mode 100644 crates/vim2/src/visual.rs create mode 100644 crates/vim2/test_data/neovim_backed_test_context_works.json create mode 100644 crates/vim2/test_data/test_a.json create mode 100644 crates/vim2/test_data/test_b.json create mode 100644 crates/vim2/test_data/test_backspace.json create mode 100644 crates/vim2/test_data/test_capital_f_and_capital_t.json create mode 100644 crates/vim2/test_data/test_cc.json create mode 100644 crates/vim2/test_data/test_change_0.json create mode 100644 crates/vim2/test_data/test_change_b.json create mode 100644 crates/vim2/test_data/test_change_backspace.json create mode 100644 crates/vim2/test_data/test_change_case.json create mode 100644 crates/vim2/test_data/test_change_e.json create mode 100644 crates/vim2/test_data/test_change_end_of_document.json create mode 100644 crates/vim2/test_data/test_change_end_of_line.json create mode 100644 crates/vim2/test_data/test_change_gg.json create mode 100644 crates/vim2/test_data/test_change_h.json create mode 100644 crates/vim2/test_data/test_change_j.json create mode 100644 crates/vim2/test_data/test_change_k.json create mode 100644 crates/vim2/test_data/test_change_l.json create mode 100644 crates/vim2/test_data/test_change_sentence_object.json create mode 100644 crates/vim2/test_data/test_change_surrounding_character_objects.json create mode 100644 crates/vim2/test_data/test_change_w.json create mode 100644 crates/vim2/test_data/test_change_word_object.json create mode 100644 crates/vim2/test_data/test_clear_counts.json create mode 100644 crates/vim2/test_data/test_comma_semicolon.json create mode 100644 crates/vim2/test_data/test_command_basics.json create mode 100644 crates/vim2/test_data/test_command_goto.json create mode 100644 crates/vim2/test_data/test_command_replace.json create mode 100644 crates/vim2/test_data/test_command_search.json create mode 100644 crates/vim2/test_data/test_ctrl_d_u.json create mode 100644 crates/vim2/test_data/test_dd.json create mode 100644 crates/vim2/test_data/test_delete_0.json create mode 100644 crates/vim2/test_data/test_delete_b.json create mode 100644 crates/vim2/test_data/test_delete_end_of_document.json create mode 100644 crates/vim2/test_data/test_delete_end_of_line.json create mode 100644 crates/vim2/test_data/test_delete_gg.json create mode 100644 crates/vim2/test_data/test_delete_h.json create mode 100644 crates/vim2/test_data/test_delete_j.json create mode 100644 crates/vim2/test_data/test_delete_k.json create mode 100644 crates/vim2/test_data/test_delete_l.json create mode 100644 crates/vim2/test_data/test_delete_left.json create mode 100644 crates/vim2/test_data/test_delete_next_word_end.json create mode 100644 crates/vim2/test_data/test_delete_sentence_object.json create mode 100644 crates/vim2/test_data/test_delete_surrounding_character_objects.json create mode 100644 crates/vim2/test_data/test_delete_to_end_of_line.json create mode 100644 crates/vim2/test_data/test_delete_w.json create mode 100644 crates/vim2/test_data/test_delete_with_counts.json create mode 100644 crates/vim2/test_data/test_delete_word_object.json create mode 100644 crates/vim2/test_data/test_dot_repeat.json create mode 100644 crates/vim2/test_data/test_end_of_document.json create mode 100644 crates/vim2/test_data/test_end_of_word.json create mode 100644 crates/vim2/test_data/test_enter.json create mode 100644 crates/vim2/test_data/test_enter_visual_line_mode.json create mode 100644 crates/vim2/test_data/test_enter_visual_mode.json create mode 100644 crates/vim2/test_data/test_f_and_t.json create mode 100644 crates/vim2/test_data/test_folds.json create mode 100644 crates/vim2/test_data/test_folds_panic.json create mode 100644 crates/vim2/test_data/test_gg.json create mode 100644 crates/vim2/test_data/test_h.json create mode 100644 crates/vim2/test_data/test_h_through_unicode.json create mode 100644 crates/vim2/test_data/test_increment.json create mode 100644 crates/vim2/test_data/test_increment_radix.json create mode 100644 crates/vim2/test_data/test_increment_steps.json create mode 100644 crates/vim2/test_data/test_insert_end_of_line.json create mode 100644 crates/vim2/test_data/test_insert_first_non_whitespace.json create mode 100644 crates/vim2/test_data/test_insert_line_above.json create mode 100644 crates/vim2/test_data/test_insert_with_counts.json create mode 100644 crates/vim2/test_data/test_insert_with_repeat.json create mode 100644 crates/vim2/test_data/test_j.json create mode 100644 crates/vim2/test_data/test_join_lines.json create mode 100644 crates/vim2/test_data/test_jump_to_end.json create mode 100644 crates/vim2/test_data/test_jump_to_first_non_whitespace.json create mode 100644 crates/vim2/test_data/test_jump_to_line_boundaries.json create mode 100644 crates/vim2/test_data/test_k.json create mode 100644 crates/vim2/test_data/test_l.json create mode 100644 crates/vim2/test_data/test_matching.json create mode 100644 crates/vim2/test_data/test_multiline_surrounding_character_objects.json create mode 100644 crates/vim2/test_data/test_neovim.json create mode 100644 crates/vim2/test_data/test_next_line_start.json create mode 100644 crates/vim2/test_data/test_o.json create mode 100644 crates/vim2/test_data/test_paragraphs_dont_wrap.json create mode 100644 crates/vim2/test_data/test_paste.json create mode 100644 crates/vim2/test_data/test_paste_visual.json create mode 100644 crates/vim2/test_data/test_paste_visual_block.json create mode 100644 crates/vim2/test_data/test_percent.json create mode 100644 crates/vim2/test_data/test_repeat_motion_counts.json create mode 100644 crates/vim2/test_data/test_repeat_visual.json create mode 100644 crates/vim2/test_data/test_repeated_cb.json create mode 100644 crates/vim2/test_data/test_repeated_ce.json create mode 100644 crates/vim2/test_data/test_repeated_cj.json create mode 100644 crates/vim2/test_data/test_repeated_cl.json create mode 100644 crates/vim2/test_data/test_repeated_word.json create mode 100644 crates/vim2/test_data/test_selection_goal.json create mode 100644 crates/vim2/test_data/test_singleline_surrounding_character_objects.json create mode 100644 crates/vim2/test_data/test_start_end_of_paragraph.json create mode 100644 crates/vim2/test_data/test_substitute_line.json create mode 100644 crates/vim2/test_data/test_visual_block_insert.json create mode 100644 crates/vim2/test_data/test_visual_block_issue_2123.json create mode 100644 crates/vim2/test_data/test_visual_block_mode.json create mode 100644 crates/vim2/test_data/test_visual_change.json create mode 100644 crates/vim2/test_data/test_visual_delete.json create mode 100644 crates/vim2/test_data/test_visual_line_change.json create mode 100644 crates/vim2/test_data/test_visual_line_delete.json create mode 100644 crates/vim2/test_data/test_visual_object.json create mode 100644 crates/vim2/test_data/test_visual_sentence_object.json create mode 100644 crates/vim2/test_data/test_visual_word_object.json create mode 100644 crates/vim2/test_data/test_visual_yank.json create mode 100644 crates/vim2/test_data/test_w.json create mode 100644 crates/vim2/test_data/test_wrapped_lines.json create mode 100644 crates/vim2/test_data/test_wrapped_motions.json create mode 100644 crates/vim2/test_data/test_x.json create mode 100644 crates/vim2/test_data/test_zero.json diff --git a/Cargo.lock b/Cargo.lock index 841812e19e..5585a357a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10894,6 +10894,40 @@ dependencies = [ "zed-actions", ] +[[package]] +name = "vim2" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-compat", + "async-trait", + "collections", + "command_palette2", + "diagnostics2", + "editor2", + "futures 0.3.28", + "gpui2", + "indoc", + "itertools 0.10.5", + "language2", + "log", + "lsp2", + "nvim-rs", + "parking_lot 0.11.2", + "project2", + "search2", + "serde", + "serde_derive", + "serde_json", + "settings2", + "theme2", + "tokio", + "ui2", + "util", + "workspace2", + "zed_actions2", +] + [[package]] name = "vte" version = "0.11.1" @@ -12113,6 +12147,7 @@ dependencies = [ "urlencoding", "util", "uuid 1.4.1", + "vim2", "welcome2", "workspace2", "zed_actions2", diff --git a/crates/command_palette2/src/command_palette.rs b/crates/command_palette2/src/command_palette.rs index 57c1fa5614..2ed5873e5c 100644 --- a/crates/command_palette2/src/command_palette.rs +++ b/crates/command_palette2/src/command_palette.rs @@ -23,6 +23,7 @@ actions!(Toggle); pub fn init(cx: &mut AppContext) { cx.set_global(HitCounts::default()); + cx.set_global(CommandPaletteFilter::default()); cx.observe_new_views(CommandPalette::register).detach(); } diff --git a/crates/editor2/src/editor.rs b/crates/editor2/src/editor.rs index 46d64fcf9d..a365fee930 100644 --- a/crates/editor2/src/editor.rs +++ b/crates/editor2/src/editor.rs @@ -1899,9 +1899,9 @@ impl Editor { self.buffer.read(cx).replica_id() } - // pub fn leader_peer_id(&self) -> Option { - // self.leader_peer_id - // } + pub fn leader_peer_id(&self) -> Option { + self.leader_peer_id + } pub fn buffer(&self) -> &Model { &self.buffer @@ -9072,7 +9072,7 @@ impl Editor { } } - fn handle_blur(&mut self, cx: &mut ViewContext) { + pub fn handle_blur(&mut self, cx: &mut ViewContext) { // todo!() // let blurred_event = EditorBlurred(cx.handle()); // cx.emit_global(blurred_event); diff --git a/crates/vim/src/editor_events.rs b/crates/vim/src/editor_events.rs index a6e0c4b801..5ccd3a6d79 100644 --- a/crates/vim/src/editor_events.rs +++ b/crates/vim/src/editor_events.rs @@ -86,7 +86,8 @@ mod test { // no panic when blurring an editor in a different window. cx.update_editor(|editor1, cx| { - editor1.focus_out(cx.handle().into_any(), cx); + todo!() + // editor1.focus_out(cx.handle().into_any(), cx); }); } } diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index 7bfec95317..87e61226c3 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + #[cfg(test)] mod test; diff --git a/crates/vim2/Cargo.toml b/crates/vim2/Cargo.toml new file mode 100644 index 0000000000..4ba0ef4041 --- /dev/null +++ b/crates/vim2/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "vim2" +version = "0.1.0" +edition = "2021" +publish = false + +[lib] +path = "src/vim.rs" +doctest = false + +[features] +neovim = ["nvim-rs", "async-compat", "async-trait", "tokio"] + +[dependencies] +anyhow.workspace = true +serde.workspace = true +serde_derive.workspace = true +itertools = "0.10" +log.workspace = true + +async-compat = { version = "0.2.1", "optional" = true } +async-trait = { workspace = true, "optional" = true } +nvim-rs = { git = "https://github.com/KillTheMule/nvim-rs", branch = "master", features = ["use_tokio"], optional = true } +tokio = { version = "1.15", "optional" = true } +serde_json.workspace = true + +collections = { path = "../collections" } +command_palette = { package = "command_palette2", path = "../command_palette2" } +editor = { package = "editor2", path = "../editor2" } +gpui = { package = "gpui2", path = "../gpui2" } +language = { package = "language2", path = "../language2" } +search = { package = "search2", path = "../search2" } +settings = { package = "settings2", path = "../settings2" } +workspace = { package = "workspace2", path = "../workspace2" } +theme = { package = "theme2", path = "../theme2" } +ui = { package = "ui2", path = "../ui2"} +diagnostics = { package = "diagnostics2", path = "../diagnostics2" } +zed_actions = { package = "zed_actions2", path = "../zed_actions2" } + +[dev-dependencies] +indoc.workspace = true +parking_lot.workspace = true +futures.workspace = true + +editor = { package = "editor2", path = "../editor2", features = ["test-support"] } +gpui = { package = "gpui2", path = "../gpui2", features = ["test-support"] } +language = { package = "language2", path = "../language2", features = ["test-support"] } +project = { package = "project2", path = "../project2", features = ["test-support"] } +util = { path = "../util", features = ["test-support"] } +settings = { package = "settings2", path = "../settings2" } +workspace = { package = "workspace2", path = "../workspace2", features = ["test-support"] } +theme = { package = "theme2", path = "../theme2", features = ["test-support"] } +lsp = { package = "lsp2", path = "../lsp2", features = ["test-support"] } diff --git a/crates/vim2/src/command.rs b/crates/vim2/src/command.rs new file mode 100644 index 0000000000..d9a273179d --- /dev/null +++ b/crates/vim2/src/command.rs @@ -0,0 +1,438 @@ +use command_palette::CommandInterceptResult; +use editor::{SortLinesCaseInsensitive, SortLinesCaseSensitive}; +use gpui::{Action, AppContext}; +use serde_derive::Deserialize; +use workspace::{SaveIntent, Workspace}; + +use crate::{ + motion::{EndOfDocument, Motion}, + normal::{ + move_cursor, + search::{FindCommand, ReplaceCommand}, + JoinLines, + }, + state::Mode, + Vim, +}; + +#[derive(Action, Debug, Clone, PartialEq, Deserialize)] +pub struct GoToLine { + pub line: u32, +} + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_: &mut Workspace, action: &GoToLine, cx| { + // Vim::update(cx, |vim, cx| { + // vim.switch_mode(Mode::Normal, false, cx); + // move_cursor(vim, Motion::StartOfDocument, Some(action.line as usize), cx); + // }); + // }); +} + +pub fn command_interceptor(mut query: &str, _: &AppContext) -> Option { + // Note: this is a very poor simulation of vim's command palette. + // In the future we should adjust it to handle parsing range syntax, + // and then calling the appropriate commands with/without ranges. + // + // We also need to support passing arguments to commands like :w + // (ideally with filename autocompletion). + // + // For now, you can only do a replace on the % range, and you can + // only use a specific line number range to "go to line" + while query.starts_with(":") { + query = &query[1..]; + } + + let (name, action) = match query { + // save and quit + "w" | "wr" | "wri" | "writ" | "write" => ( + "write", + workspace::Save { + save_intent: Some(SaveIntent::Save), + } + .boxed_clone(), + ), + "w!" | "wr!" | "wri!" | "writ!" | "write!" => ( + "write!", + workspace::Save { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "q" | "qu" | "qui" | "quit" => ( + "quit", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Close), + } + .boxed_clone(), + ), + "q!" | "qu!" | "qui!" | "quit!" => ( + "quit!", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Skip), + } + .boxed_clone(), + ), + "wq" => ( + "wq", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Save), + } + .boxed_clone(), + ), + "wq!" => ( + "wq!", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "x" | "xi" | "xit" | "exi" | "exit" => ( + "exit", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::SaveAll), + } + .boxed_clone(), + ), + "x!" | "xi!" | "xit!" | "exi!" | "exit!" => ( + "exit!", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "up" | "upd" | "upda" | "updat" | "update" => ( + "update", + workspace::Save { + save_intent: Some(SaveIntent::SaveAll), + } + .boxed_clone(), + ), + "wa" | "wal" | "wall" => ( + "wall", + workspace::SaveAll { + save_intent: Some(SaveIntent::SaveAll), + } + .boxed_clone(), + ), + "wa!" | "wal!" | "wall!" => ( + "wall!", + workspace::SaveAll { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "qa" | "qal" | "qall" | "quita" | "quital" | "quitall" => ( + "quitall", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::Close), + } + .boxed_clone(), + ), + "qa!" | "qal!" | "qall!" | "quita!" | "quital!" | "quitall!" => ( + "quitall!", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::Skip), + } + .boxed_clone(), + ), + "xa" | "xal" | "xall" => ( + "xall", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::SaveAll), + } + .boxed_clone(), + ), + "xa!" | "xal!" | "xall!" => ( + "xall!", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "wqa" | "wqal" | "wqall" => ( + "wqall", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::SaveAll), + } + .boxed_clone(), + ), + "wqa!" | "wqal!" | "wqall!" => ( + "wqall!", + workspace::CloseAllItemsAndPanes { + save_intent: Some(SaveIntent::Overwrite), + } + .boxed_clone(), + ), + "cq" | "cqu" | "cqui" | "cquit" | "cq!" | "cqu!" | "cqui!" | "cquit!" => { + // ("cquit!", zed_actions::Quit.boxed_clone()) + todo!(); // Quit is no longer in zed actions :/ + } + + // pane management + "sp" | "spl" | "spli" | "split" => ("split", workspace::SplitUp.boxed_clone()), + "vs" | "vsp" | "vspl" | "vspli" | "vsplit" => { + ("vsplit", workspace::SplitLeft.boxed_clone()) + } + "new" => ( + "new", + workspace::NewFileInDirection(workspace::SplitDirection::Up).boxed_clone(), + ), + "vne" | "vnew" => ( + "vnew", + workspace::NewFileInDirection(workspace::SplitDirection::Left).boxed_clone(), + ), + "tabe" | "tabed" | "tabedi" | "tabedit" => ("tabedit", workspace::NewFile.boxed_clone()), + "tabnew" => ("tabnew", workspace::NewFile.boxed_clone()), + + "tabn" | "tabne" | "tabnex" | "tabnext" => { + ("tabnext", workspace::ActivateNextItem.boxed_clone()) + } + "tabp" | "tabpr" | "tabpre" | "tabprev" | "tabprevi" | "tabprevio" | "tabpreviou" + | "tabprevious" => ("tabprevious", workspace::ActivatePrevItem.boxed_clone()), + "tabN" | "tabNe" | "tabNex" | "tabNext" => { + ("tabNext", workspace::ActivatePrevItem.boxed_clone()) + } + "tabc" | "tabcl" | "tabclo" | "tabclos" | "tabclose" => ( + "tabclose", + workspace::CloseActiveItem { + save_intent: Some(SaveIntent::Close), + } + .boxed_clone(), + ), + + // quickfix / loclist (merged together for now) + "cl" | "cli" | "clis" | "clist" => ("clist", diagnostics::Deploy.boxed_clone()), + "cc" => ("cc", editor::Hover.boxed_clone()), + "ll" => ("ll", editor::Hover.boxed_clone()), + "cn" | "cne" | "cnex" | "cnext" => ("cnext", editor::GoToDiagnostic.boxed_clone()), + "lne" | "lnex" | "lnext" => ("cnext", editor::GoToDiagnostic.boxed_clone()), + + "cpr" | "cpre" | "cprev" | "cprevi" | "cprevio" | "cpreviou" | "cprevious" => { + ("cprevious", editor::GoToPrevDiagnostic.boxed_clone()) + } + "cN" | "cNe" | "cNex" | "cNext" => ("cNext", editor::GoToPrevDiagnostic.boxed_clone()), + "lp" | "lpr" | "lpre" | "lprev" | "lprevi" | "lprevio" | "lpreviou" | "lprevious" => { + ("lprevious", editor::GoToPrevDiagnostic.boxed_clone()) + } + "lN" | "lNe" | "lNex" | "lNext" => ("lNext", editor::GoToPrevDiagnostic.boxed_clone()), + + // modify the buffer (should accept [range]) + "j" | "jo" | "joi" | "join" => ("join", JoinLines.boxed_clone()), + "d" | "de" | "del" | "dele" | "delet" | "delete" | "dl" | "dell" | "delel" | "deletl" + | "deletel" | "dp" | "dep" | "delp" | "delep" | "deletp" | "deletep" => { + ("delete", editor::DeleteLine.boxed_clone()) + } + "sor" | "sor " | "sort" | "sort " => ("sort", SortLinesCaseSensitive.boxed_clone()), + "sor i" | "sort i" => ("sort i", SortLinesCaseInsensitive.boxed_clone()), + + // goto (other ranges handled under _ => ) + "$" => ("$", EndOfDocument.boxed_clone()), + + _ => { + if query.starts_with("/") || query.starts_with("?") { + ( + query, + FindCommand { + query: query[1..].to_string(), + backwards: query.starts_with("?"), + } + .boxed_clone(), + ) + } else if query.starts_with("%") { + ( + query, + ReplaceCommand { + query: query.to_string(), + } + .boxed_clone(), + ) + } else if let Ok(line) = query.parse::() { + (query, GoToLine { line }.boxed_clone()) + } else { + return None; + } + } + }; + + let string = ":".to_owned() + name; + let positions = generate_positions(&string, query); + + Some(CommandInterceptResult { + action, + string, + positions, + }) +} + +fn generate_positions(string: &str, query: &str) -> Vec { + let mut positions = Vec::new(); + let mut chars = query.chars().into_iter(); + + let Some(mut current) = chars.next() else { + return positions; + }; + + for (i, c) in string.chars().enumerate() { + if c == current { + positions.push(i); + if let Some(c) = chars.next() { + current = c; + } else { + break; + } + } + } + + positions +} + +// #[cfg(test)] +// mod test { +// use std::path::Path; + +// use crate::test::{NeovimBackedTestContext, VimTestContext}; +// use gpui::TestAppContext; +// use indoc::indoc; + +// #[gpui::test] +// async fn test_command_basics(cx: &mut TestAppContext) { +// if let Foreground::Deterministic { cx_id: _, executor } = cx.foreground().as_ref() { +// executor.run_until_parked(); +// } +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇa +// b +// c"}) +// .await; + +// cx.simulate_shared_keystrokes([":", "j", "enter"]).await; + +// // hack: our cursor positionining after a join command is wrong +// cx.simulate_shared_keystrokes(["^"]).await; +// cx.assert_shared_state(indoc! { +// "ˇa b +// c" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_command_goto(cx: &mut TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇa +// b +// c"}) +// .await; +// cx.simulate_shared_keystrokes([":", "3", "enter"]).await; +// cx.assert_shared_state(indoc! {" +// a +// b +// ˇc"}) +// .await; +// } + +// #[gpui::test] +// async fn test_command_replace(cx: &mut TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇa +// b +// c"}) +// .await; +// cx.simulate_shared_keystrokes([":", "%", "s", "/", "b", "/", "d", "enter"]) +// .await; +// cx.assert_shared_state(indoc! {" +// a +// ˇd +// c"}) +// .await; +// cx.simulate_shared_keystrokes([ +// ":", "%", "s", ":", ".", ":", "\\", "0", "\\", "0", "enter", +// ]) +// .await; +// cx.assert_shared_state(indoc! {" +// aa +// dd +// ˇcc"}) +// .await; +// } + +// #[gpui::test] +// async fn test_command_search(cx: &mut TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇa +// b +// a +// c"}) +// .await; +// cx.simulate_shared_keystrokes([":", "/", "b", "enter"]) +// .await; +// cx.assert_shared_state(indoc! {" +// a +// ˇb +// a +// c"}) +// .await; +// cx.simulate_shared_keystrokes([":", "?", "a", "enter"]) +// .await; +// cx.assert_shared_state(indoc! {" +// ˇa +// b +// a +// c"}) +// .await; +// } + +// #[gpui::test] +// async fn test_command_write(cx: &mut TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; +// let path = Path::new("/root/dir/file.rs"); +// let fs = cx.workspace(|workspace, cx| workspace.project().read(cx).fs().clone()); + +// cx.simulate_keystrokes(["i", "@", "escape"]); +// cx.simulate_keystrokes([":", "w", "enter"]); + +// assert_eq!(fs.load(&path).await.unwrap(), "@\n"); + +// fs.as_fake() +// .write_file_internal(path, "oops\n".to_string()) +// .unwrap(); + +// // conflict! +// cx.simulate_keystrokes(["i", "@", "escape"]); +// cx.simulate_keystrokes([":", "w", "enter"]); +// let window = cx.window; +// assert!(window.has_pending_prompt(cx.cx)); +// // "Cancel" +// window.simulate_prompt_answer(0, cx.cx); +// assert_eq!(fs.load(&path).await.unwrap(), "oops\n"); +// assert!(!window.has_pending_prompt(cx.cx)); +// // force overwrite +// cx.simulate_keystrokes([":", "w", "!", "enter"]); +// assert!(!window.has_pending_prompt(cx.cx)); +// assert_eq!(fs.load(&path).await.unwrap(), "@@\n"); +// } + +// #[gpui::test] +// async fn test_command_quit(cx: &mut TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.simulate_keystrokes([":", "n", "e", "w", "enter"]); +// cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2)); +// cx.simulate_keystrokes([":", "q", "enter"]); +// cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 1)); +// cx.simulate_keystrokes([":", "n", "e", "w", "enter"]); +// cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 2)); +// cx.simulate_keystrokes([":", "q", "a", "enter"]); +// cx.workspace(|workspace, cx| assert_eq!(workspace.items(cx).count(), 0)); +// } +// } diff --git a/crates/vim2/src/editor_events.rs b/crates/vim2/src/editor_events.rs new file mode 100644 index 0000000000..e4eb9047ab --- /dev/null +++ b/crates/vim2/src/editor_events.rs @@ -0,0 +1,101 @@ +use crate::{Vim, VimEvent}; +use editor::{EditorBlurred, EditorFocused, EditorReleased}; +use gpui::AppContext; + +pub fn init(cx: &mut AppContext) { + // 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) + // }); + // }); + // }); + // } + + // 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, + // }); + // } + // }); + // }); +} + +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; + // } + // } + + // 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()) + // }); + // }); +} + +// #[cfg(test)] +// mod test { +// use crate::{test::VimTestContext, Vim}; +// use editor::Editor; +// use gpui::{Context, Entity}; +// use language::Buffer; + +// // regression test for blur called with a different active editor +// #[gpui::test] +// async fn test_blur_focus(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// let buffer = cx.build_model(|_| Buffer::new(0, 0, "a = 1\nb = 2\n")); +// let window2 = cx.add_window(|cx| Editor::for_buffer(buffer, None, cx)); +// let editor2 = cx +// .update(|cx| window2.update(cx, |editor, cx| cx.view())) +// .unwrap(); + +// cx.update(|cx| { +// let vim = Vim::read(cx); +// assert_eq!( +// vim.active_editor.unwrap().entity_id().unwrap(), +// editor2.entity_id() +// ) +// }); + +// // no panic when blurring an editor in a different window. +// cx.update_editor(|editor1, cx| { +// editor1.focus_out(cx.handle().into_any(), cx); +// }); +// } +// } diff --git a/crates/vim2/src/insert.rs b/crates/vim2/src/insert.rs new file mode 100644 index 0000000000..a9ca8087da --- /dev/null +++ b/crates/vim2/src/insert.rs @@ -0,0 +1,136 @@ +use crate::{normal::repeat, state::Mode, Vim}; +use editor::{scroll::autoscroll::Autoscroll, Bias}; +use gpui::{actions, Action, AppContext, ViewContext}; +use language::SelectionGoal; +use workspace::Workspace; + +actions!(NormalBefore); + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(normal_before); +} + +fn normal_before(_: &mut Workspace, action: &NormalBefore, cx: &mut ViewContext) { + let should_repeat = Vim::update(cx, |vim, cx| { + let count = vim.take_count(cx).unwrap_or(1); + vim.stop_recording_immediately(action.boxed_clone()); + if count <= 1 || vim.workspace_state.replaying { + vim.update_active_editor(cx, |editor, cx| { + editor.cancel(&Default::default(), cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, mut cursor, _| { + *cursor.column_mut() = cursor.column().saturating_sub(1); + (map.clip_point(cursor, Bias::Left), SelectionGoal::None) + }); + }); + }); + vim.switch_mode(Mode::Normal, false, cx); + false + } else { + true + } + }); + + if should_repeat { + repeat::repeat(cx, true) + } +} + +// #[cfg(test)] +// mod test { +// use std::sync::Arc; + +// use gpui::executor::Deterministic; + +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; + +// #[gpui::test] +// async fn test_enter_and_exit_insert_mode(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; +// cx.simulate_keystroke("i"); +// assert_eq!(cx.mode(), Mode::Insert); +// cx.simulate_keystrokes(["T", "e", "s", "t"]); +// cx.assert_editor_state("Testˇ"); +// cx.simulate_keystroke("escape"); +// assert_eq!(cx.mode(), Mode::Normal); +// cx.assert_editor_state("Tesˇt"); +// } + +// #[gpui::test] +// async fn test_insert_with_counts( +// deterministic: Arc, +// cx: &mut gpui::TestAppContext, +// ) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["5", "i", "-", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("----ˇ-hello\n").await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["5", "a", "-", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("h----ˇ-ello\n").await; + +// cx.simulate_shared_keystrokes(["4", "shift-i", "-", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("---ˇ-h-----ello\n").await; + +// cx.simulate_shared_keystrokes(["3", "shift-a", "-", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("----h-----ello--ˇ-\n").await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["3", "o", "o", "i", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("hello\noi\noi\noˇi\n").await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["3", "shift-o", "o", "i", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("oi\noi\noˇi\nhello\n").await; +// } + +// #[gpui::test] +// async fn test_insert_with_repeat( +// deterministic: Arc, +// cx: &mut gpui::TestAppContext, +// ) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["3", "i", "-", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("--ˇ-hello\n").await; +// cx.simulate_shared_keystrokes(["."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("----ˇ--hello\n").await; +// cx.simulate_shared_keystrokes(["2", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("-----ˇ---hello\n").await; + +// cx.set_shared_state("ˇhello\n").await; +// cx.simulate_shared_keystrokes(["2", "o", "k", "k", "escape"]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("hello\nkk\nkˇk\n").await; +// cx.simulate_shared_keystrokes(["."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("hello\nkk\nkk\nkk\nkˇk\n").await; +// cx.simulate_shared_keystrokes(["1", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("hello\nkk\nkk\nkk\nkk\nkˇk\n").await; +// } +// } diff --git a/crates/vim2/src/mode_indicator.rs b/crates/vim2/src/mode_indicator.rs new file mode 100644 index 0000000000..9a59aa3f37 --- /dev/null +++ b/crates/vim2/src/mode_indicator.rs @@ -0,0 +1,91 @@ +use gpui::{div, AnyElement, Div, Element, Entity, IntoElement, Render, Subscription, ViewContext}; +use settings::{Settings, SettingsStore}; +use workspace::{item::ItemHandle, ui::Label, StatusItemView}; + +use crate::{state::Mode, Vim, VimEvent, VimModeSetting}; + +pub struct ModeIndicator { + pub mode: Option, + // _subscription: Subscription, +} + +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::(move |mode_indicator, cx| { + if VimModeSetting::get_global(cx).0 { + mode_indicator.mode = cx + .has_global::() + .then(|| cx.global::().state().mode); + } else { + mode_indicator.mode.take(); + } + }) + .detach(); + + // Vim doesn't exist in some tests + let mode = cx + .has_global::() + .then(|| { + let vim = cx.global::(); + vim.enabled.then(|| vim.state().mode) + }) + .flatten(); + + Self { + mode, + // _subscription, + } + } + + pub fn set_mode(&mut self, mode: Mode, cx: &mut ViewContext) { + if self.mode != Some(mode) { + self.mode = Some(mode); + cx.notify(); + } + } +} + +impl Render for ModeIndicator { + type Element = AnyElement; + + fn render(&mut self, cx: &mut ViewContext) -> AnyElement { + let Some(mode) = self.mode.as_ref() else { + return div().into_any(); + }; + + let text = match mode { + Mode::Normal => "-- NORMAL --", + Mode::Insert => "-- INSERT --", + Mode::Visual => "-- VISUAL --", + Mode::VisualLine => "-- VISUAL LINE --", + Mode::VisualBlock => "-- VISUAL BLOCK --", + }; + Label::new(text).into_any_element() + } +} + +impl StatusItemView for ModeIndicator { + fn set_active_pane_item( + &mut self, + _active_pane_item: Option<&dyn ItemHandle>, + _cx: &mut ViewContext, + ) { + // nothing to do. + } +} diff --git a/crates/vim2/src/motion.rs b/crates/vim2/src/motion.rs new file mode 100644 index 0000000000..95c55e5d66 --- /dev/null +++ b/crates/vim2/src/motion.rs @@ -0,0 +1,1072 @@ +use editor::{ + char_kind, + display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint}, + movement::{self, find_boundary, find_preceding_boundary, FindRange, TextLayoutDetails}, + Bias, CharKind, DisplayPoint, ToOffset, +}; +use gpui::{actions, px, Action, AppContext, WindowContext}; +use language::{Point, Selection, SelectionGoal}; +use serde::Deserialize; +use workspace::Workspace; + +use crate::{ + normal::normal_motion, + state::{Mode, Operator}, + visual::visual_motion, + Vim, +}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Motion { + Left, + Backspace, + Down { display_lines: bool }, + Up { display_lines: bool }, + Right, + NextWordStart { ignore_punctuation: bool }, + NextWordEnd { ignore_punctuation: bool }, + PreviousWordStart { ignore_punctuation: bool }, + FirstNonWhitespace { display_lines: bool }, + CurrentLine, + StartOfLine { display_lines: bool }, + EndOfLine { display_lines: bool }, + StartOfParagraph, + EndOfParagraph, + StartOfDocument, + EndOfDocument, + Matching, + FindForward { before: bool, char: char }, + FindBackward { after: bool, char: char }, + NextLineStart, + StartOfLineDownward, + EndOfLineDownward, + GoToColumn, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct NextWordStart { + #[serde(default)] + ignore_punctuation: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct NextWordEnd { + #[serde(default)] + ignore_punctuation: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct PreviousWordStart { + #[serde(default)] + ignore_punctuation: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub(crate) struct Up { + #[serde(default)] + pub(crate) display_lines: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct Down { + #[serde(default)] + display_lines: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct FirstNonWhitespace { + #[serde(default)] + display_lines: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct EndOfLine { + #[serde(default)] + display_lines: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub struct StartOfLine { + #[serde(default)] + pub(crate) display_lines: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +struct RepeatFind { + #[serde(default)] + backwards: bool, +} + +actions!( + Left, + Backspace, + Right, + CurrentLine, + StartOfParagraph, + EndOfParagraph, + StartOfDocument, + EndOfDocument, + Matching, + NextLineStart, + StartOfLineDownward, + EndOfLineDownward, + GoToColumn, +); + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_: &mut Workspace, _: &Left, cx: _| motion(Motion::Left, cx)); + // cx.add_action(|_: &mut Workspace, _: &Backspace, cx: _| motion(Motion::Backspace, cx)); + // cx.add_action(|_: &mut Workspace, action: &Down, cx: _| { + // motion( + // Motion::Down { + // display_lines: action.display_lines, + // }, + // cx, + // ) + // }); + // cx.add_action(|_: &mut Workspace, action: &Up, cx: _| { + // motion( + // Motion::Up { + // display_lines: action.display_lines, + // }, + // cx, + // ) + // }); + // cx.add_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx)); + // cx.add_action(|_: &mut Workspace, action: &FirstNonWhitespace, cx: _| { + // motion( + // Motion::FirstNonWhitespace { + // display_lines: action.display_lines, + // }, + // cx, + // ) + // }); + // cx.add_action(|_: &mut Workspace, action: &StartOfLine, cx: _| { + // motion( + // Motion::StartOfLine { + // display_lines: action.display_lines, + // }, + // cx, + // ) + // }); + // cx.add_action(|_: &mut Workspace, action: &EndOfLine, cx: _| { + // motion( + // Motion::EndOfLine { + // display_lines: action.display_lines, + // }, + // cx, + // ) + // }); + // cx.add_action(|_: &mut Workspace, _: &CurrentLine, cx: _| motion(Motion::CurrentLine, cx)); + // cx.add_action(|_: &mut Workspace, _: &StartOfParagraph, cx: _| { + // motion(Motion::StartOfParagraph, cx) + // }); + // cx.add_action(|_: &mut Workspace, _: &EndOfParagraph, cx: _| { + // motion(Motion::EndOfParagraph, cx) + // }); + // cx.add_action(|_: &mut Workspace, _: &StartOfDocument, cx: _| { + // motion(Motion::StartOfDocument, cx) + // }); + // cx.add_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| motion(Motion::EndOfDocument, cx)); + // cx.add_action(|_: &mut Workspace, _: &Matching, cx: _| motion(Motion::Matching, cx)); + + // cx.add_action( + // |_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| { + // motion(Motion::NextWordStart { ignore_punctuation }, cx) + // }, + // ); + // cx.add_action( + // |_: &mut Workspace, &NextWordEnd { ignore_punctuation }: &NextWordEnd, cx: _| { + // motion(Motion::NextWordEnd { ignore_punctuation }, cx) + // }, + // ); + // cx.add_action( + // |_: &mut Workspace, + // &PreviousWordStart { ignore_punctuation }: &PreviousWordStart, + // cx: _| { motion(Motion::PreviousWordStart { ignore_punctuation }, cx) }, + // ); + // cx.add_action(|_: &mut Workspace, &NextLineStart, cx: _| motion(Motion::NextLineStart, cx)); + // cx.add_action(|_: &mut Workspace, &StartOfLineDownward, cx: _| { + // motion(Motion::StartOfLineDownward, cx) + // }); + // cx.add_action(|_: &mut Workspace, &EndOfLineDownward, cx: _| { + // motion(Motion::EndOfLineDownward, cx) + // }); + // cx.add_action(|_: &mut Workspace, &GoToColumn, cx: _| motion(Motion::GoToColumn, cx)); + // cx.add_action(|_: &mut Workspace, action: &RepeatFind, cx: _| { + // repeat_motion(action.backwards, cx) + // }) +} + +pub(crate) fn motion(motion: Motion, cx: &mut WindowContext) { + if let Some(Operator::FindForward { .. }) | Some(Operator::FindBackward { .. }) = + Vim::read(cx).active_operator() + { + Vim::update(cx, |vim, cx| vim.pop_operator(cx)); + } + + let count = Vim::update(cx, |vim, cx| vim.take_count(cx)); + let operator = Vim::read(cx).active_operator(); + match Vim::read(cx).state().mode { + Mode::Normal => normal_motion(motion, operator, count, cx), + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_motion(motion, count, cx), + Mode::Insert => { + // Shouldn't execute a motion in insert mode. Ignoring + } + } + Vim::update(cx, |vim, cx| vim.clear_operator(cx)); +} + +fn repeat_motion(backwards: bool, cx: &mut WindowContext) { + let find = match Vim::read(cx).workspace_state.last_find.clone() { + Some(Motion::FindForward { before, char }) => { + if backwards { + Motion::FindBackward { + after: before, + char, + } + } else { + Motion::FindForward { before, char } + } + } + + Some(Motion::FindBackward { after, char }) => { + if backwards { + Motion::FindForward { + before: after, + char, + } + } else { + Motion::FindBackward { after, char } + } + } + _ => return, + }; + + motion(find, cx) +} + +// Motion handling is specified here: +// https://github.com/vim/vim/blob/master/runtime/doc/motion.txt +impl Motion { + pub fn linewise(&self) -> bool { + use Motion::*; + match self { + Down { .. } + | Up { .. } + | StartOfDocument + | EndOfDocument + | CurrentLine + | NextLineStart + | StartOfLineDownward + | StartOfParagraph + | EndOfParagraph => true, + EndOfLine { .. } + | NextWordEnd { .. } + | Matching + | FindForward { .. } + | Left + | Backspace + | Right + | StartOfLine { .. } + | EndOfLineDownward + | GoToColumn + | NextWordStart { .. } + | PreviousWordStart { .. } + | FirstNonWhitespace { .. } + | FindBackward { .. } => false, + } + } + + pub fn infallible(&self) -> bool { + use Motion::*; + match self { + StartOfDocument | EndOfDocument | CurrentLine => true, + Down { .. } + | Up { .. } + | EndOfLine { .. } + | NextWordEnd { .. } + | Matching + | FindForward { .. } + | Left + | Backspace + | Right + | StartOfLine { .. } + | StartOfParagraph + | EndOfParagraph + | StartOfLineDownward + | EndOfLineDownward + | GoToColumn + | NextWordStart { .. } + | PreviousWordStart { .. } + | FirstNonWhitespace { .. } + | FindBackward { .. } + | NextLineStart => false, + } + } + + pub fn inclusive(&self) -> bool { + use Motion::*; + match self { + Down { .. } + | Up { .. } + | StartOfDocument + | EndOfDocument + | CurrentLine + | EndOfLine { .. } + | EndOfLineDownward + | NextWordEnd { .. } + | Matching + | FindForward { .. } + | NextLineStart => true, + Left + | Backspace + | Right + | StartOfLine { .. } + | StartOfLineDownward + | StartOfParagraph + | EndOfParagraph + | GoToColumn + | NextWordStart { .. } + | PreviousWordStart { .. } + | FirstNonWhitespace { .. } + | FindBackward { .. } => false, + } + } + + pub fn move_point( + &self, + map: &DisplaySnapshot, + point: DisplayPoint, + goal: SelectionGoal, + maybe_times: Option, + text_layout_details: &TextLayoutDetails, + ) -> Option<(DisplayPoint, SelectionGoal)> { + let times = maybe_times.unwrap_or(1); + use Motion::*; + let infallible = self.infallible(); + let (new_point, goal) = match self { + Left => (left(map, point, times), SelectionGoal::None), + Backspace => (backspace(map, point, times), SelectionGoal::None), + Down { + display_lines: false, + } => up_down_buffer_rows(map, point, goal, times as isize, &text_layout_details), + Down { + display_lines: true, + } => down_display(map, point, goal, times, &text_layout_details), + Up { + display_lines: false, + } => up_down_buffer_rows(map, point, goal, 0 - times as isize, &text_layout_details), + Up { + display_lines: true, + } => up_display(map, point, goal, times, &text_layout_details), + Right => (right(map, point, times), SelectionGoal::None), + NextWordStart { ignore_punctuation } => ( + next_word_start(map, point, *ignore_punctuation, times), + SelectionGoal::None, + ), + NextWordEnd { ignore_punctuation } => ( + next_word_end(map, point, *ignore_punctuation, times), + SelectionGoal::None, + ), + PreviousWordStart { ignore_punctuation } => ( + previous_word_start(map, point, *ignore_punctuation, times), + SelectionGoal::None, + ), + FirstNonWhitespace { display_lines } => ( + first_non_whitespace(map, *display_lines, point), + SelectionGoal::None, + ), + StartOfLine { display_lines } => ( + start_of_line(map, *display_lines, point), + SelectionGoal::None, + ), + EndOfLine { display_lines } => { + (end_of_line(map, *display_lines, point), SelectionGoal::None) + } + StartOfParagraph => ( + movement::start_of_paragraph(map, point, times), + SelectionGoal::None, + ), + EndOfParagraph => ( + map.clip_at_line_end(movement::end_of_paragraph(map, point, times)), + SelectionGoal::None, + ), + CurrentLine => (next_line_end(map, point, times), SelectionGoal::None), + StartOfDocument => (start_of_document(map, point, times), SelectionGoal::None), + EndOfDocument => ( + end_of_document(map, point, maybe_times), + SelectionGoal::None, + ), + Matching => (matching(map, point), SelectionGoal::None), + FindForward { before, char } => ( + find_forward(map, point, *before, *char, times), + SelectionGoal::None, + ), + FindBackward { after, char } => ( + find_backward(map, point, *after, *char, times), + SelectionGoal::None, + ), + NextLineStart => (next_line_start(map, point, times), SelectionGoal::None), + StartOfLineDownward => (next_line_start(map, point, times - 1), SelectionGoal::None), + EndOfLineDownward => (next_line_end(map, point, times), SelectionGoal::None), + GoToColumn => (go_to_column(map, point, times), SelectionGoal::None), + }; + + (new_point != point || infallible).then_some((new_point, goal)) + } + + // Expands a selection using self motion for an operator + pub fn expand_selection( + &self, + map: &DisplaySnapshot, + selection: &mut Selection, + times: Option, + expand_to_surrounding_newline: bool, + text_layout_details: &TextLayoutDetails, + ) -> bool { + if let Some((new_head, goal)) = self.move_point( + map, + selection.head(), + selection.goal, + times, + &text_layout_details, + ) { + selection.set_head(new_head, goal); + + if self.linewise() { + selection.start = map.prev_line_boundary(selection.start.to_point(map)).1; + + if expand_to_surrounding_newline { + if selection.end.row() < map.max_point().row() { + *selection.end.row_mut() += 1; + *selection.end.column_mut() = 0; + selection.end = map.clip_point(selection.end, Bias::Right); + // Don't reset the end here + return true; + } else if selection.start.row() > 0 { + *selection.start.row_mut() -= 1; + *selection.start.column_mut() = map.line_len(selection.start.row()); + selection.start = map.clip_point(selection.start, Bias::Left); + } + } + + (_, selection.end) = map.next_line_boundary(selection.end.to_point(map)); + } else { + // Another special case: When using the "w" motion in combination with an + // operator and the last word moved over is at the end of a line, the end of + // that word becomes the end of the operated text, not the first word in the + // next line. + if let Motion::NextWordStart { + ignore_punctuation: _, + } = self + { + let start_row = selection.start.to_point(&map).row; + if selection.end.to_point(&map).row > start_row { + selection.end = + Point::new(start_row, map.buffer_snapshot.line_len(start_row)) + .to_display_point(&map) + } + } + + // If the motion is exclusive and the end of the motion is in column 1, the + // end of the motion is moved to the end of the previous line and the motion + // becomes inclusive. Example: "}" moves to the first line after a paragraph, + // but "d}" will not include that line. + let mut inclusive = self.inclusive(); + if !inclusive + && self != &Motion::Backspace + && selection.end.row() > selection.start.row() + && selection.end.column() == 0 + { + inclusive = true; + *selection.end.row_mut() -= 1; + *selection.end.column_mut() = 0; + selection.end = map.clip_point( + map.next_line_boundary(selection.end.to_point(map)).1, + Bias::Left, + ); + } + + if inclusive && selection.end.column() < map.line_len(selection.end.row()) { + *selection.end.column_mut() += 1; + } + } + true + } else { + false + } + } +} + +fn left(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> DisplayPoint { + for _ in 0..times { + point = movement::saturating_left(map, point); + if point.column() == 0 { + break; + } + } + point +} + +fn backspace(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> DisplayPoint { + for _ in 0..times { + point = movement::left(map, point); + } + point +} + +pub(crate) fn start_of_relative_buffer_row( + map: &DisplaySnapshot, + point: DisplayPoint, + times: isize, +) -> DisplayPoint { + let start = map.display_point_to_fold_point(point, Bias::Left); + let target = start.row() as isize + times; + let new_row = (target.max(0) as u32).min(map.fold_snapshot.max_point().row()); + + map.clip_point( + map.fold_point_to_display_point( + map.fold_snapshot + .clip_point(FoldPoint::new(new_row, 0), Bias::Right), + ), + Bias::Right, + ) +} + +fn up_down_buffer_rows( + map: &DisplaySnapshot, + point: DisplayPoint, + mut goal: SelectionGoal, + times: isize, + text_layout_details: &TextLayoutDetails, +) -> (DisplayPoint, SelectionGoal) { + let start = map.display_point_to_fold_point(point, Bias::Left); + let begin_folded_line = map.fold_point_to_display_point( + map.fold_snapshot + .clip_point(FoldPoint::new(start.row(), 0), Bias::Left), + ); + let select_nth_wrapped_row = point.row() - begin_folded_line.row(); + + let (goal_wrap, goal_x) = match goal { + SelectionGoal::WrappedHorizontalPosition((row, x)) => (row, x), + SelectionGoal::HorizontalRange { end, .. } => (select_nth_wrapped_row, end), + SelectionGoal::HorizontalPosition(x) => (select_nth_wrapped_row, x), + _ => { + let x = map.x_for_display_point(point, text_layout_details); + goal = SelectionGoal::WrappedHorizontalPosition((select_nth_wrapped_row, x.0)); + (select_nth_wrapped_row, x.0) + } + }; + + let target = start.row() as isize + times; + let new_row = (target.max(0) as u32).min(map.fold_snapshot.max_point().row()); + + let mut begin_folded_line = map.fold_point_to_display_point( + map.fold_snapshot + .clip_point(FoldPoint::new(new_row, 0), Bias::Left), + ); + + let mut i = 0; + while i < goal_wrap && begin_folded_line.row() < map.max_point().row() { + let next_folded_line = DisplayPoint::new(begin_folded_line.row() + 1, 0); + if map + .display_point_to_fold_point(next_folded_line, Bias::Right) + .row() + == new_row + { + i += 1; + begin_folded_line = next_folded_line; + } else { + break; + } + } + + let new_col = if i == goal_wrap { + map.display_column_for_x(begin_folded_line.row(), px(goal_x), text_layout_details) + } else { + map.line_len(begin_folded_line.row()) + }; + + ( + map.clip_point( + DisplayPoint::new(begin_folded_line.row(), new_col), + Bias::Left, + ), + goal, + ) +} + +fn down_display( + map: &DisplaySnapshot, + mut point: DisplayPoint, + mut goal: SelectionGoal, + times: usize, + text_layout_details: &TextLayoutDetails, +) -> (DisplayPoint, SelectionGoal) { + for _ in 0..times { + (point, goal) = movement::down(map, point, goal, true, text_layout_details); + } + + (point, goal) +} + +fn up_display( + map: &DisplaySnapshot, + mut point: DisplayPoint, + mut goal: SelectionGoal, + times: usize, + text_layout_details: &TextLayoutDetails, +) -> (DisplayPoint, SelectionGoal) { + for _ in 0..times { + (point, goal) = movement::up(map, point, goal, true, &text_layout_details); + } + + (point, goal) +} + +pub(crate) fn right(map: &DisplaySnapshot, mut point: DisplayPoint, times: usize) -> DisplayPoint { + for _ in 0..times { + let new_point = movement::saturating_right(map, point); + if point == new_point { + break; + } + point = new_point; + } + point +} + +pub(crate) fn next_word_start( + map: &DisplaySnapshot, + mut point: DisplayPoint, + ignore_punctuation: bool, + times: usize, +) -> DisplayPoint { + let scope = map.buffer_snapshot.language_scope_at(point.to_point(map)); + for _ in 0..times { + let mut crossed_newline = false; + point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| { + let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation); + let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation); + let at_newline = right == '\n'; + + let found = (left_kind != right_kind && right_kind != CharKind::Whitespace) + || at_newline && crossed_newline + || at_newline && left == '\n'; // Prevents skipping repeated empty lines + + crossed_newline |= at_newline; + found + }) + } + point +} + +fn next_word_end( + map: &DisplaySnapshot, + mut point: DisplayPoint, + ignore_punctuation: bool, + times: usize, +) -> DisplayPoint { + let scope = map.buffer_snapshot.language_scope_at(point.to_point(map)); + for _ in 0..times { + if point.column() < map.line_len(point.row()) { + *point.column_mut() += 1; + } else if point.row() < map.max_buffer_row() { + *point.row_mut() += 1; + *point.column_mut() = 0; + } + point = movement::find_boundary(map, point, FindRange::MultiLine, |left, right| { + let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation); + let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation); + + left_kind != right_kind && left_kind != CharKind::Whitespace + }); + + // find_boundary clips, so if the character after the next character is a newline or at the end of the document, we know + // we have backtracked already + if !map + .chars_at(point) + .nth(1) + .map(|(c, _)| c == '\n') + .unwrap_or(true) + { + *point.column_mut() = point.column().saturating_sub(1); + } + point = map.clip_point(point, Bias::Left); + } + point +} + +fn previous_word_start( + map: &DisplaySnapshot, + mut point: DisplayPoint, + ignore_punctuation: bool, + times: usize, +) -> DisplayPoint { + let scope = map.buffer_snapshot.language_scope_at(point.to_point(map)); + for _ in 0..times { + // This works even though find_preceding_boundary is called for every character in the line containing + // cursor because the newline is checked only once. + point = + movement::find_preceding_boundary(map, point, FindRange::MultiLine, |left, right| { + let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation); + let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation); + + (left_kind != right_kind && !right.is_whitespace()) || left == '\n' + }); + } + point +} + +pub(crate) fn first_non_whitespace( + map: &DisplaySnapshot, + display_lines: bool, + from: DisplayPoint, +) -> DisplayPoint { + let mut last_point = start_of_line(map, display_lines, from); + let scope = map.buffer_snapshot.language_scope_at(from.to_point(map)); + for (ch, point) in map.chars_at(last_point) { + if ch == '\n' { + return from; + } + + last_point = point; + + if char_kind(&scope, ch) != CharKind::Whitespace { + break; + } + } + + map.clip_point(last_point, Bias::Left) +} + +pub(crate) fn start_of_line( + map: &DisplaySnapshot, + display_lines: bool, + point: DisplayPoint, +) -> DisplayPoint { + if display_lines { + map.clip_point(DisplayPoint::new(point.row(), 0), Bias::Right) + } else { + map.prev_line_boundary(point.to_point(map)).1 + } +} + +pub(crate) fn end_of_line( + map: &DisplaySnapshot, + display_lines: bool, + point: DisplayPoint, +) -> DisplayPoint { + if display_lines { + map.clip_point( + DisplayPoint::new(point.row(), map.line_len(point.row())), + Bias::Left, + ) + } else { + map.clip_point(map.next_line_boundary(point.to_point(map)).1, Bias::Left) + } +} + +fn start_of_document(map: &DisplaySnapshot, point: DisplayPoint, line: usize) -> DisplayPoint { + let mut new_point = Point::new((line - 1) as u32, 0).to_display_point(map); + *new_point.column_mut() = point.column(); + map.clip_point(new_point, Bias::Left) +} + +fn end_of_document( + map: &DisplaySnapshot, + point: DisplayPoint, + line: Option, +) -> DisplayPoint { + let new_row = if let Some(line) = line { + (line - 1) as u32 + } else { + map.max_buffer_row() + }; + + let new_point = Point::new(new_row, point.column()); + map.clip_point(new_point.to_display_point(map), Bias::Left) +} + +fn matching(map: &DisplaySnapshot, display_point: DisplayPoint) -> DisplayPoint { + // https://github.com/vim/vim/blob/1d87e11a1ef201b26ed87585fba70182ad0c468a/runtime/doc/motion.txt#L1200 + let point = display_point.to_point(map); + let offset = point.to_offset(&map.buffer_snapshot); + + // Ensure the range is contained by the current line. + let mut line_end = map.next_line_boundary(point).0; + if line_end == point { + line_end = map.max_point().to_point(map); + } + + let line_range = map.prev_line_boundary(point).0..line_end; + let visible_line_range = + line_range.start..Point::new(line_range.end.row, line_range.end.column.saturating_sub(1)); + let ranges = map + .buffer_snapshot + .bracket_ranges(visible_line_range.clone()); + if let Some(ranges) = ranges { + let line_range = line_range.start.to_offset(&map.buffer_snapshot) + ..line_range.end.to_offset(&map.buffer_snapshot); + let mut closest_pair_destination = None; + let mut closest_distance = usize::MAX; + + for (open_range, close_range) in ranges { + if open_range.start >= offset && line_range.contains(&open_range.start) { + let distance = open_range.start - offset; + if distance < closest_distance { + closest_pair_destination = Some(close_range.start); + closest_distance = distance; + continue; + } + } + + if close_range.start >= offset && line_range.contains(&close_range.start) { + let distance = close_range.start - offset; + if distance < closest_distance { + closest_pair_destination = Some(open_range.start); + closest_distance = distance; + continue; + } + } + + continue; + } + + closest_pair_destination + .map(|destination| destination.to_display_point(map)) + .unwrap_or(display_point) + } else { + display_point + } +} + +fn find_forward( + map: &DisplaySnapshot, + from: DisplayPoint, + before: bool, + target: char, + times: usize, +) -> DisplayPoint { + let mut to = from; + let mut found = false; + + for _ in 0..times { + found = false; + to = find_boundary(map, to, FindRange::SingleLine, |_, right| { + found = right == target; + found + }); + } + + if found { + if before && to.column() > 0 { + *to.column_mut() -= 1; + map.clip_point(to, Bias::Left) + } else { + to + } + } else { + from + } +} + +fn find_backward( + map: &DisplaySnapshot, + from: DisplayPoint, + after: bool, + target: char, + times: usize, +) -> DisplayPoint { + let mut to = from; + + for _ in 0..times { + to = find_preceding_boundary(map, to, FindRange::SingleLine, |_, right| right == target); + } + + if map.buffer_snapshot.chars_at(to.to_point(map)).next() == Some(target) { + if after { + *to.column_mut() += 1; + map.clip_point(to, Bias::Right) + } else { + to + } + } else { + from + } +} + +fn next_line_start(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint { + let correct_line = start_of_relative_buffer_row(map, point, times as isize); + first_non_whitespace(map, false, correct_line) +} + +fn go_to_column(map: &DisplaySnapshot, point: DisplayPoint, times: usize) -> DisplayPoint { + let correct_line = start_of_relative_buffer_row(map, point, 0); + right(map, correct_line, times.saturating_sub(1)) +} + +pub(crate) fn next_line_end( + map: &DisplaySnapshot, + mut point: DisplayPoint, + times: usize, +) -> DisplayPoint { + if times > 1 { + point = start_of_relative_buffer_row(map, point, times as isize - 1); + } + end_of_line(map, false, point) +} + +// #[cfg(test)] +// mod test { + +// use crate::test::NeovimBackedTestContext; +// use indoc::indoc; + +// #[gpui::test] +// async fn test_start_end_of_paragraph(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// let initial_state = indoc! {r"ˇabc +// def + +// paragraph +// the second + +// third and +// final"}; + +// // goes down once +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes(["}"]).await; +// cx.assert_shared_state(indoc! {r"abc +// def +// ˇ +// paragraph +// the second + +// third and +// final"}) +// .await; + +// // goes up once +// cx.simulate_shared_keystrokes(["{"]).await; +// cx.assert_shared_state(initial_state).await; + +// // goes down twice +// cx.simulate_shared_keystrokes(["2", "}"]).await; +// cx.assert_shared_state(indoc! {r"abc +// def + +// paragraph +// the second +// ˇ + +// third and +// final"}) +// .await; + +// // goes down over multiple blanks +// cx.simulate_shared_keystrokes(["}"]).await; +// cx.assert_shared_state(indoc! {r"abc +// def + +// paragraph +// the second + +// third and +// finaˇl"}) +// .await; + +// // goes up twice +// cx.simulate_shared_keystrokes(["2", "{"]).await; +// cx.assert_shared_state(indoc! {r"abc +// def +// ˇ +// paragraph +// the second + +// third and +// final"}) +// .await +// } + +// #[gpui::test] +// async fn test_matching(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {r"func ˇ(a string) { +// do(something(with.and_arrays[0, 2])) +// }"}) +// .await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state(indoc! {r"func (a stringˇ) { +// do(something(with.and_arrays[0, 2])) +// }"}) +// .await; + +// // test it works on the last character of the line +// cx.set_shared_state(indoc! {r"func (a string) ˇ{ +// do(something(with.and_arrays[0, 2])) +// }"}) +// .await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state(indoc! {r"func (a string) { +// do(something(with.and_arrays[0, 2])) +// ˇ}"}) +// .await; + +// // test it works on immediate nesting +// cx.set_shared_state("ˇ{()}").await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state("{()ˇ}").await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state("ˇ{()}").await; + +// // test it works on immediate nesting inside braces +// cx.set_shared_state("{\n ˇ{()}\n}").await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state("{\n {()ˇ}\n}").await; + +// // test it jumps to the next paren on a line +// cx.set_shared_state("func ˇboop() {\n}").await; +// cx.simulate_shared_keystrokes(["%"]).await; +// cx.assert_shared_state("func boop(ˇ) {\n}").await; +// } + +// #[gpui::test] +// async fn test_comma_semicolon(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("ˇone two three four").await; +// cx.simulate_shared_keystrokes(["f", "o"]).await; +// cx.assert_shared_state("one twˇo three four").await; +// cx.simulate_shared_keystrokes([","]).await; +// cx.assert_shared_state("ˇone two three four").await; +// cx.simulate_shared_keystrokes(["2", ";"]).await; +// cx.assert_shared_state("one two three fˇour").await; +// cx.simulate_shared_keystrokes(["shift-t", "e"]).await; +// cx.assert_shared_state("one two threeˇ four").await; +// cx.simulate_shared_keystrokes(["3", ";"]).await; +// cx.assert_shared_state("oneˇ two three four").await; +// cx.simulate_shared_keystrokes([","]).await; +// cx.assert_shared_state("one two thˇree four").await; +// } + +// #[gpui::test] +// async fn test_next_line_start(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_shared_state("ˇone\n two\nthree").await; +// cx.simulate_shared_keystrokes(["enter"]).await; +// cx.assert_shared_state("one\n ˇtwo\nthree").await; +// } +// } diff --git a/crates/vim2/src/normal.rs b/crates/vim2/src/normal.rs new file mode 100644 index 0000000000..cba5dadb3f --- /dev/null +++ b/crates/vim2/src/normal.rs @@ -0,0 +1,903 @@ +mod case; +mod change; +mod delete; +mod increment; +mod paste; +pub(crate) mod repeat; +mod scroll; +pub(crate) mod search; +pub mod substitute; +mod yank; + +use std::sync::Arc; + +use crate::{ + motion::{self, first_non_whitespace, next_line_end, right, Motion}, + object::Object, + state::{Mode, Operator}, + Vim, +}; +use collections::HashSet; +use editor::scroll::autoscroll::Autoscroll; +use editor::{Bias, DisplayPoint}; +use gpui::{actions, AppContext, ViewContext, WindowContext}; +use language::SelectionGoal; +use log::error; +use workspace::Workspace; + +use self::{ + case::change_case, + change::{change_motion, change_object}, + delete::{delete_motion, delete_object}, + yank::{yank_motion, yank_object}, +}; + +actions!( + InsertAfter, + InsertBefore, + InsertFirstNonWhitespace, + InsertEndOfLine, + InsertLineAbove, + InsertLineBelow, + DeleteLeft, + DeleteRight, + ChangeToEndOfLine, + DeleteToEndOfLine, + Yank, + YankLine, + ChangeCase, + 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 fn normal_motion( + motion: Motion, + operator: Option, + times: Option, + cx: &mut WindowContext, +) { + Vim::update(cx, |vim, cx| { + match operator { + None => move_cursor(vim, motion, times, cx), + Some(Operator::Change) => change_motion(vim, motion, times, cx), + Some(Operator::Delete) => delete_motion(vim, motion, times, cx), + Some(Operator::Yank) => yank_motion(vim, motion, times, cx), + Some(operator) => { + // Can't do anything for text objects, Ignoring + error!("Unexpected normal mode motion operator: {:?}", operator) + } + } + }); +} + +pub fn normal_object(object: Object, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + match vim.maybe_pop_operator() { + Some(Operator::Object { around }) => match vim.maybe_pop_operator() { + Some(Operator::Change) => change_object(vim, object, around, cx), + Some(Operator::Delete) => delete_object(vim, object, around, cx), + Some(Operator::Yank) => yank_object(vim, object, around, cx), + _ => { + // Can't do anything for namespace operators. Ignoring + } + }, + _ => { + // Can't do anything with change/delete/yank and text objects. Ignoring + } + } + vim.clear_operator(cx); + }) +} + +pub(crate) fn move_cursor( + vim: &mut Vim, + motion: Motion, + times: Option, + cx: &mut WindowContext, +) { + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, cursor, goal| { + motion + .move_point(map, cursor, goal, times, &text_layout_details) + .unwrap_or((cursor, goal)) + }) + }) + }); +} + +fn insert_after(_: &mut Workspace, _: &InsertAfter, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + vim.update_active_editor(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, cursor, _| (right(map, cursor, 1), SelectionGoal::None)); + }); + }); + }); +} + +fn insert_before(_: &mut Workspace, _: &InsertBefore, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + }); +} + +fn insert_first_non_whitespace( + _: &mut Workspace, + _: &InsertFirstNonWhitespace, + cx: &mut ViewContext, +) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + vim.update_active_editor(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, cursor, _| { + ( + first_non_whitespace(map, false, cursor), + SelectionGoal::None, + ) + }); + }); + }); + }); +} + +fn insert_end_of_line(_: &mut Workspace, _: &InsertEndOfLine, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + vim.update_active_editor(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, cursor, _| { + (next_line_end(map, cursor, 1), SelectionGoal::None) + }); + }); + }); + }); +} + +fn insert_line_above(_: &mut Workspace, _: &InsertLineAbove, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + vim.update_active_editor(cx, |editor, cx| { + editor.transact(cx, |editor, cx| { + let (map, old_selections) = editor.selections.all_display(cx); + let selection_start_rows: HashSet = old_selections + .into_iter() + .map(|selection| selection.start.row()) + .collect(); + let edits = selection_start_rows.into_iter().map(|row| { + let (indent, _) = map.line_indent(row); + let start_of_line = + motion::start_of_line(&map, false, DisplayPoint::new(row, 0)) + .to_point(&map); + let mut new_text = " ".repeat(indent as usize); + new_text.push('\n'); + (start_of_line..start_of_line, new_text) + }); + editor.edit_with_autoindent(edits, cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_cursors_with(|map, cursor, _| { + let previous_line = motion::start_of_relative_buffer_row(map, cursor, -1); + let insert_point = motion::end_of_line(map, false, previous_line); + (insert_point, SelectionGoal::None) + }); + }); + }); + }); + }); +} + +fn insert_line_below(_: &mut Workspace, _: &InsertLineBelow, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.start_recording(cx); + vim.switch_mode(Mode::Insert, false, cx); + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.transact(cx, |editor, cx| { + let (map, old_selections) = editor.selections.all_display(cx); + + let selection_end_rows: HashSet = old_selections + .into_iter() + .map(|selection| selection.end.row()) + .collect(); + let edits = selection_end_rows.into_iter().map(|row| { + let (indent, _) = map.line_indent(row); + let end_of_line = + motion::end_of_line(&map, false, DisplayPoint::new(row, 0)).to_point(&map); + + let mut new_text = "\n".to_string(); + new_text.push_str(&" ".repeat(indent as usize)); + (end_of_line..end_of_line, new_text) + }); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.maybe_move_cursors_with(|map, cursor, goal| { + Motion::CurrentLine.move_point( + map, + cursor, + goal, + None, + &text_layout_details, + ) + }); + }); + editor.edit_with_autoindent(edits, cx); + }); + }); + }); +} + +fn yank_line(_: &mut Workspace, _: &YankLine, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + let count = vim.take_count(cx); + yank_motion(vim, motion::Motion::CurrentLine, count, cx) + }) +} + +pub(crate) fn normal_replace(text: Arc, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + vim.stop_recording(); + vim.update_active_editor(cx, |editor, cx| { + editor.transact(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + let (map, display_selections) = editor.selections.all_display(cx); + // Selections are biased right at the start. So we need to store + // anchors that are biased left so that we can restore the selections + // after the change + let stable_anchors = editor + .selections + .disjoint_anchors() + .into_iter() + .map(|selection| { + let start = selection.start.bias_left(&map.buffer_snapshot); + start..start + }) + .collect::>(); + + let edits = display_selections + .into_iter() + .map(|selection| { + let mut range = selection.range(); + *range.end.column_mut() += 1; + range.end = map.clip_point(range.end, Bias::Right); + + ( + range.start.to_offset(&map, Bias::Left) + ..range.end.to_offset(&map, Bias::Left), + text.clone(), + ) + }) + .collect::>(); + + editor.buffer().update(cx, |buffer, cx| { + buffer.edit(edits, None, cx); + }); + editor.set_clip_at_line_ends(true, cx); + editor.change_selections(None, cx, |s| { + s.select_anchor_ranges(stable_anchors); + }); + }); + }); + vim.pop_operator(cx) + }); +} + +// #[cfg(test)] +// mod test { +// use gpui::TestAppContext; +// use indoc::indoc; + +// use crate::{ +// state::Mode::{self}, +// test::NeovimBackedTestContext, +// }; + +// #[gpui::test] +// async fn test_h(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["h"]); +// cx.assert_all(indoc! {" +// ˇThe qˇuick +// ˇbrown" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_backspace(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["backspace"]); +// cx.assert_all(indoc! {" +// ˇThe qˇuick +// ˇbrown" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_j(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// aaˇaa +// 😃😃" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j"]).await; +// cx.assert_shared_state(indoc! {" +// aaaa +// 😃ˇ😃" +// }) +// .await; + +// for marked_position in cx.each_marked_position(indoc! {" +// ˇThe qˇuick broˇwn +// ˇfox jumps" +// }) { +// cx.assert_neovim_compatible(&marked_position, ["j"]).await; +// } +// } + +// #[gpui::test] +// async fn test_enter(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["enter"]); +// cx.assert_all(indoc! {" +// ˇThe qˇuick broˇwn +// ˇfox jumps" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_k(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["k"]); +// cx.assert_all(indoc! {" +// ˇThe qˇuick +// ˇbrown fˇox jumˇps" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_l(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["l"]); +// cx.assert_all(indoc! {" +// ˇThe qˇuicˇk +// ˇbrowˇn"}) +// .await; +// } + +// #[gpui::test] +// async fn test_jump_to_line_boundaries(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_binding_matches_all( +// ["$"], +// indoc! {" +// ˇThe qˇuicˇk +// ˇbrowˇn"}, +// ) +// .await; +// cx.assert_binding_matches_all( +// ["0"], +// indoc! {" +// ˇThe qˇuicˇk +// ˇbrowˇn"}, +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_jump_to_end(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-g"]); + +// cx.assert_all(indoc! {" +// The ˇquick + +// brown fox jumps +// overˇ the lazy doˇg"}) +// .await; +// cx.assert(indoc! {" +// The quiˇck + +// brown"}) +// .await; +// cx.assert(indoc! {" +// The quiˇck + +// "}) +// .await; +// } + +// #[gpui::test] +// async fn test_w(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["w"]); +// cx.assert_all(indoc! {" +// The ˇquickˇ-ˇbrown +// ˇ +// ˇ +// ˇfox_jumps ˇover +// ˇthˇe"}) +// .await; +// let mut cx = cx.binding(["shift-w"]); +// cx.assert_all(indoc! {" +// The ˇquickˇ-ˇbrown +// ˇ +// ˇ +// ˇfox_jumps ˇover +// ˇthˇe"}) +// .await; +// } + +// #[gpui::test] +// async fn test_end_of_word(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["e"]); +// cx.assert_all(indoc! {" +// Thˇe quicˇkˇ-browˇn + +// fox_jumpˇs oveˇr +// thˇe"}) +// .await; +// let mut cx = cx.binding(["shift-e"]); +// cx.assert_all(indoc! {" +// Thˇe quicˇkˇ-browˇn + +// fox_jumpˇs oveˇr +// thˇe"}) +// .await; +// } + +// #[gpui::test] +// async fn test_b(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["b"]); +// cx.assert_all(indoc! {" +// ˇThe ˇquickˇ-ˇbrown +// ˇ +// ˇ +// ˇfox_jumps ˇover +// ˇthe"}) +// .await; +// let mut cx = cx.binding(["shift-b"]); +// cx.assert_all(indoc! {" +// ˇThe ˇquickˇ-ˇbrown +// ˇ +// ˇ +// ˇfox_jumps ˇover +// ˇthe"}) +// .await; +// } + +// #[gpui::test] +// async fn test_gg(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_binding_matches_all( +// ["g", "g"], +// indoc! {" +// The qˇuick + +// brown fox jumps +// over ˇthe laˇzy dog"}, +// ) +// .await; +// cx.assert_binding_matches( +// ["g", "g"], +// indoc! {" + +// brown fox jumps +// over the laˇzy dog"}, +// ) +// .await; +// cx.assert_binding_matches( +// ["2", "g", "g"], +// indoc! {" +// ˇ + +// brown fox jumps +// over the lazydog"}, +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_end_of_document(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_binding_matches_all( +// ["shift-g"], +// indoc! {" +// The qˇuick + +// brown fox jumps +// over ˇthe laˇzy dog"}, +// ) +// .await; +// cx.assert_binding_matches( +// ["shift-g"], +// indoc! {" + +// brown fox jumps +// over the laˇzy dog"}, +// ) +// .await; +// cx.assert_binding_matches( +// ["2", "shift-g"], +// indoc! {" +// ˇ + +// brown fox jumps +// over the lazydog"}, +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_a(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["a"]); +// cx.assert_all("The qˇuicˇk").await; +// } + +// #[gpui::test] +// async fn test_insert_end_of_line(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-a"]); +// cx.assert_all(indoc! {" +// ˇ +// The qˇuick +// brown ˇfox "}) +// .await; +// } + +// #[gpui::test] +// async fn test_jump_to_first_non_whitespace(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["^"]); +// cx.assert("The qˇuick").await; +// cx.assert(" The qˇuick").await; +// cx.assert("ˇ").await; +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// ˇ +// The quick"}) +// .await; +// // Indoc disallows trailing whitespace. +// cx.assert(" ˇ \nThe quick").await; +// } + +// #[gpui::test] +// async fn test_insert_first_non_whitespace(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-i"]); +// cx.assert("The qˇuick").await; +// cx.assert(" The qˇuick").await; +// cx.assert("ˇ").await; +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// ˇ +// The quick"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_to_end_of_line(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-d"]); +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; +// } + +// #[gpui::test] +// async fn test_x(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["x"]); +// cx.assert_all("ˇTeˇsˇt").await; +// cx.assert(indoc! {" +// Tesˇt +// test"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_left(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["shift-x"]); +// cx.assert_all("ˇTˇeˇsˇt").await; +// cx.assert(indoc! {" +// Test +// ˇtest"}) +// .await; +// } + +// #[gpui::test] +// async fn test_o(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["o"]); +// cx.assert("ˇ").await; +// cx.assert("The ˇquick").await; +// cx.assert_all(indoc! {" +// The qˇuick +// brown ˇfox +// jumps ˇover"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; + +// cx.assert_manual( +// indoc! {" +// fn test() { +// println!(ˇ); +// }"}, +// Mode::Normal, +// indoc! {" +// fn test() { +// println!(); +// ˇ +// }"}, +// Mode::Insert, +// ); + +// cx.assert_manual( +// indoc! {" +// fn test(ˇ) { +// println!(); +// }"}, +// Mode::Normal, +// indoc! {" +// fn test() { +// ˇ +// println!(); +// }"}, +// Mode::Insert, +// ); +// } + +// #[gpui::test] +// async fn test_insert_line_above(cx: &mut gpui::TestAppContext) { +// let cx = NeovimBackedTestContext::new(cx).await; +// let mut cx = cx.binding(["shift-o"]); +// cx.assert("ˇ").await; +// cx.assert("The ˇquick").await; +// cx.assert_all(indoc! {" +// The qˇuick +// brown ˇfox +// jumps ˇover"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; + +// // Our indentation is smarter than vims. So we don't match here +// cx.assert_manual( +// indoc! {" +// fn test() { +// println!(ˇ); +// }"}, +// Mode::Normal, +// indoc! {" +// fn test() { +// ˇ +// println!(); +// }"}, +// Mode::Insert, +// ); +// cx.assert_manual( +// indoc! {" +// fn test(ˇ) { +// println!(); +// }"}, +// Mode::Normal, +// indoc! {" +// ˇ +// fn test() { +// println!(); +// }"}, +// Mode::Insert, +// ); +// } + +// #[gpui::test] +// async fn test_dd(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible("ˇ", ["d", "d"]).await; +// cx.assert_neovim_compatible("The ˇquick", ["d", "d"]).await; +// for marked_text in cx.each_marked_position(indoc! {" +// The qˇuick +// brown ˇfox +// jumps ˇover"}) +// { +// cx.assert_neovim_compatible(&marked_text, ["d", "d"]).await; +// } +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// ˇ +// brown fox"}, +// ["d", "d"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_cc(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "c"]); +// cx.assert("ˇ").await; +// cx.assert("The ˇquick").await; +// cx.assert_all(indoc! {" +// The quˇick +// brown ˇfox +// jumps ˇover"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; +// } + +// #[gpui::test] +// async fn test_repeated_word(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=5 { +// cx.assert_binding_matches_all( +// [&count.to_string(), "w"], +// indoc! {" +// ˇThe quˇickˇ browˇn +// ˇ +// ˇfox ˇjumpsˇ-ˇoˇver +// ˇthe lazy dog +// "}, +// ) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_h_through_unicode(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["h"]); +// cx.assert_all("Testˇ├ˇ──ˇ┐ˇTest").await; +// } + +// #[gpui::test] +// async fn test_f_and_t(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=3 { +// let test_case = indoc! {" +// ˇaaaˇbˇ ˇbˇ ˇbˇbˇ aˇaaˇbaaa +// ˇ ˇbˇaaˇa ˇbˇbˇb +// ˇ +// ˇb +// "}; + +// cx.assert_binding_matches_all([&count.to_string(), "f", "b"], test_case) +// .await; + +// cx.assert_binding_matches_all([&count.to_string(), "t", "b"], test_case) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_capital_f_and_capital_t(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// let test_case = indoc! {" +// ˇaaaˇbˇ ˇbˇ ˇbˇbˇ aˇaaˇbaaa +// ˇ ˇbˇaaˇa ˇbˇbˇb +// ˇ••• +// ˇb +// " +// }; + +// for count in 1..=3 { +// cx.assert_binding_matches_all([&count.to_string(), "shift-f", "b"], test_case) +// .await; + +// cx.assert_binding_matches_all([&count.to_string(), "shift-t", "b"], test_case) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_percent(cx: &mut TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["%"]); +// cx.assert_all("ˇconsole.logˇ(ˇvaˇrˇ)ˇ;").await; +// cx.assert_all("ˇconsole.logˇ(ˇ'var', ˇ[ˇ1, ˇ2, 3ˇ]ˇ)ˇ;") +// .await; +// cx.assert_all("let result = curried_funˇ(ˇ)ˇ(ˇ)ˇ;").await; +// } +// } diff --git a/crates/vim2/src/normal/case.rs b/crates/vim2/src/normal/case.rs new file mode 100644 index 0000000000..6f321faa7f --- /dev/null +++ b/crates/vim2/src/normal/case.rs @@ -0,0 +1,116 @@ +use editor::scroll::autoscroll::Autoscroll; +use gpui::ViewContext; +use language::{Bias, Point}; +use workspace::Workspace; + +use crate::{normal::ChangeCase, state::Mode, Vim}; + +pub fn change_case(_: &mut Workspace, _: &ChangeCase, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.record_current_action(cx); + let count = vim.take_count(cx).unwrap_or(1) as u32; + vim.update_active_editor(cx, |editor, cx| { + let mut ranges = Vec::new(); + let mut cursor_positions = Vec::new(); + let snapshot = editor.buffer().read(cx).snapshot(cx); + for selection in editor.selections.all::(cx) { + match vim.state().mode { + Mode::VisualLine => { + let start = Point::new(selection.start.row, 0); + let end = + Point::new(selection.end.row, snapshot.line_len(selection.end.row)); + ranges.push(start..end); + cursor_positions.push(start..start); + } + Mode::Visual => { + ranges.push(selection.start..selection.end); + cursor_positions.push(selection.start..selection.start); + } + Mode::VisualBlock => { + ranges.push(selection.start..selection.end); + if cursor_positions.len() == 0 { + cursor_positions.push(selection.start..selection.start); + } + } + Mode::Insert | Mode::Normal => { + let start = selection.start; + let mut end = start; + for _ in 0..count { + end = snapshot.clip_point(end + Point::new(0, 1), Bias::Right); + } + ranges.push(start..end); + + if end.column == snapshot.line_len(end.row) { + end = snapshot.clip_point(end - Point::new(0, 1), Bias::Left); + } + cursor_positions.push(end..end) + } + } + } + editor.transact(cx, |editor, cx| { + for range in ranges.into_iter().rev() { + let snapshot = editor.buffer().read(cx).snapshot(cx); + editor.buffer().update(cx, |buffer, cx| { + let text = snapshot + .text_for_range(range.start..range.end) + .flat_map(|s| s.chars()) + .flat_map(|c| { + if c.is_lowercase() { + c.to_uppercase().collect::>() + } else { + c.to_lowercase().collect::>() + } + }) + .collect::(); + + buffer.edit([(range, text)], None, cx) + }) + } + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.select_ranges(cursor_positions) + }) + }); + }); + vim.switch_mode(Mode::Normal, true, cx) + }) +} +// #[cfg(test)] +// mod test { +// use crate::{state::Mode, test::NeovimBackedTestContext}; + +// #[gpui::test] +// async fn test_change_case(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_shared_state("ˇabC\n").await; +// cx.simulate_shared_keystrokes(["~"]).await; +// cx.assert_shared_state("AˇbC\n").await; +// cx.simulate_shared_keystrokes(["2", "~"]).await; +// cx.assert_shared_state("ABˇc\n").await; + +// // works in visual mode +// cx.set_shared_state("a😀C«dÉ1*fˇ»\n").await; +// cx.simulate_shared_keystrokes(["~"]).await; +// cx.assert_shared_state("a😀CˇDé1*F\n").await; + +// // works with multibyte characters +// cx.simulate_shared_keystrokes(["~"]).await; +// cx.set_shared_state("aˇC😀é1*F\n").await; +// cx.simulate_shared_keystrokes(["4", "~"]).await; +// cx.assert_shared_state("ac😀É1ˇ*F\n").await; + +// // works with line selections +// cx.set_shared_state("abˇC\n").await; +// cx.simulate_shared_keystrokes(["shift-v", "~"]).await; +// cx.assert_shared_state("ˇABc\n").await; + +// // works in visual block mode +// cx.set_shared_state("ˇaa\nbb\ncc").await; +// cx.simulate_shared_keystrokes(["ctrl-v", "j", "~"]).await; +// cx.assert_shared_state("ˇAa\nBb\ncc").await; + +// // works with multiple cursors (zed only) +// cx.set_state("aˇßcdˇe\n", Mode::Normal); +// cx.simulate_keystroke("~"); +// cx.assert_state("aSSˇcdˇE\n", Mode::Normal); +// } +// } diff --git a/crates/vim2/src/normal/change.rs b/crates/vim2/src/normal/change.rs new file mode 100644 index 0000000000..6fb0883393 --- /dev/null +++ b/crates/vim2/src/normal/change.rs @@ -0,0 +1,502 @@ +use crate::{motion::Motion, object::Object, state::Mode, utils::copy_selections_content, Vim}; +use editor::{ + char_kind, + display_map::DisplaySnapshot, + movement::{self, FindRange, TextLayoutDetails}, + scroll::autoscroll::Autoscroll, + CharKind, DisplayPoint, +}; +use gpui::WindowContext; +use language::Selection; + +pub fn change_motion(vim: &mut Vim, motion: Motion, times: Option, cx: &mut WindowContext) { + // Some motions ignore failure when switching to normal mode + let mut motion_succeeded = matches!( + motion, + Motion::Left + | Motion::Right + | Motion::EndOfLine { .. } + | Motion::Backspace + | Motion::StartOfLine { .. } + ); + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.transact(cx, |editor, cx| { + // We are swapping to insert mode anyway. Just set the line end clipping behavior now + editor.set_clip_at_line_ends(false, cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + motion_succeeded |= if let Motion::NextWordStart { ignore_punctuation } = motion + { + expand_changed_word_selection( + map, + selection, + times, + ignore_punctuation, + &text_layout_details, + ) + } else { + motion.expand_selection(map, selection, times, false, &text_layout_details) + }; + }); + }); + copy_selections_content(editor, motion.linewise(), cx); + editor.insert("", cx); + }); + }); + + if motion_succeeded { + vim.switch_mode(Mode::Insert, false, cx) + } else { + vim.switch_mode(Mode::Normal, false, cx) + } +} + +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 + editor.set_clip_at_line_ends(false, cx); + editor.transact(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + objects_found |= object.expand_selection(map, selection, around); + }); + }); + if objects_found { + copy_selections_content(editor, false, cx); + editor.insert("", cx); + } + }); + }); + + if objects_found { + vim.switch_mode(Mode::Insert, false, cx); + } else { + vim.switch_mode(Mode::Normal, false, cx); + } +} + +// From the docs https://vimdoc.sourceforge.net/htmldoc/motion.html +// Special case: "cw" and "cW" are treated like "ce" and "cE" if the cursor is +// on a non-blank. This is because "cw" is interpreted as change-word, and a +// word does not include the following white space. {Vi: "cw" when on a blank +// followed by other blanks changes only the first blank; this is probably a +// bug, because "dw" deletes all the blanks} +fn expand_changed_word_selection( + map: &DisplaySnapshot, + selection: &mut Selection, + times: Option, + ignore_punctuation: bool, + text_layout_details: &TextLayoutDetails, +) -> bool { + if times.is_none() || times.unwrap() == 1 { + let scope = map + .buffer_snapshot + .language_scope_at(selection.start.to_point(map)); + let in_word = map + .chars_at(selection.head()) + .next() + .map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace) + .unwrap_or_default(); + + if in_word { + selection.end = + movement::find_boundary(map, selection.end, FindRange::MultiLine, |left, right| { + let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation); + let right_kind = + char_kind(&scope, right).coerce_punctuation(ignore_punctuation); + + left_kind != right_kind && left_kind != CharKind::Whitespace + }); + true + } else { + Motion::NextWordStart { ignore_punctuation }.expand_selection( + map, + selection, + None, + false, + &text_layout_details, + ) + } + } else { + Motion::NextWordStart { ignore_punctuation }.expand_selection( + map, + selection, + times, + false, + &text_layout_details, + ) + } +} + +// #[cfg(test)] +// mod test { +// use indoc::indoc; + +// use crate::test::NeovimBackedTestContext; + +// #[gpui::test] +// async fn test_change_h(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "h"]); +// cx.assert("Teˇst").await; +// cx.assert("Tˇest").await; +// cx.assert("ˇTest").await; +// cx.assert(indoc! {" +// Test +// ˇtest"}) +// .await; +// } + +// #[gpui::test] +// async fn test_change_backspace(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["c", "backspace"]); +// cx.assert("Teˇst").await; +// cx.assert("Tˇest").await; +// cx.assert("ˇTest").await; +// cx.assert(indoc! {" +// Test +// ˇtest"}) +// .await; +// } + +// #[gpui::test] +// async fn test_change_l(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "l"]); +// cx.assert("Teˇst").await; +// cx.assert("Tesˇt").await; +// } + +// #[gpui::test] +// async fn test_change_w(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "w"]); +// cx.assert("Teˇst").await; +// cx.assert("Tˇest test").await; +// cx.assert("Testˇ test").await; +// cx.assert(indoc! {" +// Test teˇst +// test"}) +// .await; +// cx.assert(indoc! {" +// Test tesˇt +// test"}) +// .await; +// cx.assert(indoc! {" +// Test test +// ˇ +// test"}) +// .await; + +// let mut cx = cx.binding(["c", "shift-w"]); +// cx.assert("Test teˇst-test test").await; +// } + +// #[gpui::test] +// async fn test_change_e(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "e"]); +// cx.assert("Teˇst Test").await; +// cx.assert("Tˇest test").await; +// cx.assert(indoc! {" +// Test teˇst +// test"}) +// .await; +// cx.assert(indoc! {" +// Test tesˇt +// test"}) +// .await; +// cx.assert(indoc! {" +// Test test +// ˇ +// test"}) +// .await; + +// let mut cx = cx.binding(["c", "shift-e"]); +// cx.assert("Test teˇst-test test").await; +// } + +// #[gpui::test] +// async fn test_change_b(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "b"]); +// cx.assert("Teˇst Test").await; +// cx.assert("Test ˇtest").await; +// cx.assert("Test1 test2 ˇtest3").await; +// cx.assert(indoc! {" +// Test test +// ˇtest"}) +// .await; +// cx.assert(indoc! {" +// Test test +// ˇ +// test"}) +// .await; + +// let mut cx = cx.binding(["c", "shift-b"]); +// cx.assert("Test test-test ˇtest").await; +// } + +// #[gpui::test] +// async fn test_change_end_of_line(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["c", "$"]); +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; +// } + +// #[gpui::test] +// async fn test_change_0(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_neovim_compatible( +// indoc! {" +// The qˇuick +// brown fox"}, +// ["c", "0"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// ˇ +// brown fox"}, +// ["c", "0"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_change_k(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown ˇfox +// jumps over"}, +// ["c", "k"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps ˇover"}, +// ["c", "k"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The qˇuick +// brown fox +// jumps over"}, +// ["c", "k"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// ˇ +// brown fox +// jumps over"}, +// ["c", "k"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_change_j(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown ˇfox +// jumps over"}, +// ["c", "j"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps ˇover"}, +// ["c", "j"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The qˇuick +// brown fox +// jumps over"}, +// ["c", "j"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// ˇ"}, +// ["c", "j"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_change_end_of_document(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["c", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["c", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// the lˇazy"}, +// ["c", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// ˇ"}, +// ["c", "shift-g"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_change_gg(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["c", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// the lˇazy"}, +// ["c", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The qˇuick +// brown fox +// jumps over +// the lazy"}, +// ["c", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// ˇ +// brown fox +// jumps over +// the lazy"}, +// ["c", "g", "g"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_repeated_cj(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=5 { +// cx.assert_binding_matches_all( +// ["c", &count.to_string(), "j"], +// indoc! {" +// ˇThe quˇickˇ browˇn +// ˇ +// ˇfox ˇjumpsˇ-ˇoˇver +// ˇthe lazy dog +// "}, +// ) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_repeated_cl(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=5 { +// cx.assert_binding_matches_all( +// ["c", &count.to_string(), "l"], +// indoc! {" +// ˇThe quˇickˇ browˇn +// ˇ +// ˇfox ˇjumpsˇ-ˇoˇver +// ˇthe lazy dog +// "}, +// ) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_repeated_cb(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=5 { +// for marked_text in cx.each_marked_position(indoc! {" +// ˇThe quˇickˇ browˇn +// ˇ +// ˇfox ˇjumpsˇ-ˇoˇver +// ˇthe lazy dog +// "}) +// { +// cx.assert_neovim_compatible(&marked_text, ["c", &count.to_string(), "b"]) +// .await; +// } +// } +// } + +// #[gpui::test] +// async fn test_repeated_ce(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for count in 1..=5 { +// cx.assert_binding_matches_all( +// ["c", &count.to_string(), "e"], +// indoc! {" +// ˇThe quˇickˇ browˇn +// ˇ +// ˇfox ˇjumpsˇ-ˇoˇver +// ˇthe lazy dog +// "}, +// ) +// .await; +// } +// } +// } diff --git a/crates/vim2/src/normal/delete.rs b/crates/vim2/src/normal/delete.rs new file mode 100644 index 0000000000..62c7c383c9 --- /dev/null +++ b/crates/vim2/src/normal/delete.rs @@ -0,0 +1,475 @@ +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::WindowContext; +use language::Point; + +pub fn delete_motion(vim: &mut Vim, motion: Motion, times: Option, cx: &mut WindowContext) { + vim.stop_recording(); + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.transact(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + let mut original_columns: HashMap<_, _> = Default::default(); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let original_head = selection.head(); + original_columns.insert(selection.id, original_head.column()); + motion.expand_selection(map, selection, times, true, &text_layout_details); + + // Motion::NextWordStart on an empty line should delete it. + if let Motion::NextWordStart { + ignore_punctuation: _, + } = motion + { + if selection.is_empty() + && map + .buffer_snapshot + .line_len(selection.start.to_point(&map).row) + == 0 + { + selection.end = map + .buffer_snapshot + .clip_point( + Point::new(selection.start.to_point(&map).row + 1, 0), + Bias::Left, + ) + .to_display_point(map) + } + } + }); + }); + copy_selections_content(editor, motion.linewise(), cx); + editor.insert("", cx); + + // Fixup cursor position after the deletion + editor.set_clip_at_line_ends(true, cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let mut cursor = selection.head(); + if motion.linewise() { + if let Some(column) = original_columns.get(&selection.id) { + *cursor.column_mut() = *column + } + } + cursor = map.clip_point(cursor, Bias::Left); + selection.collapse_to(cursor, selection.goal) + }); + }); + }); + }); +} + +pub fn delete_object(vim: &mut Vim, object: Object, around: bool, cx: &mut WindowContext) { + vim.stop_recording(); + vim.update_active_editor(cx, |editor, cx| { + editor.transact(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + // Emulates behavior in vim where if we expanded backwards to include a newline + // the cursor gets set back to the start of the line + let mut should_move_to_start: HashSet<_> = Default::default(); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + object.expand_selection(map, selection, around); + let offset_range = selection.map(|p| p.to_offset(map, Bias::Left)).range(); + let contains_only_newlines = map + .chars_at(selection.start) + .take_while(|(_, p)| p < &selection.end) + .all(|(char, _)| char == '\n') + && !offset_range.is_empty(); + let end_at_newline = map + .chars_at(selection.end) + .next() + .map(|(c, _)| c == '\n') + .unwrap_or(false); + + // If expanded range contains only newlines and + // the object is around or sentence, expand to include a newline + // at the end or start + if (around || object == Object::Sentence) && contains_only_newlines { + if end_at_newline { + selection.end = + (offset_range.end + '\n'.len_utf8()).to_display_point(map); + } else if selection.start.row() > 0 { + should_move_to_start.insert(selection.id); + selection.start = + (offset_range.start - '\n'.len_utf8()).to_display_point(map); + } + } + }); + }); + copy_selections_content(editor, false, cx); + editor.insert("", cx); + + // Fixup cursor position after the deletion + editor.set_clip_at_line_ends(true, cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let mut cursor = selection.head(); + if should_move_to_start.contains(&selection.id) { + *cursor.column_mut() = 0; + } + cursor = map.clip_point(cursor, Bias::Left); + selection.collapse_to(cursor, selection.goal) + }); + }); + }); + }); +} + +// #[cfg(test)] +// mod test { +// use indoc::indoc; + +// use crate::{ +// state::Mode, +// test::{ExemptionFeatures, NeovimBackedTestContext, VimTestContext}, +// }; + +// #[gpui::test] +// async fn test_delete_h(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "h"]); +// cx.assert("Teˇst").await; +// cx.assert("Tˇest").await; +// cx.assert("ˇTest").await; +// cx.assert(indoc! {" +// Test +// ˇtest"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_l(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "l"]); +// cx.assert("ˇTest").await; +// cx.assert("Teˇst").await; +// cx.assert("Tesˇt").await; +// cx.assert(indoc! {" +// Tesˇt +// test"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_w(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible( +// indoc! {" +// Test tesˇt +// test"}, +// ["d", "w"], +// ) +// .await; + +// cx.assert_neovim_compatible("Teˇst", ["d", "w"]).await; +// cx.assert_neovim_compatible("Tˇest test", ["d", "w"]).await; +// cx.assert_neovim_compatible( +// indoc! {" +// Test teˇst +// test"}, +// ["d", "w"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// Test tesˇt +// test"}, +// ["d", "w"], +// ) +// .await; + +// cx.assert_neovim_compatible( +// indoc! {" +// Test test +// ˇ +// test"}, +// ["d", "w"], +// ) +// .await; + +// let mut cx = cx.binding(["d", "shift-w"]); +// cx.assert_neovim_compatible("Test teˇst-test test", ["d", "shift-w"]) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_next_word_end(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "e"]); +// // cx.assert("Teˇst Test").await; +// // cx.assert("Tˇest test").await; +// cx.assert(indoc! {" +// Test teˇst +// test"}) +// .await; +// cx.assert(indoc! {" +// Test tesˇt +// test"}) +// .await; +// cx.assert_exempted( +// indoc! {" +// Test test +// ˇ +// test"}, +// ExemptionFeatures::OperatorLastNewlineRemains, +// ) +// .await; + +// let mut cx = cx.binding(["d", "shift-e"]); +// cx.assert("Test teˇst-test test").await; +// } + +// #[gpui::test] +// async fn test_delete_b(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "b"]); +// cx.assert("Teˇst Test").await; +// cx.assert("Test ˇtest").await; +// cx.assert("Test1 test2 ˇtest3").await; +// cx.assert(indoc! {" +// Test test +// ˇtest"}) +// .await; +// cx.assert(indoc! {" +// Test test +// ˇ +// test"}) +// .await; + +// let mut cx = cx.binding(["d", "shift-b"]); +// cx.assert("Test test-test ˇtest").await; +// } + +// #[gpui::test] +// async fn test_delete_end_of_line(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "$"]); +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_0(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "0"]); +// cx.assert(indoc! {" +// The qˇuick +// brown fox"}) +// .await; +// cx.assert(indoc! {" +// The quick +// ˇ +// brown fox"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_k(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "k"]); +// cx.assert(indoc! {" +// The quick +// brown ˇfox +// jumps over"}) +// .await; +// cx.assert(indoc! {" +// The quick +// brown fox +// jumps ˇover"}) +// .await; +// cx.assert(indoc! {" +// The qˇuick +// brown fox +// jumps over"}) +// .await; +// cx.assert(indoc! {" +// ˇbrown fox +// jumps over"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_j(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await.binding(["d", "j"]); +// cx.assert(indoc! {" +// The quick +// brown ˇfox +// jumps over"}) +// .await; +// cx.assert(indoc! {" +// The quick +// brown fox +// jumps ˇover"}) +// .await; +// cx.assert(indoc! {" +// The qˇuick +// brown fox +// jumps over"}) +// .await; +// cx.assert(indoc! {" +// The quick +// brown fox +// ˇ"}) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_end_of_document(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["d", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["d", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// the lˇazy"}, +// ["d", "shift-g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// ˇ"}, +// ["d", "shift-g"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_gg(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["d", "g", "g"]); +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brownˇ fox +// jumps over +// the lazy"}, +// ["d", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The quick +// brown fox +// jumps over +// the lˇazy"}, +// ["d", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// The qˇuick +// brown fox +// jumps over +// the lazy"}, +// ["d", "g", "g"], +// ) +// .await; +// cx.assert_neovim_compatible( +// indoc! {" +// ˇ +// brown fox +// jumps over +// the lazy"}, +// ["d", "g", "g"], +// ) +// .await; +// } + +// #[gpui::test] +// async fn test_cancel_delete_operator(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; +// cx.set_state( +// indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}, +// Mode::Normal, +// ); + +// // Canceling operator twice reverts to normal mode with no active operator +// cx.simulate_keystrokes(["d", "escape", "k"]); +// assert_eq!(cx.active_operator(), None); +// assert_eq!(cx.mode(), Mode::Normal); +// cx.assert_editor_state(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}); +// } + +// #[gpui::test] +// async fn test_unbound_command_cancels_pending_operator(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; +// cx.set_state( +// indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}, +// Mode::Normal, +// ); + +// // Canceling operator twice reverts to normal mode with no active operator +// cx.simulate_keystrokes(["d", "y"]); +// assert_eq!(cx.active_operator(), None); +// assert_eq!(cx.mode(), Mode::Normal); +// } + +// #[gpui::test] +// async fn test_delete_with_counts(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["d", "2", "d"]).await; +// cx.assert_shared_state(indoc! {" +// the ˇlazy dog"}) +// .await; + +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["2", "d", "d"]).await; +// cx.assert_shared_state(indoc! {" +// the ˇlazy dog"}) +// .await; + +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the moon, +// a star, and +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["2", "d", "2", "d"]).await; +// cx.assert_shared_state(indoc! {" +// the ˇlazy dog"}) +// .await; +// } +// } diff --git a/crates/vim2/src/normal/increment.rs b/crates/vim2/src/normal/increment.rs new file mode 100644 index 0000000000..6e160bc04d --- /dev/null +++ b/crates/vim2/src/normal/increment.rs @@ -0,0 +1,277 @@ +use std::ops::Range; + +use editor::{scroll::autoscroll::Autoscroll, MultiBufferSnapshot, ToOffset, ToPoint}; +use gpui::{Action, AppContext, WindowContext}; +use language::{Bias, Point}; +use serde::Deserialize; +use workspace::Workspace; + +use crate::{state::Mode, Vim}; + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct Increment { + #[serde(default)] + step: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct Decrement { + #[serde(default)] + step: bool, +} + +pub fn init(cx: &mut AppContext) { + // todo!(); + // cx.add_action(|_: &mut Workspace, action: &Increment, cx| { + // Vim::update(cx, |vim, cx| { + // vim.record_current_action(cx); + // let count = vim.take_count(cx).unwrap_or(1); + // let step = if action.step { 1 } else { 0 }; + // increment(vim, count as i32, step, cx) + // }) + // }); + // cx.add_action(|_: &mut Workspace, action: &Decrement, cx| { + // Vim::update(cx, |vim, cx| { + // vim.record_current_action(cx); + // let count = vim.take_count(cx).unwrap_or(1); + // let step = if action.step { -1 } else { 0 }; + // increment(vim, count as i32 * -1, step, cx) + // }) + // }); +} + +fn increment(vim: &mut Vim, mut delta: i32, step: i32, cx: &mut WindowContext) { + vim.update_active_editor(cx, |editor, cx| { + let mut edits = Vec::new(); + let mut new_anchors = Vec::new(); + + let snapshot = editor.buffer().read(cx).snapshot(cx); + for selection in editor.selections.all_adjusted(cx) { + if !selection.is_empty() { + if vim.state().mode != Mode::VisualBlock || new_anchors.is_empty() { + new_anchors.push((true, snapshot.anchor_before(selection.start))) + } + } + for row in selection.start.row..=selection.end.row { + let start = if row == selection.start.row { + selection.start + } else { + Point::new(row, 0) + }; + + if let Some((range, num, radix)) = find_number(&snapshot, start) { + if let Ok(val) = i32::from_str_radix(&num, radix) { + let result = val + delta; + delta += step; + let replace = match radix { + 10 => format!("{}", result), + 16 => { + if num.to_ascii_lowercase() == num { + format!("{:x}", result) + } else { + format!("{:X}", result) + } + } + 2 => format!("{:b}", result), + _ => unreachable!(), + }; + edits.push((range.clone(), replace)); + } + if selection.is_empty() { + new_anchors.push((false, snapshot.anchor_after(range.end))) + } + } else { + if selection.is_empty() { + new_anchors.push((true, snapshot.anchor_after(start))) + } + } + } + } + editor.transact(cx, |editor, cx| { + editor.edit(edits, cx); + + let snapshot = editor.buffer().read(cx).snapshot(cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + let mut new_ranges = Vec::new(); + for (visual, anchor) in new_anchors.iter() { + let mut point = anchor.to_point(&snapshot); + if !*visual && point.column > 0 { + point.column -= 1; + point = snapshot.clip_point(point, Bias::Left) + } + new_ranges.push(point..point); + } + s.select_ranges(new_ranges) + }) + }); + }); + vim.switch_mode(Mode::Normal, true, cx) +} + +fn find_number( + snapshot: &MultiBufferSnapshot, + start: Point, +) -> Option<(Range, String, u32)> { + let mut offset = start.to_offset(snapshot); + + // go backwards to the start of any number the selection is within + for ch in snapshot.reversed_chars_at(offset) { + if ch.is_ascii_digit() || ch == '-' || ch == 'b' || ch == 'x' { + offset -= ch.len_utf8(); + continue; + } + break; + } + + let mut begin = None; + let mut end = None; + let mut num = String::new(); + let mut radix = 10; + + let mut chars = snapshot.chars_at(offset).peekable(); + // find the next number on the line (may start after the original cursor position) + while let Some(ch) = chars.next() { + if num == "0" && ch == 'b' && chars.peek().is_some() && chars.peek().unwrap().is_digit(2) { + radix = 2; + begin = None; + num = String::new(); + } + if num == "0" && ch == 'x' && chars.peek().is_some() && chars.peek().unwrap().is_digit(16) { + radix = 16; + begin = None; + num = String::new(); + } + + if ch.is_digit(radix) + || (begin.is_none() + && ch == '-' + && chars.peek().is_some() + && chars.peek().unwrap().is_digit(radix)) + { + if begin.is_none() { + begin = Some(offset); + } + num.push(ch); + } else { + if begin.is_some() { + end = Some(offset); + break; + } else if ch == '\n' { + break; + } + } + offset += ch.len_utf8(); + } + if let Some(begin) = begin { + let end = end.unwrap_or(offset); + Some((begin.to_point(snapshot)..end.to_point(snapshot), num, radix)) + } else { + None + } +} + +// #[cfg(test)] +// mod test { +// use indoc::indoc; + +// use crate::test::NeovimBackedTestContext; + +// #[gpui::test] +// async fn test_increment(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// 1ˇ2 +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["ctrl-a"]).await; +// cx.assert_shared_state(indoc! {" +// 1ˇ3 +// "}) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-x"]).await; +// cx.assert_shared_state(indoc! {" +// 1ˇ2 +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["9", "9", "ctrl-a"]).await; +// cx.assert_shared_state(indoc! {" +// 11ˇ1 +// "}) +// .await; +// cx.simulate_shared_keystrokes(["1", "1", "1", "ctrl-x"]) +// .await; +// cx.assert_shared_state(indoc! {" +// ˇ0 +// "}) +// .await; +// cx.simulate_shared_keystrokes(["."]).await; +// cx.assert_shared_state(indoc! {" +// -11ˇ1 +// "}) +// .await; +// } + +// #[gpui::test] +// async fn test_increment_radix(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_matches_neovim("ˇ total: 0xff", ["ctrl-a"], " total: 0x10ˇ0") +// .await; +// cx.assert_matches_neovim("ˇ total: 0xff", ["ctrl-x"], " total: 0xfˇe") +// .await; +// cx.assert_matches_neovim("ˇ total: 0xFF", ["ctrl-x"], " total: 0xFˇE") +// .await; +// cx.assert_matches_neovim("(ˇ0b10f)", ["ctrl-a"], "(0b1ˇ1f)") +// .await; +// cx.assert_matches_neovim("ˇ-1", ["ctrl-a"], "ˇ0").await; +// cx.assert_matches_neovim("banˇana", ["ctrl-a"], "banˇana") +// .await; +// } + +// #[gpui::test] +// async fn test_increment_steps(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇ1 +// 1 +// 1 2 +// 1 +// 1"}) +// .await; + +// cx.simulate_shared_keystrokes(["j", "v", "shift-g", "g", "ctrl-a"]) +// .await; +// cx.assert_shared_state(indoc! {" +// 1 +// ˇ2 +// 3 2 +// 4 +// 5"}) +// .await; + +// cx.simulate_shared_keystrokes(["shift-g", "ctrl-v", "g", "g"]) +// .await; +// cx.assert_shared_state(indoc! {" +// «1ˇ» +// «2ˇ» +// «3ˇ» 2 +// «4ˇ» +// «5ˇ»"}) +// .await; + +// cx.simulate_shared_keystrokes(["g", "ctrl-x"]).await; +// cx.assert_shared_state(indoc! {" +// ˇ0 +// 0 +// 0 2 +// 0 +// 0"}) +// .await; +// } +// } diff --git a/crates/vim2/src/normal/paste.rs b/crates/vim2/src/normal/paste.rs new file mode 100644 index 0000000000..67bbfad2c1 --- /dev/null +++ b/crates/vim2/src/normal/paste.rs @@ -0,0 +1,475 @@ +use std::{borrow::Cow, cmp}; + +use editor::{ + display_map::ToDisplayPoint, movement, scroll::autoscroll::Autoscroll, ClipboardSelection, + DisplayPoint, +}; +use gpui::{Action, AppContext, ViewContext}; +use language::{Bias, SelectionGoal}; +use serde::Deserialize; +use workspace::Workspace; + +use crate::{state::Mode, utils::copy_selections_content, Vim}; + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct Paste { + #[serde(default)] + before: bool, + #[serde(default)] + preserve_clipboard: bool, +} + +pub(crate) fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(paste); +} + +fn paste(_: &mut Workspace, action: &Paste, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.record_current_action(cx); + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.transact(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + + let Some(item) = cx.read_from_clipboard() else { + return; + }; + let clipboard_text = Cow::Borrowed(item.text()); + if clipboard_text.is_empty() { + return; + } + + if !action.preserve_clipboard && vim.state().mode.is_visual() { + copy_selections_content(editor, vim.state().mode == Mode::VisualLine, cx); + } + + // if we are copying from multi-cursor (of visual block mode), we want + // to + let clipboard_selections = + item.metadata::>() + .filter(|clipboard_selections| { + clipboard_selections.len() > 1 && vim.state().mode != Mode::VisualLine + }); + + let (display_map, current_selections) = editor.selections.all_adjusted_display(cx); + + // unlike zed, if you have a multi-cursor selection from vim block mode, + // pasting it will paste it on subsequent lines, even if you don't yet + // have a cursor there. + let mut selections_to_process = Vec::new(); + let mut i = 0; + while i < current_selections.len() { + selections_to_process + .push((current_selections[i].start..current_selections[i].end, true)); + i += 1; + } + if let Some(clipboard_selections) = clipboard_selections.as_ref() { + let left = current_selections + .iter() + .map(|selection| cmp::min(selection.start.column(), selection.end.column())) + .min() + .unwrap(); + let mut row = current_selections.last().unwrap().end.row() + 1; + while i < clipboard_selections.len() { + let cursor = + display_map.clip_point(DisplayPoint::new(row, left), Bias::Left); + selections_to_process.push((cursor..cursor, false)); + i += 1; + row += 1; + } + } + + let first_selection_indent_column = + clipboard_selections.as_ref().and_then(|zed_selections| { + zed_selections + .first() + .map(|selection| selection.first_line_indent) + }); + let before = action.before || vim.state().mode == Mode::VisualLine; + + let mut edits = Vec::new(); + let mut new_selections = Vec::new(); + let mut original_indent_columns = Vec::new(); + let mut start_offset = 0; + + for (ix, (selection, preserve)) in selections_to_process.iter().enumerate() { + let (mut to_insert, original_indent_column) = + if let Some(clipboard_selections) = &clipboard_selections { + if let Some(clipboard_selection) = clipboard_selections.get(ix) { + let end_offset = start_offset + clipboard_selection.len; + let text = clipboard_text[start_offset..end_offset].to_string(); + start_offset = end_offset + 1; + (text, Some(clipboard_selection.first_line_indent)) + } else { + ("".to_string(), first_selection_indent_column) + } + } else { + (clipboard_text.to_string(), first_selection_indent_column) + }; + let line_mode = to_insert.ends_with("\n"); + let is_multiline = to_insert.contains("\n"); + + if line_mode && !before { + if selection.is_empty() { + to_insert = + "\n".to_owned() + &to_insert[..to_insert.len() - "\n".len()]; + } else { + to_insert = "\n".to_owned() + &to_insert; + } + } else if !line_mode && vim.state().mode == Mode::VisualLine { + to_insert = to_insert + "\n"; + } + + let display_range = if !selection.is_empty() { + selection.start..selection.end + } else if line_mode { + let point = if before { + movement::line_beginning(&display_map, selection.start, false) + } else { + movement::line_end(&display_map, selection.start, false) + }; + point..point + } else { + let point = if before { + selection.start + } else { + movement::saturating_right(&display_map, selection.start) + }; + point..point + }; + + let point_range = display_range.start.to_point(&display_map) + ..display_range.end.to_point(&display_map); + let anchor = if is_multiline || vim.state().mode == Mode::VisualLine { + display_map.buffer_snapshot.anchor_before(point_range.start) + } else { + display_map.buffer_snapshot.anchor_after(point_range.end) + }; + + if *preserve { + new_selections.push((anchor, line_mode, is_multiline)); + } + edits.push((point_range, to_insert)); + original_indent_columns.extend(original_indent_column); + } + + editor.edit_with_block_indent(edits, original_indent_columns, cx); + + // in line_mode vim will insert the new text on the next (or previous if before) line + // and put the cursor on the first non-blank character of the first inserted line (or at the end if the first line is blank). + // otherwise vim will insert the next text at (or before) the current cursor position, + // the cursor will go to the last (or first, if is_multiline) inserted character. + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.replace_cursors_with(|map| { + let mut cursors = Vec::new(); + for (anchor, line_mode, is_multiline) in &new_selections { + let mut cursor = anchor.to_display_point(map); + if *line_mode { + if !before { + cursor = movement::down( + map, + cursor, + SelectionGoal::None, + false, + &text_layout_details, + ) + .0; + } + cursor = movement::indented_line_beginning(map, cursor, true); + } else if !is_multiline { + cursor = movement::saturating_left(map, cursor) + } + cursors.push(cursor); + if vim.state().mode == Mode::VisualBlock { + break; + } + } + + cursors + }); + }) + }); + }); + vim.switch_mode(Mode::Normal, true, cx); + }); +} + +// #[cfg(test)] +// mod test { +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; +// use indoc::indoc; + +// #[gpui::test] +// async fn test_paste(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// // single line +// cx.set_shared_state(indoc! {" +// The quick brown +// fox ˇjumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "w", "y"]).await; +// cx.assert_shared_clipboard("jumps o").await; +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jumps oveˇr +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystroke("p").await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps overjumps ˇo +// the lazy dog"}) +// .await; + +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jumps oveˇr +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystroke("shift-p").await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps ovejumps ˇor +// the lazy dog"}) +// .await; + +// // line mode +// cx.set_shared_state(indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["d", "d"]).await; +// cx.assert_shared_clipboard("fox jumps over\n").await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// the laˇzy dog"}) +// .await; +// cx.simulate_shared_keystroke("p").await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// the lazy dog +// ˇfox jumps over"}) +// .await; +// cx.simulate_shared_keystrokes(["k", "shift-p"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// ˇfox jumps over +// the lazy dog +// fox jumps over"}) +// .await; + +// // multiline, cursor to first character of pasted text. +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jumps ˇover +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "j", "y"]).await; +// cx.assert_shared_clipboard("over\nthe lazy do").await; + +// cx.simulate_shared_keystroke("p").await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps oˇover +// the lazy dover +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["u", "shift-p"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps ˇover +// the lazy doover +// the lazy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_paste_visual(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// // copy in visual mode +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jˇumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "w", "y"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox ˇjumps over +// the lazy dog"}) +// .await; +// // paste in visual mode +// cx.simulate_shared_keystrokes(["w", "v", "i", "w", "p"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps jumpˇs +// the lazy dog"}) +// .await; +// cx.assert_shared_clipboard("over").await; +// // paste in visual line mode +// cx.simulate_shared_keystrokes(["up", "shift-v", "shift-p"]) +// .await; +// cx.assert_shared_state(indoc! {" +// ˇover +// fox jumps jumps +// the lazy dog"}) +// .await; +// cx.assert_shared_clipboard("over").await; +// // paste in visual block mode +// cx.simulate_shared_keystrokes(["ctrl-v", "down", "down", "p"]) +// .await; +// cx.assert_shared_state(indoc! {" +// oveˇrver +// overox jumps jumps +// overhe lazy dog"}) +// .await; + +// // copy in visual line mode +// cx.set_shared_state(indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "d"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// the laˇzy dog"}) +// .await; +// // paste in visual mode +// cx.simulate_shared_keystrokes(["v", "i", "w", "p"]).await; +// cx.assert_shared_state( +// &indoc! {" +// The quick brown +// the_ +// ˇfox jumps over +// _dog"} +// .replace("_", " "), // Hack for trailing whitespace +// ) +// .await; +// cx.assert_shared_clipboard("lazy").await; +// cx.set_shared_state(indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "d"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// the laˇzy dog"}) +// .await; +// // paste in visual line mode +// cx.simulate_shared_keystrokes(["k", "shift-v", "p"]).await; +// cx.assert_shared_state(indoc! {" +// ˇfox jumps over +// the lazy dog"}) +// .await; +// cx.assert_shared_clipboard("The quick brown\n").await; +// } + +// #[gpui::test] +// async fn test_paste_visual_block(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// // copy in visual block mode +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "2", "j", "y"]) +// .await; +// cx.assert_shared_clipboard("q\nj\nl").await; +// cx.simulate_shared_keystrokes(["p"]).await; +// cx.assert_shared_state(indoc! {" +// The qˇquick brown +// fox jjumps over +// the llazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "w", "shift-p"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The ˇq brown +// fox jjjumps over +// the lllazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "w", "shift-p"]) +// .await; + +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "j", "y"]).await; +// cx.assert_shared_clipboard("q\nj").await; +// cx.simulate_shared_keystrokes(["l", "ctrl-v", "2", "j", "shift-p"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The qˇqick brown +// fox jjmps over +// the lzy dog"}) +// .await; + +// cx.simulate_shared_keystrokes(["shift-v", "p"]).await; +// cx.assert_shared_state(indoc! {" +// ˇq +// j +// fox jjmps over +// the lzy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_paste_indent(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new_typescript(cx).await; + +// cx.set_state( +// indoc! {" +// class A {ˇ +// } +// "}, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["o", "a", "(", ")", "{", "escape"]); +// cx.assert_state( +// indoc! {" +// class A { +// a()ˇ{} +// } +// "}, +// Mode::Normal, +// ); +// // cursor goes to the first non-blank character in the line; +// cx.simulate_keystrokes(["y", "y", "p"]); +// cx.assert_state( +// indoc! {" +// class A { +// a(){} +// ˇa(){} +// } +// "}, +// Mode::Normal, +// ); +// // indentation is preserved when pasting +// cx.simulate_keystrokes(["u", "shift-v", "up", "y", "shift-p"]); +// cx.assert_state( +// indoc! {" +// ˇclass A { +// a(){} +// class A { +// a(){} +// } +// "}, +// Mode::Normal, +// ); +// } +// } diff --git a/crates/vim2/src/normal/repeat.rs b/crates/vim2/src/normal/repeat.rs new file mode 100644 index 0000000000..1187927eac --- /dev/null +++ b/crates/vim2/src/normal/repeat.rs @@ -0,0 +1,524 @@ +use crate::{ + insert::NormalBefore, + motion::Motion, + state::{Mode, RecordedSelection, ReplayableAction}, + visual::visual_motion, + Vim, +}; +use gpui::{actions, Action, AppContext, WindowContext}; +use workspace::Workspace; + +actions!(Repeat, EndRepeat); + +fn should_replay(action: &Box) -> bool { + // skip so that we don't leave the character palette open + if editor::ShowCharacterPalette.partial_eq(&**action) { + return false; + } + true +} + +fn repeatable_insert(action: &ReplayableAction) -> Option> { + match action { + ReplayableAction::Action(action) => { + if super::InsertBefore.partial_eq(&**action) + || super::InsertAfter.partial_eq(&**action) + || super::InsertFirstNonWhitespace.partial_eq(&**action) + || super::InsertEndOfLine.partial_eq(&**action) + { + Some(super::InsertBefore.boxed_clone()) + } else if super::InsertLineAbove.partial_eq(&**action) + || super::InsertLineBelow.partial_eq(&**action) + { + Some(super::InsertLineBelow.boxed_clone()) + } else { + None + } + } + ReplayableAction::Insertion { .. } => None, + } +} + +pub(crate) fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_: &mut Workspace, _: &EndRepeat, cx| { + // Vim::update(cx, |vim, cx| { + // vim.workspace_state.replaying = false; + // vim.switch_mode(Mode::Normal, false, cx) + // }); + // }); + + // cx.add_action(|_: &mut Workspace, _: &Repeat, cx| repeat(cx, false)); +} + +pub(crate) fn repeat(cx: &mut WindowContext, from_insert_mode: bool) { + let Some((mut actions, editor, selection)) = Vim::update(cx, |vim, cx| { + let actions = vim.workspace_state.recorded_actions.clone(); + if actions.is_empty() { + return None; + } + + let Some(editor) = vim.active_editor.clone() else { + return None; + }; + let count = vim.take_count(cx); + + let selection = vim.workspace_state.recorded_selection.clone(); + match selection { + RecordedSelection::SingleLine { .. } | RecordedSelection::Visual { .. } => { + vim.workspace_state.recorded_count = None; + vim.switch_mode(Mode::Visual, false, cx) + } + RecordedSelection::VisualLine { .. } => { + vim.workspace_state.recorded_count = None; + vim.switch_mode(Mode::VisualLine, false, cx) + } + RecordedSelection::VisualBlock { .. } => { + vim.workspace_state.recorded_count = None; + vim.switch_mode(Mode::VisualBlock, false, cx) + } + RecordedSelection::None => { + if let Some(count) = count { + vim.workspace_state.recorded_count = Some(count); + } + } + } + + Some((actions, editor, selection)) + }) else { + return; + }; + + match selection { + RecordedSelection::SingleLine { cols } => { + if cols > 1 { + visual_motion(Motion::Right, Some(cols as usize - 1), cx) + } + } + RecordedSelection::Visual { rows, cols } => { + visual_motion( + Motion::Down { + display_lines: false, + }, + Some(rows as usize), + cx, + ); + visual_motion( + Motion::StartOfLine { + display_lines: false, + }, + None, + cx, + ); + if cols > 1 { + visual_motion(Motion::Right, Some(cols as usize - 1), cx) + } + } + RecordedSelection::VisualBlock { rows, cols } => { + visual_motion( + Motion::Down { + display_lines: false, + }, + Some(rows as usize), + cx, + ); + if cols > 1 { + visual_motion(Motion::Right, Some(cols as usize - 1), cx); + } + } + RecordedSelection::VisualLine { rows } => { + visual_motion( + Motion::Down { + display_lines: false, + }, + Some(rows as usize), + cx, + ); + } + RecordedSelection::None => {} + } + + // insert internally uses repeat to handle counts + // vim doesn't treat 3a1 as though you literally repeated a1 + // 3 times, instead it inserts the content thrice at the insert position. + if let Some(to_repeat) = repeatable_insert(&actions[0]) { + if let Some(ReplayableAction::Action(action)) = actions.last() { + if NormalBefore.partial_eq(&**action) { + actions.pop(); + } + } + + let mut new_actions = actions.clone(); + actions[0] = ReplayableAction::Action(to_repeat.boxed_clone()); + + let mut count = Vim::read(cx).workspace_state.recorded_count.unwrap_or(1); + + // if we came from insert mode we're just doing repititions 2 onwards. + if from_insert_mode { + count -= 1; + new_actions[0] = actions[0].clone(); + } + + for _ in 1..count { + new_actions.append(actions.clone().as_mut()); + } + new_actions.push(ReplayableAction::Action(NormalBefore.boxed_clone())); + actions = new_actions; + } + + Vim::update(cx, |vim, _| vim.workspace_state.replaying = true); + let window = cx.window_handle(); + cx.spawn(move |mut cx| async move { + editor.update(&mut cx, |editor, _| { + editor.show_local_selections = false; + })?; + for action in actions { + match action { + ReplayableAction::Action(action) => { + if should_replay(&action) { + window.update(&mut cx, |_, cx| cx.dispatch_action(action)) + } else { + Ok(()) + } + } + ReplayableAction::Insertion { + text, + utf16_range_to_replace, + } => editor.update(&mut cx, |editor, cx| { + editor.replay_insert_event(&text, utf16_range_to_replace.clone(), cx) + }), + }? + } + editor.update(&mut cx, |editor, _| { + editor.show_local_selections = true; + })?; + window.update(&mut cx, |_, cx| cx.dispatch_action(EndRepeat.boxed_clone())) + }) + .detach_and_log_err(cx); +} + +// #[cfg(test)] +// mod test { +// use std::sync::Arc; + +// use editor::test::editor_lsp_test_context::EditorLspTestContext; +// use futures::StreamExt; +// use indoc::indoc; + +// use gpui::{executor::Deterministic, View}; + +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; + +// #[gpui::test] +// async fn test_dot_repeat(deterministic: Arc, cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// // "o" +// cx.set_shared_state("ˇhello").await; +// cx.simulate_shared_keystrokes(["o", "w", "o", "r", "l", "d", "escape"]) +// .await; +// cx.assert_shared_state("hello\nworlˇd").await; +// cx.simulate_shared_keystrokes(["."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("hello\nworld\nworlˇd").await; + +// // "d" +// cx.simulate_shared_keystrokes(["^", "d", "f", "o"]).await; +// cx.simulate_shared_keystrokes(["g", "g", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("ˇ\nworld\nrld").await; + +// // "p" (note that it pastes the current clipboard) +// cx.simulate_shared_keystrokes(["j", "y", "y", "p"]).await; +// cx.simulate_shared_keystrokes(["shift-g", "y", "y", "."]) +// .await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("\nworld\nworld\nrld\nˇrld").await; + +// // "~" (note that counts apply to the action taken, not . itself) +// cx.set_shared_state("ˇthe quick brown fox").await; +// cx.simulate_shared_keystrokes(["2", "~", "."]).await; +// deterministic.run_until_parked(); +// cx.set_shared_state("THE ˇquick brown fox").await; +// cx.simulate_shared_keystrokes(["3", "."]).await; +// deterministic.run_until_parked(); +// cx.set_shared_state("THE QUIˇck brown fox").await; +// deterministic.run_until_parked(); +// cx.simulate_shared_keystrokes(["."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state("THE QUICK ˇbrown fox").await; +// } + +// #[gpui::test] +// async fn test_repeat_ime(deterministic: Arc, cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("hˇllo", Mode::Normal); +// cx.simulate_keystrokes(["i"]); + +// // simulate brazilian input for ä. +// cx.update_editor(|editor, cx| { +// editor.replace_and_mark_text_in_range(None, "\"", Some(1..1), cx); +// editor.replace_text_in_range(None, "ä", cx); +// }); +// cx.simulate_keystrokes(["escape"]); +// cx.assert_state("hˇällo", Mode::Normal); +// cx.simulate_keystrokes(["."]); +// deterministic.run_until_parked(); +// cx.assert_state("hˇäällo", Mode::Normal); +// } + +// #[gpui::test] +// async fn test_repeat_completion( +// deterministic: Arc, +// cx: &mut gpui::TestAppContext, +// ) { +// let cx = EditorLspTestContext::new_rust( +// lsp::ServerCapabilities { +// completion_provider: Some(lsp::CompletionOptions { +// trigger_characters: Some(vec![".".to_string(), ":".to_string()]), +// resolve_provider: Some(true), +// ..Default::default() +// }), +// ..Default::default() +// }, +// cx, +// ) +// .await; +// let mut cx = VimTestContext::new_with_lsp(cx, true); + +// cx.set_state( +// indoc! {" +// onˇe +// two +// three +// "}, +// Mode::Normal, +// ); + +// let mut request = +// cx.handle_request::(move |_, params, _| async move { +// let position = params.text_document_position.position; +// Ok(Some(lsp::CompletionResponse::Array(vec![ +// lsp::CompletionItem { +// label: "first".to_string(), +// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { +// range: lsp::Range::new(position.clone(), position.clone()), +// new_text: "first".to_string(), +// })), +// ..Default::default() +// }, +// lsp::CompletionItem { +// label: "second".to_string(), +// text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit { +// range: lsp::Range::new(position.clone(), position.clone()), +// new_text: "second".to_string(), +// })), +// ..Default::default() +// }, +// ]))) +// }); +// cx.simulate_keystrokes(["a", "."]); +// request.next().await; +// cx.condition(|editor, _| editor.context_menu_visible()) +// .await; +// cx.simulate_keystrokes(["down", "enter", "!", "escape"]); + +// cx.assert_state( +// indoc! {" +// one.secondˇ! +// two +// three +// "}, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["j", "."]); +// deterministic.run_until_parked(); +// cx.assert_state( +// indoc! {" +// one.second! +// two.secondˇ! +// three +// "}, +// Mode::Normal, +// ); +// } + +// #[gpui::test] +// async fn test_repeat_visual(deterministic: Arc, cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// // single-line (3 columns) +// cx.set_shared_state(indoc! { +// "ˇthe quick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "w", "s", "o", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { +// "ˇo quick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "w", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "o quick brown +// fox ˇops over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["f", "r", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "o quick brown +// fox ops oveˇothe lazy dog" +// }) +// .await; + +// // visual +// cx.set_shared_state(indoc! { +// "the ˇquick brown +// fox jumps over +// fox jumps over +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "j", "x"]).await; +// cx.assert_shared_state(indoc! { +// "the ˇumps over +// fox jumps over +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "the ˇumps over +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["w", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "the umps ˇumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "the umps umps over +// the ˇog" +// }) +// .await; + +// // block mode (3 rows) +// cx.set_shared_state(indoc! { +// "ˇthe quick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "j", "j", "shift-i", "o", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { +// "ˇothe quick brown +// ofox jumps over +// othe lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "4", "l", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "othe quick brown +// ofoxˇo jumps over +// otheo lazy dog" +// }) +// .await; + +// // line mode +// cx.set_shared_state(indoc! { +// "ˇthe quick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "shift-r", "o", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { +// "ˇo +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// "o +// ˇo +// the lazy dog" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_repeat_motion_counts( +// deterministic: Arc, +// cx: &mut gpui::TestAppContext, +// ) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "ˇthe quick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["3", "d", "3", "l"]).await; +// cx.assert_shared_state(indoc! { +// "ˇ brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// " brown +// ˇ over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "2", "."]).await; +// deterministic.run_until_parked(); +// cx.assert_shared_state(indoc! { +// " brown +// over +// ˇe lazy dog" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_record_interrupted( +// deterministic: Arc, +// cx: &mut gpui::TestAppContext, +// ) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("ˇhello\n", Mode::Normal); +// cx.simulate_keystrokes(["4", "i", "j", "cmd-shift-p", "escape", "escape"]); +// deterministic.run_until_parked(); +// cx.assert_state("ˇjhello\n", Mode::Normal); +// } +// } diff --git a/crates/vim2/src/normal/scroll.rs b/crates/vim2/src/normal/scroll.rs new file mode 100644 index 0000000000..3bef78bc11 --- /dev/null +++ b/crates/vim2/src/normal/scroll.rs @@ -0,0 +1,227 @@ +use crate::Vim; +use editor::{ + display_map::ToDisplayPoint, + scroll::{scroll_amount::ScrollAmount, VERTICAL_SCROLL_MARGIN}, + DisplayPoint, Editor, +}; +use gpui::{actions, AppContext, ViewContext}; +use language::Bias; +use workspace::Workspace; + +actions!(LineUp, LineDown, ScrollUp, ScrollDown, PageUp, PageDown,); + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_: &mut Workspace, _: &LineDown, cx| { + // scroll(cx, false, |c| ScrollAmount::Line(c.unwrap_or(1.))) + // }); + // cx.add_action(|_: &mut Workspace, _: &LineUp, cx| { + // scroll(cx, false, |c| ScrollAmount::Line(-c.unwrap_or(1.))) + // }); + // cx.add_action(|_: &mut Workspace, _: &PageDown, cx| { + // scroll(cx, false, |c| ScrollAmount::Page(c.unwrap_or(1.))) + // }); + // cx.add_action(|_: &mut Workspace, _: &PageUp, cx| { + // scroll(cx, false, |c| ScrollAmount::Page(-c.unwrap_or(1.))) + // }); + // cx.add_action(|_: &mut Workspace, _: &ScrollDown, cx| { + // scroll(cx, true, |c| { + // if let Some(c) = c { + // ScrollAmount::Line(c) + // } else { + // ScrollAmount::Page(0.5) + // } + // }) + // }); + // cx.add_action(|_: &mut Workspace, _: &ScrollUp, cx| { + // scroll(cx, true, |c| { + // if let Some(c) = c { + // ScrollAmount::Line(-c) + // } else { + // ScrollAmount::Page(-0.5) + // } + // }) + // }); +} + +fn scroll( + cx: &mut ViewContext, + move_cursor: bool, + by: fn(c: Option) -> ScrollAmount, +) { + Vim::update(cx, |vim, cx| { + let amount = by(vim.take_count(cx).map(|c| c as f32)); + vim.update_active_editor(cx, |editor, cx| { + scroll_editor(editor, move_cursor, &amount, cx) + }); + }) +} + +fn scroll_editor( + editor: &mut Editor, + preserve_cursor_position: bool, + amount: &ScrollAmount, + cx: &mut ViewContext, +) { + let should_move_cursor = editor.newest_selection_on_screen(cx).is_eq(); + let old_top_anchor = editor.scroll_manager.anchor().anchor; + + editor.scroll_screen(amount, cx); + if should_move_cursor { + let visible_rows = if let Some(visible_rows) = editor.visible_line_count() { + visible_rows as u32 + } else { + return; + }; + + let top_anchor = editor.scroll_manager.anchor().anchor; + + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + let mut head = selection.head(); + let top = top_anchor.to_display_point(map); + + if preserve_cursor_position { + let old_top = old_top_anchor.to_display_point(map); + let new_row = top.row() + selection.head().row() - old_top.row(); + head = map.clip_point(DisplayPoint::new(new_row, head.column()), Bias::Left) + } + let min_row = top.row() + VERTICAL_SCROLL_MARGIN as u32; + let max_row = top.row() + visible_rows - VERTICAL_SCROLL_MARGIN as u32 - 1; + + let new_head = if head.row() < min_row { + map.clip_point(DisplayPoint::new(min_row, head.column()), Bias::Left) + } else if head.row() > max_row { + map.clip_point(DisplayPoint::new(max_row, head.column()), Bias::Left) + } else { + head + }; + if selection.is_empty() { + selection.collapse_to(new_head, selection.goal) + } else { + selection.set_head(new_head, selection.goal) + }; + }) + }); + } +} + +// #[cfg(test)] +// mod test { +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; +// use gpui::geometry::vector::vec2f; +// use indoc::indoc; +// use language::Point; + +// #[gpui::test] +// async fn test_scroll(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// let window = cx.window; +// let line_height = cx.editor(|editor, cx| editor.style().text.line_height(cx.font_cache())); +// window.simulate_resize(vec2f(1000., 8.0 * line_height - 1.0), &mut cx); + +// cx.set_state( +// indoc!( +// "ˇone +// two +// three +// four +// five +// six +// seven +// eight +// nine +// ten +// eleven +// twelve +// " +// ), +// Mode::Normal, +// ); + +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.)) +// }); +// cx.simulate_keystrokes(["ctrl-e"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 1.)) +// }); +// cx.simulate_keystrokes(["2", "ctrl-e"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.)) +// }); +// cx.simulate_keystrokes(["ctrl-y"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 2.)) +// }); + +// // does not select in normal mode +// cx.simulate_keystrokes(["g", "g"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.)) +// }); +// cx.simulate_keystrokes(["ctrl-d"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.0)); +// assert_eq!( +// editor.selections.newest(cx).range(), +// Point::new(6, 0)..Point::new(6, 0) +// ) +// }); + +// // does select in visual mode +// cx.simulate_keystrokes(["g", "g"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 0.)) +// }); +// cx.simulate_keystrokes(["v", "ctrl-d"]); +// cx.update_editor(|editor, cx| { +// assert_eq!(editor.snapshot(cx).scroll_position(), vec2f(0., 3.0)); +// assert_eq!( +// editor.selections.newest(cx).range(), +// Point::new(0, 0)..Point::new(6, 1) +// ) +// }); +// } +// #[gpui::test] +// async fn test_ctrl_d_u(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_scroll_height(10).await; + +// pub fn sample_text(rows: usize, cols: usize, start_char: char) -> String { +// let mut text = String::new(); +// for row in 0..rows { +// let c: char = (start_char as u32 + row as u32) as u8 as char; +// let mut line = c.to_string().repeat(cols); +// if row < rows - 1 { +// line.push('\n'); +// } +// text += &line; +// } +// text +// } +// let content = "ˇ".to_owned() + &sample_text(26, 2, 'a'); +// cx.set_shared_state(&content).await; + +// // skip over the scrolloff at the top +// // test ctrl-d +// cx.simulate_shared_keystrokes(["4", "j", "ctrl-d"]).await; +// cx.assert_state_matches().await; +// cx.simulate_shared_keystrokes(["ctrl-d"]).await; +// cx.assert_state_matches().await; +// cx.simulate_shared_keystrokes(["g", "g", "ctrl-d"]).await; +// cx.assert_state_matches().await; + +// // test ctrl-u +// cx.simulate_shared_keystrokes(["ctrl-u"]).await; +// cx.assert_state_matches().await; +// cx.simulate_shared_keystrokes(["ctrl-d", "ctrl-d", "4", "j", "ctrl-u", "ctrl-u"]) +// .await; +// cx.assert_state_matches().await; +// } +// } diff --git a/crates/vim2/src/normal/search.rs b/crates/vim2/src/normal/search.rs new file mode 100644 index 0000000000..79df67821c --- /dev/null +++ b/crates/vim2/src/normal/search.rs @@ -0,0 +1,492 @@ +use gpui::{actions, Action, AppContext, ViewContext}; +use search::{buffer_search, BufferSearchBar, SearchMode, SearchOptions}; +use serde_derive::Deserialize; +use workspace::{searchable::Direction, Pane, Workspace}; + +use crate::{motion::Motion, normal::move_cursor, state::SearchState, Vim}; + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub(crate) struct MoveToNext { + #[serde(default)] + partial_word: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +pub(crate) struct MoveToPrev { + #[serde(default)] + partial_word: bool, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +pub(crate) struct Search { + #[serde(default)] + backwards: bool, +} + +#[derive(Action, Debug, Clone, PartialEq, Deserialize)] +pub struct FindCommand { + pub query: String, + pub backwards: bool, +} + +#[derive(Action, Debug, Clone, PartialEq, Deserialize)] +pub struct ReplaceCommand { + pub query: String, +} + +#[derive(Debug, Default)] +struct Replacement { + search: String, + replacement: String, + should_replace_all: bool, + is_case_sensitive: bool, +} + +actions!(SearchSubmit); + +pub(crate) fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(move_to_next); + // cx.add_action(move_to_prev); + // cx.add_action(search); + // cx.add_action(search_submit); + // cx.add_action(search_deploy); + + // cx.add_action(find_command); + // cx.add_action(replace_command); +} + +fn move_to_next(workspace: &mut Workspace, action: &MoveToNext, cx: &mut ViewContext) { + move_to_internal(workspace, Direction::Next, !action.partial_word, cx) +} + +fn move_to_prev(workspace: &mut Workspace, action: &MoveToPrev, cx: &mut ViewContext) { + move_to_internal(workspace, Direction::Prev, !action.partial_word, cx) +} + +fn search(workspace: &mut Workspace, action: &Search, cx: &mut ViewContext) { + let pane = workspace.active_pane().clone(); + let direction = if action.backwards { + Direction::Prev + } else { + Direction::Next + }; + Vim::update(cx, |vim, cx| { + let count = vim.take_count(cx).unwrap_or(1); + pane.update(cx, |pane, cx| { + if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::() { + search_bar.update(cx, |search_bar, cx| { + if !search_bar.show(cx) { + return; + } + let query = search_bar.query(cx); + + search_bar.select_query(cx); + cx.focus_self(); + + if query.is_empty() { + search_bar.set_replacement(None, cx); + search_bar.set_search_options(SearchOptions::CASE_SENSITIVE, cx); + search_bar.activate_search_mode(SearchMode::Regex, cx); + } + vim.workspace_state.search = SearchState { + direction, + count, + initial_query: query.clone(), + }; + }); + } + }) + }) +} + +// hook into the existing to clear out any vim search state on cmd+f or edit -> find. +fn search_deploy(_: &mut Pane, _: &buffer_search::Deploy, cx: &mut ViewContext) { + Vim::update(cx, |vim, _| vim.workspace_state.search = Default::default()); + cx.propagate(); +} + +fn search_submit(workspace: &mut Workspace, _: &SearchSubmit, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + let pane = workspace.active_pane().clone(); + pane.update(cx, |pane, cx| { + if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::() { + search_bar.update(cx, |search_bar, cx| { + let state = &mut vim.workspace_state.search; + let mut count = state.count; + let direction = state.direction; + + // in the case that the query has changed, the search bar + // will have selected the next match already. + if (search_bar.query(cx) != state.initial_query) + && state.direction == Direction::Next + { + count = count.saturating_sub(1) + } + state.count = 1; + search_bar.select_match(direction, count, cx); + search_bar.focus_editor(&Default::default(), cx); + }); + } + }); + }) +} + +pub fn move_to_internal( + workspace: &mut Workspace, + direction: Direction, + whole_word: bool, + cx: &mut ViewContext, +) { + Vim::update(cx, |vim, cx| { + let pane = workspace.active_pane().clone(); + let count = vim.take_count(cx).unwrap_or(1); + pane.update(cx, |pane, cx| { + if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::() { + let search = search_bar.update(cx, |search_bar, cx| { + let mut options = SearchOptions::CASE_SENSITIVE; + options.set(SearchOptions::WHOLE_WORD, whole_word); + if search_bar.show(cx) { + search_bar + .query_suggestion(cx) + .map(|query| search_bar.search(&query, Some(options), cx)) + } else { + None + } + }); + + if let Some(search) = search { + let search_bar = search_bar.downgrade(); + cx.spawn(|_, mut cx| async move { + search.await?; + search_bar.update(&mut cx, |search_bar, cx| { + search_bar.select_match(direction, count, cx) + })?; + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } + } + }); + vim.clear_operator(cx); + }); +} + +fn find_command(workspace: &mut Workspace, action: &FindCommand, cx: &mut ViewContext) { + let pane = workspace.active_pane().clone(); + pane.update(cx, |pane, cx| { + if let Some(search_bar) = pane.toolbar().read(cx).item_of_type::() { + let search = search_bar.update(cx, |search_bar, cx| { + if !search_bar.show(cx) { + return None; + } + let mut query = action.query.clone(); + if query == "" { + query = search_bar.query(cx); + }; + + search_bar.activate_search_mode(SearchMode::Regex, cx); + Some(search_bar.search(&query, Some(SearchOptions::CASE_SENSITIVE), cx)) + }); + let Some(search) = search else { return }; + let search_bar = search_bar.downgrade(); + let direction = if action.backwards { + Direction::Prev + } else { + Direction::Next + }; + cx.spawn(|_, mut cx| async move { + search.await?; + search_bar.update(&mut cx, |search_bar, cx| { + search_bar.select_match(direction, 1, cx) + })?; + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + } + }) +} + +fn replace_command( + workspace: &mut Workspace, + action: &ReplaceCommand, + cx: &mut ViewContext, +) { + let replacement = parse_replace_all(&action.query); + let pane = workspace.active_pane().clone(); + pane.update(cx, |pane, cx| { + let Some(search_bar) = pane.toolbar().read(cx).item_of_type::() else { + return; + }; + let search = search_bar.update(cx, |search_bar, cx| { + if !search_bar.show(cx) { + return None; + } + + let mut options = SearchOptions::default(); + if replacement.is_case_sensitive { + options.set(SearchOptions::CASE_SENSITIVE, true) + } + let search = if replacement.search == "" { + search_bar.query(cx) + } else { + replacement.search + }; + + search_bar.set_replacement(Some(&replacement.replacement), cx); + search_bar.activate_search_mode(SearchMode::Regex, cx); + Some(search_bar.search(&search, Some(options), cx)) + }); + let Some(search) = search else { return }; + let search_bar = search_bar.downgrade(); + cx.spawn(|_, mut cx| async move { + search.await?; + search_bar.update(&mut cx, |search_bar, cx| { + if replacement.should_replace_all { + search_bar.select_last_match(cx); + search_bar.replace_all(&Default::default(), cx); + Vim::update(cx, |vim, cx| { + move_cursor( + vim, + Motion::StartOfLine { + display_lines: false, + }, + None, + cx, + ) + }) + } + })?; + anyhow::Ok(()) + }) + .detach_and_log_err(cx); + }) +} + +// convert a vim query into something more usable by zed. +// we don't attempt to fully convert between the two regex syntaxes, +// but we do flip \( and \) to ( and ) (and vice-versa) in the pattern, +// and convert \0..\9 to $0..$9 in the replacement so that common idioms work. +fn parse_replace_all(query: &str) -> Replacement { + let mut chars = query.chars(); + if Some('%') != chars.next() || Some('s') != chars.next() { + return Replacement::default(); + } + + let Some(delimeter) = chars.next() else { + return Replacement::default(); + }; + + let mut search = String::new(); + let mut replacement = String::new(); + let mut flags = String::new(); + + let mut buffer = &mut search; + + let mut escaped = false; + // 0 - parsing search + // 1 - parsing replacement + // 2 - parsing flags + let mut phase = 0; + + for c in chars { + if escaped { + escaped = false; + if phase == 1 && c.is_digit(10) { + buffer.push('$') + // unescape escaped parens + } else if phase == 0 && c == '(' || c == ')' { + } else if c != delimeter { + buffer.push('\\') + } + buffer.push(c) + } else if c == '\\' { + escaped = true; + } else if c == delimeter { + if phase == 0 { + buffer = &mut replacement; + phase = 1; + } else if phase == 1 { + buffer = &mut flags; + phase = 2; + } else { + break; + } + } else { + // escape unescaped parens + if phase == 0 && c == '(' || c == ')' { + buffer.push('\\') + } + buffer.push(c) + } + } + + let mut replacement = Replacement { + search, + replacement, + should_replace_all: true, + is_case_sensitive: true, + }; + + for c in flags.chars() { + match c { + 'g' | 'I' => {} + 'c' | 'n' => replacement.should_replace_all = false, + 'i' => replacement.is_case_sensitive = false, + _ => {} + } + } + + replacement +} + +// #[cfg(test)] +// mod test { +// use std::sync::Arc; + +// use editor::DisplayPoint; +// use search::BufferSearchBar; + +// use crate::{state::Mode, test::VimTestContext}; + +// #[gpui::test] +// async fn test_move_to_next( +// cx: &mut gpui::TestAppContext, +// deterministic: Arc, +// ) { +// let mut cx = VimTestContext::new(cx, true).await; +// cx.set_state("ˇhi\nhigh\nhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["*"]); +// deterministic.run_until_parked(); +// cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["*"]); +// deterministic.run_until_parked(); +// cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["#"]); +// deterministic.run_until_parked(); +// cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["#"]); +// deterministic.run_until_parked(); +// cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["2", "*"]); +// deterministic.run_until_parked(); +// cx.assert_state("ˇhi\nhigh\nhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["g", "*"]); +// deterministic.run_until_parked(); +// cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["n"]); +// cx.assert_state("hi\nhigh\nˇhi\n", Mode::Normal); + +// cx.simulate_keystrokes(["g", "#"]); +// deterministic.run_until_parked(); +// cx.assert_state("hi\nˇhigh\nhi\n", Mode::Normal); +// } + +// #[gpui::test] +// async fn test_search( +// cx: &mut gpui::TestAppContext, +// deterministic: Arc, +// ) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal); +// cx.simulate_keystrokes(["/", "c", "c"]); + +// let search_bar = cx.workspace(|workspace, cx| { +// workspace +// .active_pane() +// .read(cx) +// .toolbar() +// .read(cx) +// .item_of_type::() +// .expect("Buffer search bar should be deployed") +// }); + +// search_bar.read_with(cx.cx, |bar, cx| { +// assert_eq!(bar.query(cx), "cc"); +// }); + +// deterministic.run_until_parked(); + +// cx.update_editor(|editor, cx| { +// let highlights = editor.all_text_background_highlights(cx); +// assert_eq!(3, highlights.len()); +// assert_eq!( +// DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2), +// highlights[0].0 +// ) +// }); + +// cx.simulate_keystrokes(["enter"]); +// cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal); + +// // n to go to next/N to go to previous +// cx.simulate_keystrokes(["n"]); +// cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal); +// cx.simulate_keystrokes(["shift-n"]); +// cx.assert_state("aa\nbb\nˇcc\ncc\ncc\n", Mode::Normal); + +// // ? to go to previous +// cx.simulate_keystrokes(["?", "enter"]); +// deterministic.run_until_parked(); +// cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal); +// cx.simulate_keystrokes(["?", "enter"]); +// deterministic.run_until_parked(); +// cx.assert_state("aa\nbb\ncc\nˇcc\ncc\n", Mode::Normal); + +// // / to go to next +// cx.simulate_keystrokes(["/", "enter"]); +// deterministic.run_until_parked(); +// cx.assert_state("aa\nbb\ncc\ncc\nˇcc\n", Mode::Normal); + +// // ?{search} to search backwards +// cx.simulate_keystrokes(["?", "b", "enter"]); +// deterministic.run_until_parked(); +// cx.assert_state("aa\nbˇb\ncc\ncc\ncc\n", Mode::Normal); + +// // works with counts +// cx.simulate_keystrokes(["4", "/", "c"]); +// deterministic.run_until_parked(); +// cx.simulate_keystrokes(["enter"]); +// cx.assert_state("aa\nbb\ncc\ncˇc\ncc\n", Mode::Normal); + +// // check that searching resumes from cursor, not previous match +// cx.set_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal); +// cx.simulate_keystrokes(["/", "d"]); +// deterministic.run_until_parked(); +// cx.simulate_keystrokes(["enter"]); +// cx.assert_state("aa\nbb\nˇdd\ncc\nbb\n", Mode::Normal); +// cx.update_editor(|editor, cx| editor.move_to_beginning(&Default::default(), cx)); +// cx.assert_state("ˇaa\nbb\ndd\ncc\nbb\n", Mode::Normal); +// cx.simulate_keystrokes(["/", "b"]); +// deterministic.run_until_parked(); +// cx.simulate_keystrokes(["enter"]); +// cx.assert_state("aa\nˇbb\ndd\ncc\nbb\n", Mode::Normal); +// } + +// #[gpui::test] +// async fn test_non_vim_search( +// cx: &mut gpui::TestAppContext, +// deterministic: Arc, +// ) { +// let mut cx = VimTestContext::new(cx, false).await; +// cx.set_state("ˇone one one one", Mode::Normal); +// cx.simulate_keystrokes(["cmd-f"]); +// deterministic.run_until_parked(); + +// cx.assert_editor_state("«oneˇ» one one one"); +// cx.simulate_keystrokes(["enter"]); +// cx.assert_editor_state("one «oneˇ» one one"); +// cx.simulate_keystrokes(["shift-enter"]); +// cx.assert_editor_state("«oneˇ» one one one"); +// } +// } diff --git a/crates/vim2/src/normal/substitute.rs b/crates/vim2/src/normal/substitute.rs new file mode 100644 index 0000000000..22cecb176a --- /dev/null +++ b/crates/vim2/src/normal/substitute.rs @@ -0,0 +1,277 @@ +use editor::movement; +use gpui::{actions, AppContext, WindowContext}; +use language::Point; +use workspace::Workspace; + +use crate::{motion::Motion, utils::copy_selections_content, Mode, Vim}; + +actions!(Substitute, SubstituteLine); + +pub(crate) fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_: &mut Workspace, _: &Substitute, cx| { + // Vim::update(cx, |vim, cx| { + // vim.start_recording(cx); + // let count = vim.take_count(cx); + // substitute(vim, count, vim.state().mode == Mode::VisualLine, cx); + // }) + // }); + + // cx.add_action(|_: &mut Workspace, _: &SubstituteLine, cx| { + // Vim::update(cx, |vim, cx| { + // vim.start_recording(cx); + // if matches!(vim.state().mode, Mode::VisualBlock | Mode::Visual) { + // vim.switch_mode(Mode::VisualLine, false, cx) + // } + // let count = vim.take_count(cx); + // substitute(vim, count, true, cx) + // }) + // }); +} + +pub fn substitute(vim: &mut Vim, count: Option, line_mode: bool, cx: &mut WindowContext) { + vim.update_active_editor(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + editor.transact(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + if selection.start == selection.end { + Motion::Right.expand_selection( + map, + selection, + count, + true, + &text_layout_details, + ); + } + if line_mode { + // in Visual mode when the selection contains the newline at the end + // of the line, we should exclude it. + if !selection.is_empty() && selection.end.column() == 0 { + selection.end = movement::left(map, selection.end); + } + Motion::CurrentLine.expand_selection( + map, + selection, + None, + false, + &text_layout_details, + ); + if let Some((point, _)) = (Motion::FirstNonWhitespace { + display_lines: false, + }) + .move_point( + map, + selection.start, + selection.goal, + None, + &text_layout_details, + ) { + selection.start = point; + } + } + }) + }); + copy_selections_content(editor, line_mode, cx); + let selections = editor.selections.all::(cx).into_iter(); + let edits = selections.map(|selection| (selection.start..selection.end, "")); + editor.edit(edits, cx); + }); + }); + vim.switch_mode(Mode::Insert, true, cx); +} + +// #[cfg(test)] +// mod test { +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; +// use indoc::indoc; + +// #[gpui::test] +// async fn test_substitute(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// // supports a single cursor +// cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["s", "x"]); +// cx.assert_editor_state("xˇbc\n"); + +// // supports a selection +// cx.set_state(indoc! {"a«bcˇ»\n"}, Mode::Visual); +// cx.assert_editor_state("a«bcˇ»\n"); +// cx.simulate_keystrokes(["s", "x"]); +// cx.assert_editor_state("axˇ\n"); + +// // supports counts +// cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["2", "s", "x"]); +// cx.assert_editor_state("xˇc\n"); + +// // supports multiple cursors +// cx.set_state(indoc! {"a«bcˇ»deˇffg\n"}, Mode::Normal); +// cx.simulate_keystrokes(["2", "s", "x"]); +// cx.assert_editor_state("axˇdexˇg\n"); + +// // does not read beyond end of line +// cx.set_state(indoc! {"ˇabc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["5", "s", "x"]); +// cx.assert_editor_state("xˇ\n"); + +// // it handles multibyte characters +// cx.set_state(indoc! {"ˇcàfé\n"}, Mode::Normal); +// cx.simulate_keystrokes(["4", "s"]); +// cx.assert_editor_state("ˇ\n"); + +// // should transactionally undo selection changes +// cx.simulate_keystrokes(["escape", "u"]); +// cx.assert_editor_state("ˇcàfé\n"); + +// // it handles visual line mode +// cx.set_state( +// indoc! {" +// alpha +// beˇta +// gamma"}, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["shift-v", "s"]); +// cx.assert_editor_state(indoc! {" +// alpha +// ˇ +// gamma"}); +// } + +// #[gpui::test] +// async fn test_visual_change(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("The quick ˇbrown").await; +// cx.simulate_shared_keystrokes(["v", "w", "c"]).await; +// cx.assert_shared_state("The quick ˇ").await; + +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "w", "j", "c"]).await; +// cx.assert_shared_state(indoc! {" +// The ˇver +// the lazy dog"}) +// .await; + +// let cases = cx.each_marked_position(indoc! {" +// The ˇquick brown +// fox jumps ˇover +// the ˇlazy dog"}); +// for initial_state in cases { +// cx.assert_neovim_compatible(&initial_state, ["v", "w", "j", "c"]) +// .await; +// cx.assert_neovim_compatible(&initial_state, ["v", "w", "k", "c"]) +// .await; +// } +// } + +// #[gpui::test] +// async fn test_visual_line_change(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["shift-v", "c"]); +// cx.assert(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}) +// .await; +// // Test pasting code copied on change +// cx.simulate_shared_keystrokes(["escape", "j", "p"]).await; +// cx.assert_state_matches().await; + +// cx.assert_all(indoc! {" +// The quick brown +// fox juˇmps over +// the laˇzy dog"}) +// .await; +// let mut cx = cx.binding(["shift-v", "j", "c"]); +// cx.assert(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}) +// .await; +// // Test pasting code copied on delete +// cx.simulate_shared_keystrokes(["escape", "j", "p"]).await; +// cx.assert_state_matches().await; + +// cx.assert_all(indoc! {" +// The quick brown +// fox juˇmps over +// the laˇzy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_substitute_line(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// let initial_state = indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog +// "}; + +// // normal mode +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes(["shift-s", "o"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// oˇ +// the lazy dog +// "}) +// .await; + +// // visual mode +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes(["v", "k", "shift-s", "o"]) +// .await; +// cx.assert_shared_state(indoc! {" +// oˇ +// the lazy dog +// "}) +// .await; + +// // visual block mode +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes(["ctrl-v", "j", "shift-s", "o"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// oˇ +// "}) +// .await; + +// // visual mode including newline +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes(["v", "$", "shift-s", "o"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// oˇ +// the lazy dog +// "}) +// .await; + +// // indentation +// cx.set_neovim_option("shiftwidth=4").await; +// cx.set_shared_state(initial_state).await; +// cx.simulate_shared_keystrokes([">", ">", "shift-s", "o"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// oˇ +// the lazy dog +// "}) +// .await; +// } +// } diff --git a/crates/vim2/src/normal/yank.rs b/crates/vim2/src/normal/yank.rs new file mode 100644 index 0000000000..33833500fa --- /dev/null +++ b/crates/vim2/src/normal/yank.rs @@ -0,0 +1,50 @@ +use crate::{motion::Motion, object::Object, utils::copy_selections_content, Vim}; +use collections::HashMap; +use gpui::WindowContext; + +pub fn yank_motion(vim: &mut Vim, motion: Motion, times: Option, cx: &mut WindowContext) { + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + editor.transact(cx, |editor, cx| { + editor.set_clip_at_line_ends(false, cx); + let mut original_positions: HashMap<_, _> = Default::default(); + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + let original_position = (selection.head(), selection.goal); + original_positions.insert(selection.id, original_position); + motion.expand_selection(map, selection, times, true, &text_layout_details); + }); + }); + copy_selections_content(editor, motion.linewise(), cx); + editor.change_selections(None, cx, |s| { + s.move_with(|_, selection| { + let (head, goal) = original_positions.remove(&selection.id).unwrap(); + selection.collapse_to(head, goal); + }); + }); + }); + }); +} + +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); + let mut original_positions: HashMap<_, _> = Default::default(); + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + let original_position = (selection.head(), selection.goal); + object.expand_selection(map, selection, around); + original_positions.insert(selection.id, original_position); + }); + }); + copy_selections_content(editor, false, cx); + editor.change_selections(None, cx, |s| { + s.move_with(|_, selection| { + let (head, goal) = original_positions.remove(&selection.id).unwrap(); + selection.collapse_to(head, goal); + }); + }); + }); + }); +} diff --git a/crates/vim2/src/object.rs b/crates/vim2/src/object.rs new file mode 100644 index 0000000000..18fcaf0177 --- /dev/null +++ b/crates/vim2/src/object.rs @@ -0,0 +1,1009 @@ +use std::ops::Range; + +use editor::{ + char_kind, + display_map::{DisplaySnapshot, ToDisplayPoint}, + movement::{self, FindRange}, + Bias, CharKind, DisplayPoint, +}; +use gpui::{actions, Action, AppContext, WindowContext}; +use language::Selection; +use serde::Deserialize; +use workspace::Workspace; + +use crate::{motion::right, normal::normal_object, state::Mode, visual::visual_object, Vim}; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Object { + Word { ignore_punctuation: bool }, + Sentence, + Quotes, + BackQuotes, + DoubleQuotes, + VerticalBars, + Parentheses, + SquareBrackets, + CurlyBrackets, + AngleBrackets, +} + +#[derive(Action, Clone, Deserialize, PartialEq)] +#[serde(rename_all = "camelCase")] +struct Word { + #[serde(default)] + ignore_punctuation: bool, +} + +actions!( + Sentence, + Quotes, + BackQuotes, + DoubleQuotes, + VerticalBars, + Parentheses, + SquareBrackets, + CurlyBrackets, + AngleBrackets +); + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action( + // |_: &mut Workspace, &Word { ignore_punctuation }: &Word, cx: _| { + // object(Object::Word { ignore_punctuation }, cx) + // }, + // ); + // cx.add_action(|_: &mut Workspace, _: &Sentence, cx: _| object(Object::Sentence, cx)); + // cx.add_action(|_: &mut Workspace, _: &Quotes, cx: _| object(Object::Quotes, cx)); + // cx.add_action(|_: &mut Workspace, _: &BackQuotes, cx: _| object(Object::BackQuotes, cx)); + // cx.add_action(|_: &mut Workspace, _: &DoubleQuotes, cx: _| object(Object::DoubleQuotes, cx)); + // cx.add_action(|_: &mut Workspace, _: &Parentheses, cx: _| object(Object::Parentheses, cx)); + // cx.add_action(|_: &mut Workspace, _: &SquareBrackets, cx: _| { + // object(Object::SquareBrackets, cx) + // }); + // cx.add_action(|_: &mut Workspace, _: &CurlyBrackets, cx: _| object(Object::CurlyBrackets, cx)); + // cx.add_action(|_: &mut Workspace, _: &AngleBrackets, cx: _| object(Object::AngleBrackets, cx)); + // cx.add_action(|_: &mut Workspace, _: &VerticalBars, cx: _| object(Object::VerticalBars, cx)); +} + +fn object(object: Object, cx: &mut WindowContext) { + match Vim::read(cx).state().mode { + Mode::Normal => normal_object(object, cx), + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_object(object, cx), + Mode::Insert => { + // Shouldn't execute a text object in insert mode. Ignoring + } + } +} + +impl Object { + pub fn is_multiline(self) -> bool { + match self { + Object::Word { .. } + | Object::Quotes + | Object::BackQuotes + | Object::VerticalBars + | Object::DoubleQuotes => false, + Object::Sentence + | Object::Parentheses + | Object::AngleBrackets + | Object::CurlyBrackets + | Object::SquareBrackets => true, + } + } + + pub fn always_expands_both_ways(self) -> bool { + match self { + Object::Word { .. } | Object::Sentence => false, + Object::Quotes + | Object::BackQuotes + | Object::DoubleQuotes + | Object::VerticalBars + | Object::Parentheses + | Object::SquareBrackets + | Object::CurlyBrackets + | Object::AngleBrackets => true, + } + } + + pub fn target_visual_mode(self, current_mode: Mode) -> Mode { + match self { + Object::Word { .. } if current_mode == Mode::VisualLine => Mode::Visual, + Object::Word { .. } => current_mode, + Object::Sentence + | Object::Quotes + | Object::BackQuotes + | Object::DoubleQuotes + | Object::VerticalBars + | Object::Parentheses + | Object::SquareBrackets + | Object::CurlyBrackets + | Object::AngleBrackets => Mode::Visual, + } + } + + pub fn range( + self, + map: &DisplaySnapshot, + relative_to: DisplayPoint, + around: bool, + ) -> Option> { + match self { + Object::Word { ignore_punctuation } => { + if around { + around_word(map, relative_to, ignore_punctuation) + } else { + in_word(map, relative_to, ignore_punctuation) + } + } + Object::Sentence => sentence(map, relative_to, around), + Object::Quotes => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '\'', '\'') + } + Object::BackQuotes => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '`', '`') + } + Object::DoubleQuotes => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '"', '"') + } + Object::VerticalBars => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '|', '|') + } + Object::Parentheses => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '(', ')') + } + Object::SquareBrackets => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '[', ']') + } + Object::CurlyBrackets => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '{', '}') + } + Object::AngleBrackets => { + surrounding_markers(map, relative_to, around, self.is_multiline(), '<', '>') + } + } + } + + pub fn expand_selection( + self, + map: &DisplaySnapshot, + selection: &mut Selection, + around: bool, + ) -> bool { + if let Some(range) = self.range(map, selection.head(), around) { + selection.start = range.start; + selection.end = range.end; + true + } else { + false + } + } +} + +/// Return a range that surrounds the word relative_to is in +/// If relative_to is at the start of a word, return the word. +/// If relative_to is between words, return the space between +fn in_word( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + ignore_punctuation: bool, +) -> Option> { + // Use motion::right so that we consider the character under the cursor when looking for the start + let scope = map + .buffer_snapshot + .language_scope_at(relative_to.to_point(map)); + let start = movement::find_preceding_boundary( + map, + right(map, relative_to, 1), + movement::FindRange::SingleLine, + |left, right| { + char_kind(&scope, left).coerce_punctuation(ignore_punctuation) + != char_kind(&scope, right).coerce_punctuation(ignore_punctuation) + }, + ); + + let end = movement::find_boundary(map, relative_to, FindRange::SingleLine, |left, right| { + char_kind(&scope, left).coerce_punctuation(ignore_punctuation) + != char_kind(&scope, right).coerce_punctuation(ignore_punctuation) + }); + + Some(start..end) +} + +/// Return a range that surrounds the word and following whitespace +/// relative_to is in. +/// If relative_to is at the start of a word, return the word and following whitespace. +/// If relative_to is between words, return the whitespace back and the following word + +/// if in word +/// delete that word +/// if there is whitespace following the word, delete that as well +/// otherwise, delete any preceding whitespace +/// otherwise +/// delete whitespace around cursor +/// delete word following the cursor +fn around_word( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + ignore_punctuation: bool, +) -> Option> { + let scope = map + .buffer_snapshot + .language_scope_at(relative_to.to_point(map)); + let in_word = map + .chars_at(relative_to) + .next() + .map(|(c, _)| char_kind(&scope, c) != CharKind::Whitespace) + .unwrap_or(false); + + if in_word { + around_containing_word(map, relative_to, ignore_punctuation) + } else { + around_next_word(map, relative_to, ignore_punctuation) + } +} + +fn around_containing_word( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + ignore_punctuation: bool, +) -> Option> { + in_word(map, relative_to, ignore_punctuation) + .map(|range| expand_to_include_whitespace(map, range, true)) +} + +fn around_next_word( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + ignore_punctuation: bool, +) -> Option> { + let scope = map + .buffer_snapshot + .language_scope_at(relative_to.to_point(map)); + // Get the start of the word + let start = movement::find_preceding_boundary( + map, + right(map, relative_to, 1), + FindRange::SingleLine, + |left, right| { + char_kind(&scope, left).coerce_punctuation(ignore_punctuation) + != char_kind(&scope, right).coerce_punctuation(ignore_punctuation) + }, + ); + + let mut word_found = false; + let end = movement::find_boundary(map, relative_to, FindRange::MultiLine, |left, right| { + let left_kind = char_kind(&scope, left).coerce_punctuation(ignore_punctuation); + let right_kind = char_kind(&scope, right).coerce_punctuation(ignore_punctuation); + + let found = (word_found && left_kind != right_kind) || right == '\n' && left == '\n'; + + if right_kind != CharKind::Whitespace { + word_found = true; + } + + found + }); + + Some(start..end) +} + +fn sentence( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + around: bool, +) -> Option> { + let mut start = None; + let mut previous_end = relative_to; + + let mut chars = map.chars_at(relative_to).peekable(); + + // Search backwards for the previous sentence end or current sentence start. Include the character under relative_to + for (char, point) in chars + .peek() + .cloned() + .into_iter() + .chain(map.reverse_chars_at(relative_to)) + { + if is_sentence_end(map, point) { + break; + } + + if is_possible_sentence_start(char) { + start = Some(point); + } + + previous_end = point; + } + + // Search forward for the end of the current sentence or if we are between sentences, the start of the next one + let mut end = relative_to; + for (char, point) in chars { + if start.is_none() && is_possible_sentence_start(char) { + if around { + start = Some(point); + continue; + } else { + end = point; + break; + } + } + + end = point; + *end.column_mut() += char.len_utf8() as u32; + end = map.clip_point(end, Bias::Left); + + if is_sentence_end(map, end) { + break; + } + } + + let mut range = start.unwrap_or(previous_end)..end; + if around { + range = expand_to_include_whitespace(map, range, false); + } + + Some(range) +} + +fn is_possible_sentence_start(character: char) -> bool { + !character.is_whitespace() && character != '.' +} + +const SENTENCE_END_PUNCTUATION: &[char] = &['.', '!', '?']; +const SENTENCE_END_FILLERS: &[char] = &[')', ']', '"', '\'']; +const SENTENCE_END_WHITESPACE: &[char] = &[' ', '\t', '\n']; +fn is_sentence_end(map: &DisplaySnapshot, point: DisplayPoint) -> bool { + let mut next_chars = map.chars_at(point).peekable(); + if let Some((char, _)) = next_chars.next() { + // We are at a double newline. This position is a sentence end. + if char == '\n' && next_chars.peek().map(|(c, _)| c == &'\n').unwrap_or(false) { + return true; + } + + // The next text is not a valid whitespace. This is not a sentence end + if !SENTENCE_END_WHITESPACE.contains(&char) { + return false; + } + } + + for (char, _) in map.reverse_chars_at(point) { + if SENTENCE_END_PUNCTUATION.contains(&char) { + return true; + } + + if !SENTENCE_END_FILLERS.contains(&char) { + return false; + } + } + + return false; +} + +/// Expands the passed range to include whitespace on one side or the other in a line. Attempts to add the +/// whitespace to the end first and falls back to the start if there was none. +fn expand_to_include_whitespace( + map: &DisplaySnapshot, + mut range: Range, + stop_at_newline: bool, +) -> Range { + let mut whitespace_included = false; + + let mut chars = map.chars_at(range.end).peekable(); + while let Some((char, point)) = chars.next() { + if char == '\n' && stop_at_newline { + break; + } + + if char.is_whitespace() { + // Set end to the next display_point or the character position after the current display_point + range.end = chars.peek().map(|(_, point)| *point).unwrap_or_else(|| { + let mut end = point; + *end.column_mut() += char.len_utf8() as u32; + map.clip_point(end, Bias::Left) + }); + + if char != '\n' { + whitespace_included = true; + } + } else { + // Found non whitespace. Quit out. + break; + } + } + + if !whitespace_included { + for (char, point) in map.reverse_chars_at(range.start) { + if char == '\n' && stop_at_newline { + break; + } + + if !char.is_whitespace() { + break; + } + + range.start = point; + } + } + + range +} + +fn surrounding_markers( + map: &DisplaySnapshot, + relative_to: DisplayPoint, + around: bool, + search_across_lines: bool, + open_marker: char, + close_marker: char, +) -> Option> { + let point = relative_to.to_offset(map, Bias::Left); + + let mut matched_closes = 0; + let mut opening = None; + + if let Some((ch, range)) = movement::chars_after(map, point).next() { + if ch == open_marker { + if open_marker == close_marker { + let mut total = 0; + for (ch, _) in movement::chars_before(map, point) { + if ch == '\n' { + break; + } + if ch == open_marker { + total += 1; + } + } + if total % 2 == 0 { + opening = Some(range) + } + } else { + opening = Some(range) + } + } + } + + if opening.is_none() { + for (ch, range) in movement::chars_before(map, point) { + if ch == '\n' && !search_across_lines { + break; + } + + if ch == open_marker { + if matched_closes == 0 { + opening = Some(range); + break; + } + matched_closes -= 1; + } else if ch == close_marker { + matched_closes += 1 + } + } + } + + if opening.is_none() { + for (ch, range) in movement::chars_after(map, point) { + if ch == open_marker { + opening = Some(range); + break; + } else if ch == close_marker { + break; + } + } + } + + let Some(mut opening) = opening else { + return None; + }; + + let mut matched_opens = 0; + let mut closing = None; + + for (ch, range) in movement::chars_after(map, opening.end) { + if ch == '\n' && !search_across_lines { + break; + } + + if ch == close_marker { + if matched_opens == 0 { + closing = Some(range); + break; + } + matched_opens -= 1; + } else if ch == open_marker { + matched_opens += 1; + } + } + + let Some(mut closing) = closing else { + return None; + }; + + if around && !search_across_lines { + let mut found = false; + + for (ch, range) in movement::chars_after(map, closing.end) { + if ch.is_whitespace() && ch != '\n' { + found = true; + closing.end = range.end; + } else { + break; + } + } + + if !found { + for (ch, range) in movement::chars_before(map, opening.start) { + if ch.is_whitespace() && ch != '\n' { + opening.start = range.start + } else { + break; + } + } + } + } + + if !around && search_across_lines { + if let Some((ch, range)) = movement::chars_after(map, opening.end).next() { + if ch == '\n' { + opening.end = range.end + } + } + + for (ch, range) in movement::chars_before(map, closing.start) { + if !ch.is_whitespace() { + break; + } + if ch != '\n' { + closing.start = range.start + } + } + } + + let result = if around { + opening.start..closing.end + } else { + opening.end..closing.start + }; + + Some( + map.clip_point(result.start.to_display_point(map), Bias::Left) + ..map.clip_point(result.end.to_display_point(map), Bias::Right), + ) +} + +// #[cfg(test)] +// mod test { +// use indoc::indoc; + +// use crate::{ +// state::Mode, +// test::{ExemptionFeatures, NeovimBackedTestContext, VimTestContext}, +// }; + +// const WORD_LOCATIONS: &'static str = indoc! {" +// The quick ˇbrowˇnˇ••• +// fox ˇjuˇmpsˇ over +// the lazy dogˇ•• +// ˇ +// ˇ +// ˇ +// Thˇeˇ-ˇquˇickˇ ˇbrownˇ• +// ˇ•• +// ˇ•• +// ˇ fox-jumpˇs over +// the lazy dogˇ• +// ˇ +// " +// }; + +// #[gpui::test] +// async fn test_change_word_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_binding_matches_all(["c", "i", "w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["c", "i", "shift-w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["c", "a", "w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["c", "a", "shift-w"], WORD_LOCATIONS) +// .await; +// } + +// #[gpui::test] +// async fn test_delete_word_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_binding_matches_all(["d", "i", "w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["d", "i", "shift-w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["d", "a", "w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all(["d", "a", "shift-w"], WORD_LOCATIONS) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_word_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// /* +// cx.set_shared_state("The quick ˇbrown\nfox").await; +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state("The quick «bˇ»rown\nfox").await; +// cx.simulate_shared_keystrokes(["i", "w"]).await; +// cx.assert_shared_state("The quick «brownˇ»\nfox").await; +// */ +// cx.set_shared_state("The quick brown\nˇ\nfox").await; +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state("The quick brown\n«\nˇ»fox").await; +// cx.simulate_shared_keystrokes(["i", "w"]).await; +// cx.assert_shared_state("The quick brown\n«\nˇ»fox").await; + +// cx.assert_binding_matches_all(["v", "i", "w"], WORD_LOCATIONS) +// .await; +// cx.assert_binding_matches_all_exempted( +// ["v", "h", "i", "w"], +// WORD_LOCATIONS, +// ExemptionFeatures::NonEmptyVisualTextObjects, +// ) +// .await; +// cx.assert_binding_matches_all_exempted( +// ["v", "l", "i", "w"], +// WORD_LOCATIONS, +// ExemptionFeatures::NonEmptyVisualTextObjects, +// ) +// .await; +// cx.assert_binding_matches_all(["v", "i", "shift-w"], WORD_LOCATIONS) +// .await; + +// cx.assert_binding_matches_all_exempted( +// ["v", "i", "h", "shift-w"], +// WORD_LOCATIONS, +// ExemptionFeatures::NonEmptyVisualTextObjects, +// ) +// .await; +// cx.assert_binding_matches_all_exempted( +// ["v", "i", "l", "shift-w"], +// WORD_LOCATIONS, +// ExemptionFeatures::NonEmptyVisualTextObjects, +// ) +// .await; + +// cx.assert_binding_matches_all_exempted( +// ["v", "a", "w"], +// WORD_LOCATIONS, +// ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine, +// ) +// .await; +// cx.assert_binding_matches_all_exempted( +// ["v", "a", "shift-w"], +// WORD_LOCATIONS, +// ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine, +// ) +// .await; +// } + +// const SENTENCE_EXAMPLES: &[&'static str] = &[ +// "ˇThe quick ˇbrownˇ?ˇ ˇFox Jˇumpsˇ!ˇ Ovˇer theˇ lazyˇ.", +// indoc! {" +// ˇThe quick ˇbrownˇ +// fox jumps over +// the lazy doˇgˇ.ˇ ˇThe quick ˇ +// brown fox jumps over +// "}, +// indoc! {" +// The quick brown fox jumps. +// Over the lazy dog +// ˇ +// ˇ +// ˇ fox-jumpˇs over +// the lazy dog.ˇ +// ˇ +// "}, +// r#"ˇThe ˇquick brownˇ.)ˇ]ˇ'ˇ" Brown ˇfox jumpsˇ.ˇ "#, +// ]; + +// #[gpui::test] +// async fn test_change_sentence_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["c", "i", "s"]); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n", +// ExemptionFeatures::SentenceOnEmptyLines); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n", +// ExemptionFeatures::SentenceAtStartOfLineWithWhitespace); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n", +// ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile); +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all(sentence_example).await; +// } + +// let mut cx = cx.binding(["c", "a", "s"]); +// cx.add_initial_state_exemptions( +// "The quick brown?ˇ Fox Jumps! Over the lazy.", +// ExemptionFeatures::IncorrectLandingPosition, +// ); +// cx.add_initial_state_exemptions( +// "The quick brown.)]\'\" Brown fox jumps.ˇ ", +// ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine, +// ); + +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all(sentence_example).await; +// } +// } + +// #[gpui::test] +// async fn test_delete_sentence_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["d", "i", "s"]); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\nˇ\nˇ\n fox-jumps over\nthe lazy dog.\n\n", +// ExemptionFeatures::SentenceOnEmptyLines); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\n\n\nˇ foxˇ-ˇjumpˇs over\nthe lazy dog.\n\n", +// ExemptionFeatures::SentenceAtStartOfLineWithWhitespace); +// cx.add_initial_state_exemptions( +// "The quick brown fox jumps.\nOver the lazy dog\n\n\n fox-jumps over\nthe lazy dog.ˇ\nˇ\n", +// ExemptionFeatures::SentenceAfterPunctuationAtEndOfFile); + +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all(sentence_example).await; +// } + +// let mut cx = cx.binding(["d", "a", "s"]); +// cx.add_initial_state_exemptions( +// "The quick brown?ˇ Fox Jumps! Over the lazy.", +// ExemptionFeatures::IncorrectLandingPosition, +// ); +// cx.add_initial_state_exemptions( +// "The quick brown.)]\'\" Brown fox jumps.ˇ ", +// ExemptionFeatures::AroundObjectLeavesWhitespaceAtEndOfLine, +// ); + +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all(sentence_example).await; +// } +// } + +// #[gpui::test] +// async fn test_visual_sentence_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx) +// .await +// .binding(["v", "i", "s"]); +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all_exempted(sentence_example, ExemptionFeatures::SentenceOnEmptyLines) +// .await; +// } + +// let mut cx = cx.binding(["v", "a", "s"]); +// for sentence_example in SENTENCE_EXAMPLES { +// cx.assert_all_exempted( +// sentence_example, +// ExemptionFeatures::AroundSentenceStartingBetweenIncludesWrongWhitespace, +// ) +// .await; +// } +// } + +// // Test string with "`" for opening surrounders and "'" for closing surrounders +// const SURROUNDING_MARKER_STRING: &str = indoc! {" +// ˇTh'ˇe ˇ`ˇ'ˇquˇi`ˇck broˇ'wn` +// 'ˇfox juˇmps ovˇ`ˇer +// the ˇlazy dˇ'ˇoˇ`ˇg"}; + +// const SURROUNDING_OBJECTS: &[(char, char)] = &[ +// ('\'', '\''), // Quote +// ('`', '`'), // Back Quote +// ('"', '"'), // Double Quote +// ('(', ')'), // Parentheses +// ('[', ']'), // SquareBrackets +// ('{', '}'), // CurlyBrackets +// ('<', '>'), // AngleBrackets +// ]; + +// #[gpui::test] +// async fn test_change_surrounding_character_objects(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for (start, end) in SURROUNDING_OBJECTS { +// let marked_string = SURROUNDING_MARKER_STRING +// .replace('`', &start.to_string()) +// .replace('\'', &end.to_string()); + +// cx.assert_binding_matches_all(["c", "i", &start.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["c", "i", &end.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["c", "a", &start.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["c", "a", &end.to_string()], &marked_string) +// .await; +// } +// } +// #[gpui::test] +// async fn test_singleline_surrounding_character_objects(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_shared_wrap(12).await; + +// cx.set_shared_state(indoc! { +// "helˇlo \"world\"!" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "\""]).await; +// cx.assert_shared_state(indoc! { +// "hello \"«worldˇ»\"!" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "hello \"wˇorld\"!" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "\""]).await; +// cx.assert_shared_state(indoc! { +// "hello \"«worldˇ»\"!" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "hello \"wˇorld\"!" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "a", "\""]).await; +// cx.assert_shared_state(indoc! { +// "hello« \"world\"ˇ»!" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "hello \"wˇorld\" !" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "a", "\""]).await; +// cx.assert_shared_state(indoc! { +// "hello «\"world\" ˇ»!" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "hello \"wˇorld\"• +// goodbye" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "a", "\""]).await; +// cx.assert_shared_state(indoc! { +// "hello «\"world\" ˇ» +// goodbye" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_multiline_surrounding_character_objects(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "func empty(a string) bool { +// if a == \"\" { +// return true +// } +// ˇreturn false +// }" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "{"]).await; +// cx.assert_shared_state(indoc! {" +// func empty(a string) bool { +// « if a == \"\" { +// return true +// } +// return false +// ˇ»}"}) +// .await; +// cx.set_shared_state(indoc! { +// "func empty(a string) bool { +// if a == \"\" { +// ˇreturn true +// } +// return false +// }" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "{"]).await; +// cx.assert_shared_state(indoc! {" +// func empty(a string) bool { +// if a == \"\" { +// « return true +// ˇ» } +// return false +// }"}) +// .await; + +// cx.set_shared_state(indoc! { +// "func empty(a string) bool { +// if a == \"\" ˇ{ +// return true +// } +// return false +// }" +// }) +// .await; +// cx.simulate_shared_keystrokes(["v", "i", "{"]).await; +// cx.assert_shared_state(indoc! {" +// func empty(a string) bool { +// if a == \"\" { +// « return true +// ˇ» } +// return false +// }"}) +// .await; +// } + +// #[gpui::test] +// async fn test_vertical_bars(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; +// cx.set_state( +// indoc! {" +// fn boop() { +// baz(ˇ|a, b| { bar(|j, k| { })}) +// }" +// }, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["c", "i", "|"]); +// cx.assert_state( +// indoc! {" +// fn boop() { +// baz(|ˇ| { bar(|j, k| { })}) +// }" +// }, +// Mode::Insert, +// ); +// cx.simulate_keystrokes(["escape", "1", "8", "|"]); +// cx.assert_state( +// indoc! {" +// fn boop() { +// baz(|| { bar(ˇ|j, k| { })}) +// }" +// }, +// Mode::Normal, +// ); + +// cx.simulate_keystrokes(["v", "a", "|"]); +// cx.assert_state( +// indoc! {" +// fn boop() { +// baz(|| { bar(«|j, k| ˇ»{ })}) +// }" +// }, +// Mode::Visual, +// ); +// } + +// #[gpui::test] +// async fn test_delete_surrounding_character_objects(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// for (start, end) in SURROUNDING_OBJECTS { +// let marked_string = SURROUNDING_MARKER_STRING +// .replace('`', &start.to_string()) +// .replace('\'', &end.to_string()); + +// cx.assert_binding_matches_all(["d", "i", &start.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["d", "i", &end.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["d", "a", &start.to_string()], &marked_string) +// .await; +// cx.assert_binding_matches_all(["d", "a", &end.to_string()], &marked_string) +// .await; +// } +// } +// } diff --git a/crates/vim2/src/state.rs b/crates/vim2/src/state.rs new file mode 100644 index 0000000000..3452898255 --- /dev/null +++ b/crates/vim2/src/state.rs @@ -0,0 +1,234 @@ +use std::{ops::Range, sync::Arc}; + +use gpui::{Action, KeyContext}; +use language::CursorShape; +use serde::{Deserialize, Serialize}; +use workspace::searchable::Direction; + +use crate::motion::Motion; + +#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)] +pub enum Mode { + Normal, + Insert, + Visual, + VisualLine, + VisualBlock, +} + +impl Mode { + pub fn is_visual(&self) -> bool { + match self { + Mode::Normal | Mode::Insert => false, + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => true, + } + } +} + +impl Default for Mode { + fn default() -> Self { + Self::Normal + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)] +pub enum Operator { + Change, + Delete, + Yank, + Replace, + Object { around: bool }, + FindForward { before: bool }, + FindBackward { after: bool }, +} + +#[derive(Default, Clone)] +pub struct EditorState { + pub mode: Mode, + pub last_mode: Mode, + + /// pre_count is the number before an operator is specified (3 in 3d2d) + pub pre_count: Option, + /// post_count is the number after an operator is specified (2 in 3d2d) + pub post_count: Option, + + pub operator_stack: Vec, +} + +#[derive(Default, Clone, Debug)] +pub enum RecordedSelection { + #[default] + None, + Visual { + rows: u32, + cols: u32, + }, + SingleLine { + cols: u32, + }, + VisualBlock { + rows: u32, + cols: u32, + }, + VisualLine { + rows: u32, + }, +} + +#[derive(Default, Clone)] +pub struct WorkspaceState { + pub search: SearchState, + pub last_find: Option, + + pub recording: bool, + pub stop_recording_after_next_action: bool, + pub replaying: bool, + pub recorded_count: Option, + pub recorded_actions: Vec, + pub recorded_selection: RecordedSelection, +} + +#[derive(Debug)] +pub enum ReplayableAction { + Action(Box), + Insertion { + text: Arc, + utf16_range_to_replace: Option>, + }, +} + +impl Clone for ReplayableAction { + fn clone(&self) -> Self { + match self { + Self::Action(action) => Self::Action(action.boxed_clone()), + Self::Insertion { + text, + utf16_range_to_replace, + } => Self::Insertion { + text: text.clone(), + utf16_range_to_replace: utf16_range_to_replace.clone(), + }, + } + } +} + +#[derive(Clone)] +pub struct SearchState { + pub direction: Direction, + pub count: usize, + pub initial_query: String, +} + +impl Default for SearchState { + fn default() -> Self { + Self { + direction: Direction::Next, + count: 1, + initial_query: "".to_string(), + } + } +} + +impl EditorState { + pub fn cursor_shape(&self) -> CursorShape { + match self.mode { + Mode::Normal => { + if self.operator_stack.is_empty() { + CursorShape::Block + } else { + CursorShape::Underscore + } + } + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => CursorShape::Block, + Mode::Insert => CursorShape::Bar, + } + } + + pub fn vim_controlled(&self) -> bool { + !matches!(self.mode, Mode::Insert) + || matches!( + self.operator_stack.last(), + Some(Operator::FindForward { .. }) | Some(Operator::FindBackward { .. }) + ) + } + + pub fn should_autoindent(&self) -> bool { + !(self.mode == Mode::Insert && self.last_mode == Mode::VisualBlock) + } + + pub fn clip_at_line_ends(&self) -> bool { + match self.mode { + Mode::Insert | Mode::Visual | Mode::VisualLine | Mode::VisualBlock => false, + Mode::Normal => true, + } + } + + pub fn active_operator(&self) -> Option { + self.operator_stack.last().copied() + } + + pub fn keymap_context_layer(&self) -> KeyContext { + let mut context = KeyContext::default(); + context.add("VimEnabled"); + context.set( + "vim_mode", + match self.mode { + Mode::Normal => "normal", + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => "visual", + Mode::Insert => "insert", + }, + ); + + if self.vim_controlled() { + context.add("VimControl"); + } + + if self.active_operator().is_none() && self.pre_count.is_some() + || self.active_operator().is_some() && self.post_count.is_some() + { + context.add("VimCount"); + } + + let active_operator = self.active_operator(); + + if let Some(active_operator) = active_operator { + for context_flag in active_operator.context_flags().into_iter() { + context.add(*context_flag); + } + } + + context.set( + "vim_operator", + active_operator.map(|op| op.id()).unwrap_or_else(|| "none"), + ); + + context + } +} + +impl Operator { + pub fn id(&self) -> &'static str { + match self { + Operator::Object { around: false } => "i", + Operator::Object { around: true } => "a", + Operator::Change => "c", + Operator::Delete => "d", + Operator::Yank => "y", + Operator::Replace => "r", + Operator::FindForward { before: false } => "f", + Operator::FindForward { before: true } => "t", + Operator::FindBackward { after: false } => "F", + Operator::FindBackward { after: true } => "T", + } + } + + pub fn context_flags(&self) -> &'static [&'static str] { + match self { + Operator::Object { .. } => &["VimObject"], + Operator::FindForward { .. } | Operator::FindBackward { .. } | Operator::Replace => { + &["VimWaiting"] + } + _ => &[], + } + } +} diff --git a/crates/vim2/src/test.rs b/crates/vim2/src/test.rs new file mode 100644 index 0000000000..2c80452268 --- /dev/null +++ b/crates/vim2/src/test.rs @@ -0,0 +1,759 @@ +// mod neovim_backed_binding_test_context; +// mod neovim_backed_test_context; +// mod neovim_connection; +// mod vim_test_context; + +// use std::sync::Arc; + +// use command_palette::CommandPalette; +// use editor::DisplayPoint; +// pub use neovim_backed_binding_test_context::*; +// pub use neovim_backed_test_context::*; +// pub use vim_test_context::*; + +// use indoc::indoc; +// use search::BufferSearchBar; + +// use crate::{state::Mode, ModeIndicator}; + +// #[gpui::test] +// async fn test_initially_disabled(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, false).await; +// cx.simulate_keystrokes(["h", "j", "k", "l"]); +// cx.assert_editor_state("hjklˇ"); +// } + +// #[gpui::test] +// async fn test_neovim(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.simulate_shared_keystroke("i").await; +// cx.assert_state_matches().await; +// cx.simulate_shared_keystrokes([ +// "shift-T", "e", "s", "t", " ", "t", "e", "s", "t", "escape", "0", "d", "w", +// ]) +// .await; +// cx.assert_state_matches().await; +// cx.assert_editor_state("ˇtest"); +// } + +// #[gpui::test] +// async fn test_toggle_through_settings(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.simulate_keystroke("i"); +// assert_eq!(cx.mode(), Mode::Insert); + +// // Editor acts as though vim is disabled +// cx.disable_vim(); +// cx.simulate_keystrokes(["h", "j", "k", "l"]); +// cx.assert_editor_state("hjklˇ"); + +// // Selections aren't changed if editor is blurred but vim-mode is still disabled. +// cx.set_state("«hjklˇ»", Mode::Normal); +// cx.assert_editor_state("«hjklˇ»"); +// cx.update_editor(|_, cx| cx.blur()); +// cx.assert_editor_state("«hjklˇ»"); +// cx.update_editor(|_, cx| cx.focus_self()); +// cx.assert_editor_state("«hjklˇ»"); + +// // Enabling dynamically sets vim mode again and restores normal mode +// cx.enable_vim(); +// assert_eq!(cx.mode(), Mode::Normal); +// cx.simulate_keystrokes(["h", "h", "h", "l"]); +// assert_eq!(cx.buffer_text(), "hjkl".to_owned()); +// cx.assert_editor_state("hˇjkl"); +// cx.simulate_keystrokes(["i", "T", "e", "s", "t"]); +// cx.assert_editor_state("hTestˇjkl"); + +// // Disabling and enabling resets to normal mode +// assert_eq!(cx.mode(), Mode::Insert); +// cx.disable_vim(); +// cx.enable_vim(); +// assert_eq!(cx.mode(), Mode::Normal); +// } + +// #[gpui::test] +// async fn test_buffer_search(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state( +// indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}, +// Mode::Normal, +// ); +// cx.simulate_keystroke("/"); + +// let search_bar = cx.workspace(|workspace, cx| { +// workspace +// .active_pane() +// .read(cx) +// .toolbar() +// .read(cx) +// .item_of_type::() +// .expect("Buffer search bar should be deployed") +// }); + +// cx.update_view(search_bar, |bar, cx| { +// assert_eq!(bar.query(cx), ""); +// }) +// } + +// #[gpui::test] +// async fn test_count_down(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state(indoc! {"aˇa\nbb\ncc\ndd\nee"}, Mode::Normal); +// cx.simulate_keystrokes(["2", "down"]); +// cx.assert_editor_state("aa\nbb\ncˇc\ndd\nee"); +// cx.simulate_keystrokes(["9", "down"]); +// cx.assert_editor_state("aa\nbb\ncc\ndd\neˇe"); +// } + +// #[gpui::test] +// async fn test_end_of_document_710(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// // goes to end by default +// cx.set_state(indoc! {"aˇa\nbb\ncc"}, Mode::Normal); +// cx.simulate_keystrokes(["shift-g"]); +// cx.assert_editor_state("aa\nbb\ncˇc"); + +// // can go to line 1 (https://github.com/zed-industries/community/issues/710) +// cx.simulate_keystrokes(["1", "shift-g"]); +// cx.assert_editor_state("aˇa\nbb\ncc"); +// } + +// #[gpui::test] +// async fn test_indent_outdent(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// // works in normal mode +// cx.set_state(indoc! {"aa\nbˇb\ncc"}, Mode::Normal); +// cx.simulate_keystrokes([">", ">"]); +// cx.assert_editor_state("aa\n bˇb\ncc"); +// cx.simulate_keystrokes(["<", "<"]); +// cx.assert_editor_state("aa\nbˇb\ncc"); + +// // works in visuial mode +// cx.simulate_keystrokes(["shift-v", "down", ">"]); +// cx.assert_editor_state("aa\n b«b\n ccˇ»"); +// } + +// #[gpui::test] +// async fn test_escape_command_palette(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("aˇbc\n", Mode::Normal); +// cx.simulate_keystrokes(["i", "cmd-shift-p"]); + +// assert!(cx.workspace(|workspace, _| workspace.modal::().is_some())); +// cx.simulate_keystroke("escape"); +// assert!(!cx.workspace(|workspace, _| workspace.modal::().is_some())); +// cx.assert_state("aˇbc\n", Mode::Insert); +// } + +// #[gpui::test] +// async fn test_escape_cancels(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("aˇbˇc", Mode::Normal); +// cx.simulate_keystrokes(["escape"]); + +// cx.assert_state("aˇbc", Mode::Normal); +// } + +// #[gpui::test] +// async fn test_selection_on_search(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state(indoc! {"aa\nbˇb\ncc\ncc\ncc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["/", "c", "c"]); + +// let search_bar = cx.workspace(|workspace, cx| { +// workspace +// .active_pane() +// .read(cx) +// .toolbar() +// .read(cx) +// .item_of_type::() +// .expect("Buffer search bar should be deployed") +// }); + +// search_bar.read_with(cx.cx, |bar, cx| { +// assert_eq!(bar.query(cx), "cc"); +// }); + +// cx.update_editor(|editor, cx| { +// let highlights = editor.all_text_background_highlights(cx); +// assert_eq!(3, highlights.len()); +// assert_eq!( +// DisplayPoint::new(2, 0)..DisplayPoint::new(2, 2), +// highlights[0].0 +// ) +// }); +// cx.simulate_keystrokes(["enter"]); + +// cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["n"]); +// cx.assert_state(indoc! {"aa\nbb\ncc\nˇcc\ncc\n"}, Mode::Normal); +// cx.simulate_keystrokes(["shift-n"]); +// cx.assert_state(indoc! {"aa\nbb\nˇcc\ncc\ncc\n"}, Mode::Normal); +// } + +// #[gpui::test] +// async fn test_status_indicator( +// cx: &mut gpui::TestAppContext, +// deterministic: Arc, +// ) { +// let mut cx = VimTestContext::new(cx, true).await; +// deterministic.run_until_parked(); + +// let mode_indicator = cx.workspace(|workspace, cx| { +// let status_bar = workspace.status_bar().read(cx); +// let mode_indicator = status_bar.item_of_type::(); +// assert!(mode_indicator.is_some()); +// mode_indicator.unwrap() +// }); + +// assert_eq!( +// cx.workspace(|_, cx| mode_indicator.read(cx).mode), +// Some(Mode::Normal) +// ); + +// // shows the correct mode +// cx.simulate_keystrokes(["i"]); +// deterministic.run_until_parked(); +// assert_eq!( +// cx.workspace(|_, cx| mode_indicator.read(cx).mode), +// Some(Mode::Insert) +// ); + +// // shows even in search +// cx.simulate_keystrokes(["escape", "v", "/"]); +// deterministic.run_until_parked(); +// assert_eq!( +// cx.workspace(|_, cx| mode_indicator.read(cx).mode), +// Some(Mode::Visual) +// ); + +// // hides if vim mode is disabled +// cx.disable_vim(); +// deterministic.run_until_parked(); +// cx.workspace(|workspace, cx| { +// let status_bar = workspace.status_bar().read(cx); +// let mode_indicator = status_bar.item_of_type::().unwrap(); +// assert!(mode_indicator.read(cx).mode.is_none()); +// }); + +// cx.enable_vim(); +// deterministic.run_until_parked(); +// cx.workspace(|workspace, cx| { +// let status_bar = workspace.status_bar().read(cx); +// let mode_indicator = status_bar.item_of_type::().unwrap(); +// assert!(mode_indicator.read(cx).mode.is_some()); +// }); +// } + +// #[gpui::test] +// async fn test_word_characters(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new_typescript(cx).await; +// cx.set_state( +// indoc! { " +// class A { +// #ˇgoop = 99; +// $ˇgoop () { return this.#gˇoop }; +// }; +// console.log(new A().$gooˇp()) +// "}, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["v", "i", "w"]); +// cx.assert_state( +// indoc! {" +// class A { +// «#goopˇ» = 99; +// «$goopˇ» () { return this.«#goopˇ» }; +// }; +// console.log(new A().«$goopˇ»()) +// "}, +// Mode::Visual, +// ) +// } + +// #[gpui::test] +// async fn test_join_lines(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ˇone +// two +// three +// four +// five +// six +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-j"]).await; +// cx.assert_shared_state(indoc! {" +// oneˇ two +// three +// four +// five +// six +// "}) +// .await; +// cx.simulate_shared_keystrokes(["3", "shift-j"]).await; +// cx.assert_shared_state(indoc! {" +// one two threeˇ four +// five +// six +// "}) +// .await; + +// cx.set_shared_state(indoc! {" +// ˇone +// two +// three +// four +// five +// six +// "}) +// .await; +// cx.simulate_shared_keystrokes(["j", "v", "3", "j", "shift-j"]) +// .await; +// cx.assert_shared_state(indoc! {" +// one +// two three fourˇ five +// six +// "}) +// .await; +// } + +// #[gpui::test] +// async fn test_wrapped_lines(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_wrap(12).await; +// // tests line wrap as follows: +// // 1: twelve char +// // twelve char +// // 2: twelve char +// cx.set_shared_state(indoc! { " +// tˇwelve char twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["j"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char twelve char +// tˇwelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["k"]).await; +// cx.assert_shared_state(indoc! { " +// tˇwelve char twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["g", "j"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char tˇwelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["g", "j"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char twelve char +// tˇwelve char +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["g", "k"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char tˇwelve char +// twelve char +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["g", "^"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char ˇtwelve char +// twelve char +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["^"]).await; +// cx.assert_shared_state(indoc! { " +// ˇtwelve char twelve char +// twelve char +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["g", "$"]).await; +// cx.assert_shared_state(indoc! { " +// twelve charˇ twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["$"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char twelve chaˇr +// twelve char +// "}) +// .await; + +// cx.set_shared_state(indoc! { " +// tˇwelve char twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["enter"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char twelve char +// ˇtwelve char +// "}) +// .await; + +// cx.set_shared_state(indoc! { " +// twelve char +// tˇwelve char twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["o", "o", "escape"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char +// twelve char twelve char +// ˇo +// twelve char +// "}) +// .await; + +// cx.set_shared_state(indoc! { " +// twelve char +// tˇwelve char twelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-a", "a", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { " +// twelve char +// twelve char twelve charˇa +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-i", "i", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { " +// twelve char +// ˇitwelve char twelve chara +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-d"]).await; +// cx.assert_shared_state(indoc! { " +// twelve char +// ˇ +// twelve char +// "}) +// .await; + +// cx.set_shared_state(indoc! { " +// twelve char +// twelve char tˇwelve char +// twelve char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-o", "o", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { " +// twelve char +// ˇo +// twelve char twelve char +// twelve char +// "}) +// .await; + +// // line wraps as: +// // fourteen ch +// // ar +// // fourteen ch +// // ar +// cx.set_shared_state(indoc! { " +// fourteen chaˇr +// fourteen char +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["d", "i", "w"]).await; +// cx.assert_shared_state(indoc! {" +// fourteenˇ• +// fourteen char +// "}) +// .await; +// cx.simulate_shared_keystrokes(["j", "shift-f", "e", "f", "r"]) +// .await; +// cx.assert_shared_state(indoc! {" +// fourteen• +// fourteen chaˇr +// "}) +// .await; +// } + +// #[gpui::test] +// async fn test_folds(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_neovim_option("foldmethod=manual").await; + +// cx.set_shared_state(indoc! { " +// fn boop() { +// ˇbarp() +// bazp() +// } +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "j", "z", "f"]) +// .await; + +// // visual display is now: +// // fn boop () { +// // [FOLDED] +// // } + +// // TODO: this should not be needed but currently zf does not +// // return to normal mode. +// cx.simulate_shared_keystrokes(["escape"]).await; + +// // skip over fold downward +// cx.simulate_shared_keystrokes(["g", "g"]).await; +// cx.assert_shared_state(indoc! { " +// ˇfn boop() { +// barp() +// bazp() +// } +// "}) +// .await; + +// cx.simulate_shared_keystrokes(["j", "j"]).await; +// cx.assert_shared_state(indoc! { " +// fn boop() { +// barp() +// bazp() +// ˇ} +// "}) +// .await; + +// // skip over fold upward +// cx.simulate_shared_keystrokes(["2", "k"]).await; +// cx.assert_shared_state(indoc! { " +// ˇfn boop() { +// barp() +// bazp() +// } +// "}) +// .await; + +// // yank the fold +// cx.simulate_shared_keystrokes(["down", "y", "y"]).await; +// cx.assert_shared_clipboard(" barp()\n bazp()\n").await; + +// // re-open +// cx.simulate_shared_keystrokes(["z", "o"]).await; +// cx.assert_shared_state(indoc! { " +// fn boop() { +// ˇ barp() +// bazp() +// } +// "}) +// .await; +// } + +// #[gpui::test] +// async fn test_folds_panic(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; +// cx.set_neovim_option("foldmethod=manual").await; + +// cx.set_shared_state(indoc! { " +// fn boop() { +// ˇbarp() +// bazp() +// } +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "j", "z", "f"]) +// .await; +// cx.simulate_shared_keystrokes(["escape"]).await; +// cx.simulate_shared_keystrokes(["g", "g"]).await; +// cx.simulate_shared_keystrokes(["5", "d", "j"]).await; +// cx.assert_shared_state(indoc! { "ˇ"}).await; +// } + +// #[gpui::test] +// async fn test_clear_counts(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// The quick brown +// fox juˇmps over +// the lazy dog"}) +// .await; + +// cx.simulate_shared_keystrokes(["4", "escape", "3", "d", "l"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox juˇ over +// the lazy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_zero(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}) +// .await; + +// cx.simulate_shared_keystrokes(["0"]).await; +// cx.assert_shared_state(indoc! {" +// ˇThe quick brown +// fox jumps over +// the lazy dog"}) +// .await; + +// cx.simulate_shared_keystrokes(["1", "0", "l"]).await; +// cx.assert_shared_state(indoc! {" +// The quick ˇbrown +// fox jumps over +// the lazy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_selection_goal(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// ;;ˇ; +// Lorem Ipsum"}) +// .await; + +// cx.simulate_shared_keystrokes(["a", "down", "up", ";", "down", "up"]) +// .await; +// cx.assert_shared_state(indoc! {" +// ;;;;ˇ +// Lorem Ipsum"}) +// .await; +// } + +// #[gpui::test] +// async fn test_wrapped_motions(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_wrap(12).await; + +// cx.set_shared_state(indoc! {" +// aaˇaa +// 😃😃" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j"]).await; +// cx.assert_shared_state(indoc! {" +// aaaa +// 😃ˇ😃" +// }) +// .await; + +// cx.set_shared_state(indoc! {" +// 123456789012aaˇaa +// 123456789012😃😃" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j"]).await; +// cx.assert_shared_state(indoc! {" +// 123456789012aaaa +// 123456789012😃ˇ😃" +// }) +// .await; + +// cx.set_shared_state(indoc! {" +// 123456789012aaˇaa +// 123456789012😃😃" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j"]).await; +// cx.assert_shared_state(indoc! {" +// 123456789012aaaa +// 123456789012😃ˇ😃" +// }) +// .await; + +// cx.set_shared_state(indoc! {" +// 123456789012aaaaˇaaaaaaaa123456789012 +// wow +// 123456789012😃😃😃😃😃😃123456789012" +// }) +// .await; +// cx.simulate_shared_keystrokes(["j", "j"]).await; +// cx.assert_shared_state(indoc! {" +// 123456789012aaaaaaaaaaaa123456789012 +// wow +// 123456789012😃😃ˇ😃😃😃😃123456789012" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_paragraphs_dont_wrap(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// one +// ˇ +// two"}) +// .await; + +// cx.simulate_shared_keystrokes(["}", "}"]).await; +// cx.assert_shared_state(indoc! {" +// one + +// twˇo"}) +// .await; + +// cx.simulate_shared_keystrokes(["{", "{", "{"]).await; +// cx.assert_shared_state(indoc! {" +// ˇone + +// two"}) +// .await; +// } + +// #[gpui::test] +// async fn test_select_all_issue_2170(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state( +// indoc! {" +// defmodule Test do +// def test(a, ˇ[_, _] = b), do: IO.puts('hi') +// end +// "}, +// Mode::Normal, +// ); +// cx.simulate_keystrokes(["g", "a"]); +// cx.assert_state( +// indoc! {" +// defmodule Test do +// def test(a, «[ˇ»_, _] = b), do: IO.puts('hi') +// end +// "}, +// Mode::Visual, +// ); +// } diff --git a/crates/vim2/src/test/neovim_backed_binding_test_context.rs b/crates/vim2/src/test/neovim_backed_binding_test_context.rs new file mode 100644 index 0000000000..15fce99aad --- /dev/null +++ b/crates/vim2/src/test/neovim_backed_binding_test_context.rs @@ -0,0 +1,95 @@ +use std::ops::{Deref, DerefMut}; + +use crate::state::Mode; + +use super::{ExemptionFeatures, NeovimBackedTestContext, SUPPORTED_FEATURES}; + +pub struct NeovimBackedBindingTestContext<'a, const COUNT: usize> { + cx: NeovimBackedTestContext<'a>, + keystrokes_under_test: [&'static str; COUNT], +} + +impl<'a, const COUNT: usize> NeovimBackedBindingTestContext<'a, COUNT> { + pub fn new( + keystrokes_under_test: [&'static str; COUNT], + cx: NeovimBackedTestContext<'a>, + ) -> Self { + Self { + cx, + keystrokes_under_test, + } + } + + pub fn consume(self) -> NeovimBackedTestContext<'a> { + self.cx + } + + pub fn binding( + self, + keystrokes: [&'static str; NEW_COUNT], + ) -> NeovimBackedBindingTestContext<'a, NEW_COUNT> { + self.consume().binding(keystrokes) + } + + pub async fn assert(&mut self, marked_positions: &str) { + self.cx + .assert_binding_matches(self.keystrokes_under_test, marked_positions) + .await; + } + + pub async fn assert_exempted(&mut self, marked_positions: &str, feature: ExemptionFeatures) { + if SUPPORTED_FEATURES.contains(&feature) { + self.cx + .assert_binding_matches(self.keystrokes_under_test, marked_positions) + .await + } + } + + pub fn assert_manual( + &mut self, + initial_state: &str, + mode_before: Mode, + state_after: &str, + mode_after: Mode, + ) { + self.cx.assert_binding( + self.keystrokes_under_test, + initial_state, + mode_before, + state_after, + mode_after, + ); + } + + pub async fn assert_all(&mut self, marked_positions: &str) { + self.cx + .assert_binding_matches_all(self.keystrokes_under_test, marked_positions) + .await + } + + pub async fn assert_all_exempted( + &mut self, + marked_positions: &str, + feature: ExemptionFeatures, + ) { + if SUPPORTED_FEATURES.contains(&feature) { + self.cx + .assert_binding_matches_all(self.keystrokes_under_test, marked_positions) + .await + } + } +} + +impl<'a, const COUNT: usize> Deref for NeovimBackedBindingTestContext<'a, COUNT> { + type Target = NeovimBackedTestContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.cx + } +} + +impl<'a, const COUNT: usize> DerefMut for NeovimBackedBindingTestContext<'a, COUNT> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cx + } +} diff --git a/crates/vim2/src/test/neovim_backed_test_context.rs b/crates/vim2/src/test/neovim_backed_test_context.rs new file mode 100644 index 0000000000..c4a7c52056 --- /dev/null +++ b/crates/vim2/src/test/neovim_backed_test_context.rs @@ -0,0 +1,427 @@ +use editor::scroll::VERTICAL_SCROLL_MARGIN; +use indoc::indoc; +use settings::SettingsStore; +use std::{ + ops::{Deref, DerefMut}, + panic, thread, +}; + +use collections::{HashMap, HashSet}; +use gpui::{geometry::vector::vec2f, ContextHandle}; +use language::language_settings::{AllLanguageSettings, SoftWrap}; +use util::test::marked_text_offsets; + +use super::{neovim_connection::NeovimConnection, NeovimBackedBindingTestContext, VimTestContext}; +use crate::state::Mode; + +pub const SUPPORTED_FEATURES: &[ExemptionFeatures] = &[]; + +/// Enum representing features we have tests for but which don't work, yet. Used +/// to add exemptions and automatically +#[derive(PartialEq, Eq)] +pub enum ExemptionFeatures { + // MOTIONS + // When an operator completes at the end of the file, an extra newline is left + OperatorLastNewlineRemains, + + // OBJECTS + // Resulting position after the operation is slightly incorrect for unintuitive reasons. + IncorrectLandingPosition, + // Operator around the text object at the end of the line doesn't remove whitespace. + AroundObjectLeavesWhitespaceAtEndOfLine, + // Sentence object on empty lines + SentenceOnEmptyLines, + // Whitespace isn't included with text objects at the start of the line + SentenceAtStartOfLineWithWhitespace, + // Whitespace around sentences is slightly incorrect when starting between sentences + AroundSentenceStartingBetweenIncludesWrongWhitespace, + // Non empty selection with text objects in visual mode + NonEmptyVisualTextObjects, + // Sentence Doesn't backtrack when its at the end of the file + SentenceAfterPunctuationAtEndOfFile, +} + +impl ExemptionFeatures { + pub fn supported(&self) -> bool { + SUPPORTED_FEATURES.contains(self) + } +} + +pub struct NeovimBackedTestContext<'a> { + cx: VimTestContext<'a>, + // Lookup for exempted assertions. Keyed by the insertion text, and with a value indicating which + // bindings are exempted. If None, all bindings are ignored for that insertion text. + exemptions: HashMap>>, + neovim: NeovimConnection, + + last_set_state: Option, + recent_keystrokes: Vec, + + is_dirty: bool, +} + +impl<'a> NeovimBackedTestContext<'a> { + pub async fn new(cx: &'a mut gpui::TestAppContext) -> NeovimBackedTestContext<'a> { + // rust stores the name of the test on the current thread. + // We use this to automatically name a file that will store + // the neovim connection's requests/responses so that we can + // run without neovim on CI. + let thread = thread::current(); + let test_name = thread + .name() + .expect("thread is not named") + .split(":") + .last() + .unwrap() + .to_string(); + Self { + cx: VimTestContext::new(cx, true).await, + exemptions: Default::default(), + neovim: NeovimConnection::new(test_name).await, + + last_set_state: None, + recent_keystrokes: Default::default(), + is_dirty: false, + } + } + + pub fn add_initial_state_exemptions( + &mut self, + marked_positions: &str, + missing_feature: ExemptionFeatures, // Feature required to support this exempted test case + ) { + if !missing_feature.supported() { + let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions); + + for cursor_offset in cursor_offsets.iter() { + let mut marked_text = unmarked_text.clone(); + marked_text.insert(*cursor_offset, 'ˇ'); + + // None represents all key bindings being exempted for that initial state + self.exemptions.insert(marked_text, None); + } + } + } + + pub async fn simulate_shared_keystroke(&mut self, keystroke_text: &str) -> ContextHandle { + self.neovim.send_keystroke(keystroke_text).await; + self.simulate_keystroke(keystroke_text) + } + + pub async fn simulate_shared_keystrokes( + &mut self, + keystroke_texts: [&str; COUNT], + ) { + for keystroke_text in keystroke_texts.into_iter() { + self.recent_keystrokes.push(keystroke_text.to_string()); + self.neovim.send_keystroke(keystroke_text).await; + } + self.simulate_keystrokes(keystroke_texts); + } + + pub async fn set_shared_state(&mut self, marked_text: &str) { + let mode = if marked_text.contains("»") { + Mode::Visual + } else { + Mode::Normal + }; + self.set_state(marked_text, mode); + self.last_set_state = Some(marked_text.to_string()); + self.recent_keystrokes = Vec::new(); + self.neovim.set_state(marked_text).await; + self.is_dirty = true; + } + + pub async fn set_shared_wrap(&mut self, columns: u32) { + if columns < 12 { + panic!("nvim doesn't support columns < 12") + } + self.neovim.set_option("wrap").await; + self.neovim + .set_option(&format!("columns={}", columns)) + .await; + + self.update(|cx| { + cx.update_global(|settings: &mut SettingsStore, cx| { + settings.update_user_settings::(cx, |settings| { + settings.defaults.soft_wrap = Some(SoftWrap::PreferredLineLength); + settings.defaults.preferred_line_length = Some(columns); + }); + }) + }) + } + + pub async fn set_scroll_height(&mut self, rows: u32) { + // match Zed's scrolling behavior + self.neovim + .set_option(&format!("scrolloff={}", VERTICAL_SCROLL_MARGIN)) + .await; + // +2 to account for the vim command UI at the bottom. + self.neovim.set_option(&format!("lines={}", rows + 2)).await; + let window = self.window; + let line_height = + self.editor(|editor, cx| editor.style().text.line_height(cx.font_cache())); + + window.simulate_resize(vec2f(1000., (rows as f32) * line_height), &mut self.cx); + } + + pub async fn set_neovim_option(&mut self, option: &str) { + self.neovim.set_option(option).await; + } + + pub async fn assert_shared_state(&mut self, marked_text: &str) { + self.is_dirty = false; + let marked_text = marked_text.replace("•", " "); + let neovim = self.neovim_state().await; + let editor = self.editor_state(); + if neovim == marked_text && neovim == editor { + return; + } + let initial_state = self + .last_set_state + .as_ref() + .unwrap_or(&"N/A".to_string()) + .clone(); + + let message = if neovim != marked_text { + "Test is incorrect (currently expected != neovim_state)" + } else { + "Editor does not match nvim behaviour" + }; + panic!( + indoc! {"{} + # initial state: + {} + # keystrokes: + {} + # currently expected: + {} + # neovim state: + {} + # zed state: + {}"}, + message, + initial_state, + self.recent_keystrokes.join(" "), + marked_text.replace(" \n", "•\n"), + neovim.replace(" \n", "•\n"), + editor.replace(" \n", "•\n") + ) + } + + pub async fn assert_shared_clipboard(&mut self, text: &str) { + let neovim = self.neovim.read_register('"').await; + let editor = self + .platform() + .read_from_clipboard() + .unwrap() + .text() + .clone(); + + if text == neovim && text == editor { + return; + } + + let message = if neovim != text { + "Test is incorrect (currently expected != neovim)" + } else { + "Editor does not match nvim behaviour" + }; + + let initial_state = self + .last_set_state + .as_ref() + .unwrap_or(&"N/A".to_string()) + .clone(); + + panic!( + indoc! {"{} + # initial state: + {} + # keystrokes: + {} + # currently expected: + {} + # neovim clipboard: + {} + # zed clipboard: + {}"}, + message, + initial_state, + self.recent_keystrokes.join(" "), + text, + neovim, + editor + ) + } + + pub async fn neovim_state(&mut self) -> String { + self.neovim.marked_text().await + } + + pub async fn neovim_mode(&mut self) -> Mode { + self.neovim.mode().await.unwrap() + } + + pub async fn assert_state_matches(&mut self) { + self.is_dirty = false; + let neovim = self.neovim_state().await; + let editor = self.editor_state(); + let initial_state = self + .last_set_state + .as_ref() + .unwrap_or(&"N/A".to_string()) + .clone(); + + if neovim != editor { + panic!( + indoc! {"Test failed (zed does not match nvim behaviour) + # initial state: + {} + # keystrokes: + {} + # neovim state: + {} + # zed state: + {}"}, + initial_state, + self.recent_keystrokes.join(" "), + neovim, + editor, + ) + } + } + + pub async fn assert_binding_matches( + &mut self, + keystrokes: [&str; COUNT], + initial_state: &str, + ) { + if let Some(possible_exempted_keystrokes) = self.exemptions.get(initial_state) { + match possible_exempted_keystrokes { + Some(exempted_keystrokes) => { + if exempted_keystrokes.contains(&format!("{keystrokes:?}")) { + // This keystroke was exempted for this insertion text + return; + } + } + None => { + // All keystrokes for this insertion text are exempted + return; + } + } + } + + let _state_context = self.set_shared_state(initial_state).await; + let _keystroke_context = self.simulate_shared_keystrokes(keystrokes).await; + self.assert_state_matches().await; + } + + pub async fn assert_binding_matches_all( + &mut self, + keystrokes: [&str; COUNT], + marked_positions: &str, + ) { + let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions); + + for cursor_offset in cursor_offsets.iter() { + let mut marked_text = unmarked_text.clone(); + marked_text.insert(*cursor_offset, 'ˇ'); + + self.assert_binding_matches(keystrokes, &marked_text).await; + } + } + + pub fn each_marked_position(&self, marked_positions: &str) -> Vec { + let (unmarked_text, cursor_offsets) = marked_text_offsets(marked_positions); + let mut ret = Vec::with_capacity(cursor_offsets.len()); + + for cursor_offset in cursor_offsets.iter() { + let mut marked_text = unmarked_text.clone(); + marked_text.insert(*cursor_offset, 'ˇ'); + ret.push(marked_text) + } + + ret + } + + pub async fn assert_neovim_compatible( + &mut self, + marked_positions: &str, + keystrokes: [&str; COUNT], + ) { + self.set_shared_state(&marked_positions).await; + self.simulate_shared_keystrokes(keystrokes).await; + self.assert_state_matches().await; + } + + pub async fn assert_matches_neovim( + &mut self, + marked_positions: &str, + keystrokes: [&str; COUNT], + result: &str, + ) { + self.set_shared_state(marked_positions).await; + self.simulate_shared_keystrokes(keystrokes).await; + self.assert_shared_state(result).await; + } + + pub async fn assert_binding_matches_all_exempted( + &mut self, + keystrokes: [&str; COUNT], + marked_positions: &str, + feature: ExemptionFeatures, + ) { + if SUPPORTED_FEATURES.contains(&feature) { + self.assert_binding_matches_all(keystrokes, marked_positions) + .await + } + } + + pub fn binding( + self, + keystrokes: [&'static str; COUNT], + ) -> NeovimBackedBindingTestContext<'a, COUNT> { + NeovimBackedBindingTestContext::new(keystrokes, self) + } +} + +impl<'a> Deref for NeovimBackedTestContext<'a> { + type Target = VimTestContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.cx + } +} + +impl<'a> DerefMut for NeovimBackedTestContext<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cx + } +} + +// a common mistake in tests is to call set_shared_state when +// you mean asswert_shared_state. This notices that and lets +// you know. +impl<'a> Drop for NeovimBackedTestContext<'a> { + fn drop(&mut self) { + if self.is_dirty { + panic!("Test context was dropped after set_shared_state before assert_shared_state") + } + } +} + +#[cfg(test)] +mod test { + use gpui::TestAppContext; + + use crate::test::NeovimBackedTestContext; + + #[gpui::test] + async fn neovim_backed_test_context_works(cx: &mut TestAppContext) { + let mut cx = NeovimBackedTestContext::new(cx).await; + cx.assert_state_matches().await; + cx.set_shared_state("This is a tesˇt").await; + cx.assert_state_matches().await; + } +} diff --git a/crates/vim2/src/test/neovim_connection.rs b/crates/vim2/src/test/neovim_connection.rs new file mode 100644 index 0000000000..16c718b857 --- /dev/null +++ b/crates/vim2/src/test/neovim_connection.rs @@ -0,0 +1,591 @@ +use std::path::PathBuf; +#[cfg(feature = "neovim")] +use std::{ + cmp, + ops::{Deref, DerefMut, Range}, +}; + +#[cfg(feature = "neovim")] +use async_compat::Compat; +#[cfg(feature = "neovim")] +use async_trait::async_trait; +#[cfg(feature = "neovim")] +use gpui::keymap_matcher::Keystroke; + +#[cfg(feature = "neovim")] +use language::Point; + +#[cfg(feature = "neovim")] +use nvim_rs::{ + create::tokio::new_child_cmd, error::LoopError, Handler, Neovim, UiAttachOptions, Value, +}; +#[cfg(feature = "neovim")] +use parking_lot::ReentrantMutex; +use serde::{Deserialize, Serialize}; +#[cfg(feature = "neovim")] +use tokio::{ + process::{Child, ChildStdin, Command}, + task::JoinHandle, +}; + +use crate::state::Mode; +use collections::VecDeque; + +// Neovim doesn't like to be started simultaneously from multiple threads. We use this lock +// to ensure we are only constructing one neovim connection at a time. +#[cfg(feature = "neovim")] +static NEOVIM_LOCK: ReentrantMutex<()> = ReentrantMutex::new(()); + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] +pub enum NeovimData { + Put { state: String }, + Key(String), + Get { state: String, mode: Option }, + ReadRegister { name: char, value: String }, + SetOption { value: String }, +} + +pub struct NeovimConnection { + data: VecDeque, + #[cfg(feature = "neovim")] + test_case_id: String, + #[cfg(feature = "neovim")] + nvim: Neovim>, + #[cfg(feature = "neovim")] + _join_handle: JoinHandle>>, + #[cfg(feature = "neovim")] + _child: Child, +} + +impl NeovimConnection { + pub async fn new(test_case_id: String) -> Self { + #[cfg(feature = "neovim")] + let handler = NvimHandler {}; + #[cfg(feature = "neovim")] + let (nvim, join_handle, child) = Compat::new(async { + // Ensure we don't create neovim connections in parallel + let _lock = NEOVIM_LOCK.lock(); + let (nvim, join_handle, child) = new_child_cmd( + &mut Command::new("nvim") + .arg("--embed") + .arg("--clean") + // disable swap (otherwise after about 1000 test runs you run out of swap file names) + .arg("-n") + // disable writing files (just in case) + .arg("-m"), + handler, + ) + .await + .expect("Could not connect to neovim process"); + + nvim.ui_attach(100, 100, &UiAttachOptions::default()) + .await + .expect("Could not attach to ui"); + + // Makes system act a little more like zed in terms of indentation + nvim.set_option("smartindent", nvim_rs::Value::Boolean(true)) + .await + .expect("Could not set smartindent on startup"); + + (nvim, join_handle, child) + }) + .await; + + Self { + #[cfg(feature = "neovim")] + data: Default::default(), + #[cfg(not(feature = "neovim"))] + data: Self::read_test_data(&test_case_id), + #[cfg(feature = "neovim")] + test_case_id, + #[cfg(feature = "neovim")] + nvim, + #[cfg(feature = "neovim")] + _join_handle: join_handle, + #[cfg(feature = "neovim")] + _child: child, + } + } + + // Sends a keystroke to the neovim process. + #[cfg(feature = "neovim")] + pub async fn send_keystroke(&mut self, keystroke_text: &str) { + let mut keystroke = Keystroke::parse(keystroke_text).unwrap(); + + if keystroke.key == "<" { + keystroke.key = "lt".to_string() + } + + let special = keystroke.shift + || keystroke.ctrl + || keystroke.alt + || keystroke.cmd + || keystroke.key.len() > 1; + let start = if special { "<" } else { "" }; + let shift = if keystroke.shift { "S-" } else { "" }; + let ctrl = if keystroke.ctrl { "C-" } else { "" }; + let alt = if keystroke.alt { "M-" } else { "" }; + let cmd = if keystroke.cmd { "D-" } else { "" }; + let end = if special { ">" } else { "" }; + + let key = format!("{start}{shift}{ctrl}{alt}{cmd}{}{end}", keystroke.key); + + self.data + .push_back(NeovimData::Key(keystroke_text.to_string())); + self.nvim + .input(&key) + .await + .expect("Could not input keystroke"); + } + + #[cfg(not(feature = "neovim"))] + pub async fn send_keystroke(&mut self, keystroke_text: &str) { + if matches!(self.data.front(), Some(NeovimData::Get { .. })) { + self.data.pop_front(); + } + assert_eq!( + self.data.pop_front(), + Some(NeovimData::Key(keystroke_text.to_string())), + "operation does not match recorded script. re-record with --features=neovim" + ); + } + + #[cfg(feature = "neovim")] + pub async fn set_state(&mut self, marked_text: &str) { + let (text, selections) = parse_state(&marked_text); + + let nvim_buffer = self + .nvim + .get_current_buf() + .await + .expect("Could not get neovim buffer"); + let lines = text + .split('\n') + .map(|line| line.to_string()) + .collect::>(); + + nvim_buffer + .set_lines(0, -1, false, lines) + .await + .expect("Could not set nvim buffer text"); + + self.nvim + .input("") + .await + .expect("Could not send escape to nvim"); + self.nvim + .input("") + .await + .expect("Could not send escape to nvim"); + + let nvim_window = self + .nvim + .get_current_win() + .await + .expect("Could not get neovim window"); + + if selections.len() != 1 { + panic!("must have one selection"); + } + let selection = &selections[0]; + + let cursor = selection.start; + nvim_window + .set_cursor((cursor.row as i64 + 1, cursor.column as i64)) + .await + .expect("Could not set nvim cursor position"); + + if !selection.is_empty() { + self.nvim + .input("v") + .await + .expect("could not enter visual mode"); + + let cursor = selection.end; + nvim_window + .set_cursor((cursor.row as i64 + 1, cursor.column as i64)) + .await + .expect("Could not set nvim cursor position"); + } + + if let Some(NeovimData::Get { mode, state }) = self.data.back() { + if *mode == Some(Mode::Normal) && *state == marked_text { + return; + } + } + self.data.push_back(NeovimData::Put { + state: marked_text.to_string(), + }) + } + + #[cfg(not(feature = "neovim"))] + pub async fn set_state(&mut self, marked_text: &str) { + if let Some(NeovimData::Get { mode, state: text }) = self.data.front() { + if *mode == Some(Mode::Normal) && *text == marked_text { + return; + } + self.data.pop_front(); + } + assert_eq!( + self.data.pop_front(), + Some(NeovimData::Put { + state: marked_text.to_string() + }), + "operation does not match recorded script. re-record with --features=neovim" + ); + } + + #[cfg(feature = "neovim")] + pub async fn set_option(&mut self, value: &str) { + self.nvim + .command_output(format!("set {}", value).as_str()) + .await + .unwrap(); + + self.data.push_back(NeovimData::SetOption { + value: value.to_string(), + }) + } + + #[cfg(not(feature = "neovim"))] + pub async fn set_option(&mut self, value: &str) { + if let Some(NeovimData::Get { .. }) = self.data.front() { + self.data.pop_front(); + }; + assert_eq!( + self.data.pop_front(), + Some(NeovimData::SetOption { + value: value.to_string(), + }), + "operation does not match recorded script. re-record with --features=neovim" + ); + } + + #[cfg(not(feature = "neovim"))] + pub async fn read_register(&mut self, register: char) -> String { + if let Some(NeovimData::Get { .. }) = self.data.front() { + self.data.pop_front(); + }; + if let Some(NeovimData::ReadRegister { name, value }) = self.data.pop_front() { + if name == register { + return value; + } + } + + panic!("operation does not match recorded script. re-record with --features=neovim") + } + + #[cfg(feature = "neovim")] + pub async fn read_register(&mut self, name: char) -> String { + let value = self + .nvim + .command_output(format!("echo getreg('{}')", name).as_str()) + .await + .unwrap(); + + self.data.push_back(NeovimData::ReadRegister { + name, + value: value.clone(), + }); + + value + } + + #[cfg(feature = "neovim")] + async fn read_position(&mut self, cmd: &str) -> u32 { + self.nvim + .command_output(cmd) + .await + .unwrap() + .parse::() + .unwrap() + } + + #[cfg(feature = "neovim")] + pub async fn state(&mut self) -> (Option, String) { + let nvim_buffer = self + .nvim + .get_current_buf() + .await + .expect("Could not get neovim buffer"); + let text = nvim_buffer + .get_lines(0, -1, false) + .await + .expect("Could not get buffer text") + .join("\n"); + + // nvim columns are 1-based, so -1. + let mut cursor_row = self.read_position("echo line('.')").await - 1; + let mut cursor_col = self.read_position("echo col('.')").await - 1; + let mut selection_row = self.read_position("echo line('v')").await - 1; + let mut selection_col = self.read_position("echo col('v')").await - 1; + let total_rows = self.read_position("echo line('$')").await - 1; + + let nvim_mode_text = self + .nvim + .get_mode() + .await + .expect("Could not get mode") + .into_iter() + .find_map(|(key, value)| { + if key.as_str() == Some("mode") { + Some(value.as_str().unwrap().to_owned()) + } else { + None + } + }) + .expect("Could not find mode value"); + + let mode = match nvim_mode_text.as_ref() { + "i" => Some(Mode::Insert), + "n" => Some(Mode::Normal), + "v" => Some(Mode::Visual), + "V" => Some(Mode::VisualLine), + "\x16" => Some(Mode::VisualBlock), + _ => None, + }; + + let mut selections = Vec::new(); + // Vim uses the index of the first and last character in the selection + // Zed uses the index of the positions between the characters, so we need + // to add one to the end in visual mode. + match mode { + Some(Mode::VisualBlock) if selection_row != cursor_row => { + // in zed we fake a block selecrtion by using multiple cursors (one per line) + // this code emulates that. + // to deal with casees where the selection is not perfectly rectangular we extract + // the content of the selection via the "a register to get the shape correctly. + self.nvim.input("\"aygv").await.unwrap(); + let content = self.nvim.command_output("echo getreg('a')").await.unwrap(); + let lines = content.split("\n").collect::>(); + let top = cmp::min(selection_row, cursor_row); + let left = cmp::min(selection_col, cursor_col); + for row in top..=cmp::max(selection_row, cursor_row) { + let content = if row - top >= lines.len() as u32 { + "" + } else { + lines[(row - top) as usize] + }; + let line_len = self + .read_position(format!("echo strlen(getline({}))", row + 1).as_str()) + .await; + + if left > line_len { + continue; + } + + let start = Point::new(row, left); + let end = Point::new(row, left + content.len() as u32); + if cursor_col >= selection_col { + selections.push(start..end) + } else { + selections.push(end..start) + } + } + } + Some(Mode::Visual) | Some(Mode::VisualLine) | Some(Mode::VisualBlock) => { + if selection_col > cursor_col { + let selection_line_length = + self.read_position("echo strlen(getline(line('v')))").await; + if selection_line_length > selection_col { + selection_col += 1; + } else if selection_row < total_rows { + selection_col = 0; + selection_row += 1; + } + } else { + let cursor_line_length = + self.read_position("echo strlen(getline(line('.')))").await; + if cursor_line_length > cursor_col { + cursor_col += 1; + } else if cursor_row < total_rows { + cursor_col = 0; + cursor_row += 1; + } + } + selections.push( + Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col), + ) + } + Some(Mode::Insert) | Some(Mode::Normal) | None => selections + .push(Point::new(selection_row, selection_col)..Point::new(cursor_row, cursor_col)), + } + + let ranges = encode_ranges(&text, &selections); + let state = NeovimData::Get { + mode, + state: ranges.clone(), + }; + + if self.data.back() != Some(&state) { + self.data.push_back(state.clone()); + } + + (mode, ranges) + } + + #[cfg(not(feature = "neovim"))] + pub async fn state(&mut self) -> (Option, String) { + if let Some(NeovimData::Get { state: raw, mode }) = self.data.front() { + (*mode, raw.to_string()) + } else { + panic!("operation does not match recorded script. re-record with --features=neovim"); + } + } + + pub async fn mode(&mut self) -> Option { + self.state().await.0 + } + + pub async fn marked_text(&mut self) -> String { + self.state().await.1 + } + + fn test_data_path(test_case_id: &str) -> PathBuf { + let mut data_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + data_path.push("test_data"); + data_path.push(format!("{}.json", test_case_id)); + data_path + } + + #[cfg(not(feature = "neovim"))] + fn read_test_data(test_case_id: &str) -> VecDeque { + let path = Self::test_data_path(test_case_id); + let json = std::fs::read_to_string(path).expect( + "Could not read test data. Is it generated? Try running test with '--features neovim'", + ); + + let mut result = VecDeque::new(); + for line in json.lines() { + result.push_back( + serde_json::from_str(line) + .expect("invalid test data. regenerate it with '--features neovim'"), + ); + } + result + } + + #[cfg(feature = "neovim")] + fn write_test_data(test_case_id: &str, data: &VecDeque) { + let path = Self::test_data_path(test_case_id); + let mut json = Vec::new(); + for entry in data { + serde_json::to_writer(&mut json, entry).unwrap(); + json.push(b'\n'); + } + std::fs::create_dir_all(path.parent().unwrap()) + .expect("could not create test data directory"); + std::fs::write(path, json).expect("could not write out test data"); + } +} + +#[cfg(feature = "neovim")] +impl Deref for NeovimConnection { + type Target = Neovim>; + + fn deref(&self) -> &Self::Target { + &self.nvim + } +} + +#[cfg(feature = "neovim")] +impl DerefMut for NeovimConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.nvim + } +} + +#[cfg(feature = "neovim")] +impl Drop for NeovimConnection { + fn drop(&mut self) { + Self::write_test_data(&self.test_case_id, &self.data); + } +} + +#[cfg(feature = "neovim")] +#[derive(Clone)] +struct NvimHandler {} + +#[cfg(feature = "neovim")] +#[async_trait] +impl Handler for NvimHandler { + type Writer = nvim_rs::compat::tokio::Compat; + + async fn handle_request( + &self, + _event_name: String, + _arguments: Vec, + _neovim: Neovim, + ) -> Result { + unimplemented!(); + } + + async fn handle_notify( + &self, + _event_name: String, + _arguments: Vec, + _neovim: Neovim, + ) { + } +} + +#[cfg(feature = "neovim")] +fn parse_state(marked_text: &str) -> (String, Vec>) { + let (text, ranges) = util::test::marked_text_ranges(marked_text, true); + let point_ranges = ranges + .into_iter() + .map(|byte_range| { + let mut point_range = Point::zero()..Point::zero(); + let mut ix = 0; + let mut position = Point::zero(); + for c in text.chars().chain(['\0']) { + if ix == byte_range.start { + point_range.start = position; + } + if ix == byte_range.end { + point_range.end = position; + } + let len_utf8 = c.len_utf8(); + ix += len_utf8; + if c == '\n' { + position.row += 1; + position.column = 0; + } else { + position.column += len_utf8 as u32; + } + } + point_range + }) + .collect::>(); + (text, point_ranges) +} + +#[cfg(feature = "neovim")] +fn encode_ranges(text: &str, point_ranges: &Vec>) -> String { + let byte_ranges = point_ranges + .into_iter() + .map(|range| { + let mut byte_range = 0..0; + let mut ix = 0; + let mut position = Point::zero(); + for c in text.chars().chain(['\0']) { + if position == range.start { + byte_range.start = ix; + } + if position == range.end { + byte_range.end = ix; + } + let len_utf8 = c.len_utf8(); + ix += len_utf8; + if c == '\n' { + position.row += 1; + position.column = 0; + } else { + position.column += len_utf8 as u32; + } + } + byte_range + }) + .collect::>(); + util::test::generate_marked_text(text, &byte_ranges[..], true) +} diff --git a/crates/vim2/src/test/vim_test_context.rs b/crates/vim2/src/test/vim_test_context.rs new file mode 100644 index 0000000000..bcd133f50b --- /dev/null +++ b/crates/vim2/src/test/vim_test_context.rs @@ -0,0 +1,165 @@ +use std::ops::{Deref, DerefMut}; + +use editor::test::{ + editor_lsp_test_context::EditorLspTestContext, editor_test_context::EditorTestContext, +}; +use futures::Future; +use gpui::{Context, View, VisualContext}; +use lsp::request; +use search::BufferSearchBar; + +use crate::{state::Operator, *}; + +pub struct VimTestContext<'a> { + cx: EditorLspTestContext<'a>, +} + +impl<'a> VimTestContext<'a> { + pub async fn new(cx: &'a mut gpui::TestAppContext, enabled: bool) -> VimTestContext<'a> { + let lsp = EditorLspTestContext::new_rust(Default::default(), cx).await; + Self::new_with_lsp(lsp, enabled) + } + + pub async fn new_typescript(cx: &'a mut gpui::TestAppContext) -> VimTestContext<'a> { + Self::new_with_lsp( + EditorLspTestContext::new_typescript(Default::default(), cx).await, + true, + ) + } + + pub fn new_with_lsp(mut cx: EditorLspTestContext<'a>, enabled: bool) -> VimTestContext<'a> { + cx.update(|cx| { + search::init(cx); + crate::init(cx); + command_palette::init(cx); + }); + + cx.update(|cx| { + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings::(cx, |s| *s = Some(enabled)); + }); + settings::KeymapFile::load_asset("keymaps/default.json", cx).unwrap(); + settings::KeymapFile::load_asset("keymaps/vim.json", cx).unwrap(); + }); + + // Setup search toolbars and keypress hook + cx.update_workspace(|workspace, cx| { + observe_keystrokes(cx); + workspace.active_pane().update(cx, |pane, cx| { + pane.toolbar().update(cx, |toolbar, cx| { + let buffer_search_bar = cx.build_view(BufferSearchBar::new); + toolbar.add_item(buffer_search_bar, cx); + // todo!(); + // let project_search_bar = cx.add_view(|_| ProjectSearchBar::new()); + // toolbar.add_item(project_search_bar, cx); + }) + }); + workspace.status_bar().update(cx, |status_bar, cx| { + let vim_mode_indicator = cx.build_view(ModeIndicator::new); + status_bar.add_right_item(vim_mode_indicator, cx); + }); + }); + + Self { cx } + } + + pub fn update_view(&mut self, view: View, update: F) -> R + where + F: FnOnce(&mut T, &mut ViewContext) -> R, + { + self.update_window(self.window, |_, cx| view.update(cx, update)) + .unwrap() + } + + pub fn workspace(&mut self, update: F) -> T + where + F: FnOnce(&mut Workspace, &mut ViewContext) -> T, + { + self.update_window(self.window, |_, cx| self.cx.workspace.update(cx, update)) + .unwrap() + } + + pub fn enable_vim(&mut self) { + self.cx.update(|cx| { + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings::(cx, |s| *s = Some(true)); + }); + }) + } + + pub fn disable_vim(&mut self) { + self.cx.update(|cx| { + cx.update_global(|store: &mut SettingsStore, cx| { + store.update_user_settings::(cx, |s| *s = Some(false)); + }); + }) + } + + pub fn mode(&mut self) -> Mode { + self.cx.read(|cx| cx.global::().state().mode) + } + + pub fn active_operator(&mut self) -> Option { + self.cx + .read(|cx| cx.global::().state().operator_stack.last().copied()) + } + + pub fn set_state(&mut self, text: &str, mode: Mode) { + let window = self.window; + self.cx.set_state(text); + self.update_window(window, |_, cx| { + Vim::update(cx, |vim, cx| { + vim.switch_mode(mode, true, cx); + }) + }); + self.cx.cx.cx.run_until_parked(); + } + + #[track_caller] + pub fn assert_state(&mut self, text: &str, mode: Mode) { + self.assert_editor_state(text); + assert_eq!(self.mode(), mode, "{}", self.assertion_context()); + } + + pub fn assert_binding( + &mut self, + keystrokes: [&str; COUNT], + initial_state: &str, + initial_mode: Mode, + state_after: &str, + mode_after: Mode, + ) { + self.set_state(initial_state, initial_mode); + self.cx.simulate_keystrokes(keystrokes); + self.cx.assert_editor_state(state_after); + assert_eq!(self.mode(), mode_after, "{}", self.assertion_context()); + assert_eq!(self.active_operator(), None, "{}", self.assertion_context()); + } + + pub fn handle_request( + &self, + handler: F, + ) -> futures::channel::mpsc::UnboundedReceiver<()> + where + T: 'static + request::Request, + T::Params: 'static + Send, + F: 'static + Send + FnMut(lsp::Url, T::Params, gpui::AsyncAppContext) -> Fut, + Fut: 'static + Send + Future>, + { + self.cx.handle_request::(handler) + } +} + +impl<'a> Deref for VimTestContext<'a> { + type Target = EditorTestContext<'a>; + + fn deref(&self) -> &Self::Target { + &self.cx + } +} + +impl<'a> DerefMut for VimTestContext<'a> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.cx + } +} diff --git a/crates/vim2/src/utils.rs b/crates/vim2/src/utils.rs new file mode 100644 index 0000000000..797e94b0fa --- /dev/null +++ b/crates/vim2/src/utils.rs @@ -0,0 +1,50 @@ +use editor::{ClipboardSelection, Editor}; +use gpui::{AppContext, ClipboardItem}; +use language::Point; + +pub fn copy_selections_content(editor: &mut Editor, linewise: bool, cx: &mut AppContext) { + let selections = editor.selections.all_adjusted(cx); + let buffer = editor.buffer().read(cx).snapshot(cx); + let mut text = String::new(); + let mut clipboard_selections = Vec::with_capacity(selections.len()); + { + let mut is_first = true; + for selection in selections.iter() { + let mut start = selection.start; + let end = selection.end; + if is_first { + is_first = false; + } else { + text.push_str("\n"); + } + let initial_len = text.len(); + + // if the file does not end with \n, and our line-mode selection ends on + // that line, we will have expanded the start of the selection to ensure it + // contains a newline (so that delete works as expected). We undo that change + // here. + let is_last_line = linewise + && end.row == buffer.max_buffer_row() + && buffer.max_point().column > 0 + && start.row < buffer.max_buffer_row() + && start == Point::new(start.row, buffer.line_len(start.row)); + + if is_last_line { + start = Point::new(start.row + 1, 0); + } + for chunk in buffer.text_for_range(start..end) { + text.push_str(chunk); + } + if is_last_line { + text.push_str("\n"); + } + clipboard_selections.push(ClipboardSelection { + len: text.len() - initial_len, + is_entire_line: linewise, + first_line_indent: buffer.indent_size_for_line(start.row).len, + }); + } + } + + cx.write_to_clipboard(ClipboardItem::new(text).with_metadata(clipboard_selections)); +} diff --git a/crates/vim2/src/vim.rs b/crates/vim2/src/vim.rs new file mode 100644 index 0000000000..4403a8e881 --- /dev/null +++ b/crates/vim2/src/vim.rs @@ -0,0 +1,603 @@ +#[cfg(test)] +mod test; + +mod command; +mod editor_events; +mod insert; +mod mode_indicator; +mod motion; +mod normal; +mod object; +mod state; +mod utils; +mod visual; + +use anyhow::Result; +use collections::{CommandPaletteFilter, HashMap}; +use command_palette::CommandPaletteInterceptor; +use editor::{movement, Editor, EditorEvent, EditorMode}; +use gpui::{ + actions, Action, AppContext, EntityId, KeyContext, Subscription, View, ViewContext, WeakModel, + WeakView, WindowContext, +}; +use language::{CursorShape, Point, Selection, SelectionGoal}; +pub use mode_indicator::ModeIndicator; +use motion::Motion; +use normal::normal_replace; +use serde::Deserialize; +use settings::{update_settings_file, Settings, SettingsStore}; +use state::{EditorState, Mode, Operator, RecordedSelection, WorkspaceState}; +use std::{ops::Range, sync::Arc}; +use visual::{visual_block_motion, visual_replace}; +use workspace::{self, Workspace}; + +use crate::state::ReplayableAction; + +pub struct VimModeSetting(pub bool); + +#[derive(Action, Clone, Deserialize, PartialEq)] +pub struct SwitchMode(pub Mode); + +#[derive(Action, Clone, Deserialize, PartialEq)] +pub struct PushOperator(pub Operator); + +#[derive(Action, Clone, Deserialize, PartialEq)] +struct Number(usize); + +actions!(Tab, Enter, Object, InnerObject, FindForward, FindBackward); +// todo! +// actions!(workspace, [ToggleVimMode]); + +#[derive(Copy, Clone, Debug)] +enum VimEvent { + ModeChanged { mode: Mode }, +} + +pub fn init(cx: &mut AppContext) { + cx.set_global(Vim::default()); + VimModeSetting::register(cx); + + editor_events::init(cx); + normal::init(cx); + 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. + cx.update_global::(|filter, _| { + filter.hidden_namespaces.insert("vim"); + }); + cx.update_global(|vim: &mut Vim, cx: &mut AppContext| { + vim.set_enabled(VimModeSetting::get_global(cx).0, cx) + }); + cx.observe_global::(|cx| { + cx.update_global(|vim: &mut Vim, cx: &mut AppContext| { + vim.set_enabled(VimModeSetting::get_global(cx).0, cx) + }); + }) + .detach(); +} + +pub fn observe_keystrokes(cx: &mut WindowContext) { + // todo!() + + // cx.observe_keystrokes(|_keystroke, result, handled_by, cx| { + // if result == &MatchResult::Pending { + // return true; + // } + // if let Some(handled_by) = handled_by { + // Vim::update(cx, |vim, _| { + // if vim.workspace_state.recording { + // vim.workspace_state + // .recorded_actions + // .push(ReplayableAction::Action(handled_by.boxed_clone())); + + // if vim.workspace_state.stop_recording_after_next_action { + // vim.workspace_state.recording = false; + // vim.workspace_state.stop_recording_after_next_action = false; + // } + // } + // }); + + // // Keystroke is handled by the vim system, so continue forward + // if handled_by.namespace() == "vim" { + // return true; + // } + // } + + // Vim::update(cx, |vim, cx| match vim.active_operator() { + // Some( + // Operator::FindForward { .. } | Operator::FindBackward { .. } | Operator::Replace, + // ) => {} + // Some(_) => { + // vim.clear_operator(cx); + // } + // _ => {} + // }); + // true + // }) + // .detach() +} + +#[derive(Default)] +pub struct Vim { + active_editor: Option>, + editor_subscription: Option, + enabled: bool, + editor_states: HashMap, + workspace_state: WorkspaceState, + default_state: EditorState, +} + +impl Vim { + fn read(cx: &mut AppContext) -> &Self { + cx.default_global() + } + + fn update(cx: &mut WindowContext, update: F) -> S + where + F: FnOnce(&mut Self, &mut WindowContext) -> S, + { + cx.update_global(update) + } + + fn set_active_editor(&mut self, editor: View, cx: &mut WindowContext) { + self.active_editor = Some(editor.clone().downgrade()); + self.editor_subscription = Some(cx.subscribe(&editor, |editor, event, cx| match event { + EditorEvent::SelectionsChanged { local: true } => { + let editor = editor.read(cx); + if editor.leader_peer_id().is_none() { + let newest = editor.selections.newest::(cx); + local_selections_changed(newest, cx); + } + } + EditorEvent::InputIgnored { text } => { + Vim::active_editor_input_ignored(text.clone(), cx); + Vim::record_insertion(text, None, cx) + } + EditorEvent::InputHandled { + text, + utf16_range_to_replace: range_to_replace, + } => Vim::record_insertion(text, range_to_replace.clone(), cx), + _ => {} + })); + + if self.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 + && self.state().mode == Mode::Normal + // When following someone, don't switch vim mode. + && editor.leader_peer_id().is_none() + { + self.switch_mode(Mode::Visual, true, cx); + } + } + + self.sync_vim_settings(cx); + } + + fn record_insertion( + text: &Arc, + range_to_replace: Option>, + cx: &mut WindowContext, + ) { + Vim::update(cx, |vim, _| { + if vim.workspace_state.recording { + vim.workspace_state + .recorded_actions + .push(ReplayableAction::Insertion { + text: text.clone(), + utf16_range_to_replace: range_to_replace, + }); + if vim.workspace_state.stop_recording_after_next_action { + vim.workspace_state.recording = false; + vim.workspace_state.stop_recording_after_next_action = false; + } + } + }); + } + + fn update_active_editor( + &self, + cx: &mut WindowContext, + update: impl FnOnce(&mut Editor, &mut ViewContext) -> S, + ) -> Option { + let editor = self.active_editor.clone()?.upgrade()?; + Some(editor.update(cx, update)) + } + + pub fn start_recording(&mut self, cx: &mut WindowContext) { + if !self.workspace_state.replaying { + self.workspace_state.recording = true; + self.workspace_state.recorded_actions = Default::default(); + self.workspace_state.recorded_count = None; + + let selections = self + .active_editor + .as_ref() + .and_then(|editor| editor.upgrade()) + .map(|editor| { + let editor = editor.read(cx); + ( + editor.selections.oldest::(cx), + editor.selections.newest::(cx), + ) + }); + + if let Some((oldest, newest)) = selections { + self.workspace_state.recorded_selection = match self.state().mode { + Mode::Visual if newest.end.row == newest.start.row => { + RecordedSelection::SingleLine { + cols: newest.end.column - newest.start.column, + } + } + Mode::Visual => RecordedSelection::Visual { + rows: newest.end.row - newest.start.row, + cols: newest.end.column, + }, + Mode::VisualLine => RecordedSelection::VisualLine { + rows: newest.end.row - newest.start.row, + }, + Mode::VisualBlock => RecordedSelection::VisualBlock { + rows: newest.end.row.abs_diff(oldest.start.row), + cols: newest.end.column.abs_diff(oldest.start.column), + }, + _ => RecordedSelection::None, + } + } else { + self.workspace_state.recorded_selection = RecordedSelection::None; + } + } + } + + pub fn stop_recording(&mut self) { + if self.workspace_state.recording { + self.workspace_state.stop_recording_after_next_action = true; + } + } + + pub fn stop_recording_immediately(&mut self, action: Box) { + if self.workspace_state.recording { + self.workspace_state + .recorded_actions + .push(ReplayableAction::Action(action.boxed_clone())); + self.workspace_state.recording = false; + self.workspace_state.stop_recording_after_next_action = false; + } + } + + pub fn record_current_action(&mut self, cx: &mut WindowContext) { + self.start_recording(cx); + self.stop_recording(); + } + + fn switch_mode(&mut self, mode: Mode, leave_selections: bool, cx: &mut WindowContext) { + let state = self.state(); + let last_mode = state.mode; + let prior_mode = state.last_mode; + self.update_state(|state| { + state.last_mode = last_mode; + state.mode = mode; + state.operator_stack.clear(); + }); + if mode != Mode::Insert { + self.take_count(cx); + } + + // todo!() + // cx.emit_global(VimEvent::ModeChanged { mode }); + + // Sync editor settings like clip mode + self.sync_vim_settings(cx); + + if leave_selections { + return; + } + + // Adjust selections + self.update_active_editor(cx, |editor, cx| { + if last_mode != Mode::VisualBlock && last_mode.is_visual() && mode == Mode::VisualBlock + { + visual_block_motion(true, editor, cx, |_, point, goal| Some((point, goal))) + } + + editor.change_selections(None, cx, |s| { + // we cheat with visual block mode and use multiple cursors. + // the cost of this cheat is we need to convert back to a single + // cursor whenever vim would. + if last_mode == Mode::VisualBlock + && (mode != Mode::VisualBlock && mode != Mode::Insert) + { + let tail = s.oldest_anchor().tail(); + let head = s.newest_anchor().head(); + s.select_anchor_ranges(vec![tail..head]); + } else if last_mode == Mode::Insert + && prior_mode == Mode::VisualBlock + && mode != Mode::VisualBlock + { + let pos = s.first_anchor().head(); + s.select_anchor_ranges(vec![pos..pos]) + } + + s.move_with(|map, selection| { + if last_mode.is_visual() && !mode.is_visual() { + let mut point = selection.head(); + if !selection.reversed && !selection.is_empty() { + point = movement::left(map, selection.head()); + } + selection.collapse_to(point, selection.goal) + } else if !last_mode.is_visual() && mode.is_visual() { + if selection.is_empty() { + selection.end = movement::right(map, selection.start); + } + } + }); + }) + }); + } + + fn push_count_digit(&mut self, number: usize, cx: &mut WindowContext) { + if self.active_operator().is_some() { + self.update_state(|state| { + state.post_count = Some(state.post_count.unwrap_or(0) * 10 + number) + }) + } else { + self.update_state(|state| { + state.pre_count = Some(state.pre_count.unwrap_or(0) * 10 + number) + }) + } + // update the keymap so that 0 works + self.sync_vim_settings(cx) + } + + fn take_count(&mut self, cx: &mut WindowContext) -> Option { + if self.workspace_state.replaying { + return self.workspace_state.recorded_count; + } + + let count = if self.state().post_count == None && self.state().pre_count == None { + return None; + } else { + Some(self.update_state(|state| { + state.post_count.take().unwrap_or(1) * state.pre_count.take().unwrap_or(1) + })) + }; + if self.workspace_state.recording { + self.workspace_state.recorded_count = count; + } + self.sync_vim_settings(cx); + count + } + + fn push_operator(&mut self, operator: Operator, cx: &mut WindowContext) { + if matches!( + operator, + Operator::Change | Operator::Delete | Operator::Replace + ) { + self.start_recording(cx) + }; + self.update_state(|state| state.operator_stack.push(operator)); + self.sync_vim_settings(cx); + } + + fn maybe_pop_operator(&mut self) -> Option { + self.update_state(|state| state.operator_stack.pop()) + } + + fn pop_operator(&mut self, cx: &mut WindowContext) -> Operator { + let popped_operator = self.update_state( |state| 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 clear_operator(&mut self, cx: &mut WindowContext) { + self.take_count(cx); + self.update_state(|state| state.operator_stack.clear()); + self.sync_vim_settings(cx); + } + + fn active_operator(&self) -> Option { + self.state().operator_stack.last().copied() + } + + fn active_editor_input_ignored(text: Arc, cx: &mut WindowContext) { + if text.is_empty() { + return; + } + + match Vim::read(cx).active_operator() { + Some(Operator::FindForward { before }) => { + let find = Motion::FindForward { + before, + char: text.chars().next().unwrap(), + }; + Vim::update(cx, |vim, _| { + vim.workspace_state.last_find = Some(find.clone()) + }); + motion::motion(find, cx) + } + Some(Operator::FindBackward { after }) => { + let find = Motion::FindBackward { + after, + char: text.chars().next().unwrap(), + }; + Vim::update(cx, |vim, _| { + vim.workspace_state.last_find = Some(find.clone()) + }); + motion::motion(find, cx) + } + Some(Operator::Replace) => match Vim::read(cx).state().mode { + Mode::Normal => normal_replace(text, cx), + Mode::Visual | Mode::VisualLine | Mode::VisualBlock => visual_replace(text, cx), + _ => Vim::update(cx, |vim, cx| vim.clear_operator(cx)), + }, + _ => {} + } + } + + fn set_enabled(&mut self, enabled: bool, cx: &mut AppContext) { + if self.enabled != enabled { + self.enabled = enabled; + + cx.update_global::(|filter, _| { + if self.enabled { + filter.hidden_namespaces.remove("vim"); + } else { + filter.hidden_namespaces.insert("vim"); + } + }); + + if self.enabled { + cx.set_global::(Box::new(command::command_interceptor)); + } else if cx.has_global::() { + let _ = cx.remove_global::(); + } + + // todo!(); + // cx.update_active_window(|cx| { + // if self.enabled { + // let active_editor = cx + // .root_view() + // .downcast_ref::() + // .and_then(|workspace| workspace.read(cx).active_item(cx)) + // .and_then(|item| item.downcast::()); + // if let Some(active_editor) = active_editor { + // self.set_active_editor(active_editor, cx); + // } + // self.switch_mode(Mode::Normal, false, cx); + // } + // self.sync_vim_settings(cx); + // }); + } + } + + pub fn state(&self) -> &EditorState { + if let Some(active_editor) = self.active_editor.as_ref() { + if let Some(state) = self.editor_states.get(&active_editor.entity_id()) { + return state; + } + } + + &self.default_state + } + + pub fn update_state(&mut self, func: impl FnOnce(&mut EditorState) -> T) -> T { + let mut state = self.state().clone(); + let ret = func(&mut state); + + if let Some(active_editor) = self.active_editor.as_ref() { + self.editor_states.insert(active_editor.entity_id(), state); + } + + ret + } + + fn sync_vim_settings(&self, cx: &mut WindowContext) { + let state = self.state(); + let cursor_shape = state.cursor_shape(); + + self.update_active_editor(cx, |editor, cx| { + if self.enabled && editor.mode() == EditorMode::Full { + editor.set_cursor_shape(cursor_shape, cx); + editor.set_clip_at_line_ends(state.clip_at_line_ends(), cx); + editor.set_collapse_matches(true); + editor.set_input_enabled(!state.vim_controlled()); + editor.set_autoindent(state.should_autoindent()); + editor.selections.line_mode = matches!(state.mode, Mode::VisualLine); + let context_layer = state.keymap_context_layer(); + editor.set_keymap_context_layer::(context_layer, cx); + } else { + // Note: set_collapse_matches is not in unhook_vim_settings, as that method is called on blur, + // but we need collapse_matches to persist when the search bar is focused. + editor.set_collapse_matches(false); + self.unhook_vim_settings(editor, cx); + } + }); + } + + fn unhook_vim_settings(&self, editor: &mut Editor, cx: &mut ViewContext) { + editor.set_cursor_shape(CursorShape::Bar, cx); + editor.set_clip_at_line_ends(false, cx); + editor.set_input_enabled(true); + editor.set_autoindent(true); + editor.selections.line_mode = false; + + // we set the VimEnabled context on all editors so that we + // can distinguish between vim mode and non-vim mode in the BufferSearchBar. + // This is a bit of a hack, but currently the search crate does not depend on vim, + // and it seems nice to keep it that way. + if self.enabled { + let mut context = KeyContext::default(); + context.add("VimEnabled"); + editor.set_keymap_context_layer::(context, cx) + } else { + editor.remove_keymap_context_layer::(cx); + } + } +} + +impl Settings for VimModeSetting { + const KEY: Option<&'static str> = Some("vim_mode"); + + type FileContent = Option; + + fn load( + default_value: &Self::FileContent, + user_values: &[&Self::FileContent], + _: &mut AppContext, + ) -> Result { + Ok(Self(user_values.iter().rev().find_map(|v| **v).unwrap_or( + default_value.ok_or_else(Self::missing_default)?, + ))) + } +} + +fn local_selections_changed(newest: Selection, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + if vim.enabled && vim.state().mode == Mode::Normal && !newest.is_empty() { + if matches!(newest.goal, SelectionGoal::HorizontalRange { .. }) { + vim.switch_mode(Mode::VisualBlock, false, cx); + } else { + vim.switch_mode(Mode::Visual, false, cx) + } + } + }) +} diff --git a/crates/vim2/src/visual.rs b/crates/vim2/src/visual.rs new file mode 100644 index 0000000000..0daa7ed4c4 --- /dev/null +++ b/crates/vim2/src/visual.rs @@ -0,0 +1,1023 @@ +use anyhow::Result; +use std::sync::Arc; + +use collections::HashMap; +use editor::{ + display_map::{DisplaySnapshot, ToDisplayPoint}, + movement, + scroll::autoscroll::Autoscroll, + Bias, DisplayPoint, Editor, +}; +use gpui::{actions, AppContext, ViewContext, WindowContext}; +use language::{Selection, SelectionGoal}; +use workspace::Workspace; + +use crate::{ + motion::{start_of_line, Motion}, + object::Object, + state::{Mode, Operator}, + utils::copy_selections_content, + Vim, +}; + +actions!( + ToggleVisual, + ToggleVisualLine, + ToggleVisualBlock, + VisualDelete, + VisualYank, + OtherEnd, + SelectNext, + SelectPrevious, +); + +pub fn init(cx: &mut AppContext) { + // todo!() + // cx.add_action(|_, _: &ToggleVisual, cx: &mut ViewContext| { + // toggle_mode(Mode::Visual, cx) + // }); + // cx.add_action(|_, _: &ToggleVisualLine, cx: &mut ViewContext| { + // toggle_mode(Mode::VisualLine, cx) + // }); + // cx.add_action( + // |_, _: &ToggleVisualBlock, cx: &mut ViewContext| { + // toggle_mode(Mode::VisualBlock, cx) + // }, + // ); + // cx.add_action(other_end); + // cx.add_action(delete); + // cx.add_action(yank); + + // cx.add_action(select_next); + // cx.add_action(select_previous); +} + +pub fn visual_motion(motion: Motion, times: Option, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + vim.update_active_editor(cx, |editor, cx| { + let text_layout_details = editor.text_layout_details(cx); + if vim.state().mode == Mode::VisualBlock + && !matches!( + motion, + Motion::EndOfLine { + display_lines: false + } + ) + { + let is_up_or_down = matches!(motion, Motion::Up { .. } | Motion::Down { .. }); + visual_block_motion(is_up_or_down, editor, cx, |map, point, goal| { + motion.move_point(map, point, goal, times, &text_layout_details) + }) + } else { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let was_reversed = selection.reversed; + let mut current_head = selection.head(); + + // our motions assume the current character is after the cursor, + // but in (forward) visual mode the current character is just + // before the end of the selection. + + // If the file ends with a newline (which is common) we don't do this. + // so that if you go to the end of such a file you can use "up" to go + // to the previous line and have it work somewhat as expected. + if !selection.reversed + && !selection.is_empty() + && !(selection.end.column() == 0 && selection.end == map.max_point()) + { + current_head = movement::left(map, selection.end) + } + + let Some((new_head, goal)) = motion.move_point( + map, + current_head, + selection.goal, + times, + &text_layout_details, + ) else { + return; + }; + + selection.set_head(new_head, goal); + + // ensure the current character is included in the selection. + if !selection.reversed { + let next_point = if vim.state().mode == Mode::VisualBlock { + movement::saturating_right(map, selection.end) + } else { + movement::right(map, selection.end) + }; + + if !(next_point.column() == 0 && next_point == map.max_point()) { + selection.end = next_point; + } + } + + // vim always ensures the anchor character stays selected. + // if our selection has reversed, we need to move the opposite end + // to ensure the anchor is still selected. + if was_reversed && !selection.reversed { + selection.start = movement::left(map, selection.start); + } else if !was_reversed && selection.reversed { + selection.end = movement::right(map, selection.end); + } + }) + }); + } + }); + }); +} + +pub fn visual_block_motion( + preserve_goal: bool, + editor: &mut Editor, + cx: &mut ViewContext, + mut move_selection: impl FnMut( + &DisplaySnapshot, + DisplayPoint, + SelectionGoal, + ) -> Option<(DisplayPoint, SelectionGoal)>, +) { + let text_layout_details = editor.text_layout_details(cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + let map = &s.display_map(); + let mut head = s.newest_anchor().head().to_display_point(map); + let mut tail = s.oldest_anchor().tail().to_display_point(map); + + let mut head_x = map.x_for_display_point(head, &text_layout_details); + let mut tail_x = map.x_for_display_point(tail, &text_layout_details); + + let (start, end) = match s.newest_anchor().goal { + SelectionGoal::HorizontalRange { start, end } if preserve_goal => (start, end), + SelectionGoal::HorizontalPosition(start) if preserve_goal => (start, start), + _ => (tail_x.0, head_x.0), + }; + let mut goal = SelectionGoal::HorizontalRange { start, end }; + + let was_reversed = tail_x > head_x; + if !was_reversed && !preserve_goal { + head = movement::saturating_left(map, head); + } + + let Some((new_head, _)) = move_selection(&map, head, goal) else { + return; + }; + head = new_head; + head_x = map.x_for_display_point(head, &text_layout_details); + + let is_reversed = tail_x > head_x; + if was_reversed && !is_reversed { + tail = movement::saturating_left(map, tail); + tail_x = map.x_for_display_point(tail, &text_layout_details); + } else if !was_reversed && is_reversed { + tail = movement::saturating_right(map, tail); + tail_x = map.x_for_display_point(tail, &text_layout_details); + } + if !is_reversed && !preserve_goal { + head = movement::saturating_right(map, head); + head_x = map.x_for_display_point(head, &text_layout_details); + } + + let positions = if is_reversed { + head_x..tail_x + } else { + tail_x..head_x + }; + + if !preserve_goal { + goal = SelectionGoal::HorizontalRange { + start: positions.start.0, + end: positions.end.0, + }; + } + + let mut selections = Vec::new(); + let mut row = tail.row(); + + loop { + let layed_out_line = map.layout_row(row, &text_layout_details); + let start = DisplayPoint::new( + row, + layed_out_line.closest_index_for_x(positions.start) as u32, + ); + let mut end = DisplayPoint::new( + row, + layed_out_line.closest_index_for_x(positions.end) as u32, + ); + if end <= start { + if start.column() == map.line_len(start.row()) { + end = start; + } else { + end = movement::saturating_right(map, start); + } + } + + if positions.start <= layed_out_line.width { + let selection = Selection { + id: s.new_selection_id(), + start: start.to_point(map), + end: end.to_point(map), + reversed: is_reversed, + goal: goal.clone(), + }; + + selections.push(selection); + } + if row == head.row() { + break; + } + if tail.row() > head.row() { + row -= 1 + } else { + row += 1 + } + } + + s.select(selections); + }) +} + +pub fn visual_object(object: Object, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + if let Some(Operator::Object { around }) = vim.active_operator() { + vim.pop_operator(cx); + let current_mode = vim.state().mode; + let target_mode = object.target_visual_mode(current_mode); + if target_mode != current_mode { + vim.switch_mode(target_mode, true, cx); + } + + vim.update_active_editor(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let mut head = selection.head(); + + // all our motions assume that the current character is + // after the cursor; however in the case of a visual selection + // the current character is before the cursor. + if !selection.reversed { + head = movement::left(map, head); + } + + if let Some(range) = object.range(map, head, around) { + if !range.is_empty() { + let expand_both_ways = object.always_expands_both_ways() + || selection.is_empty() + || movement::right(map, selection.start) == selection.end; + + if expand_both_ways { + selection.start = range.start; + selection.end = range.end; + } else if selection.reversed { + selection.start = range.start; + } else { + selection.end = range.end; + } + } + } + }); + }); + }); + } + }); +} + +fn toggle_mode(mode: Mode, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + if vim.state().mode == mode { + vim.switch_mode(Mode::Normal, false, cx); + } else { + vim.switch_mode(mode, false, cx); + } + }) +} + +pub fn other_end(_: &mut Workspace, _: &OtherEnd, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.update_active_editor(cx, |editor, cx| { + editor.change_selections(None, cx, |s| { + s.move_with(|_, selection| { + selection.reversed = !selection.reversed; + }) + }) + }) + }); +} + +pub fn delete(_: &mut Workspace, _: &VisualDelete, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.record_current_action(cx); + vim.update_active_editor(cx, |editor, cx| { + let mut original_columns: HashMap<_, _> = Default::default(); + let line_mode = editor.selections.line_mode; + + editor.transact(cx, |editor, cx| { + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + if line_mode { + let mut position = selection.head(); + if !selection.reversed { + position = movement::left(map, position); + } + original_columns.insert(selection.id, position.to_point(map).column); + } + selection.goal = SelectionGoal::None; + }); + }); + copy_selections_content(editor, line_mode, cx); + editor.insert("", cx); + + // Fixup cursor position after the deletion + editor.set_clip_at_line_ends(true, cx); + editor.change_selections(Some(Autoscroll::fit()), cx, |s| { + s.move_with(|map, selection| { + let mut cursor = selection.head().to_point(map); + + if let Some(column) = original_columns.get(&selection.id) { + cursor.column = *column + } + let cursor = map.clip_point(cursor.to_display_point(map), Bias::Left); + selection.collapse_to(cursor, selection.goal) + }); + if vim.state().mode == Mode::VisualBlock { + s.select_anchors(vec![s.first_anchor()]) + } + }); + }) + }); + vim.switch_mode(Mode::Normal, true, cx); + }); +} + +pub fn yank(_: &mut Workspace, _: &VisualYank, cx: &mut ViewContext) { + Vim::update(cx, |vim, cx| { + vim.update_active_editor(cx, |editor, cx| { + let line_mode = editor.selections.line_mode; + copy_selections_content(editor, line_mode, cx); + editor.change_selections(None, cx, |s| { + s.move_with(|map, selection| { + if line_mode { + selection.start = start_of_line(map, false, selection.start); + }; + selection.collapse_to(selection.start, SelectionGoal::None) + }); + if vim.state().mode == Mode::VisualBlock { + s.select_anchors(vec![s.first_anchor()]) + } + }); + }); + vim.switch_mode(Mode::Normal, true, cx); + }); +} + +pub(crate) fn visual_replace(text: Arc, cx: &mut WindowContext) { + Vim::update(cx, |vim, cx| { + vim.stop_recording(); + vim.update_active_editor(cx, |editor, cx| { + editor.transact(cx, |editor, cx| { + let (display_map, selections) = editor.selections.all_adjusted_display(cx); + + // Selections are biased right at the start. So we need to store + // anchors that are biased left so that we can restore the selections + // after the change + let stable_anchors = editor + .selections + .disjoint_anchors() + .into_iter() + .map(|selection| { + let start = selection.start.bias_left(&display_map.buffer_snapshot); + start..start + }) + .collect::>(); + + let mut edits = Vec::new(); + for selection in selections.iter() { + let selection = selection.clone(); + for row_range in + movement::split_display_range_by_lines(&display_map, selection.range()) + { + let range = row_range.start.to_offset(&display_map, Bias::Right) + ..row_range.end.to_offset(&display_map, Bias::Right); + let text = text.repeat(range.len()); + edits.push((range, text)); + } + } + + editor.buffer().update(cx, |buffer, cx| { + buffer.edit(edits, None, cx); + }); + editor.change_selections(None, cx, |s| s.select_ranges(stable_anchors)); + }); + }); + vim.switch_mode(Mode::Normal, false, cx); + }); +} + +pub fn select_next( + _: &mut Workspace, + _: &SelectNext, + cx: &mut ViewContext, +) -> Result<()> { + Vim::update(cx, |vim, cx| { + let count = + vim.take_count(cx) + .unwrap_or_else(|| if vim.state().mode.is_visual() { 1 } else { 2 }); + vim.update_active_editor(cx, |editor, cx| { + for _ in 0..count { + match editor.select_next(&Default::default(), cx) { + Err(a) => return Err(a), + _ => {} + } + } + Ok(()) + }) + }) + .unwrap_or(Ok(())) +} + +pub fn select_previous( + _: &mut Workspace, + _: &SelectPrevious, + cx: &mut ViewContext, +) -> Result<()> { + Vim::update(cx, |vim, cx| { + let count = + vim.take_count(cx) + .unwrap_or_else(|| if vim.state().mode.is_visual() { 1 } else { 2 }); + vim.update_active_editor(cx, |editor, cx| { + for _ in 0..count { + match editor.select_previous(&Default::default(), cx) { + Err(a) => return Err(a), + _ => {} + } + } + Ok(()) + }) + }) + .unwrap_or(Ok(())) +} + +// #[cfg(test)] +// mod test { +// use indoc::indoc; +// use workspace::item::Item; + +// use crate::{ +// state::Mode, +// test::{NeovimBackedTestContext, VimTestContext}, +// }; + +// #[gpui::test] +// async fn test_enter_visual_mode(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "The ˇquick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx)); + +// // entering visual mode should select the character +// // under cursor +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state(indoc! { "The «qˇ»uick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); + +// // forwards motions should extend the selection +// cx.simulate_shared_keystrokes(["w", "j"]).await; +// cx.assert_shared_state(indoc! { "The «quick brown +// fox jumps oˇ»ver +// the lazy dog"}) +// .await; + +// cx.simulate_shared_keystrokes(["escape"]).await; +// assert_eq!(Mode::Normal, cx.neovim_mode().await); +// cx.assert_shared_state(indoc! { "The quick brown +// fox jumps ˇover +// the lazy dog"}) +// .await; + +// // motions work backwards +// cx.simulate_shared_keystrokes(["v", "k", "b"]).await; +// cx.assert_shared_state(indoc! { "The «ˇquick brown +// fox jumps o»ver +// the lazy dog"}) +// .await; + +// // works on empty lines +// cx.set_shared_state(indoc! {" +// a +// ˇ +// b +// "}) +// .await; +// let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx)); +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state(indoc! {" +// a +// « +// ˇ»b +// "}) +// .await; +// cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); + +// // toggles off again +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state(indoc! {" +// a +// ˇ +// b +// "}) +// .await; + +// // works at the end of a document +// cx.set_shared_state(indoc! {" +// a +// b +// ˇ"}) +// .await; + +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state(indoc! {" +// a +// b +// ˇ"}) +// .await; +// assert_eq!(cx.mode(), cx.neovim_mode().await); +// } + +// #[gpui::test] +// async fn test_enter_visual_line_mode(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "The ˇquick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["shift-v"]).await; +// cx.assert_shared_state(indoc! { "The «qˇ»uick brown +// fox jumps over +// the lazy dog"}) +// .await; +// assert_eq!(cx.mode(), cx.neovim_mode().await); +// cx.simulate_shared_keystrokes(["x"]).await; +// cx.assert_shared_state(indoc! { "fox ˇjumps over +// the lazy dog"}) +// .await; + +// // it should work on empty lines +// cx.set_shared_state(indoc! {" +// a +// ˇ +// b"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v"]).await; +// cx.assert_shared_state(indoc! { " +// a +// « +// ˇ»b"}) +// .await; +// cx.simulate_shared_keystrokes(["x"]).await; +// cx.assert_shared_state(indoc! { " +// a +// ˇb"}) +// .await; + +// // it should work at the end of the document +// cx.set_shared_state(indoc! {" +// a +// b +// ˇ"}) +// .await; +// let cursor = cx.update_editor(|editor, cx| editor.pixel_position_of_cursor(cx)); +// cx.simulate_shared_keystrokes(["shift-v"]).await; +// cx.assert_shared_state(indoc! {" +// a +// b +// ˇ"}) +// .await; +// assert_eq!(cx.mode(), cx.neovim_mode().await); +// cx.update_editor(|editor, cx| assert_eq!(cursor, editor.pixel_position_of_cursor(cx))); +// cx.simulate_shared_keystrokes(["x"]).await; +// cx.assert_shared_state(indoc! {" +// a +// ˇb"}) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_delete(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.assert_binding_matches(["v", "w"], "The quick ˇbrown") +// .await; + +// cx.assert_binding_matches(["v", "w", "x"], "The quick ˇbrown") +// .await; +// cx.assert_binding_matches( +// ["v", "w", "j", "x"], +// indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}, +// ) +// .await; +// // Test pasting code copied on delete +// cx.simulate_shared_keystrokes(["j", "p"]).await; +// cx.assert_state_matches().await; + +// let mut cx = cx.binding(["v", "w", "j", "x"]); +// cx.assert_all(indoc! {" +// The ˇquick brown +// fox jumps over +// the ˇlazy dog"}) +// .await; +// let mut cx = cx.binding(["v", "b", "k", "x"]); +// cx.assert_all(indoc! {" +// The ˇquick brown +// fox jumps ˇover +// the ˇlazy dog"}) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_line_delete(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "x"]).await; +// cx.assert_state_matches().await; + +// // Test pasting code copied on delete +// cx.simulate_shared_keystroke("p").await; +// cx.assert_state_matches().await; + +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jumps over +// the laˇzy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "x"]).await; +// cx.assert_state_matches().await; +// cx.assert_shared_clipboard("the lazy dog\n").await; + +// for marked_text in cx.each_marked_position(indoc! {" +// The quˇick brown +// fox jumps over +// the lazy dog"}) +// { +// cx.set_shared_state(&marked_text).await; +// cx.simulate_shared_keystrokes(["shift-v", "j", "x"]).await; +// cx.assert_state_matches().await; +// // Test pasting code copied on delete +// cx.simulate_shared_keystroke("p").await; +// cx.assert_state_matches().await; +// } + +// cx.set_shared_state(indoc! {" +// The ˇlong line +// should not +// crash +// "}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "$", "x"]).await; +// cx.assert_state_matches().await; +// } + +// #[gpui::test] +// async fn test_visual_yank(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("The quick ˇbrown").await; +// cx.simulate_shared_keystrokes(["v", "w", "y"]).await; +// cx.assert_shared_state("The quick ˇbrown").await; +// cx.assert_shared_clipboard("brown").await; + +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await; +// cx.assert_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.assert_shared_clipboard(indoc! {" +// quick brown +// fox jumps o"}) +// .await; + +// cx.set_shared_state(indoc! {" +// The quick brown +// fox jumps over +// the ˇlazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "w", "j", "y"]).await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// fox jumps over +// the ˇlazy dog"}) +// .await; +// cx.assert_shared_clipboard("lazy d").await; +// cx.simulate_shared_keystrokes(["shift-v", "y"]).await; +// cx.assert_shared_clipboard("the lazy dog\n").await; + +// let mut cx = cx.binding(["v", "b", "k", "y"]); +// cx.set_shared_state(indoc! {" +// The ˇquick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["v", "b", "k", "y"]).await; +// cx.assert_shared_state(indoc! {" +// ˇThe quick brown +// fox jumps over +// the lazy dog"}) +// .await; +// cx.assert_clipboard_content(Some("The q")); + +// cx.set_shared_state(indoc! {" +// The quick brown +// fox ˇjumps over +// the lazy dog"}) +// .await; +// cx.simulate_shared_keystrokes(["shift-v", "shift-g", "shift-y"]) +// .await; +// cx.assert_shared_state(indoc! {" +// The quick brown +// ˇfox jumps over +// the lazy dog"}) +// .await; +// cx.assert_shared_clipboard("fox jumps over\nthe lazy dog\n") +// .await; +// } + +// #[gpui::test] +// async fn test_visual_block_mode(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "The ˇquick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v"]).await; +// cx.assert_shared_state(indoc! { +// "The «qˇ»uick brown +// fox jumps over +// the lazy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["2", "down"]).await; +// cx.assert_shared_state(indoc! { +// "The «qˇ»uick brown +// fox «jˇ»umps over +// the «lˇ»azy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["e"]).await; +// cx.assert_shared_state(indoc! { +// "The «quicˇ»k brown +// fox «jumpˇ»s over +// the «lazyˇ» dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["^"]).await; +// cx.assert_shared_state(indoc! { +// "«ˇThe q»uick brown +// «ˇfox j»umps over +// «ˇthe l»azy dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["$"]).await; +// cx.assert_shared_state(indoc! { +// "The «quick brownˇ» +// fox «jumps overˇ» +// the «lazy dogˇ»" +// }) +// .await; +// cx.simulate_shared_keystrokes(["shift-f", " "]).await; +// cx.assert_shared_state(indoc! { +// "The «quickˇ» brown +// fox «jumpsˇ» over +// the «lazy ˇ»dog" +// }) +// .await; + +// // toggling through visual mode works as expected +// cx.simulate_shared_keystrokes(["v"]).await; +// cx.assert_shared_state(indoc! { +// "The «quick brown +// fox jumps over +// the lazy ˇ»dog" +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v"]).await; +// cx.assert_shared_state(indoc! { +// "The «quickˇ» brown +// fox «jumpsˇ» over +// the «lazy ˇ»dog" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "The ˇquick +// brown +// fox +// jumps over the + +// lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "down", "down"]) +// .await; +// cx.assert_shared_state(indoc! { +// "The«ˇ q»uick +// bro«ˇwn» +// foxˇ +// jumps over the + +// lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["down"]).await; +// cx.assert_shared_state(indoc! { +// "The «qˇ»uick +// brow«nˇ» +// fox +// jump«sˇ» over the + +// lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystroke("left").await; +// cx.assert_shared_state(indoc! { +// "The«ˇ q»uick +// bro«ˇwn» +// foxˇ +// jum«ˇps» over the + +// lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["s", "o", "escape"]).await; +// cx.assert_shared_state(indoc! { +// "Theˇouick +// broo +// foxo +// jumo over the + +// lazy dog +// " +// }) +// .await; + +// //https://github.com/zed-industries/community/issues/1950 +// cx.set_shared_state(indoc! { +// "Theˇ quick brown + +// fox jumps over +// the lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["l", "ctrl-v", "j", "j"]) +// .await; +// cx.assert_shared_state(indoc! { +// "The «qˇ»uick brown + +// fox «jˇ»umps over +// the lazy dog +// " +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_block_issue_2123(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "The ˇquick brown +// fox jumps over +// the lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "right", "down"]) +// .await; +// cx.assert_shared_state(indoc! { +// "The «quˇ»ick brown +// fox «juˇ»mps over +// the lazy dog +// " +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_block_insert(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state(indoc! { +// "ˇThe quick brown +// fox jumps over +// the lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "9", "down"]).await; +// cx.assert_shared_state(indoc! { +// "«Tˇ»he quick brown +// «fˇ»ox jumps over +// «tˇ»he lazy dog +// ˇ" +// }) +// .await; + +// cx.simulate_shared_keystrokes(["shift-i", "k", "escape"]) +// .await; +// cx.assert_shared_state(indoc! { +// "ˇkThe quick brown +// kfox jumps over +// kthe lazy dog +// k" +// }) +// .await; + +// cx.set_shared_state(indoc! { +// "ˇThe quick brown +// fox jumps over +// the lazy dog +// " +// }) +// .await; +// cx.simulate_shared_keystrokes(["ctrl-v", "9", "down"]).await; +// cx.assert_shared_state(indoc! { +// "«Tˇ»he quick brown +// «fˇ»ox jumps over +// «tˇ»he lazy dog +// ˇ" +// }) +// .await; +// cx.simulate_shared_keystrokes(["c", "k", "escape"]).await; +// cx.assert_shared_state(indoc! { +// "ˇkhe quick brown +// kox jumps over +// khe lazy dog +// k" +// }) +// .await; +// } + +// #[gpui::test] +// async fn test_visual_object(cx: &mut gpui::TestAppContext) { +// let mut cx = NeovimBackedTestContext::new(cx).await; + +// cx.set_shared_state("hello (in [parˇens] o)").await; +// cx.simulate_shared_keystrokes(["ctrl-v", "l"]).await; +// cx.simulate_shared_keystrokes(["a", "]"]).await; +// cx.assert_shared_state("hello (in «[parens]ˇ» o)").await; +// assert_eq!(cx.mode(), Mode::Visual); +// cx.simulate_shared_keystrokes(["i", "("]).await; +// cx.assert_shared_state("hello («in [parens] oˇ»)").await; + +// cx.set_shared_state("hello in a wˇord again.").await; +// cx.simulate_shared_keystrokes(["ctrl-v", "l", "i", "w"]) +// .await; +// cx.assert_shared_state("hello in a w«ordˇ» again.").await; +// assert_eq!(cx.mode(), Mode::VisualBlock); +// cx.simulate_shared_keystrokes(["o", "a", "s"]).await; +// cx.assert_shared_state("«ˇhello in a word» again.").await; +// assert_eq!(cx.mode(), Mode::Visual); +// } + +// #[gpui::test] +// async fn test_mode_across_command(cx: &mut gpui::TestAppContext) { +// let mut cx = VimTestContext::new(cx, true).await; + +// cx.set_state("aˇbc", Mode::Normal); +// cx.simulate_keystrokes(["ctrl-v"]); +// assert_eq!(cx.mode(), Mode::VisualBlock); +// cx.simulate_keystrokes(["cmd-shift-p", "escape"]); +// assert_eq!(cx.mode(), Mode::VisualBlock); +// } +// } diff --git a/crates/vim2/test_data/neovim_backed_test_context_works.json b/crates/vim2/test_data/neovim_backed_test_context_works.json new file mode 100644 index 0000000000..3ed9f40f88 --- /dev/null +++ b/crates/vim2/test_data/neovim_backed_test_context_works.json @@ -0,0 +1,3 @@ +{"Get":{"state":"ˇ","mode":"Normal"}} +{"Put":{"state":"This is a tesˇt"}} +{"Get":{"state":"This is a tesˇt","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_a.json b/crates/vim2/test_data/test_a.json new file mode 100644 index 0000000000..8094974f98 --- /dev/null +++ b/crates/vim2/test_data/test_a.json @@ -0,0 +1,6 @@ +{"Put":{"state":"The qˇuick"}} +{"Key":"a"} +{"Get":{"state":"The quˇick","mode":"Insert"}} +{"Put":{"state":"The quicˇk"}} +{"Key":"a"} +{"Get":{"state":"The quickˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_b.json b/crates/vim2/test_data/test_b.json new file mode 100644 index 0000000000..4324f9610d --- /dev/null +++ b/crates/vim2/test_data/test_b.json @@ -0,0 +1,54 @@ +{"Put":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-ˇbrown\n\n\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"The quick-ˇbrown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe"}} +{"Key":"b"} +{"Get":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe"}} +{"Key":"b"} +{"Get":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nfox_jumps over\nˇthe"}} +{"Key":"b"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe","mode":"Normal"}} +{"Put":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"ˇThe quick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-ˇbrown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-brown\n\n\nfox_jumps over\nˇthe"}} +{"Key":"shift-b"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_backspace.json b/crates/vim2/test_data/test_backspace.json new file mode 100644 index 0000000000..b11a2562db --- /dev/null +++ b/crates/vim2/test_data/test_backspace.json @@ -0,0 +1,9 @@ +{"Put":{"state":"ˇThe quick\nbrown"}} +{"Key":"backspace"} +{"Get":{"state":"ˇThe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown"}} +{"Key":"backspace"} +{"Get":{"state":"The ˇquick\nbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown"}} +{"Key":"backspace"} +{"Get":{"state":"The quicˇk\nbrown","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_capital_f_and_capital_t.json b/crates/vim2/test_data/test_capital_f_and_capital_t.json new file mode 100644 index 0000000000..8ef45ec623 --- /dev/null +++ b/crates/vim2/test_data/test_capital_f_and_capital_t.json @@ -0,0 +1,570 @@ +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"1"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"1"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"2"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"2"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"3"} +{"Key":"shift-f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ \nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n"}} +{"Key":"3"} +{"Key":"shift-t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n \nˇb\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_cc.json b/crates/vim2/test_data/test_cc.json new file mode 100644 index 0000000000..d4b4a499bb --- /dev/null +++ b/crates/vim2/test_data/test_cc.json @@ -0,0 +1,24 @@ +{"Put":{"state":"ˇ"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The ˇquick"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quˇick\nbrown fox\njumps over"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"ˇ\nbrown fox\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"The quick\nˇ\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"The quick\nbrown fox\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"c"} +{"Key":"c"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_0.json b/crates/vim2/test_data/test_change_0.json new file mode 100644 index 0000000000..90668f4a17 --- /dev/null +++ b/crates/vim2/test_data/test_change_0.json @@ -0,0 +1,8 @@ +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"c"} +{"Key":"0"} +{"Get":{"state":"ˇuick\nbrown fox","mode":"Insert"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"c"} +{"Key":"0"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_b.json b/crates/vim2/test_data/test_change_b.json new file mode 100644 index 0000000000..d43cc04c45 --- /dev/null +++ b/crates/vim2/test_data/test_change_b.json @@ -0,0 +1,24 @@ +{"Put":{"state":"Teˇst Test"}} +{"Key":"c"} +{"Key":"b"} +{"Get":{"state":"ˇst Test","mode":"Insert"}} +{"Put":{"state":"Test ˇtest"}} +{"Key":"c"} +{"Key":"b"} +{"Get":{"state":"ˇtest","mode":"Insert"}} +{"Put":{"state":"Test1 test2 ˇtest3"}} +{"Key":"c"} +{"Key":"b"} +{"Get":{"state":"Test1 ˇtest3","mode":"Insert"}} +{"Put":{"state":"Test test\nˇtest"}} +{"Key":"c"} +{"Key":"b"} +{"Get":{"state":"Test ˇ\ntest","mode":"Insert"}} +{"Put":{"state":"Test test\nˇ\ntest"}} +{"Key":"c"} +{"Key":"b"} +{"Get":{"state":"Test ˇ\n\ntest","mode":"Insert"}} +{"Put":{"state":"Test test-test ˇtest"}} +{"Key":"c"} +{"Key":"shift-b"} +{"Get":{"state":"Test ˇtest","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_backspace.json b/crates/vim2/test_data/test_change_backspace.json new file mode 100644 index 0000000000..508500163b --- /dev/null +++ b/crates/vim2/test_data/test_change_backspace.json @@ -0,0 +1,16 @@ +{"Put":{"state":"Teˇst"}} +{"Key":"c"} +{"Key":"backspace"} +{"Get":{"state":"Tˇst","mode":"Insert"}} +{"Put":{"state":"Tˇest"}} +{"Key":"c"} +{"Key":"backspace"} +{"Get":{"state":"ˇest","mode":"Insert"}} +{"Put":{"state":"ˇTest"}} +{"Key":"c"} +{"Key":"backspace"} +{"Get":{"state":"ˇTest","mode":"Insert"}} +{"Put":{"state":"Test\nˇtest"}} +{"Key":"c"} +{"Key":"backspace"} +{"Get":{"state":"Testˇtest","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_case.json b/crates/vim2/test_data/test_change_case.json new file mode 100644 index 0000000000..10eb93b227 --- /dev/null +++ b/crates/vim2/test_data/test_change_case.json @@ -0,0 +1,23 @@ +{"Put":{"state":"ˇabC\n"}} +{"Key":"~"} +{"Get":{"state":"AˇbC\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"~"} +{"Get":{"state":"ABˇc\n","mode":"Normal"}} +{"Put":{"state":"a😀C«dÉ1*fˇ»\n"}} +{"Key":"~"} +{"Get":{"state":"a😀CˇDé1*F\n","mode":"Normal"}} +{"Key":"~"} +{"Put":{"state":"aˇC😀é1*F\n"}} +{"Key":"4"} +{"Key":"~"} +{"Get":{"state":"ac😀É1ˇ*F\n","mode":"Normal"}} +{"Put":{"state":"abˇC\n"}} +{"Key":"shift-v"} +{"Key":"~"} +{"Get":{"state":"ˇABc\n","mode":"Normal"}} +{"Put":{"state":"ˇaa\nbb\ncc"}} +{"Key":"ctrl-v"} +{"Key":"j"} +{"Key":"~"} +{"Get":{"state":"ˇAa\nBb\ncc","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_change_e.json b/crates/vim2/test_data/test_change_e.json new file mode 100644 index 0000000000..fc9f91fe02 --- /dev/null +++ b/crates/vim2/test_data/test_change_e.json @@ -0,0 +1,24 @@ +{"Put":{"state":"Teˇst Test"}} +{"Key":"c"} +{"Key":"e"} +{"Get":{"state":"Teˇ Test","mode":"Insert"}} +{"Put":{"state":"Tˇest test"}} +{"Key":"c"} +{"Key":"e"} +{"Get":{"state":"Tˇ test","mode":"Insert"}} +{"Put":{"state":"Test teˇst\ntest"}} +{"Key":"c"} +{"Key":"e"} +{"Get":{"state":"Test teˇ\ntest","mode":"Insert"}} +{"Put":{"state":"Test tesˇt\ntest"}} +{"Key":"c"} +{"Key":"e"} +{"Get":{"state":"Test tesˇ","mode":"Insert"}} +{"Put":{"state":"Test test\nˇ\ntest"}} +{"Key":"c"} +{"Key":"e"} +{"Get":{"state":"Test test\nˇ","mode":"Insert"}} +{"Put":{"state":"Test teˇst-test test"}} +{"Key":"c"} +{"Key":"shift-e"} +{"Get":{"state":"Test teˇ test","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_end_of_document.json b/crates/vim2/test_data/test_change_end_of_document.json new file mode 100644 index 0000000000..a3f09e4453 --- /dev/null +++ b/crates/vim2/test_data/test_change_end_of_document.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"c"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"c"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nthe lˇazy"}} +{"Key":"c"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nbrown fox\njumps over\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nˇ"}} +{"Key":"c"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nbrown fox\njumps over\nˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_end_of_line.json b/crates/vim2/test_data/test_change_end_of_line.json new file mode 100644 index 0000000000..44766df85e --- /dev/null +++ b/crates/vim2/test_data/test_change_end_of_line.json @@ -0,0 +1,8 @@ +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"c"} +{"Key":"$"} +{"Get":{"state":"The qˇ\nbrown fox","mode":"Insert"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"c"} +{"Key":"$"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_gg.json b/crates/vim2/test_data/test_change_gg.json new file mode 100644 index 0000000000..f4271f7120 --- /dev/null +++ b/crates/vim2/test_data/test_change_gg.json @@ -0,0 +1,20 @@ +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"c"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ\njumps over\nthe lazy","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nthe lˇazy"}} +{"Key":"c"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over\nthe lazy"}} +{"Key":"c"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ\nbrown fox\njumps over\nthe lazy","mode":"Insert"}} +{"Put":{"state":"ˇ\nbrown fox\njumps over\nthe lazy"}} +{"Key":"c"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ\nbrown fox\njumps over\nthe lazy","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_h.json b/crates/vim2/test_data/test_change_h.json new file mode 100644 index 0000000000..6acfb5d080 --- /dev/null +++ b/crates/vim2/test_data/test_change_h.json @@ -0,0 +1,16 @@ +{"Put":{"state":"Teˇst"}} +{"Key":"c"} +{"Key":"h"} +{"Get":{"state":"Tˇst","mode":"Insert"}} +{"Put":{"state":"Tˇest"}} +{"Key":"c"} +{"Key":"h"} +{"Get":{"state":"ˇest","mode":"Insert"}} +{"Put":{"state":"ˇTest"}} +{"Key":"c"} +{"Key":"h"} +{"Get":{"state":"ˇTest","mode":"Insert"}} +{"Put":{"state":"Test\nˇtest"}} +{"Key":"c"} +{"Key":"h"} +{"Get":{"state":"Test\nˇtest","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_j.json b/crates/vim2/test_data/test_change_j.json new file mode 100644 index 0000000000..827fe18c0d --- /dev/null +++ b/crates/vim2/test_data/test_change_j.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"c"} +{"Key":"j"} +{"Get":{"state":"The quick\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"c"} +{"Key":"j"} +{"Get":{"state":"The quick\nbrown fox\njumps ˇover","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"c"} +{"Key":"j"} +{"Get":{"state":"ˇ\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\nˇ"}} +{"Key":"c"} +{"Key":"j"} +{"Get":{"state":"The quick\nbrown fox\nˇ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_change_k.json b/crates/vim2/test_data/test_change_k.json new file mode 100644 index 0000000000..4f89a82b80 --- /dev/null +++ b/crates/vim2/test_data/test_change_k.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"c"} +{"Key":"k"} +{"Get":{"state":"ˇ\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"c"} +{"Key":"k"} +{"Get":{"state":"The quick\nˇ","mode":"Insert"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"c"} +{"Key":"k"} +{"Get":{"state":"The qˇuick\nbrown fox\njumps over","mode":"Normal"}} +{"Put":{"state":"ˇ\nbrown fox\njumps over"}} +{"Key":"c"} +{"Key":"k"} +{"Get":{"state":"ˇ\nbrown fox\njumps over","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_change_l.json b/crates/vim2/test_data/test_change_l.json new file mode 100644 index 0000000000..378c5dc7ca --- /dev/null +++ b/crates/vim2/test_data/test_change_l.json @@ -0,0 +1,8 @@ +{"Put":{"state":"Teˇst"}} +{"Key":"c"} +{"Key":"l"} +{"Get":{"state":"Teˇt","mode":"Insert"}} +{"Put":{"state":"Tesˇt"}} +{"Key":"c"} +{"Key":"l"} +{"Get":{"state":"Tesˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_sentence_object.json b/crates/vim2/test_data/test_change_sentence_object.json new file mode 100644 index 0000000000..4afbae2713 --- /dev/null +++ b/crates/vim2/test_data/test_change_sentence_object.json @@ -0,0 +1,270 @@ +{"Put":{"state":"ˇThe quick brown? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown?ˇ Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown?ˇFox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? ˇFox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jˇumps! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumpsˇ! Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps!ˇ Over the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇOver the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Ovˇer the lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps! ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over theˇ lazy."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps! ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over the lazyˇ."}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps! ˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy doˇg. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇThe quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. The quick ˇ\nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇ\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The ˇquick brown.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)ˇ]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]ˇ'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'ˇ\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'\" Brown ˇfox jumps. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumpsˇ. "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumps.ˇ "}} +{"Key":"c"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" Brown fox jumps.ˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ? Fox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? ˇFox Jumps! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jˇumps! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumpsˇ! Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps!ˇ Over the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Ovˇer the lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over theˇ lazy."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over the lazyˇ."}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy doˇg. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ. The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ The quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇThe quick \nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. The quick ˇ\nbrown fox jumps over\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The ˇquick brown.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ.)]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)ˇ]'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]ˇ'\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'ˇ\" Brown fox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'\" Brown ˇfox jumps. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumpsˇ. "}} +{"Key":"c"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_surrounding_character_objects.json b/crates/vim2/test_data/test_change_surrounding_character_objects.json new file mode 100644 index 0000000000..2e60b7729b --- /dev/null +++ b/crates/vim2/test_data/test_change_surrounding_character_objects.json @@ -0,0 +1,2380 @@ +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'ˇ'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'ˇ'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''quiˇwn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck broˇ\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''quiˇwn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck broˇ\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`ˇ`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`ˇ`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``quiˇwn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck broˇ\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``quiˇwn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck broˇ\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"ˇ\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"ˇ\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"quiˇwn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck broˇ\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"quiˇwn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck broˇ\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Insert"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Insert"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Insert"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Insert"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox juˇmps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>oe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"<"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox juˇmps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>o"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"c"} +{"Key":"i"} +{"Key":">"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox juˇmps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"<"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox juˇmps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>o"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"c"} +{"Key":"a"} +{"Key":">"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_change_w.json b/crates/vim2/test_data/test_change_w.json new file mode 100644 index 0000000000..586fbdf799 --- /dev/null +++ b/crates/vim2/test_data/test_change_w.json @@ -0,0 +1,28 @@ +{"Put":{"state":"Teˇst"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Teˇ","mode":"Insert"}} +{"Put":{"state":"Tˇest test"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Tˇ test","mode":"Insert"}} +{"Put":{"state":"Testˇ test"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Testˇtest","mode":"Insert"}} +{"Put":{"state":"Test teˇst\ntest"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Test teˇ\ntest","mode":"Insert"}} +{"Put":{"state":"Test tesˇt\ntest"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Test tesˇ\ntest","mode":"Insert"}} +{"Put":{"state":"Test test\nˇ\ntest"}} +{"Key":"c"} +{"Key":"w"} +{"Get":{"state":"Test test\nˇ\ntest","mode":"Insert"}} +{"Put":{"state":"Test teˇst-test test"}} +{"Key":"c"} +{"Key":"shift-w"} +{"Get":{"state":"Test teˇ test","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_change_word_object.json b/crates/vim2/test_data/test_change_word_object.json new file mode 100644 index 0000000000..18baf78c6e --- /dev/null +++ b/crates/vim2/test_data/test_change_word_object.json @@ -0,0 +1,460 @@ +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumpsˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ\n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇfox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-ˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ\n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumpsˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ\n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇfox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n ˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ\n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"c"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brownˇ jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumpsˇ\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-ˇover\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ","mode":"Insert"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brownˇ jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumpsˇ\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ over\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n ˇover\nthe lazy dog \n\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"c"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_clear_counts.json b/crates/vim2/test_data/test_clear_counts.json new file mode 100644 index 0000000000..6ef6b36017 --- /dev/null +++ b/crates/vim2/test_data/test_clear_counts.json @@ -0,0 +1,7 @@ +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"4"} +{"Key":"escape"} +{"Key":"3"} +{"Key":"d"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nfox juˇ over\nthe lazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_comma_semicolon.json b/crates/vim2/test_data/test_comma_semicolon.json new file mode 100644 index 0000000000..8cde887ed1 --- /dev/null +++ b/crates/vim2/test_data/test_comma_semicolon.json @@ -0,0 +1,17 @@ +{"Put":{"state":"ˇone two three four"}} +{"Key":"f"} +{"Key":"o"} +{"Get":{"state":"one twˇo three four","mode":"Normal"}} +{"Key":","} +{"Get":{"state":"ˇone two three four","mode":"Normal"}} +{"Key":"2"} +{"Key":";"} +{"Get":{"state":"one two three fˇour","mode":"Normal"}} +{"Key":"shift-t"} +{"Key":"e"} +{"Get":{"state":"one two threeˇ four","mode":"Normal"}} +{"Key":"3"} +{"Key":";"} +{"Get":{"state":"oneˇ two three four","mode":"Normal"}} +{"Key":","} +{"Get":{"state":"one two thˇree four","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_command_basics.json b/crates/vim2/test_data/test_command_basics.json new file mode 100644 index 0000000000..669d34409f --- /dev/null +++ b/crates/vim2/test_data/test_command_basics.json @@ -0,0 +1,6 @@ +{"Put":{"state":"ˇa\nb\nc"}} +{"Key":":"} +{"Key":"j"} +{"Key":"enter"} +{"Key":"^"} +{"Get":{"state":"ˇa b\nc","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_command_goto.json b/crates/vim2/test_data/test_command_goto.json new file mode 100644 index 0000000000..2f7ed10eeb --- /dev/null +++ b/crates/vim2/test_data/test_command_goto.json @@ -0,0 +1,5 @@ +{"Put":{"state":"ˇa\nb\nc"}} +{"Key":":"} +{"Key":"3"} +{"Key":"enter"} +{"Get":{"state":"a\nb\nˇc","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_command_replace.json b/crates/vim2/test_data/test_command_replace.json new file mode 100644 index 0000000000..13928d5c7e --- /dev/null +++ b/crates/vim2/test_data/test_command_replace.json @@ -0,0 +1,22 @@ +{"Put":{"state":"ˇa\nb\nc"}} +{"Key":":"} +{"Key":"%"} +{"Key":"s"} +{"Key":"/"} +{"Key":"b"} +{"Key":"/"} +{"Key":"d"} +{"Key":"enter"} +{"Get":{"state":"a\nˇd\nc","mode":"Normal"}} +{"Key":":"} +{"Key":"%"} +{"Key":"s"} +{"Key":":"} +{"Key":"."} +{"Key":":"} +{"Key":"\\"} +{"Key":"0"} +{"Key":"\\"} +{"Key":"0"} +{"Key":"enter"} +{"Get":{"state":"aa\ndd\nˇcc","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_command_search.json b/crates/vim2/test_data/test_command_search.json new file mode 100644 index 0000000000..705ce51fb7 --- /dev/null +++ b/crates/vim2/test_data/test_command_search.json @@ -0,0 +1,11 @@ +{"Put":{"state":"ˇa\nb\na\nc"}} +{"Key":":"} +{"Key":"/"} +{"Key":"b"} +{"Key":"enter"} +{"Get":{"state":"a\nˇb\na\nc","mode":"Normal"}} +{"Key":":"} +{"Key":"?"} +{"Key":"a"} +{"Key":"enter"} +{"Get":{"state":"ˇa\nb\na\nc","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_ctrl_d_u.json b/crates/vim2/test_data/test_ctrl_d_u.json new file mode 100644 index 0000000000..4235d8d278 --- /dev/null +++ b/crates/vim2/test_data/test_ctrl_d_u.json @@ -0,0 +1,22 @@ +{"SetOption":{"value":"scrolloff=3"}} +{"SetOption":{"value":"lines=12"}} +{"Put":{"state":"ˇaa\nbb\ncc\ndd\nee\nff\ngg\nhh\nii\njj\nkk\nll\nmm\nnn\noo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz"}} +{"Key":"4"} +{"Key":"j"} +{"Key":"ctrl-d"} +{"Get":{"state":"aa\nbb\ncc\ndd\nee\nff\ngg\nhh\nii\nˇjj\nkk\nll\nmm\nnn\noo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz","mode":"Normal"}} +{"Key":"ctrl-d"} +{"Get":{"state":"aa\nbb\ncc\ndd\nee\nff\ngg\nhh\nii\njj\nkk\nll\nmm\nnn\nˇoo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz","mode":"Normal"}} +{"Key":"g"} +{"Key":"g"} +{"Key":"ctrl-d"} +{"Get":{"state":"aa\nbb\ncc\ndd\nee\nff\ngg\nhh\nˇii\njj\nkk\nll\nmm\nnn\noo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz","mode":"Normal"}} +{"Key":"ctrl-u"} +{"Get":{"state":"aa\nbb\ncc\nˇdd\nee\nff\ngg\nhh\nii\njj\nkk\nll\nmm\nnn\noo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz","mode":"Normal"}} +{"Key":"ctrl-d"} +{"Key":"ctrl-d"} +{"Key":"4"} +{"Key":"j"} +{"Key":"ctrl-u"} +{"Key":"ctrl-u"} +{"Get":{"state":"aa\nbb\ncc\ndd\nee\nff\ngg\nˇhh\nii\njj\nkk\nll\nmm\nnn\noo\npp\nqq\nrr\nss\ntt\nuu\nvv\nww\nxx\nyy\nzz","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_dd.json b/crates/vim2/test_data/test_dd.json new file mode 100644 index 0000000000..c6dc30882e --- /dev/null +++ b/crates/vim2/test_data/test_dd.json @@ -0,0 +1,24 @@ +{"Put":{"state":"ˇ"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"ˇ","mode":"Normal"}} +{"Put":{"state":"The ˇquick"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"ˇ","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"brownˇ fox\njumps over","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"The quick\njumps ˇover","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"The quick\nbrown ˇfox","mode":"Normal"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"The quick\nˇbrown fox","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_0.json b/crates/vim2/test_data/test_delete_0.json new file mode 100644 index 0000000000..10095cefbb --- /dev/null +++ b/crates/vim2/test_data/test_delete_0.json @@ -0,0 +1,8 @@ +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"d"} +{"Key":"0"} +{"Get":{"state":"ˇuick\nbrown fox","mode":"Normal"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"d"} +{"Key":"0"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_b.json b/crates/vim2/test_data/test_delete_b.json new file mode 100644 index 0000000000..932a4c1967 --- /dev/null +++ b/crates/vim2/test_data/test_delete_b.json @@ -0,0 +1,24 @@ +{"Put":{"state":"Teˇst Test"}} +{"Key":"d"} +{"Key":"b"} +{"Get":{"state":"ˇst Test","mode":"Normal"}} +{"Put":{"state":"Test ˇtest"}} +{"Key":"d"} +{"Key":"b"} +{"Get":{"state":"ˇtest","mode":"Normal"}} +{"Put":{"state":"Test1 test2 ˇtest3"}} +{"Key":"d"} +{"Key":"b"} +{"Get":{"state":"Test1 ˇtest3","mode":"Normal"}} +{"Put":{"state":"Test test\nˇtest"}} +{"Key":"d"} +{"Key":"b"} +{"Get":{"state":"Testˇ \ntest","mode":"Normal"}} +{"Put":{"state":"Test test\nˇ\ntest"}} +{"Key":"d"} +{"Key":"b"} +{"Get":{"state":"Testˇ \n\ntest","mode":"Normal"}} +{"Put":{"state":"Test test-test ˇtest"}} +{"Key":"d"} +{"Key":"shift-b"} +{"Get":{"state":"Test ˇtest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_end_of_document.json b/crates/vim2/test_data/test_delete_end_of_document.json new file mode 100644 index 0000000000..863d15aca1 --- /dev/null +++ b/crates/vim2/test_data/test_delete_end_of_document.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"d"} +{"Key":"shift-g"} +{"Get":{"state":"The qˇuick","mode":"Normal"}} +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"d"} +{"Key":"shift-g"} +{"Get":{"state":"The qˇuick","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nthe lˇazy"}} +{"Key":"d"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nbrown fox\njumpsˇ over","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nˇ"}} +{"Key":"d"} +{"Key":"shift-g"} +{"Get":{"state":"The quick\nbrown fox\nˇjumps over","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_end_of_line.json b/crates/vim2/test_data/test_delete_end_of_line.json new file mode 100644 index 0000000000..93f0cc2459 --- /dev/null +++ b/crates/vim2/test_data/test_delete_end_of_line.json @@ -0,0 +1,8 @@ +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"d"} +{"Key":"$"} +{"Get":{"state":"The ˇq\nbrown fox","mode":"Normal"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"d"} +{"Key":"$"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_gg.json b/crates/vim2/test_data/test_delete_gg.json new file mode 100644 index 0000000000..de6aca9665 --- /dev/null +++ b/crates/vim2/test_data/test_delete_gg.json @@ -0,0 +1,20 @@ +{"Put":{"state":"The quick\nbrownˇ fox\njumps over\nthe lazy"}} +{"Key":"d"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"jumpsˇ over\nthe lazy","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps over\nthe lˇazy"}} +{"Key":"d"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over\nthe lazy"}} +{"Key":"d"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"brownˇ fox\njumps over\nthe lazy","mode":"Normal"}} +{"Put":{"state":"ˇ\nbrown fox\njumps over\nthe lazy"}} +{"Key":"d"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇbrown fox\njumps over\nthe lazy","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_h.json b/crates/vim2/test_data/test_delete_h.json new file mode 100644 index 0000000000..cf842a386e --- /dev/null +++ b/crates/vim2/test_data/test_delete_h.json @@ -0,0 +1,16 @@ +{"Put":{"state":"Teˇst"}} +{"Key":"d"} +{"Key":"h"} +{"Get":{"state":"Tˇst","mode":"Normal"}} +{"Put":{"state":"Tˇest"}} +{"Key":"d"} +{"Key":"h"} +{"Get":{"state":"ˇest","mode":"Normal"}} +{"Put":{"state":"ˇTest"}} +{"Key":"d"} +{"Key":"h"} +{"Get":{"state":"ˇTest","mode":"Normal"}} +{"Put":{"state":"Test\nˇtest"}} +{"Key":"d"} +{"Key":"h"} +{"Get":{"state":"Test\nˇtest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_j.json b/crates/vim2/test_data/test_delete_j.json new file mode 100644 index 0000000000..76c2f098d3 --- /dev/null +++ b/crates/vim2/test_data/test_delete_j.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"d"} +{"Key":"j"} +{"Get":{"state":"The quˇick","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"d"} +{"Key":"j"} +{"Get":{"state":"The quick\nbrown fox\njumps ˇover","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"d"} +{"Key":"j"} +{"Get":{"state":"jumpsˇ over","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\nˇ"}} +{"Key":"d"} +{"Key":"j"} +{"Get":{"state":"The quick\nbrown fox\nˇ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_k.json b/crates/vim2/test_data/test_delete_k.json new file mode 100644 index 0000000000..75c032430c --- /dev/null +++ b/crates/vim2/test_data/test_delete_k.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"d"} +{"Key":"k"} +{"Get":{"state":"jumps ˇover","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"d"} +{"Key":"k"} +{"Get":{"state":"The quˇick","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"d"} +{"Key":"k"} +{"Get":{"state":"The qˇuick\nbrown fox\njumps over","mode":"Normal"}} +{"Put":{"state":"ˇbrown fox\njumps over"}} +{"Key":"d"} +{"Key":"k"} +{"Get":{"state":"ˇbrown fox\njumps over","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_l.json b/crates/vim2/test_data/test_delete_l.json new file mode 100644 index 0000000000..60b3a6c9b1 --- /dev/null +++ b/crates/vim2/test_data/test_delete_l.json @@ -0,0 +1,16 @@ +{"Put":{"state":"ˇTest"}} +{"Key":"d"} +{"Key":"l"} +{"Get":{"state":"ˇest","mode":"Normal"}} +{"Put":{"state":"Teˇst"}} +{"Key":"d"} +{"Key":"l"} +{"Get":{"state":"Teˇt","mode":"Normal"}} +{"Put":{"state":"Tesˇt"}} +{"Key":"d"} +{"Key":"l"} +{"Get":{"state":"Teˇs","mode":"Normal"}} +{"Put":{"state":"Tesˇt\ntest"}} +{"Key":"d"} +{"Key":"l"} +{"Get":{"state":"Teˇs\ntest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_left.json b/crates/vim2/test_data/test_delete_left.json new file mode 100644 index 0000000000..a8a242f1f6 --- /dev/null +++ b/crates/vim2/test_data/test_delete_left.json @@ -0,0 +1,15 @@ +{"Put":{"state":"ˇTest"}} +{"Key":"shift-x"} +{"Get":{"state":"ˇTest","mode":"Normal"}} +{"Put":{"state":"Tˇest"}} +{"Key":"shift-x"} +{"Get":{"state":"ˇest","mode":"Normal"}} +{"Put":{"state":"Teˇst"}} +{"Key":"shift-x"} +{"Get":{"state":"Tˇst","mode":"Normal"}} +{"Put":{"state":"Tesˇt"}} +{"Key":"shift-x"} +{"Get":{"state":"Teˇt","mode":"Normal"}} +{"Put":{"state":"Test\nˇtest"}} +{"Key":"shift-x"} +{"Get":{"state":"Test\nˇtest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_next_word_end.json b/crates/vim2/test_data/test_delete_next_word_end.json new file mode 100644 index 0000000000..85615e4d58 --- /dev/null +++ b/crates/vim2/test_data/test_delete_next_word_end.json @@ -0,0 +1,12 @@ +{"Put":{"state":"Test teˇst\ntest"}} +{"Key":"d"} +{"Key":"e"} +{"Get":{"state":"Test tˇe\ntest","mode":"Normal"}} +{"Put":{"state":"Test tesˇt\ntest"}} +{"Key":"d"} +{"Key":"e"} +{"Get":{"state":"Test teˇs","mode":"Normal"}} +{"Put":{"state":"Test teˇst-test test"}} +{"Key":"d"} +{"Key":"shift-e"} +{"Get":{"state":"Test teˇ test","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_sentence_object.json b/crates/vim2/test_data/test_delete_sentence_object.json new file mode 100644 index 0000000000..e45ebd5c4e --- /dev/null +++ b/crates/vim2/test_data/test_delete_sentence_object.json @@ -0,0 +1,270 @@ +{"Put":{"state":"ˇThe quick brown? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Fox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown?ˇ Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown?ˇFox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? ˇFox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jˇumps! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumpsˇ! Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇ Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps!ˇ Over the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇOver the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Ovˇer the lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ ","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over theˇ lazy."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ ","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over the lazyˇ."}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumps!ˇ ","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy doˇg. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ The quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇThe quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ \n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. The quick ˇ\nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ \n","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)ˇ]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]ˇ'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'ˇ\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"ˇ Brown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'\" Brown ˇfox jumps. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumpsˇ. "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" ˇ ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumps.ˇ "}} +{"Key":"d"} +{"Key":"i"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\" Brown fox jumpsˇ.","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ? Fox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇFox Jumps! Over the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? ˇFox Jumps! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jˇumps! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumpsˇ! Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? ˇOver the lazy.","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps!ˇ Over the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumpsˇ!","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Ovˇer the lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumpsˇ!","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over theˇ lazy."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumpsˇ!","mode":"Normal"}} +{"Put":{"state":"The quick brown? Fox Jumps! Over the lazyˇ."}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown? Fox Jumpsˇ!","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ\nfox jumps over\nthe lazy dog. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy doˇg. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ. The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇThe quick \nbrown fox jumps over\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog.ˇ The quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ.\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. ˇThe quick \nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ.\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe lazy dog. The quick ˇ\nbrown fox jumps over\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe lazy dogˇ.\n","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ.)]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)ˇ]'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]ˇ'\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'ˇ\" Brown fox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"ˇBrown fox jumps. ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'\" Brown ˇfox jumps. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\"ˇ ","mode":"Normal"}} +{"Put":{"state":"The quick brown.)]'\" Brown fox jumpsˇ. "}} +{"Key":"d"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"The quick brown.)]'\"ˇ ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_surrounding_character_objects.json b/crates/vim2/test_data/test_delete_surrounding_character_objects.json new file mode 100644 index 0000000000..a468b612d9 --- /dev/null +++ b/crates/vim2/test_data/test_delete_surrounding_character_objects.json @@ -0,0 +1,2372 @@ +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'ˇ'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''ˇ'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'ˇ'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'ˇ'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇ'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''quiˇwn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck brˇo\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'ˇe ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ˇ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Thˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e 'ˇ'qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''ˇqui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''quˇi'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e 'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ˇck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''quiˇwn'\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck broˇ'wn'\n'fox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck brˇo\n'fox jumps ov'er\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'ˇfox jumps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox juˇmps ov'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ovˇ'er\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\nˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'ˇer\nthe lazy d'o'g","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe ˇlazy d'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇ'o'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'ˇo'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'oˇ'g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"'"} +{"Get":{"state":"Th'e ''qui'ck bro'wn'\n'fox jumps ov'er\nthe lazy d'o'ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`ˇ`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``ˇ`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`ˇ`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`ˇ`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇ`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``quiˇwn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck brˇo\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`ˇe ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ˇ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Thˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e `ˇ`qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``ˇqui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``quˇi`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e `ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ˇck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``quiˇwn`\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck broˇ`wn`\n`fox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck brˇo\n`fox jumps ov`er\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`ˇfox jumps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox juˇmps ov`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ovˇ`er\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\nˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`ˇer\nthe lazy d`o`g","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe ˇlazy d`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇ`o`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`ˇo`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`oˇ`g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"`"} +{"Get":{"state":"Th`e ``qui`ck bro`wn`\n`fox jumps ov`er\nthe lazy d`o`ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"ˇ\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"ˇ\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"ˇ\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇ\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇ\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"quiˇwn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck brˇo\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"ˇe \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e ˇ\"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Thˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"ˇ\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"ˇqui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"quˇi\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ˇck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"quiˇwn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck broˇ\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck brˇo\n\"fox jumps ov\"er\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"ˇfox jumps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox juˇmps ov\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ovˇ\"er\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\nˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"ˇer\nthe lazy d\"o\"g","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe ˇlazy d\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇ\"o\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"ˇo\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"oˇ\"g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy dˇg","mode":"Normal"}} +{"Put":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"Th\"e \"\"qui\"ck bro\"wn\"\n\"fox jumps ov\"er\nthe lazy d\"o\"ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇ)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"("} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"ˇTh)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)ˇe ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ˇ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e (ˇ)qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()ˇqui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()quˇi(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ˇck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck broˇ)wn(\n)fox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()quiˇwn(\n)fox jumps ov(er\nthe lazy d)o(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)ˇfox jumps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox juˇmps ov(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇ(er\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(ˇer\nthe lazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe ˇlazy d)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy dˇ)o(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ovˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)ˇo(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)oˇ(g","mode":"Normal"}} +{"Put":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":")"} +{"Get":{"state":"Th)e ()qui(ck bro)wn(\n)fox jumps ov(er\nthe lazy d)o(ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇ]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"["} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"ˇTh]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]ˇe []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e ˇ[]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e [ˇ]qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []ˇqui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []quˇi[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ˇck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck broˇ]wn[\n]fox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []quiˇwn[\n]fox jumps ov[er\nthe lazy d]o[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]ˇfox jumps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox juˇmps ov[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇ[er\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[ˇer\nthe lazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe ˇlazy d]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy dˇ]o[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ovˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]ˇo[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]oˇ[g","mode":"Normal"}} +{"Put":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"Th]e []qui[ck bro]wn[\n]fox jumps ov[er\nthe lazy d]o[ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇ}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"{"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"ˇTh}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}ˇe {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e ˇ{}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {ˇ}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}ˇqui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}quˇi{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ˇck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck broˇ}wn{\n}fox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}quiˇwn{\n}fox jumps ov{er\nthe lazy d}o{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}ˇfox jumps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox juˇmps ov{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇ{er\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{ˇer\nthe lazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe ˇlazy d}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy dˇ}o{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ovˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}ˇo{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}oˇ{g","mode":"Normal"}} +{"Put":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"}"} +{"Get":{"state":"Th}e {}qui{ck bro}wn{\n}fox jumps ov{er\nthe lazy d}o{ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoe <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox juˇmps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>oe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"<"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <ˇ>quiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>qui<ˇ>wn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox juˇmps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>o"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ov<ˇ>oe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"d"} +{"Key":"i"} +{"Key":">"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovoe ˇquiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovoe <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox juˇmps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>oe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"<"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} +{"Put":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"ˇTh>e <>quiwn<\n>fox jumps ovoˇe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe ˇ<>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe <ˇ>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e ˇquiwn<\n>fox jumps ovoe <>ˇquiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quˇiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>qui<ˇck bro>wn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiˇwn<\n>fox jumps ovoe <>quiwn<\n>ˇfox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox juˇmps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov<ˇer\nthe lazy d>o"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ovˇo"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovˇoe <>quiwn<\n>fox jumps ov"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ove <>quiwn<\n>fox jumps ovo<ˇg"}} +{"Key":"d"} +{"Key":"a"} +{"Key":">"} +{"Get":{"state":"Th>e <>quiwn<\n>fox jumps ovo<ˇg","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_to_end_of_line.json b/crates/vim2/test_data/test_delete_to_end_of_line.json new file mode 100644 index 0000000000..e15d5d0c4a --- /dev/null +++ b/crates/vim2/test_data/test_delete_to_end_of_line.json @@ -0,0 +1,6 @@ +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"shift-d"} +{"Get":{"state":"The ˇq\nbrown fox","mode":"Normal"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"shift-d"} +{"Get":{"state":"The quick\nˇ\nbrown fox","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_w.json b/crates/vim2/test_data/test_delete_w.json new file mode 100644 index 0000000000..e5e48ca444 --- /dev/null +++ b/crates/vim2/test_data/test_delete_w.json @@ -0,0 +1,28 @@ +{"Put":{"state":"Test tesˇt\n test"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Test teˇs\n test","mode":"Normal"}} +{"Put":{"state":"Teˇst"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Tˇe","mode":"Normal"}} +{"Put":{"state":"Tˇest test"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Tˇtest","mode":"Normal"}} +{"Put":{"state":"Test teˇst\ntest"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Test tˇe\ntest","mode":"Normal"}} +{"Put":{"state":"Test tesˇt\ntest"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Test teˇs\ntest","mode":"Normal"}} +{"Put":{"state":"Test test\nˇ\ntest"}} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"Test test\nˇtest","mode":"Normal"}} +{"Put":{"state":"Test teˇst-test test"}} +{"Key":"d"} +{"Key":"shift-w"} +{"Get":{"state":"Test teˇtest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_with_counts.json b/crates/vim2/test_data/test_delete_with_counts.json new file mode 100644 index 0000000000..de19c5d29d --- /dev/null +++ b/crates/vim2/test_data/test_delete_with_counts.json @@ -0,0 +1,16 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"d"} +{"Key":"2"} +{"Key":"d"} +{"Get":{"state":"the ˇlazy dog","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"2"} +{"Key":"d"} +{"Key":"d"} +{"Get":{"state":"the ˇlazy dog","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe moon,\na star, and\nthe lazy dog"}} +{"Key":"2"} +{"Key":"d"} +{"Key":"2"} +{"Key":"d"} +{"Get":{"state":"the ˇlazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_delete_word_object.json b/crates/vim2/test_data/test_delete_word_object.json new file mode 100644 index 0000000000..9c11d89a12 --- /dev/null +++ b/crates/vim2/test_data/test_delete_word_object.json @@ -0,0 +1,460 @@ +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick browˇn\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumpsˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy doˇg\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick browˇn\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ\n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇfox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-ˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy doˇg\n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick ˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick browˇn\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumpsˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy doˇg\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick browˇn\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ\n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇfox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n ˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy doˇg\n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quickˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quickˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brownˇ jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumpˇs\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy doˇg\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-ˇover\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy doˇg\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nˇthe lazy dog ","mode":"Normal"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quickˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quickˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brownˇ jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox ˇover\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumpˇs\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy doˇg\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ over\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n ˇover\nthe lazy dog \n\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy doˇg\n","mode":"Normal"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"d"} +{"Key":"a"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nˇthe lazy dog ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_dot_repeat.json b/crates/vim2/test_data/test_dot_repeat.json new file mode 100644 index 0000000000..331ef52ecb --- /dev/null +++ b/crates/vim2/test_data/test_dot_repeat.json @@ -0,0 +1,38 @@ +{"Put":{"state":"ˇhello"}} +{"Key":"o"} +{"Key":"w"} +{"Key":"o"} +{"Key":"r"} +{"Key":"l"} +{"Key":"d"} +{"Key":"escape"} +{"Get":{"state":"hello\nworlˇd","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"hello\nworld\nworlˇd","mode":"Normal"}} +{"Key":"^"} +{"Key":"d"} +{"Key":"f"} +{"Key":"o"} +{"Key":"g"} +{"Key":"g"} +{"Key":"."} +{"Get":{"state":"ˇ\nworld\nrld","mode":"Normal"}} +{"Key":"j"} +{"Key":"y"} +{"Key":"y"} +{"Key":"p"} +{"Key":"shift-g"} +{"Key":"y"} +{"Key":"y"} +{"Key":"."} +{"Get":{"state":"\nworld\nworld\nrld\nˇrld","mode":"Normal"}} +{"Put":{"state":"ˇthe quick brown fox"}} +{"Key":"2"} +{"Key":"~"} +{"Key":"."} +{"Put":{"state":"THE ˇquick brown fox"}} +{"Key":"3"} +{"Key":"."} +{"Put":{"state":"THE QUIˇck brown fox"}} +{"Key":"."} +{"Get":{"state":"THE QUICK ˇbrown fox","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_end_of_document.json b/crates/vim2/test_data/test_end_of_document.json new file mode 100644 index 0000000000..2ad056170c --- /dev/null +++ b/crates/vim2/test_data/test_end_of_document.json @@ -0,0 +1,15 @@ +{"Put":{"state":"The qˇuick\n\nbrown fox jumps\nover the lazy dog"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\nover ˇthe lazy dog","mode":"Normal"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\nover ˇthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick\n\nbrown fox jumps\nover the laˇzy dog"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\nover the laˇzy dog","mode":"Normal"}} +{"Put":{"state":"\n\nbrown fox jumps\nover the laˇzy dog"}} +{"Key":"shift-g"} +{"Get":{"state":"\n\nbrown fox jumps\nover the laˇzy dog","mode":"Normal"}} +{"Put":{"state":"ˇ\n\nbrown fox jumps\nover the lazydog"}} +{"Key":"2"} +{"Key":"shift-g"} +{"Get":{"state":"\nˇ\nbrown fox jumps\nover the lazydog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_end_of_word.json b/crates/vim2/test_data/test_end_of_word.json new file mode 100644 index 0000000000..06f80dc245 --- /dev/null +++ b/crates/vim2/test_data/test_end_of_word.json @@ -0,0 +1,32 @@ +{"Put":{"state":"Thˇe quick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"e"} +{"Get":{"state":"The quicˇk-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quick-browˇn\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumpˇs over\nthe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps oveˇr\nthe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Key":"e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Put":{"state":"Thˇe quick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-browˇn\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quicˇk-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-browˇn\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-browˇn\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumpˇs over\nthe","mode":"Normal"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps oveˇr\nthe","mode":"Normal"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Key":"shift-e"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_enter.json b/crates/vim2/test_data/test_enter.json new file mode 100644 index 0000000000..c010a1ffd2 --- /dev/null +++ b/crates/vim2/test_data/test_enter.json @@ -0,0 +1,11 @@ +{"Put":{"state":"ˇThe quick brown\nfox jumps"}} +{"Key":"enter"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} +{"Put":{"state":"The qˇuick brown\nfox jumps"}} +{"Key":"enter"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} +{"Put":{"state":"The quick broˇwn\nfox jumps"}} +{"Key":"enter"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} +{"Key":"enter"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_enter_visual_line_mode.json b/crates/vim2/test_data/test_enter_visual_line_mode.json new file mode 100644 index 0000000000..bf14ae2495 --- /dev/null +++ b/crates/vim2/test_data/test_enter_visual_line_mode.json @@ -0,0 +1,15 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Get":{"state":"The «qˇ»uick brown\nfox jumps over\nthe lazy dog","mode":"VisualLine"}} +{"Key":"x"} +{"Get":{"state":"fox ˇjumps over\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"a\nˇ\nb"}} +{"Key":"shift-v"} +{"Get":{"state":"a\n«\nˇ»b","mode":"VisualLine"}} +{"Key":"x"} +{"Get":{"state":"a\nˇb","mode":"Normal"}} +{"Put":{"state":"a\nb\nˇ"}} +{"Key":"shift-v"} +{"Get":{"state":"a\nb\nˇ","mode":"VisualLine"}} +{"Key":"x"} +{"Get":{"state":"a\nˇb","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_enter_visual_mode.json b/crates/vim2/test_data/test_enter_visual_mode.json new file mode 100644 index 0000000000..090e35cc5d --- /dev/null +++ b/crates/vim2/test_data/test_enter_visual_mode.json @@ -0,0 +1,20 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Get":{"state":"The «qˇ»uick brown\nfox jumps over\nthe lazy dog","mode":"Visual"}} +{"Key":"w"} +{"Key":"j"} +{"Get":{"state":"The «quick brown\nfox jumps oˇ»ver\nthe lazy dog","mode":"Visual"}} +{"Key":"escape"} +{"Get":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog","mode":"Normal"}} +{"Key":"v"} +{"Key":"k"} +{"Key":"b"} +{"Get":{"state":"The «ˇquick brown\nfox jumps o»ver\nthe lazy dog","mode":"Visual"}} +{"Put":{"state":"a\nˇ\nb\n"}} +{"Key":"v"} +{"Get":{"state":"a\n«\nˇ»b\n","mode":"Visual"}} +{"Key":"v"} +{"Get":{"state":"a\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"a\nb\nˇ"}} +{"Key":"v"} +{"Get":{"state":"a\nb\nˇ","mode":"Visual"}} diff --git a/crates/vim2/test_data/test_f_and_t.json b/crates/vim2/test_data/test_f_and_t.json new file mode 100644 index 0000000000..2d2a358452 --- /dev/null +++ b/crates/vim2/test_data/test_f_and_t.json @@ -0,0 +1,557 @@ +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"1"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaˇab b bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇ bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇ bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n ˇ baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaaˇ bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaaˇ bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaaˇ bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"1"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"2"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇ bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇ bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaaˇ bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"2"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"3"} +{"Key":"f"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} +{"Put":{"state":"ˇaaab b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇ bb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaaˇb b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaabˇ b bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab ˇb bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab bˇ bb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaˇabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b ˇbb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bˇb aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bbˇ aaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aˇaabaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaaˇbaaa\n baaa bbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\nˇ baaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n ˇbaaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n bˇaaa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaˇa bbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa ˇbbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bˇbb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbˇb\n\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\nˇ\nb\n","mode":"Normal"}} +{"Put":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n"}} +{"Key":"3"} +{"Key":"t"} +{"Key":"b"} +{"Get":{"state":"aaab b bb aaabaaa\n baaa bbb\n\nˇb\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_folds.json b/crates/vim2/test_data/test_folds.json new file mode 100644 index 0000000000..668df5ce26 --- /dev/null +++ b/crates/vim2/test_data/test_folds.json @@ -0,0 +1,23 @@ +{"SetOption":{"value":"foldmethod=manual"}} +{"Put":{"state":"fn boop() {\n ˇbarp()\n bazp()\n}\n"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"z"} +{"Key":"f"} +{"Key":"escape"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇfn boop() {\n barp()\n bazp()\n}\n","mode":"Normal"}} +{"Key":"j"} +{"Key":"j"} +{"Get":{"state":"fn boop() {\n barp()\n bazp()\nˇ}\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"k"} +{"Get":{"state":"ˇfn boop() {\n barp()\n bazp()\n}\n","mode":"Normal"}} +{"Key":"down"} +{"Key":"y"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":" barp()\n bazp()\n"}} +{"Key":"z"} +{"Key":"o"} +{"Get":{"state":"fn boop() {\nˇ barp()\n bazp()\n}\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_folds_panic.json b/crates/vim2/test_data/test_folds_panic.json new file mode 100644 index 0000000000..3e5e337dcb --- /dev/null +++ b/crates/vim2/test_data/test_folds_panic.json @@ -0,0 +1,13 @@ +{"SetOption":{"value":"foldmethod=manual"}} +{"Put":{"state":"fn boop() {\n ˇbarp()\n bazp()\n}\n"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"z"} +{"Key":"f"} +{"Key":"escape"} +{"Key":"g"} +{"Key":"g"} +{"Key":"5"} +{"Key":"d"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_gg.json b/crates/vim2/test_data/test_gg.json new file mode 100644 index 0000000000..7cc8291b13 --- /dev/null +++ b/crates/vim2/test_data/test_gg.json @@ -0,0 +1,21 @@ +{"Put":{"state":"The qˇuick\n\nbrown fox jumps\nover the lazy dog"}} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"The qˇuick\n\nbrown fox jumps\nover the lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick\n\nbrown fox jumps\nover ˇthe lazy dog"}} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"The qˇuick\n\nbrown fox jumps\nover the lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick\n\nbrown fox jumps\nover the laˇzy dog"}} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"The quicˇk\n\nbrown fox jumps\nover the lazy dog","mode":"Normal"}} +{"Put":{"state":"\n\nbrown fox jumps\nover the laˇzy dog"}} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"ˇ\n\nbrown fox jumps\nover the lazy dog","mode":"Normal"}} +{"Put":{"state":"ˇ\n\nbrown fox jumps\nover the lazydog"}} +{"Key":"2"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"\nˇ\nbrown fox jumps\nover the lazydog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_h.json b/crates/vim2/test_data/test_h.json new file mode 100644 index 0000000000..4cdf210326 --- /dev/null +++ b/crates/vim2/test_data/test_h.json @@ -0,0 +1,9 @@ +{"Put":{"state":"ˇThe quick\nbrown"}} +{"Key":"h"} +{"Get":{"state":"ˇThe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown"}} +{"Key":"h"} +{"Get":{"state":"The ˇquick\nbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown"}} +{"Key":"h"} +{"Get":{"state":"The quick\nˇbrown","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_h_through_unicode.json b/crates/vim2/test_data/test_h_through_unicode.json new file mode 100644 index 0000000000..95b18396d0 --- /dev/null +++ b/crates/vim2/test_data/test_h_through_unicode.json @@ -0,0 +1,12 @@ +{"Put":{"state":"Testˇ├──┐Test"}} +{"Key":"h"} +{"Get":{"state":"Tesˇt├──┐Test","mode":"Normal"}} +{"Put":{"state":"Test├ˇ──┐Test"}} +{"Key":"h"} +{"Get":{"state":"Testˇ├──┐Test","mode":"Normal"}} +{"Put":{"state":"Test├──ˇ┐Test"}} +{"Key":"h"} +{"Get":{"state":"Test├─ˇ─┐Test","mode":"Normal"}} +{"Put":{"state":"Test├──┐ˇTest"}} +{"Key":"h"} +{"Get":{"state":"Test├──ˇ┐Test","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_increment.json b/crates/vim2/test_data/test_increment.json new file mode 100644 index 0000000000..fe893bca97 --- /dev/null +++ b/crates/vim2/test_data/test_increment.json @@ -0,0 +1,16 @@ +{"Put":{"state":"1ˇ2\n"}} +{"Key":"ctrl-a"} +{"Get":{"state":"1ˇ3\n","mode":"Normal"}} +{"Key":"ctrl-x"} +{"Get":{"state":"1ˇ2\n","mode":"Normal"}} +{"Key":"9"} +{"Key":"9"} +{"Key":"ctrl-a"} +{"Get":{"state":"11ˇ1\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"1"} +{"Key":"1"} +{"Key":"ctrl-x"} +{"Get":{"state":"ˇ0\n","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"-11ˇ1\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_increment_radix.json b/crates/vim2/test_data/test_increment_radix.json new file mode 100644 index 0000000000..0f41c01599 --- /dev/null +++ b/crates/vim2/test_data/test_increment_radix.json @@ -0,0 +1,18 @@ +{"Put":{"state":"ˇ total: 0xff"}} +{"Key":"ctrl-a"} +{"Get":{"state":" total: 0x10ˇ0","mode":"Normal"}} +{"Put":{"state":"ˇ total: 0xff"}} +{"Key":"ctrl-x"} +{"Get":{"state":" total: 0xfˇe","mode":"Normal"}} +{"Put":{"state":"ˇ total: 0xFF"}} +{"Key":"ctrl-x"} +{"Get":{"state":" total: 0xFˇE","mode":"Normal"}} +{"Put":{"state":"(ˇ0b10f)"}} +{"Key":"ctrl-a"} +{"Get":{"state":"(0b1ˇ1f)","mode":"Normal"}} +{"Put":{"state":"ˇ-1"}} +{"Key":"ctrl-a"} +{"Get":{"state":"ˇ0","mode":"Normal"}} +{"Put":{"state":"banˇana"}} +{"Key":"ctrl-a"} +{"Get":{"state":"banˇana","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_increment_steps.json b/crates/vim2/test_data/test_increment_steps.json new file mode 100644 index 0000000000..2e8711d1cc --- /dev/null +++ b/crates/vim2/test_data/test_increment_steps.json @@ -0,0 +1,15 @@ +{"Put":{"state":"ˇ1\n1\n1 2\n1\n1"}} +{"Key":"j"} +{"Key":"v"} +{"Key":"shift-g"} +{"Key":"g"} +{"Key":"ctrl-a"} +{"Get":{"state":"1\nˇ2\n3 2\n4\n5","mode":"Normal"}} +{"Key":"shift-g"} +{"Key":"ctrl-v"} +{"Key":"g"} +{"Key":"g"} +{"Get":{"state":"«1ˇ»\n«2ˇ»\n«3ˇ» 2\n«4ˇ»\n«5ˇ»","mode":"VisualBlock"}} +{"Key":"g"} +{"Key":"ctrl-x"} +{"Get":{"state":"ˇ0\n0\n0 2\n0\n0","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_insert_end_of_line.json b/crates/vim2/test_data/test_insert_end_of_line.json new file mode 100644 index 0000000000..a37ad24d39 --- /dev/null +++ b/crates/vim2/test_data/test_insert_end_of_line.json @@ -0,0 +1,9 @@ +{"Put":{"state":"ˇ\nThe quick\nbrown fox "}} +{"Key":"shift-a"} +{"Get":{"state":"ˇ\nThe quick\nbrown fox ","mode":"Insert"}} +{"Put":{"state":"\nThe qˇuick\nbrown fox "}} +{"Key":"shift-a"} +{"Get":{"state":"\nThe quickˇ\nbrown fox ","mode":"Insert"}} +{"Put":{"state":"\nThe quick\nbrown ˇfox "}} +{"Key":"shift-a"} +{"Get":{"state":"\nThe quick\nbrown fox ˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_insert_first_non_whitespace.json b/crates/vim2/test_data/test_insert_first_non_whitespace.json new file mode 100644 index 0000000000..4d13cdb81c --- /dev/null +++ b/crates/vim2/test_data/test_insert_first_non_whitespace.json @@ -0,0 +1,15 @@ +{"Put":{"state":"The qˇuick"}} +{"Key":"shift-i"} +{"Get":{"state":"ˇThe quick","mode":"Insert"}} +{"Put":{"state":" The qˇuick"}} +{"Key":"shift-i"} +{"Get":{"state":" ˇThe quick","mode":"Insert"}} +{"Put":{"state":"ˇ"}} +{"Key":"shift-i"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"shift-i"} +{"Get":{"state":"ˇThe quick\nbrown fox","mode":"Insert"}} +{"Put":{"state":"ˇ\nThe quick"}} +{"Key":"shift-i"} +{"Get":{"state":"ˇ\nThe quick","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_insert_line_above.json b/crates/vim2/test_data/test_insert_line_above.json new file mode 100644 index 0000000000..ce5d0d7ac1 --- /dev/null +++ b/crates/vim2/test_data/test_insert_line_above.json @@ -0,0 +1,18 @@ +{"Put":{"state":"ˇ"}} +{"Key":"shift-o"} +{"Get":{"state":"ˇ\n","mode":"Insert"}} +{"Put":{"state":"The ˇquick"}} +{"Key":"shift-o"} +{"Get":{"state":"ˇ\nThe quick","mode":"Insert"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"shift-o"} +{"Get":{"state":"ˇ\nThe quick\nbrown fox\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"shift-o"} +{"Get":{"state":"The quick\nˇ\nbrown fox\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"shift-o"} +{"Get":{"state":"The quick\nbrown fox\nˇ\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"shift-o"} +{"Get":{"state":"The quick\nˇ\n\nbrown fox","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_insert_with_counts.json b/crates/vim2/test_data/test_insert_with_counts.json new file mode 100644 index 0000000000..470888cf6e --- /dev/null +++ b/crates/vim2/test_data/test_insert_with_counts.json @@ -0,0 +1,36 @@ +{"Put":{"state":"ˇhello\n"}} +{"Key":"5"} +{"Key":"i"} +{"Key":"-"} +{"Key":"escape"} +{"Get":{"state":"----ˇ-hello\n","mode":"Normal"}} +{"Put":{"state":"ˇhello\n"}} +{"Key":"5"} +{"Key":"a"} +{"Key":"-"} +{"Key":"escape"} +{"Get":{"state":"h----ˇ-ello\n","mode":"Normal"}} +{"Key":"4"} +{"Key":"shift-i"} +{"Key":"-"} +{"Key":"escape"} +{"Get":{"state":"---ˇ-h-----ello\n","mode":"Normal"}} +{"Key":"3"} +{"Key":"shift-a"} +{"Key":"-"} +{"Key":"escape"} +{"Get":{"state":"----h-----ello--ˇ-\n","mode":"Normal"}} +{"Put":{"state":"ˇhello\n"}} +{"Key":"3"} +{"Key":"o"} +{"Key":"o"} +{"Key":"i"} +{"Key":"escape"} +{"Get":{"state":"hello\noi\noi\noˇi\n","mode":"Normal"}} +{"Put":{"state":"ˇhello\n"}} +{"Key":"3"} +{"Key":"shift-o"} +{"Key":"o"} +{"Key":"i"} +{"Key":"escape"} +{"Get":{"state":"oi\noi\noˇi\nhello\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_insert_with_repeat.json b/crates/vim2/test_data/test_insert_with_repeat.json new file mode 100644 index 0000000000..ac6637633c --- /dev/null +++ b/crates/vim2/test_data/test_insert_with_repeat.json @@ -0,0 +1,23 @@ +{"Put":{"state":"ˇhello\n"}} +{"Key":"3"} +{"Key":"i"} +{"Key":"-"} +{"Key":"escape"} +{"Get":{"state":"--ˇ-hello\n","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"----ˇ--hello\n","mode":"Normal"}} +{"Key":"2"} +{"Key":"."} +{"Get":{"state":"-----ˇ---hello\n","mode":"Normal"}} +{"Put":{"state":"ˇhello\n"}} +{"Key":"2"} +{"Key":"o"} +{"Key":"k"} +{"Key":"k"} +{"Key":"escape"} +{"Get":{"state":"hello\nkk\nkˇk\n","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"hello\nkk\nkk\nkk\nkˇk\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"."} +{"Get":{"state":"hello\nkk\nkk\nkk\nkk\nkˇk\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_j.json b/crates/vim2/test_data/test_j.json new file mode 100644 index 0000000000..703f69d22c --- /dev/null +++ b/crates/vim2/test_data/test_j.json @@ -0,0 +1,15 @@ +{"Put":{"state":"aaˇaa\n😃😃"}} +{"Key":"j"} +{"Get":{"state":"aaaa\n😃ˇ😃","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps"}} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} +{"Put":{"state":"The qˇuick brown\nfox jumps"}} +{"Key":"j"} +{"Get":{"state":"The quick brown\nfox jˇumps","mode":"Normal"}} +{"Put":{"state":"The quick broˇwn\nfox jumps"}} +{"Key":"j"} +{"Get":{"state":"The quick brown\nfox jumpˇs","mode":"Normal"}} +{"Put":{"state":"The quick brown\nˇfox jumps"}} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇfox jumps","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_join_lines.json b/crates/vim2/test_data/test_join_lines.json new file mode 100644 index 0000000000..b4bc5c30e1 --- /dev/null +++ b/crates/vim2/test_data/test_join_lines.json @@ -0,0 +1,13 @@ +{"Put":{"state":"ˇone\ntwo\nthree\nfour\nfive\nsix\n"}} +{"Key":"shift-j"} +{"Get":{"state":"oneˇ two\nthree\nfour\nfive\nsix\n","mode":"Normal"}} +{"Key":"3"} +{"Key":"shift-j"} +{"Get":{"state":"one two threeˇ four\nfive\nsix\n","mode":"Normal"}} +{"Put":{"state":"ˇone\ntwo\nthree\nfour\nfive\nsix\n"}} +{"Key":"j"} +{"Key":"v"} +{"Key":"3"} +{"Key":"j"} +{"Key":"shift-j"} +{"Get":{"state":"one\ntwo three fourˇ five\nsix\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_jump_to_end.json b/crates/vim2/test_data/test_jump_to_end.json new file mode 100644 index 0000000000..fe9a948d43 --- /dev/null +++ b/crates/vim2/test_data/test_jump_to_end.json @@ -0,0 +1,14 @@ +{"Put":{"state":"The ˇquick\n\nbrown fox jumps\nover the lazy dog"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\noverˇ the lazy dog","mode":"Normal"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\noverˇ the lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick\n\nbrown fox jumps\nover the lazy doˇg"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrown fox jumps\nover the lazy doˇg","mode":"Normal"}} +{"Put":{"state":"The quiˇck\n\nbrown"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nbrowˇn","mode":"Normal"}} +{"Put":{"state":"The quiˇck\n\n"}} +{"Key":"shift-g"} +{"Get":{"state":"The quick\n\nˇ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_jump_to_first_non_whitespace.json b/crates/vim2/test_data/test_jump_to_first_non_whitespace.json new file mode 100644 index 0000000000..c992662195 --- /dev/null +++ b/crates/vim2/test_data/test_jump_to_first_non_whitespace.json @@ -0,0 +1,18 @@ +{"Put":{"state":"The qˇuick"}} +{"Key":"^"} +{"Get":{"state":"ˇThe quick","mode":"Normal"}} +{"Put":{"state":" The qˇuick"}} +{"Key":"^"} +{"Get":{"state":" ˇThe quick","mode":"Normal"}} +{"Put":{"state":"ˇ"}} +{"Key":"^"} +{"Get":{"state":"ˇ","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox"}} +{"Key":"^"} +{"Get":{"state":"ˇThe quick\nbrown fox","mode":"Normal"}} +{"Put":{"state":"ˇ\nThe quick"}} +{"Key":"^"} +{"Get":{"state":"ˇ\nThe quick","mode":"Normal"}} +{"Put":{"state":" ˇ \nThe quick"}} +{"Key":"^"} +{"Get":{"state":" ˇ \nThe quick","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_jump_to_line_boundaries.json b/crates/vim2/test_data/test_jump_to_line_boundaries.json new file mode 100644 index 0000000000..6d4a76ffd6 --- /dev/null +++ b/crates/vim2/test_data/test_jump_to_line_boundaries.json @@ -0,0 +1,28 @@ +{"Put":{"state":"ˇThe quick\nbrown"}} +{"Key":"$"} +{"Get":{"state":"The quicˇk\nbrown","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown"}} +{"Key":"$"} +{"Get":{"state":"The quicˇk\nbrown","mode":"Normal"}} +{"Key":"$"} +{"Get":{"state":"The quicˇk\nbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown"}} +{"Key":"$"} +{"Get":{"state":"The quick\nbrowˇn","mode":"Normal"}} +{"Key":"$"} +{"Get":{"state":"The quick\nbrowˇn","mode":"Normal"}} +{"Put":{"state":"ˇThe quick\nbrown"}} +{"Key":"0"} +{"Get":{"state":"ˇThe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown"}} +{"Key":"0"} +{"Get":{"state":"ˇThe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The quicˇk\nbrown"}} +{"Key":"0"} +{"Get":{"state":"ˇThe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown"}} +{"Key":"0"} +{"Get":{"state":"The quick\nˇbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nbrowˇn"}} +{"Key":"0"} +{"Get":{"state":"The quick\nˇbrown","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_k.json b/crates/vim2/test_data/test_k.json new file mode 100644 index 0000000000..f064fa9fd9 --- /dev/null +++ b/crates/vim2/test_data/test_k.json @@ -0,0 +1,15 @@ +{"Put":{"state":"ˇThe quick\nbrown fox jumps"}} +{"Key":"k"} +{"Get":{"state":"ˇThe quick\nbrown fox jumps","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown fox jumps"}} +{"Key":"k"} +{"Get":{"state":"The qˇuick\nbrown fox jumps","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown fox jumps"}} +{"Key":"k"} +{"Get":{"state":"ˇThe quick\nbrown fox jumps","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fˇox jumps"}} +{"Key":"k"} +{"Get":{"state":"The quiˇck\nbrown fox jumps","mode":"Normal"}} +{"Put":{"state":"The quick\nbrown fox jumˇps"}} +{"Key":"k"} +{"Get":{"state":"The quicˇk\nbrown fox jumps","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_l.json b/crates/vim2/test_data/test_l.json new file mode 100644 index 0000000000..b0db891bce --- /dev/null +++ b/crates/vim2/test_data/test_l.json @@ -0,0 +1,15 @@ +{"Put":{"state":"ˇThe quick\nbrown"}} +{"Key":"l"} +{"Get":{"state":"Tˇhe quick\nbrown","mode":"Normal"}} +{"Put":{"state":"The qˇuick\nbrown"}} +{"Key":"l"} +{"Get":{"state":"The quˇick\nbrown","mode":"Normal"}} +{"Put":{"state":"The quicˇk\nbrown"}} +{"Key":"l"} +{"Get":{"state":"The quicˇk\nbrown","mode":"Normal"}} +{"Put":{"state":"The quick\nˇbrown"}} +{"Key":"l"} +{"Get":{"state":"The quick\nbˇrown","mode":"Normal"}} +{"Put":{"state":"The quick\nbrowˇn"}} +{"Key":"l"} +{"Get":{"state":"The quick\nbrowˇn","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_matching.json b/crates/vim2/test_data/test_matching.json new file mode 100644 index 0000000000..5c8d7529b9 --- /dev/null +++ b/crates/vim2/test_data/test_matching.json @@ -0,0 +1,17 @@ +{"Put":{"state":"func ˇ(a string) {\n do(something(with.and_arrays[0, 2]))\n}"}} +{"Key":"%"} +{"Get":{"state":"func (a stringˇ) {\n do(something(with.and_arrays[0, 2]))\n}","mode":"Normal"}} +{"Put":{"state":"func (a string) ˇ{\ndo(something(with.and_arrays[0, 2]))\n}"}} +{"Key":"%"} +{"Get":{"state":"func (a string) {\ndo(something(with.and_arrays[0, 2]))\nˇ}","mode":"Normal"}} +{"Put":{"state":"ˇ{()}"}} +{"Key":"%"} +{"Get":{"state":"{()ˇ}","mode":"Normal"}} +{"Key":"%"} +{"Get":{"state":"ˇ{()}","mode":"Normal"}} +{"Put":{"state":"{\n ˇ{()}\n}"}} +{"Key":"%"} +{"Get":{"state":"{\n {()ˇ}\n}","mode":"Normal"}} +{"Put":{"state":"func ˇboop() {\n}"}} +{"Key":"%"} +{"Get":{"state":"func boop(ˇ) {\n}","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_multiline_surrounding_character_objects.json b/crates/vim2/test_data/test_multiline_surrounding_character_objects.json new file mode 100644 index 0000000000..973df647a2 --- /dev/null +++ b/crates/vim2/test_data/test_multiline_surrounding_character_objects.json @@ -0,0 +1,15 @@ +{"Put":{"state":"func empty(a string) bool {\n if a == \"\" {\n return true\n }\n ˇreturn false\n}"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"func empty(a string) bool {\n« if a == \"\" {\n return true\n }\n return false\nˇ»}","mode":"Visual"}} +{"Put":{"state":"func empty(a string) bool {\n if a == \"\" {\n ˇreturn true\n }\n return false\n}"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"func empty(a string) bool {\n if a == \"\" {\n« return true\nˇ» }\n return false\n}","mode":"Visual"}} +{"Put":{"state":"func empty(a string) bool {\n if a == \"\" ˇ{\n return true\n }\n return false\n}"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"{"} +{"Get":{"state":"func empty(a string) bool {\n if a == \"\" {\n« return true\nˇ» }\n return false\n}","mode":"Visual"}} diff --git a/crates/vim2/test_data/test_neovim.json b/crates/vim2/test_data/test_neovim.json new file mode 100644 index 0000000000..5aef81073a --- /dev/null +++ b/crates/vim2/test_data/test_neovim.json @@ -0,0 +1,16 @@ +{"Key":"i"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Key":"shift-T"} +{"Key":"e"} +{"Key":"s"} +{"Key":"t"} +{"Key":" "} +{"Key":"t"} +{"Key":"e"} +{"Key":"s"} +{"Key":"t"} +{"Key":"escape"} +{"Key":"0"} +{"Key":"d"} +{"Key":"w"} +{"Get":{"state":"ˇtest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_next_line_start.json b/crates/vim2/test_data/test_next_line_start.json new file mode 100644 index 0000000000..90ed4a4f03 --- /dev/null +++ b/crates/vim2/test_data/test_next_line_start.json @@ -0,0 +1,3 @@ +{"Put":{"state":"ˇone\n two\nthree"}} +{"Key":"enter"} +{"Get":{"state":"one\n ˇtwo\nthree","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_o.json b/crates/vim2/test_data/test_o.json new file mode 100644 index 0000000000..015890ac36 --- /dev/null +++ b/crates/vim2/test_data/test_o.json @@ -0,0 +1,18 @@ +{"Put":{"state":"ˇ"}} +{"Key":"o"} +{"Get":{"state":"\nˇ","mode":"Insert"}} +{"Put":{"state":"The ˇquick"}} +{"Key":"o"} +{"Get":{"state":"The quick\nˇ","mode":"Insert"}} +{"Put":{"state":"The qˇuick\nbrown fox\njumps over"}} +{"Key":"o"} +{"Get":{"state":"The quick\nˇ\nbrown fox\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown ˇfox\njumps over"}} +{"Key":"o"} +{"Get":{"state":"The quick\nbrown fox\nˇ\njumps over","mode":"Insert"}} +{"Put":{"state":"The quick\nbrown fox\njumps ˇover"}} +{"Key":"o"} +{"Get":{"state":"The quick\nbrown fox\njumps over\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick\nˇ\nbrown fox"}} +{"Key":"o"} +{"Get":{"state":"The quick\n\nˇ\nbrown fox","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_paragraphs_dont_wrap.json b/crates/vim2/test_data/test_paragraphs_dont_wrap.json new file mode 100644 index 0000000000..9e729651be --- /dev/null +++ b/crates/vim2/test_data/test_paragraphs_dont_wrap.json @@ -0,0 +1,8 @@ +{"Put":{"state":"one\nˇ\ntwo"}} +{"Key":"}"} +{"Key":"}"} +{"Get":{"state":"one\n\ntwˇo","mode":"Normal"}} +{"Key":"{"} +{"Key":"{"} +{"Key":"{"} +{"Get":{"state":"ˇone\n\ntwo","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_paste.json b/crates/vim2/test_data/test_paste.json new file mode 100644 index 0000000000..e70da6c435 --- /dev/null +++ b/crates/vim2/test_data/test_paste.json @@ -0,0 +1,31 @@ +{"Put":{"state":"The quick brown\nfox ˇjumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":"jumps o"}} +{"Put":{"state":"The quick brown\nfox jumps oveˇr\nthe lazy dog"}} +{"Key":"p"} +{"Get":{"state":"The quick brown\nfox jumps overjumps ˇo\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps oveˇr\nthe lazy dog"}} +{"Key":"shift-p"} +{"Get":{"state":"The quick brown\nfox jumps ovejumps ˇor\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"d"} +{"Key":"d"} +{"ReadRegister":{"name":"\"","value":"fox jumps over\n"}} +{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}} +{"Key":"p"} +{"Get":{"state":"The quick brown\nthe lazy dog\nˇfox jumps over","mode":"Normal"}} +{"Key":"k"} +{"Key":"shift-p"} +{"Get":{"state":"The quick brown\nˇfox jumps over\nthe lazy dog\nfox jumps over","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}} +{"Key":"v"} +{"Key":"j"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":"over\nthe lazy do"}} +{"Key":"p"} +{"Get":{"state":"The quick brown\nfox jumps oˇover\nthe lazy dover\nthe lazy dog","mode":"Normal"}} +{"Key":"u"} +{"Key":"shift-p"} +{"Get":{"state":"The quick brown\nfox jumps ˇover\nthe lazy doover\nthe lazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_paste_visual.json b/crates/vim2/test_data/test_paste_visual.json new file mode 100644 index 0000000000..5d85540820 --- /dev/null +++ b/crates/vim2/test_data/test_paste_visual.json @@ -0,0 +1,42 @@ +{"Put":{"state":"The quick brown\nfox jˇumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"y"} +{"Get":{"state":"The quick brown\nfox ˇjumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"w"} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"p"} +{"Get":{"state":"The quick brown\nfox jumps jumpˇs\nthe lazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"over"}} +{"Key":"up"} +{"Key":"shift-v"} +{"Key":"shift-p"} +{"Get":{"state":"ˇover\nfox jumps jumps\nthe lazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"over"}} +{"Key":"ctrl-v"} +{"Key":"down"} +{"Key":"down"} +{"Key":"p"} +{"Get":{"state":"oveˇrver\noverox jumps jumps\noverhe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"d"} +{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"p"} +{"Get":{"state":"The quick brown\nthe \nˇfox jumps over\n dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"lazy"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"d"} +{"Get":{"state":"The quick brown\nthe laˇzy dog","mode":"Normal"}} +{"Key":"k"} +{"Key":"shift-v"} +{"Key":"p"} +{"Get":{"state":"ˇfox jumps over\nthe lazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"The quick brown\n"}} diff --git a/crates/vim2/test_data/test_paste_visual_block.json b/crates/vim2/test_data/test_paste_visual_block.json new file mode 100644 index 0000000000..559e950724 --- /dev/null +++ b/crates/vim2/test_data/test_paste_visual_block.json @@ -0,0 +1,31 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"ctrl-v"} +{"Key":"2"} +{"Key":"j"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":"q\nj\nl"}} +{"Key":"p"} +{"Get":{"state":"The qˇquick brown\nfox jjumps over\nthe llazy dog","mode":"Normal"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"shift-p"} +{"Get":{"state":"The ˇq brown\nfox jjjumps over\nthe lllazy dog","mode":"Normal"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"shift-p"} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"ctrl-v"} +{"Key":"j"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":"q\nj"}} +{"Key":"l"} +{"Key":"ctrl-v"} +{"Key":"2"} +{"Key":"j"} +{"Key":"shift-p"} +{"Get":{"state":"The qˇqick brown\nfox jjmps over\nthe lzy dog","mode":"Normal"}} +{"Key":"shift-v"} +{"Key":"p"} +{"Get":{"state":"ˇq\nj\nfox jjmps over\nthe lzy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_percent.json b/crates/vim2/test_data/test_percent.json new file mode 100644 index 0000000000..2382cc9e49 --- /dev/null +++ b/crates/vim2/test_data/test_percent.json @@ -0,0 +1,58 @@ +{"Put":{"state":"ˇconsole.log(var);"}} +{"Key":"%"} +{"Get":{"state":"console.log(varˇ);","mode":"Normal"}} +{"Put":{"state":"console.logˇ(var);"}} +{"Key":"%"} +{"Get":{"state":"console.log(varˇ);","mode":"Normal"}} +{"Put":{"state":"console.log(ˇvar);"}} +{"Key":"%"} +{"Get":{"state":"console.logˇ(var);","mode":"Normal"}} +{"Put":{"state":"console.log(vaˇr);"}} +{"Key":"%"} +{"Get":{"state":"console.logˇ(var);","mode":"Normal"}} +{"Put":{"state":"console.log(varˇ);"}} +{"Key":"%"} +{"Get":{"state":"console.logˇ(var);","mode":"Normal"}} +{"Put":{"state":"console.log(var)ˇ;"}} +{"Key":"%"} +{"Get":{"state":"console.log(var)ˇ;","mode":"Normal"}} +{"Put":{"state":"ˇconsole.log('var', [1, 2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', [1, 2, 3]ˇ);","mode":"Normal"}} +{"Put":{"state":"console.logˇ('var', [1, 2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', [1, 2, 3]ˇ);","mode":"Normal"}} +{"Put":{"state":"console.log(ˇ'var', [1, 2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', [1, 2, 3ˇ]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', ˇ[1, 2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', [1, 2, 3ˇ]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', [ˇ1, 2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', ˇ[1, 2, 3]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', [1, ˇ2, 3]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', ˇ[1, 2, 3]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', [1, 2, 3ˇ]);"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', ˇ[1, 2, 3]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', [1, 2, 3]ˇ);"}} +{"Key":"%"} +{"Get":{"state":"console.logˇ('var', [1, 2, 3]);","mode":"Normal"}} +{"Put":{"state":"console.log('var', [1, 2, 3])ˇ;"}} +{"Key":"%"} +{"Get":{"state":"console.log('var', [1, 2, 3])ˇ;","mode":"Normal"}} +{"Put":{"state":"let result = curried_funˇ()();"}} +{"Key":"%"} +{"Get":{"state":"let result = curried_fun(ˇ)();","mode":"Normal"}} +{"Key":"%"} +{"Get":{"state":"let result = curried_funˇ()();","mode":"Normal"}} +{"Put":{"state":"let result = curried_fun()ˇ();"}} +{"Key":"%"} +{"Get":{"state":"let result = curried_fun()(ˇ);","mode":"Normal"}} +{"Key":"%"} +{"Get":{"state":"let result = curried_fun()ˇ();","mode":"Normal"}} +{"Put":{"state":"let result = curried_fun()()ˇ;"}} +{"Key":"%"} +{"Get":{"state":"let result = curried_fun()()ˇ;","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_repeat_motion_counts.json b/crates/vim2/test_data/test_repeat_motion_counts.json new file mode 100644 index 0000000000..c39b8b09c0 --- /dev/null +++ b/crates/vim2/test_data/test_repeat_motion_counts.json @@ -0,0 +1,13 @@ +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"3"} +{"Key":"d"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"ˇ brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"."} +{"Get":{"state":" brown\nˇ over\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"2"} +{"Key":"."} +{"Get":{"state":" brown\n over\nˇe lazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_repeat_visual.json b/crates/vim2/test_data/test_repeat_visual.json new file mode 100644 index 0000000000..cb83addcfb --- /dev/null +++ b/crates/vim2/test_data/test_repeat_visual.json @@ -0,0 +1,51 @@ +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Key":"s"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"ˇo quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"w"} +{"Key":"."} +{"Get":{"state":"o quick brown\nfox ˇops over\nthe lazy dog","mode":"Normal"}} +{"Key":"f"} +{"Key":"r"} +{"Key":"."} +{"Get":{"state":"o quick brown\nfox ops oveˇothe lazy dog","mode":"Normal"}} +{"Put":{"state":"the ˇquick brown\nfox jumps over\nfox jumps over\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"j"} +{"Key":"x"} +{"Get":{"state":"the ˇumps over\nfox jumps over\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"."} +{"Get":{"state":"the ˇumps over\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"w"} +{"Key":"."} +{"Get":{"state":"the umps ˇumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"."} +{"Get":{"state":"the umps umps over\nthe ˇog","mode":"Normal"}} +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"ctrl-v"} +{"Key":"j"} +{"Key":"j"} +{"Key":"shift-i"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"ˇothe quick brown\nofox jumps over\nothe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"4"} +{"Key":"l"} +{"Key":"."} +{"Get":{"state":"othe quick brown\nofoxˇo jumps over\notheo lazy dog","mode":"Normal"}} +{"Put":{"state":"ˇthe quick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"shift-r"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"ˇo\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"."} +{"Get":{"state":"o\nˇo\nthe lazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_repeated_cb.json b/crates/vim2/test_data/test_repeated_cb.json new file mode 100644 index 0000000000..437b55ef29 --- /dev/null +++ b/crates/vim2/test_data/test_repeated_cb.json @@ -0,0 +1,275 @@ +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The ˇick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick ˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"ˇick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The ˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox ˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"ˇick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"ˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The quick ˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox ˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nfox ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"The ˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"The quick ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"b"} +{"Get":{"state":"The quick brown\n\nˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"ˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"The ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"The quick ˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"b"} +{"Get":{"state":"The quick brown\nˇ\nthe lazy dog\n","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_repeated_ce.json b/crates/vim2/test_data/test_repeated_ce.json new file mode 100644 index 0000000000..3032185d64 --- /dev/null +++ b/crates/vim2/test_data/test_repeated_ce.json @@ -0,0 +1,275 @@ +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"ˇ quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quickˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick browˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\nˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"ˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quickˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick browˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\nˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox ˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"ˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quickˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick browˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\nˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"ˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quickˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick browˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\nˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox ˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quickˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick browˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\nˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox ˇ dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"e"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_repeated_cj.json b/crates/vim2/test_data/test_repeated_cj.json new file mode 100644 index 0000000000..e20270f97c --- /dev/null +++ b/crates/vim2/test_data/test_repeated_cj.json @@ -0,0 +1,275 @@ +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"ˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"ˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"ˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"j"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_repeated_cl.json b/crates/vim2/test_data/test_repeated_cl.json new file mode 100644 index 0000000000..397a364e5a --- /dev/null +++ b/crates/vim2/test_data/test_repeated_cl.json @@ -0,0 +1,275 @@ +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"ˇhe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quˇck brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quickˇbrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick browˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nˇox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox ˇumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇover\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇer\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"1"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇhe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"ˇe quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quˇk brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quickˇrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick browˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nˇx jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox ˇmps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇver\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇer\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇr\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"2"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"ˇ quick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quˇ brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quickˇown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick browˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nˇ jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox ˇps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇer\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇr\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"3"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇ lazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"ˇquick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quˇbrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quickˇwn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick browˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nˇjumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox ˇs-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇr\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"4"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇlazy dog\n","mode":"Insert"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"ˇuick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quˇrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quickˇn\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick browˇ\n\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nˇumps-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox ˇ-over\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-oˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"c"} +{"Key":"5"} +{"Key":"l"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇazy dog\n","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_repeated_word.json b/crates/vim2/test_data/test_repeated_word.json new file mode 100644 index 0000000000..caa7ed7367 --- /dev/null +++ b/crates/vim2/test_data/test_repeated_word.json @@ -0,0 +1,214 @@ +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The ˇquick brown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick ˇbrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick ˇbrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Key":"1"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick ˇbrown\n\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"2"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy ˇdog\n","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy ˇdog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy ˇdog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"3"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy ˇdog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"4"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quˇick brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quickˇ brown\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick browˇn\n\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\nˇ\nfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nˇfox jumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe ˇlazy dog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox ˇjumps-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy ˇdog\n","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumpsˇ-over\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-ˇover\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-oˇver\nthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} +{"Put":{"state":"The quick brown\n\nfox jumps-over\nˇthe lazy dog\n"}} +{"Key":"5"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n\nfox jumps-over\nthe lazy dog\nˇ","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_selection_goal.json b/crates/vim2/test_data/test_selection_goal.json new file mode 100644 index 0000000000..ada2ab4c8e --- /dev/null +++ b/crates/vim2/test_data/test_selection_goal.json @@ -0,0 +1,8 @@ +{"Put":{"state":";;ˇ;\nLorem Ipsum"}} +{"Key":"a"} +{"Key":"down"} +{"Key":"up"} +{"Key":";"} +{"Key":"down"} +{"Key":"up"} +{"Get":{"state":";;;;ˇ\nLorem Ipsum","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_singleline_surrounding_character_objects.json b/crates/vim2/test_data/test_singleline_surrounding_character_objects.json new file mode 100644 index 0000000000..f7f95ce697 --- /dev/null +++ b/crates/vim2/test_data/test_singleline_surrounding_character_objects.json @@ -0,0 +1,27 @@ +{"SetOption":{"value":"wrap"}} +{"SetOption":{"value":"columns=12"}} +{"Put":{"state":"helˇlo \"world\"!"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"hello \"«worldˇ»\"!","mode":"Visual"}} +{"Put":{"state":"hello \"wˇorld\"!"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"\""} +{"Get":{"state":"hello \"«worldˇ»\"!","mode":"Visual"}} +{"Put":{"state":"hello \"wˇorld\"!"}} +{"Key":"v"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"hello« \"world\"ˇ»!","mode":"Visual"}} +{"Put":{"state":"hello \"wˇorld\" !"}} +{"Key":"v"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"hello «\"world\" ˇ»!","mode":"Visual"}} +{"Put":{"state":"hello \"wˇorld\"•\ngoodbye"}} +{"Key":"v"} +{"Key":"a"} +{"Key":"\""} +{"Get":{"state":"hello «\"world\" ˇ»\ngoodbye","mode":"Visual"}} diff --git a/crates/vim2/test_data/test_start_end_of_paragraph.json b/crates/vim2/test_data/test_start_end_of_paragraph.json new file mode 100644 index 0000000000..0de4d84f50 --- /dev/null +++ b/crates/vim2/test_data/test_start_end_of_paragraph.json @@ -0,0 +1,13 @@ +{"Put":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal"}} +{"Key":"}"} +{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"{"} +{"Get":{"state":"ˇabc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"2"} +{"Key":"}"} +{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\nˇ\n\n\nthird and\nfinal","mode":"Normal"}} +{"Key":"}"} +{"Get":{"state":"abc\ndef\n\nparagraph\nthe second\n\n\n\nthird and\nfinaˇl","mode":"Normal"}} +{"Key":"2"} +{"Key":"{"} +{"Get":{"state":"abc\ndef\nˇ\nparagraph\nthe second\n\n\n\nthird and\nfinal","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_substitute_line.json b/crates/vim2/test_data/test_substitute_line.json new file mode 100644 index 0000000000..eb0a9825f8 --- /dev/null +++ b/crates/vim2/test_data/test_substitute_line.json @@ -0,0 +1,29 @@ +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog\n"}} +{"Key":"shift-s"} +{"Key":"o"} +{"Get":{"state":"The quick brown\noˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog\n"}} +{"Key":"v"} +{"Key":"k"} +{"Key":"shift-s"} +{"Key":"o"} +{"Get":{"state":"oˇ\nthe lazy dog\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog\n"}} +{"Key":"ctrl-v"} +{"Key":"j"} +{"Key":"shift-s"} +{"Key":"o"} +{"Get":{"state":"The quick brown\noˇ\n","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog\n"}} +{"Key":"v"} +{"Key":"$"} +{"Key":"shift-s"} +{"Key":"o"} +{"Get":{"state":"The quick brown\noˇ\nthe lazy dog\n","mode":"Insert"}} +{"SetOption":{"value":"shiftwidth=4"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog\n"}} +{"Key":">"} +{"Key":">"} +{"Key":"shift-s"} +{"Key":"o"} +{"Get":{"state":"The quick brown\n oˇ\nthe lazy dog\n","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_visual_block_insert.json b/crates/vim2/test_data/test_visual_block_insert.json new file mode 100644 index 0000000000..d3d2689bd3 --- /dev/null +++ b/crates/vim2/test_data/test_visual_block_insert.json @@ -0,0 +1,18 @@ +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog\n"}} +{"Key":"ctrl-v"} +{"Key":"9"} +{"Key":"down"} +{"Get":{"state":"«Tˇ»he quick brown\n«fˇ»ox jumps over\n«tˇ»he lazy dog\nˇ","mode":"VisualBlock"}} +{"Key":"shift-i"} +{"Key":"k"} +{"Key":"escape"} +{"Get":{"state":"ˇkThe quick brown\nkfox jumps over\nkthe lazy dog\nk","mode":"Normal"}} +{"Put":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog\n"}} +{"Key":"ctrl-v"} +{"Key":"9"} +{"Key":"down"} +{"Get":{"state":"«Tˇ»he quick brown\n«fˇ»ox jumps over\n«tˇ»he lazy dog\nˇ","mode":"VisualBlock"}} +{"Key":"c"} +{"Key":"k"} +{"Key":"escape"} +{"Get":{"state":"ˇkhe quick brown\nkox jumps over\nkhe lazy dog\nk","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_visual_block_issue_2123.json b/crates/vim2/test_data/test_visual_block_issue_2123.json new file mode 100644 index 0000000000..0f48bcc890 --- /dev/null +++ b/crates/vim2/test_data/test_visual_block_issue_2123.json @@ -0,0 +1,5 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog\n"}} +{"Key":"ctrl-v"} +{"Key":"right"} +{"Key":"down"} +{"Get":{"state":"The «quˇ»ick brown\nfox «juˇ»mps over\nthe lazy dog\n","mode":"VisualBlock"}} diff --git a/crates/vim2/test_data/test_visual_block_mode.json b/crates/vim2/test_data/test_visual_block_mode.json new file mode 100644 index 0000000000..2239ef43a8 --- /dev/null +++ b/crates/vim2/test_data/test_visual_block_mode.json @@ -0,0 +1,38 @@ +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"ctrl-v"} +{"Get":{"state":"The «qˇ»uick brown\nfox jumps over\nthe lazy dog","mode":"VisualBlock"}} +{"Key":"2"} +{"Key":"down"} +{"Get":{"state":"The «qˇ»uick brown\nfox «jˇ»umps over\nthe «lˇ»azy dog","mode":"VisualBlock"}} +{"Key":"e"} +{"Get":{"state":"The «quicˇ»k brown\nfox «jumpˇ»s over\nthe «lazyˇ» dog","mode":"VisualBlock"}} +{"Key":"^"} +{"Get":{"state":"«ˇThe q»uick brown\n«ˇfox j»umps over\n«ˇthe l»azy dog","mode":"VisualBlock"}} +{"Key":"$"} +{"Get":{"state":"The «quick brownˇ»\nfox «jumps overˇ»\nthe «lazy dogˇ»","mode":"VisualBlock"}} +{"Key":"shift-f"} +{"Key":" "} +{"Get":{"state":"The «quickˇ» brown\nfox «jumpsˇ» over\nthe «lazy ˇ»dog","mode":"VisualBlock"}} +{"Key":"v"} +{"Get":{"state":"The «quick brown\nfox jumps over\nthe lazy ˇ»dog","mode":"Visual"}} +{"Key":"ctrl-v"} +{"Get":{"state":"The «quickˇ» brown\nfox «jumpsˇ» over\nthe «lazy ˇ»dog","mode":"VisualBlock"}} +{"Put":{"state":"The ˇquick\nbrown\nfox\njumps over the\n\nlazy dog\n"}} +{"Key":"ctrl-v"} +{"Key":"down"} +{"Key":"down"} +{"Get":{"state":"The«ˇ q»uick\nbro«ˇwn»\nfoxˇ\njumps over the\n\nlazy dog\n","mode":"VisualBlock"}} +{"Key":"down"} +{"Get":{"state":"The «qˇ»uick\nbrow«nˇ»\nfox\njump«sˇ» over the\n\nlazy dog\n","mode":"VisualBlock"}} +{"Key":"left"} +{"Get":{"state":"The«ˇ q»uick\nbro«ˇwn»\nfoxˇ\njum«ˇps» over the\n\nlazy dog\n","mode":"VisualBlock"}} +{"Key":"s"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"Theˇouick\nbroo\nfoxo\njumo over the\n\nlazy dog\n","mode":"Normal"}} +{"Put":{"state":"Theˇ quick brown\n\nfox jumps over\nthe lazy dog\n"}} +{"Key":"l"} +{"Key":"ctrl-v"} +{"Key":"j"} +{"Key":"j"} +{"Get":{"state":"The «qˇ»uick brown\n\nfox «jˇ»umps over\nthe lazy dog\n","mode":"VisualBlock"}} diff --git a/crates/vim2/test_data/test_visual_change.json b/crates/vim2/test_data/test_visual_change.json new file mode 100644 index 0000000000..7d1efe05ce --- /dev/null +++ b/crates/vim2/test_data/test_visual_change.json @@ -0,0 +1,47 @@ +{"Put":{"state":"The quick ˇbrown"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"c"} +{"Get":{"state":"The quick ˇ","mode":"Insert"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Insert"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Insert"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"k"} +{"Key":"c"} +{"Get":{"state":"The ˇrown\nfox jumps over\nthe lazy dog","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nfox jumps ˇhe lazy dog","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"k"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nˇver\nthe lazy dog","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇog","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"k"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nfox jumpsˇazy dog","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_visual_delete.json b/crates/vim2/test_data/test_visual_delete.json new file mode 100644 index 0000000000..d9f8055600 --- /dev/null +++ b/crates/vim2/test_data/test_visual_delete.json @@ -0,0 +1,48 @@ +{"Put":{"state":"The quick ˇbrown"}} +{"Key":"v"} +{"Key":"w"} +{"Get":{"state":"The quick «brownˇ»","mode":"Visual"}} +{"Put":{"state":"The quick ˇbrown"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"x"} +{"Get":{"state":"The quickˇ ","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"x"} +{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Normal"}} +{"Key":"j"} +{"Key":"p"} +{"Get":{"state":"The ver\nthe lˇquick brown\nfox jumps oazy dog","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"x"} +{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"x"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇog","mode":"Normal"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"b"} +{"Key":"k"} +{"Key":"x"} +{"Get":{"state":"ˇuick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps ˇover\nthe lazy dog"}} +{"Key":"v"} +{"Key":"b"} +{"Key":"k"} +{"Key":"x"} +{"Get":{"state":"The ˇver\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} +{"Key":"v"} +{"Key":"b"} +{"Key":"k"} +{"Key":"x"} +{"Get":{"state":"The quick brown\nˇazy dog","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_visual_line_change.json b/crates/vim2/test_data/test_visual_line_change.json new file mode 100644 index 0000000000..336108c6cb --- /dev/null +++ b/crates/vim2/test_data/test_visual_line_change.json @@ -0,0 +1,35 @@ +{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"c"} +{"Get":{"state":"ˇ\nfox jumps over\nthe lazy dog","mode":"Insert"}} +{"Key":"escape"} +{"Key":"j"} +{"Key":"p"} +{"Get":{"state":"\nfox jumps over\nˇThe quick brown\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nˇ\nthe lazy dog","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe laˇzy dog"}} +{"Key":"shift-v"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nfox jumps over\nˇ","mode":"Insert"}} +{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"ˇ\nthe lazy dog","mode":"Insert"}} +{"Key":"escape"} +{"Key":"j"} +{"Key":"p"} +{"Get":{"state":"\nthe lazy dog\nˇThe quick brown\nfox jumps over","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox juˇmps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nˇ","mode":"Insert"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe laˇzy dog"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"c"} +{"Get":{"state":"The quick brown\nfox jumps over\nˇ","mode":"Insert"}} diff --git a/crates/vim2/test_data/test_visual_line_delete.json b/crates/vim2/test_data/test_visual_line_delete.json new file mode 100644 index 0000000000..e221a4ad5f --- /dev/null +++ b/crates/vim2/test_data/test_visual_line_delete.json @@ -0,0 +1,23 @@ +{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"x"} +{"Get":{"state":"fox juˇmps over\nthe lazy dog","mode":"Normal"}} +{"Key":"p"} +{"Get":{"state":"fox jumps over\nˇThe quick brown\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe laˇzy dog"}} +{"Key":"shift-v"} +{"Key":"x"} +{"Get":{"state":"The quick brown\nfox juˇmps over","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"the lazy dog\n"}} +{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"j"} +{"Key":"x"} +{"Get":{"state":"the laˇzy dog","mode":"Normal"}} +{"Key":"p"} +{"Get":{"state":"the lazy dog\nˇThe quick brown\nfox jumps over","mode":"Normal"}} +{"Put":{"state":"The ˇlong line\nshould not\ncrash\n"}} +{"Key":"shift-v"} +{"Key":"$"} +{"Key":"x"} +{"Get":{"state":"should noˇt\ncrash\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_visual_object.json b/crates/vim2/test_data/test_visual_object.json new file mode 100644 index 0000000000..7c95a8dc73 --- /dev/null +++ b/crates/vim2/test_data/test_visual_object.json @@ -0,0 +1,19 @@ +{"Put":{"state":"hello (in [parˇens] o)"}} +{"Key":"ctrl-v"} +{"Key":"l"} +{"Key":"a"} +{"Key":"]"} +{"Get":{"state":"hello (in «[parens]ˇ» o)","mode":"Visual"}} +{"Key":"i"} +{"Key":"("} +{"Get":{"state":"hello («in [parens] oˇ»)","mode":"Visual"}} +{"Put":{"state":"hello in a wˇord again."}} +{"Key":"ctrl-v"} +{"Key":"l"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"hello in a w«ordˇ» again.","mode":"VisualBlock"}} +{"Key":"o"} +{"Key":"a"} +{"Key":"s"} +{"Get":{"state":"«ˇhello in a word» again.","mode":"VisualBlock"}} diff --git a/crates/vim2/test_data/test_visual_sentence_object.json b/crates/vim2/test_data/test_visual_sentence_object.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/vim2/test_data/test_visual_word_object.json b/crates/vim2/test_data/test_visual_word_object.json new file mode 100644 index 0000000000..5e1a9839e9 --- /dev/null +++ b/crates/vim2/test_data/test_visual_word_object.json @@ -0,0 +1,236 @@ +{"Put":{"state":"The quick brown\nˇ\nfox"}} +{"Key":"v"} +{"Get":{"state":"The quick brown\n«\nˇ»fox","mode":"Visual"}} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown\n«\nˇ»fox","mode":"Visual"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick «brownˇ» \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick «brownˇ» \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown« ˇ»\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox «jumpsˇ» over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox «jumpsˇ» over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps« ˇ»over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog« ˇ»\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n«\nˇ»\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n«\nˇ»\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n«\nˇ»The-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\n«Theˇ»-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe«-ˇ»quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-«quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-«quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick« ˇ»brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick «brownˇ» \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown« ˇ»\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n« ˇ»\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n« ˇ»\n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n« ˇ»fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-«jumpsˇ» over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog« ˇ»\n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n«\nˇ»","mode":"Visual"}} +{"Put":{"state":"The quick ˇbrown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick «brownˇ» \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick browˇn \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick «brownˇ» \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brownˇ \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown« ˇ»\nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox ˇjumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox «jumpsˇ» over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox juˇmps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox «jumpsˇ» over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumpsˇ over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps« ˇ»over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dogˇ \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog« ˇ»\n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \nˇ\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n«\nˇ»\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\nˇ\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n«\nˇ»\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\nˇ\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n«\nˇ»The-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThˇe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\n«The-quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nTheˇ-quick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\n«The-quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-ˇquick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\n«The-quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quˇick brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\n«The-quickˇ» brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quickˇ brown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick« ˇ»brown \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick ˇbrown \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick «brownˇ» \n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brownˇ \n \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown« ˇ»\n \n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \nˇ \n \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n« ˇ»\n \n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \nˇ \n fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n« ˇ»\n fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \nˇ fox-jumps over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n« ˇ»fox-jumps over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumpˇs over\nthe lazy dog \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n «fox-jumpsˇ» over\nthe lazy dog \n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dogˇ \n\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog« ˇ»\n\n","mode":"Visual"}} +{"Put":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \nˇ\n"}} +{"Key":"v"} +{"Key":"i"} +{"Key":"shift-w"} +{"Get":{"state":"The quick brown \nfox jumps over\nthe lazy dog \n\n\n\nThe-quick brown \n \n \n fox-jumps over\nthe lazy dog \n«\nˇ»","mode":"Visual"}} diff --git a/crates/vim2/test_data/test_visual_yank.json b/crates/vim2/test_data/test_visual_yank.json new file mode 100644 index 0000000000..2e7b725371 --- /dev/null +++ b/crates/vim2/test_data/test_visual_yank.json @@ -0,0 +1,35 @@ +{"Put":{"state":"The quick ˇbrown"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"y"} +{"Get":{"state":"The quick ˇbrown","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"brown"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"y"} +{"Get":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"quick brown\nfox jumps o"}} +{"Put":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog"}} +{"Key":"v"} +{"Key":"w"} +{"Key":"j"} +{"Key":"y"} +{"Get":{"state":"The quick brown\nfox jumps over\nthe ˇlazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"lazy d"}} +{"Key":"shift-v"} +{"Key":"y"} +{"ReadRegister":{"name":"\"","value":"the lazy dog\n"}} +{"Put":{"state":"The ˇquick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"v"} +{"Key":"b"} +{"Key":"k"} +{"Key":"y"} +{"Get":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Put":{"state":"The quick brown\nfox ˇjumps over\nthe lazy dog"}} +{"Key":"shift-v"} +{"Key":"shift-g"} +{"Key":"shift-y"} +{"Get":{"state":"The quick brown\nˇfox jumps over\nthe lazy dog","mode":"Normal"}} +{"ReadRegister":{"name":"\"","value":"fox jumps over\nthe lazy dog\n"}} diff --git a/crates/vim2/test_data/test_w.json b/crates/vim2/test_data/test_w.json new file mode 100644 index 0000000000..b7b3bd0e63 --- /dev/null +++ b/crates/vim2/test_data/test_w.json @@ -0,0 +1,40 @@ +{"Put":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"w"} +{"Get":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-ˇbrown\n\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nˇthe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Key":"w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Put":{"state":"The ˇquick-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quickˇ-brown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Put":{"state":"The quick-ˇbrown\n\n\nfox_jumps over\nthe"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\nˇ\n\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\nˇ\nfox_jumps over\nthe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\n\nˇfox_jumps over\nthe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps ˇover\nthe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nˇthe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} +{"Key":"shift-w"} +{"Get":{"state":"The quick-brown\n\n\nfox_jumps over\nthˇe","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_wrapped_lines.json b/crates/vim2/test_data/test_wrapped_lines.json new file mode 100644 index 0000000000..e5b5d0eac0 --- /dev/null +++ b/crates/vim2/test_data/test_wrapped_lines.json @@ -0,0 +1,61 @@ +{"SetOption":{"value":"wrap"}} +{"SetOption":{"value":"columns=12"}} +{"Put":{"state":"tˇwelve char twelve char\ntwelve char\n"}} +{"Key":"j"} +{"Get":{"state":"twelve char twelve char\ntˇwelve char\n","mode":"Normal"}} +{"Key":"k"} +{"Get":{"state":"tˇwelve char twelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"g"} +{"Key":"j"} +{"Get":{"state":"twelve char tˇwelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"g"} +{"Key":"j"} +{"Get":{"state":"twelve char twelve char\ntˇwelve char\n","mode":"Normal"}} +{"Key":"g"} +{"Key":"k"} +{"Get":{"state":"twelve char tˇwelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"g"} +{"Key":"^"} +{"Get":{"state":"twelve char ˇtwelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"^"} +{"Get":{"state":"ˇtwelve char twelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"g"} +{"Key":"$"} +{"Get":{"state":"twelve charˇ twelve char\ntwelve char\n","mode":"Normal"}} +{"Key":"$"} +{"Get":{"state":"twelve char twelve chaˇr\ntwelve char\n","mode":"Normal"}} +{"Put":{"state":"tˇwelve char twelve char\ntwelve char\n"}} +{"Key":"enter"} +{"Get":{"state":"twelve char twelve char\nˇtwelve char\n","mode":"Normal"}} +{"Put":{"state":"twelve char\ntˇwelve char twelve char\ntwelve char\n"}} +{"Key":"o"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"twelve char\ntwelve char twelve char\nˇo\ntwelve char\n","mode":"Normal"}} +{"Put":{"state":"twelve char\ntˇwelve char twelve char\ntwelve char\n"}} +{"Key":"shift-a"} +{"Key":"a"} +{"Key":"escape"} +{"Get":{"state":"twelve char\ntwelve char twelve charˇa\ntwelve char\n","mode":"Normal"}} +{"Key":"shift-i"} +{"Key":"i"} +{"Key":"escape"} +{"Get":{"state":"twelve char\nˇitwelve char twelve chara\ntwelve char\n","mode":"Normal"}} +{"Key":"shift-d"} +{"Get":{"state":"twelve char\nˇ\ntwelve char\n","mode":"Normal"}} +{"Put":{"state":"twelve char\ntwelve char tˇwelve char\ntwelve char\n"}} +{"Key":"shift-o"} +{"Key":"o"} +{"Key":"escape"} +{"Get":{"state":"twelve char\nˇo\ntwelve char twelve char\ntwelve char\n","mode":"Normal"}} +{"Put":{"state":"fourteen chaˇr\nfourteen char\n"}} +{"Key":"d"} +{"Key":"i"} +{"Key":"w"} +{"Get":{"state":"fourteenˇ \nfourteen char\n","mode":"Normal"}} +{"Key":"j"} +{"Key":"shift-f"} +{"Key":"e"} +{"Key":"f"} +{"Key":"r"} +{"Get":{"state":"fourteen \nfourteen chaˇr\n","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_wrapped_motions.json b/crates/vim2/test_data/test_wrapped_motions.json new file mode 100644 index 0000000000..195a58f6b5 --- /dev/null +++ b/crates/vim2/test_data/test_wrapped_motions.json @@ -0,0 +1,15 @@ +{"SetOption":{"value":"wrap"}} +{"SetOption":{"value":"columns=12"}} +{"Put":{"state":"aaˇaa\n😃😃"}} +{"Key":"j"} +{"Get":{"state":"aaaa\n😃ˇ😃","mode":"Normal"}} +{"Put":{"state":"123456789012aaˇaa\n123456789012😃😃"}} +{"Key":"j"} +{"Get":{"state":"123456789012aaaa\n123456789012😃ˇ😃","mode":"Normal"}} +{"Put":{"state":"123456789012aaˇaa\n123456789012😃😃"}} +{"Key":"j"} +{"Get":{"state":"123456789012aaaa\n123456789012😃ˇ😃","mode":"Normal"}} +{"Put":{"state":"123456789012aaaaˇaaaaaaaa123456789012\nwow\n123456789012😃😃😃😃😃😃123456789012"}} +{"Key":"j"} +{"Key":"j"} +{"Get":{"state":"123456789012aaaaaaaaaaaa123456789012\nwow\n123456789012😃😃ˇ😃😃😃😃123456789012","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_x.json b/crates/vim2/test_data/test_x.json new file mode 100644 index 0000000000..cb7eb53472 --- /dev/null +++ b/crates/vim2/test_data/test_x.json @@ -0,0 +1,12 @@ +{"Put":{"state":"ˇTest"}} +{"Key":"x"} +{"Get":{"state":"ˇest","mode":"Normal"}} +{"Put":{"state":"Teˇst"}} +{"Key":"x"} +{"Get":{"state":"Teˇt","mode":"Normal"}} +{"Put":{"state":"Tesˇt"}} +{"Key":"x"} +{"Get":{"state":"Teˇs","mode":"Normal"}} +{"Put":{"state":"Tesˇt\ntest"}} +{"Key":"x"} +{"Get":{"state":"Teˇs\ntest","mode":"Normal"}} diff --git a/crates/vim2/test_data/test_zero.json b/crates/vim2/test_data/test_zero.json new file mode 100644 index 0000000000..bc1253deb5 --- /dev/null +++ b/crates/vim2/test_data/test_zero.json @@ -0,0 +1,7 @@ +{"Put":{"state":"The quˇick brown\nfox jumps over\nthe lazy dog"}} +{"Key":"0"} +{"Get":{"state":"ˇThe quick brown\nfox jumps over\nthe lazy dog","mode":"Normal"}} +{"Key":"1"} +{"Key":"0"} +{"Key":"l"} +{"Get":{"state":"The quick ˇbrown\nfox jumps over\nthe lazy dog","mode":"Normal"}} diff --git a/crates/zed2/Cargo.toml b/crates/zed2/Cargo.toml index ed7ed180f5..c1862fb116 100644 --- a/crates/zed2/Cargo.toml +++ b/crates/zed2/Cargo.toml @@ -69,7 +69,7 @@ theme = { package = "theme2", path = "../theme2" } theme_selector = { package = "theme_selector2", path = "../theme_selector2" } util = { path = "../util" } semantic_index = { package = "semantic_index2", path = "../semantic_index2" } -# vim = { path = "../vim" } +vim = { package = "vim2", path = "../vim2" } workspace = { package = "workspace2", path = "../workspace2" } welcome = { package = "welcome2", path = "../welcome2" } zed_actions = {package = "zed_actions2", path = "../zed_actions2"} diff --git a/crates/zed2/src/main.rs b/crates/zed2/src/main.rs index b97c4f40c3..4f7e1d3e72 100644 --- a/crates/zed2/src/main.rs +++ b/crates/zed2/src/main.rs @@ -211,7 +211,7 @@ fn main() { // diagnostics::init(cx); search::init(cx); semantic_index::init(fs.clone(), http.clone(), languages.clone(), cx); - // vim::init(cx); + vim::init(cx); terminal_view::init(cx); // journal2::init(app_state.clone(), cx); diff --git a/crates/zed2/src/zed2.rs b/crates/zed2/src/zed2.rs index d36d16a654..60e6467771 100644 --- a/crates/zed2/src/zed2.rs +++ b/crates/zed2/src/zed2.rs @@ -124,7 +124,7 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { activity_indicator::ActivityIndicator::new(workspace, app_state.languages.clone(), cx); let active_buffer_language = cx.build_view(|_| language_selector::ActiveBufferLanguage::new(workspace)); - // let vim_mode_indicator = cx.add_view(|cx| vim::ModeIndicator::new(cx)); + let vim_mode_indicator = cx.build_view(|cx| vim::ModeIndicator::new(cx)); let feedback_button = cx .build_view(|_| feedback::deploy_feedback_button::DeployFeedbackButton::new(workspace)); // let cursor_position = cx.add_view(|_| editor::items::CursorPosition::new()); @@ -136,13 +136,13 @@ pub fn initialize_workspace(app_state: Arc, cx: &mut AppContext) { // status_bar.add_right_item(copilot, cx); status_bar.add_right_item(copilot, cx); status_bar.add_right_item(active_buffer_language, cx); - // status_bar.add_right_item(vim_mode_indicator, cx); + status_bar.add_right_item(vim_mode_indicator, cx); status_bar.add_right_item(cursor_position, cx); }); auto_update::notify_of_any_new_update(cx); - // vim::observe_keystrokes(cx); + vim::observe_keystrokes(cx); let handle = cx.view().downgrade(); cx.on_window_should_close(move |cx| {