mod change;mod convert;mod delete;mod increment;pub(crate) mod mark;pub(crate) mod paste;pub(crate) mod repeat;mod scroll;pub(crate) mod search;pub mod substitute;mod toggle_comments;pub(crate) mod yank; use std::collections::HashMap;use std::sync::Arc; use crate::{ Vim, indent::IndentDirection, motion::{self, Motion, first_non_whitespace, next_line_end, right}, object::Object, state::{Mark, Mode, Operator}, surrounds::SurroundsType,};use collections::BTreeSet;use convert::ConvertTarget;use editor::Editor;use editor::{Anchor, SelectionEffects};use editor::{Bias, ToPoint};use editor::{display_map::ToDisplayPoint, movement};use gpui::{Context, Window, actions};use language::{Point, SelectionGoal};use log::error;use multi_buffer::MultiBufferRow; actions!( vim, [ /// Inserts text after the cursor. InsertAfter, /// Inserts text before the cursor. InsertBefore, /// Inserts at the first non-whitespace character. InsertFirstNonWhitespace, /// Inserts at the end of the line. InsertEndOfLine, /// Inserts a new line above the current line. InsertLineAbove, /// Inserts a new line below the current line. InsertLineBelow, /// Inserts an empty line above without entering insert mode. InsertEmptyLineAbove, /// Inserts an empty line below without entering insert mode. InsertEmptyLineBelow, /// Inserts at the previous insert position. InsertAtPrevious, /// Joins the current line with the next line. JoinLines, /// Joins lines without adding whitespace. JoinLinesNoWhitespace, /// Deletes character to the left. DeleteLeft, /// Deletes character to the right. DeleteRight, /// Deletes using Helix-style behavior. HelixDelete, /// Collapse the current selection HelixCollapseSelection, /// Changes from cursor to end of line. ChangeToEndOfLine, /// Deletes from cursor to end of line. DeleteToEndOfLine, /// Yanks (copies) the selected text. Yank, /// Yanks the entire line. YankLine, /// Yanks from cursor to end of line. YankToEndOfLine, /// Toggles the case of selected text. ChangeCase, /// Converts selected text to uppercase. ConvertToUpperCase, /// Converts selected text to lowercase. ConvertToLowerCase, /// Applies ROT13 cipher to selected text. ConvertToRot13, /// Applies ROT47 cipher to selected text. ConvertToRot47, /// Toggles comments for selected lines. ToggleComments, /// Shows the current location in the file. ShowLocation, /// Undoes the last change. Undo, /// Redoes the last undone change. Redo, /// Undoes all changes to the most recently changed line. UndoLastLine, /// Go to tab page (with count support). GoToTab, /// Go to previous tab page (with count support). GoToPreviousTab, /// Goes to the previous reference to the symbol under the cursor. GoToPreviousReference, /// Goes to the next reference to the symbol under the cursor. GoToNextReference, ]); pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) { Vim::action(editor, cx, Vim::insert_after); Vim::action(editor, cx, Vim::insert_before); Vim::action(editor, cx, Vim::insert_first_non_whitespace); Vim::action(editor, cx, Vim::insert_end_of_line); Vim::action(editor, cx, Vim::insert_line_above); Vim::action(editor, cx, Vim::insert_line_below); Vim::action(editor, cx, Vim::insert_empty_line_above); Vim::action(editor, cx, Vim::insert_empty_line_below); Vim::action(editor, cx, Vim::insert_at_previous); Vim::action(editor, cx, Vim::change_case); Vim::action(editor, cx, Vim::convert_to_upper_case); Vim::action(editor, cx, Vim::convert_to_lower_case); Vim::action(editor, cx, Vim::convert_to_rot13); Vim::action(editor, cx, Vim::convert_to_rot47); Vim::action(editor, cx, Vim::yank_line); Vim::action(editor, cx, Vim::yank_to_end_of_line); Vim::action(editor, cx, Vim::toggle_comments); Vim::action(editor, cx, Vim::paste); Vim::action(editor, cx, Vim::show_location); Vim::action(editor, cx, |vim, _: &DeleteLeft, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion(Motion::Left, times, forced_motion, window, cx); }); Vim::action(editor, cx, |vim, _: &DeleteRight, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion(Motion::Right, times, forced_motion, window, cx); }); Vim::action(editor, cx, |vim, _: &HelixDelete, window, cx| { vim.record_current_action(cx); vim.update_editor(cx, |_, editor, cx| { editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(|map, selection| { if selection.is_empty() { selection.end = movement::right(map, selection.end) } }) }) }); vim.visual_delete(false, window, cx); vim.switch_mode(Mode::HelixNormal, true, window, cx); }); Vim::action(editor, cx, |vim, _: &HelixCollapseSelection, window, cx| { vim.update_editor(cx, |_, editor, cx| { editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(|map, selection| { let mut point = selection.head(); if !selection.reversed && !selection.is_empty() { point = movement::left(map, selection.head()); } selection.collapse_to(point, selection.goal) }); }); }); }); Vim::action(editor, cx, |vim, _: &ChangeToEndOfLine, window, cx| { vim.start_recording(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.change_motion( Motion::EndOfLine { display_lines: false, }, times, forced_motion, window, cx, ); }); Vim::action(editor, cx, |vim, _: &DeleteToEndOfLine, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion( Motion::EndOfLine { display_lines: false, }, times, forced_motion, window, cx, ); }); Vim::action(editor, cx, |vim, _: &JoinLines, window, cx| { vim.join_lines_impl(true, window, cx); }); Vim::action(editor, cx, |vim, _: &JoinLinesNoWhitespace, window, cx| { vim.join_lines_impl(false, window, cx); }); Vim::action(editor, cx, |vim, _: &GoToPreviousReference, window, cx| { let count = Vim::take_count(cx); vim.update_editor(cx, |_, editor, cx| { let task = editor.go_to_reference_before_or_after_position( editor::Direction::Prev, count.unwrap_or(1), window, cx, ); if let Some(task) = task { task.detach_and_log_err(cx); }; }); }); Vim::action(editor, cx, |vim, _: &GoToNextReference, window, cx| { let count = Vim::take_count(cx); vim.update_editor(cx, |_, editor, cx| { let task = editor.go_to_reference_before_or_after_position( editor::Direction::Next, count.unwrap_or(1), window, cx, ); if let Some(task) = task { task.detach_and_log_err(cx); }; }); }); Vim::action(editor, cx, |vim, _: &Undo, window, cx| { let times = Vim::take_count(cx); Vim::take_forced_motion(cx); vim.update_editor(cx, |_, editor, cx| { for _ in 0..times.unwrap_or(1) { editor.undo(&editor::actions::Undo, window, cx); } }); }); Vim::action(editor, cx, |vim, _: &Redo, window, cx| { let times = Vim::take_count(cx); Vim::take_forced_motion(cx); vim.update_editor(cx, |_, editor, cx| { for _ in 0..times.unwrap_or(1) { editor.redo(&editor::actions::Redo, window, cx); } }); }); Vim::action(editor, cx, |vim, _: &UndoLastLine, window, cx| { Vim::take_forced_motion(cx); vim.update_editor(cx, |vim, editor, cx| { let snapshot = editor.buffer().read(cx).snapshot(cx); let Some(last_change) = editor.change_list.last_before_grouping() else { return; }; let anchors = last_change.to_vec(); let mut last_row = None; let ranges: Vec<_> = anchors .iter() .filter_map(|anchor| { let point = anchor.to_point(&snapshot); if last_row == Some(point.row) { return None; } last_row = Some(point.row); let line_range = Point::new(point.row, 0) ..Point::new(point.row, snapshot.line_len(MultiBufferRow(point.row))); Some(( snapshot.anchor_before(line_range.start) ..snapshot.anchor_after(line_range.end), line_range, )) }) .collect(); let edits = editor.buffer().update(cx, |buffer, cx| { let current_content = ranges .iter() .map(|(anchors, _)| { buffer .snapshot(cx) .text_for_range(anchors.clone()) .collect::<String>() }) .collect::<Vec<_>>(); let mut content_before_undo = current_content.clone(); let mut undo_count = 0; loop { let undone_tx = buffer.undo(cx); undo_count += 1; let mut content_after_undo = Vec::new(); let mut line_changed = false; for ((anchors, _), text_before_undo) in ranges.iter().zip(content_before_undo.iter()) { let snapshot = buffer.snapshot(cx); let text_after_undo = snapshot.text_for_range(anchors.clone()).collect::<String>(); if &text_after_undo != text_before_undo { line_changed = true; } content_after_undo.push(text_after_undo); } content_before_undo = content_after_undo; if !line_changed { break; } if undone_tx == vim.undo_last_line_tx { break; } } let edits = ranges .into_iter() .zip(content_before_undo.into_iter().zip(current_content)) .filter_map(|((_, mut points), (mut old_text, new_text))| { if new_text == old_text { return None; } let common_suffix_starts_at = old_text .char_indices() .rev() .zip(new_text.chars().rev()) .find_map( |((i, a), b)| { if a != b { Some(i + a.len_utf8()) } else { None } }, ) .unwrap_or(old_text.len()); points.end.column -= (old_text.len() - common_suffix_starts_at) as u32; old_text = old_text.split_at(common_suffix_starts_at).0.to_string(); let common_prefix_len = old_text .char_indices() .zip(new_text.chars()) .find_map(|((i, a), b)| if a != b { Some(i) } else { None }) .unwrap_or(0); points.start.column = common_prefix_len as u32; old_text = old_text.split_at(common_prefix_len).1.to_string(); Some((points, old_text)) }) .collect::<Vec<_>>(); for _ in 0..undo_count { buffer.redo(cx); } edits }); vim.undo_last_line_tx = editor.transact(window, cx, |editor, window, cx| { editor.change_list.invert_last_group(); editor.edit(edits, cx); editor.change_selections(SelectionEffects::default(), window, cx, |s| { s.select_anchor_ranges(anchors.into_iter().map(|a| a..a)); }) }); }); }); repeat::register(editor, cx); scroll::register(editor, cx); search::register(editor, cx); substitute::register(editor, cx); increment::register(editor, cx);} impl Vim { pub fn normal_motion( &mut self, motion: Motion, operator: Option<Operator>, times: Option<usize>, forced_motion: bool, window: &mut Window, cx: &mut Context<Self>, ) { match operator { None => self.move_cursor(motion, times, window, cx), Some(Operator::Change) => self.change_motion(motion, times, forced_motion, window, cx), Some(Operator::Delete) => self.delete_motion(motion, times, forced_motion, window, cx), Some(Operator::Yank) => self.yank_motion(motion, times, forced_motion, window, cx), Some(Operator::AddSurrounds { target: None }) => {} Some(Operator::Indent) => self.indent_motion( motion, times, forced_motion, IndentDirection::In, window, cx, ), Some(Operator::Rewrap) => self.rewrap_motion(motion, times, forced_motion, window, cx), Some(Operator::Outdent) => self.indent_motion( motion, times, forced_motion, IndentDirection::Out, window, cx, ), Some(Operator::AutoIndent) => self.indent_motion( motion, times, forced_motion, IndentDirection::Auto, window, cx, ), Some(Operator::ShellCommand) => { self.shell_command_motion(motion, times, forced_motion, window, cx) } Some(Operator::Lowercase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::LowerCase, window, cx, ), Some(Operator::Uppercase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::UpperCase, window, cx, ), Some(Operator::OppositeCase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::OppositeCase, window, cx, ), Some(Operator::Rot13) => self.convert_motion( motion, times, forced_motion, ConvertTarget::Rot13, window, cx, ), Some(Operator::Rot47) => self.convert_motion( motion, times, forced_motion, ConvertTarget::Rot47, window, cx, ), Some(Operator::ToggleComments) => { self.toggle_comments_motion(motion, times, forced_motion, window, cx) } Some(Operator::ReplaceWithRegister) => { self.replace_with_register_motion(motion, times, forced_motion, window, cx) } Some(Operator::Exchange) => { self.exchange_motion(motion, times, forced_motion, window, cx) } Some(operator) => { // Can't do anything for text objects, Ignoring error!("Unexpected normal mode motion operator: {:?}", operator) } } // Exit temporary normal mode (if active). self.exit_temporary_normal(window, cx); } pub fn normal_object( &mut self, object: Object, times: Option<usize>, opening: bool, window: &mut Window, cx: &mut Context<Self>, ) { let mut waiting_operator: Option<Operator> = None; match self.maybe_pop_operator() { Some(Operator::Object { around }) => match self.maybe_pop_operator() { Some(Operator::Change) => self.change_object(object, around, times, window, cx), Some(Operator::Delete) => self.delete_object(object, around, times, window, cx), Some(Operator::Yank) => self.yank_object(object, around, times, window, cx), Some(Operator::Indent) => { self.indent_object(object, around, IndentDirection::In, times, window, cx) } Some(Operator::Outdent) => { self.indent_object(object, around, IndentDirection::Out, times, window, cx) }Lines 1–500 of 2351. Load more
mod change; mod convert; mod delete; mod increment; pub(crate) mod mark; pub(crate) mod paste; pub(crate) mod repeat; mod scroll; pub(crate) mod search; pub mod substitute; mod toggle_comments; pub(crate) mod yank; use std::collections::HashMap; use std::sync::Arc; use crate::{ Vim, indent::IndentDirection, motion::{self, Motion, first_non_whitespace, next_line_end, right}, object::Object, state::{Mark, Mode, Operator}, surrounds::SurroundsType, }; use collections::BTreeSet; use convert::ConvertTarget; use editor::Editor; use editor::{Anchor, SelectionEffects}; use editor::{Bias, ToPoint}; use editor::{display_map::ToDisplayPoint, movement}; use gpui::{Context, Window, actions}; use language::{Point, SelectionGoal}; use log::error; use multi_buffer::MultiBufferRow; actions!( vim, [ /// Inserts text after the cursor. InsertAfter, /// Inserts text before the cursor. InsertBefore, /// Inserts at the first non-whitespace character. InsertFirstNonWhitespace, /// Inserts at the end of the line. InsertEndOfLine, /// Inserts a new line above the current line. InsertLineAbove, /// Inserts a new line below the current line. InsertLineBelow, /// Inserts an empty line above without entering insert mode. InsertEmptyLineAbove, /// Inserts an empty line below without entering insert mode. InsertEmptyLineBelow, /// Inserts at the previous insert position. InsertAtPrevious, /// Joins the current line with the next line. JoinLines, /// Joins lines without adding whitespace. JoinLinesNoWhitespace, /// Deletes character to the left. DeleteLeft, /// Deletes character to the right. DeleteRight, /// Deletes using Helix-style behavior. HelixDelete, /// Collapse the current selection HelixCollapseSelection, /// Changes from cursor to end of line. ChangeToEndOfLine, /// Deletes from cursor to end of line. DeleteToEndOfLine, /// Yanks (copies) the selected text. Yank, /// Yanks the entire line. YankLine, /// Yanks from cursor to end of line. YankToEndOfLine, /// Toggles the case of selected text. ChangeCase, /// Converts selected text to uppercase. ConvertToUpperCase, /// Converts selected text to lowercase. ConvertToLowerCase, /// Applies ROT13 cipher to selected text. ConvertToRot13, /// Applies ROT47 cipher to selected text. ConvertToRot47, /// Toggles comments for selected lines. ToggleComments, /// Shows the current location in the file. ShowLocation, /// Undoes the last change. Undo, /// Redoes the last undone change. Redo, /// Undoes all changes to the most recently changed line. UndoLastLine, /// Go to tab page (with count support). GoToTab, /// Go to previous tab page (with count support). GoToPreviousTab, /// Goes to the previous reference to the symbol under the cursor. GoToPreviousReference, /// Goes to the next reference to the symbol under the cursor. GoToNextReference, ] ); pub(crate) fn register(editor: &mut Editor, cx: &mut Context<Vim>) { Vim::action(editor, cx, Vim::insert_after); Vim::action(editor, cx, Vim::insert_before); Vim::action(editor, cx, Vim::insert_first_non_whitespace); Vim::action(editor, cx, Vim::insert_end_of_line); Vim::action(editor, cx, Vim::insert_line_above); Vim::action(editor, cx, Vim::insert_line_below); Vim::action(editor, cx, Vim::insert_empty_line_above); Vim::action(editor, cx, Vim::insert_empty_line_below); Vim::action(editor, cx, Vim::insert_at_previous); Vim::action(editor, cx, Vim::change_case); Vim::action(editor, cx, Vim::convert_to_upper_case); Vim::action(editor, cx, Vim::convert_to_lower_case); Vim::action(editor, cx, Vim::convert_to_rot13); Vim::action(editor, cx, Vim::convert_to_rot47); Vim::action(editor, cx, Vim::yank_line); Vim::action(editor, cx, Vim::yank_to_end_of_line); Vim::action(editor, cx, Vim::toggle_comments); Vim::action(editor, cx, Vim::paste); Vim::action(editor, cx, Vim::show_location); Vim::action(editor, cx, |vim, _: &DeleteLeft, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion(Motion::Left, times, forced_motion, window, cx); }); Vim::action(editor, cx, |vim, _: &DeleteRight, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion(Motion::Right, times, forced_motion, window, cx); }); Vim::action(editor, cx, |vim, _: &HelixDelete, window, cx| { vim.record_current_action(cx); vim.update_editor(cx, |_, editor, cx| { editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(|map, selection| { if selection.is_empty() { selection.end = movement::right(map, selection.end) } }) }) }); vim.visual_delete(false, window, cx); vim.switch_mode(Mode::HelixNormal, true, window, cx); }); Vim::action(editor, cx, |vim, _: &HelixCollapseSelection, window, cx| { vim.update_editor(cx, |_, editor, cx| { editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| { s.move_with(|map, selection| { let mut point = selection.head(); if !selection.reversed && !selection.is_empty() { point = movement::left(map, selection.head()); } selection.collapse_to(point, selection.goal) }); }); }); }); Vim::action(editor, cx, |vim, _: &ChangeToEndOfLine, window, cx| { vim.start_recording(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.change_motion( Motion::EndOfLine { display_lines: false, }, times, forced_motion, window, cx, ); }); Vim::action(editor, cx, |vim, _: &DeleteToEndOfLine, window, cx| { vim.record_current_action(cx); let times = Vim::take_count(cx); let forced_motion = Vim::take_forced_motion(cx); vim.delete_motion( Motion::EndOfLine { display_lines: false, }, times, forced_motion, window, cx, ); }); Vim::action(editor, cx, |vim, _: &JoinLines, window, cx| { vim.join_lines_impl(true, window, cx); }); Vim::action(editor, cx, |vim, _: &JoinLinesNoWhitespace, window, cx| { vim.join_lines_impl(false, window, cx); }); Vim::action(editor, cx, |vim, _: &GoToPreviousReference, window, cx| { let count = Vim::take_count(cx); vim.update_editor(cx, |_, editor, cx| { let task = editor.go_to_reference_before_or_after_position( editor::Direction::Prev, count.unwrap_or(1), window, cx, ); if let Some(task) = task { task.detach_and_log_err(cx); }; }); }); Vim::action(editor, cx, |vim, _: &GoToNextReference, window, cx| { let count = Vim::take_count(cx); vim.update_editor(cx, |_, editor, cx| { let task = editor.go_to_reference_before_or_after_position( editor::Direction::Next, count.unwrap_or(1), window, cx, ); if let Some(task) = task { task.detach_and_log_err(cx); }; }); }); Vim::action(editor, cx, |vim, _: &Undo, window, cx| { let times = Vim::take_count(cx); Vim::take_forced_motion(cx); vim.update_editor(cx, |_, editor, cx| { for _ in 0..times.unwrap_or(1) { editor.undo(&editor::actions::Undo, window, cx); } }); }); Vim::action(editor, cx, |vim, _: &Redo, window, cx| { let times = Vim::take_count(cx); Vim::take_forced_motion(cx); vim.update_editor(cx, |_, editor, cx| { for _ in 0..times.unwrap_or(1) { editor.redo(&editor::actions::Redo, window, cx); } }); }); Vim::action(editor, cx, |vim, _: &UndoLastLine, window, cx| { Vim::take_forced_motion(cx); vim.update_editor(cx, |vim, editor, cx| { let snapshot = editor.buffer().read(cx).snapshot(cx); let Some(last_change) = editor.change_list.last_before_grouping() else { return; }; let anchors = last_change.to_vec(); let mut last_row = None; let ranges: Vec<_> = anchors .iter() .filter_map(|anchor| { let point = anchor.to_point(&snapshot); if last_row == Some(point.row) { return None; } last_row = Some(point.row); let line_range = Point::new(point.row, 0) ..Point::new(point.row, snapshot.line_len(MultiBufferRow(point.row))); Some(( snapshot.anchor_before(line_range.start) ..snapshot.anchor_after(line_range.end), line_range, )) }) .collect(); let edits = editor.buffer().update(cx, |buffer, cx| { let current_content = ranges .iter() .map(|(anchors, _)| { buffer .snapshot(cx) .text_for_range(anchors.clone()) .collect::<String>() }) .collect::<Vec<_>>(); let mut content_before_undo = current_content.clone(); let mut undo_count = 0; loop { let undone_tx = buffer.undo(cx); undo_count += 1; let mut content_after_undo = Vec::new(); let mut line_changed = false; for ((anchors, _), text_before_undo) in ranges.iter().zip(content_before_undo.iter()) { let snapshot = buffer.snapshot(cx); let text_after_undo = snapshot.text_for_range(anchors.clone()).collect::<String>(); if &text_after_undo != text_before_undo { line_changed = true; } content_after_undo.push(text_after_undo); } content_before_undo = content_after_undo; if !line_changed { break; } if undone_tx == vim.undo_last_line_tx { break; } } let edits = ranges .into_iter() .zip(content_before_undo.into_iter().zip(current_content)) .filter_map(|((_, mut points), (mut old_text, new_text))| { if new_text == old_text { return None; } let common_suffix_starts_at = old_text .char_indices() .rev() .zip(new_text.chars().rev()) .find_map( |((i, a), b)| { if a != b { Some(i + a.len_utf8()) } else { None } }, ) .unwrap_or(old_text.len()); points.end.column -= (old_text.len() - common_suffix_starts_at) as u32; old_text = old_text.split_at(common_suffix_starts_at).0.to_string(); let common_prefix_len = old_text .char_indices() .zip(new_text.chars()) .find_map(|((i, a), b)| if a != b { Some(i) } else { None }) .unwrap_or(0); points.start.column = common_prefix_len as u32; old_text = old_text.split_at(common_prefix_len).1.to_string(); Some((points, old_text)) }) .collect::<Vec<_>>(); for _ in 0..undo_count { buffer.redo(cx); } edits }); vim.undo_last_line_tx = editor.transact(window, cx, |editor, window, cx| { editor.change_list.invert_last_group(); editor.edit(edits, cx); editor.change_selections(SelectionEffects::default(), window, cx, |s| { s.select_anchor_ranges(anchors.into_iter().map(|a| a..a)); }) }); }); }); repeat::register(editor, cx); scroll::register(editor, cx); search::register(editor, cx); substitute::register(editor, cx); increment::register(editor, cx); } impl Vim { pub fn normal_motion( &mut self, motion: Motion, operator: Option<Operator>, times: Option<usize>, forced_motion: bool, window: &mut Window, cx: &mut Context<Self>, ) { match operator { None => self.move_cursor(motion, times, window, cx), Some(Operator::Change) => self.change_motion(motion, times, forced_motion, window, cx), Some(Operator::Delete) => self.delete_motion(motion, times, forced_motion, window, cx), Some(Operator::Yank) => self.yank_motion(motion, times, forced_motion, window, cx), Some(Operator::AddSurrounds { target: None }) => {} Some(Operator::Indent) => self.indent_motion( motion, times, forced_motion, IndentDirection::In, window, cx, ), Some(Operator::Rewrap) => self.rewrap_motion(motion, times, forced_motion, window, cx), Some(Operator::Outdent) => self.indent_motion( motion, times, forced_motion, IndentDirection::Out, window, cx, ), Some(Operator::AutoIndent) => self.indent_motion( motion, times, forced_motion, IndentDirection::Auto, window, cx, ), Some(Operator::ShellCommand) => { self.shell_command_motion(motion, times, forced_motion, window, cx) } Some(Operator::Lowercase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::LowerCase, window, cx, ), Some(Operator::Uppercase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::UpperCase, window, cx, ), Some(Operator::OppositeCase) => self.convert_motion( motion, times, forced_motion, ConvertTarget::OppositeCase, window, cx, ), Some(Operator::Rot13) => self.convert_motion( motion, times, forced_motion, ConvertTarget::Rot13, window, cx, ), Some(Operator::Rot47) => self.convert_motion( motion, times, forced_motion, ConvertTarget::Rot47, window, cx, ), Some(Operator::ToggleComments) => { self.toggle_comments_motion(motion, times, forced_motion, window, cx) } Some(Operator::ReplaceWithRegister) => { self.replace_with_register_motion(motion, times, forced_motion, window, cx) } Some(Operator::Exchange) => { self.exchange_motion(motion, times, forced_motion, window, cx) } Some(operator) => { // Can't do anything for text objects, Ignoring error!("Unexpected normal mode motion operator: {:?}", operator) } } // Exit temporary normal mode (if active). self.exit_temporary_normal(window, cx); } pub fn normal_object( &mut self, object: Object, times: Option<usize>, opening: bool, window: &mut Window, cx: &mut Context<Self>, ) { let mut waiting_operator: Option<Operator> = None; match self.maybe_pop_operator() { Some(Operator::Object { around }) => match self.maybe_pop_operator() { Some(Operator::Change) => self.change_object(object, around, times, window, cx), Some(Operator::Delete) => self.delete_object(object, around, times, window, cx), Some(Operator::Yank) => self.yank_object(object, around, times, window, cx), Some(Operator::Indent) => { self.indent_object(object, around, IndentDirection::In, times, window, cx) } Some(Operator::Outdent) => { self.indent_object(object, around, IndentDirection::Out, times, window, cx) }