use editor::{ display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint}, movement::{ self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails, }, Bias, DisplayPoint, ToOffset,};use gpui::{actions, impl_actions, px, ViewContext, WindowContext};use language::{char_kind, CharKind, Point, Selection, SelectionGoal};use serde::Deserialize;use workspace::Workspace; use crate::{ normal::normal_motion, state::{Mode, Operator}, utils::coerce_punctuation, visual::visual_motion, Vim,}; #[derive(Clone, Debug, PartialEq, Eq)]pub enum Motion { Left, Backspace, Down { display_lines: bool, }, Up { display_lines: bool, }, Right, Space, NextWordStart { ignore_punctuation: bool, }, NextWordEnd { ignore_punctuation: bool, }, PreviousWordStart { ignore_punctuation: bool, }, PreviousWordEnd { ignore_punctuation: bool, }, NextSubwordStart { ignore_punctuation: bool, }, NextSubwordEnd { ignore_punctuation: bool, }, PreviousSubwordStart { ignore_punctuation: bool, }, PreviousSubwordEnd { 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, mode: FindRange, smartcase: bool, }, FindBackward { after: bool, char: char, mode: FindRange, smartcase: bool, }, RepeatFind { last_find: Box<Motion>, }, RepeatFindReversed { last_find: Box<Motion>, }, NextLineStart, StartOfLineDownward, EndOfLineDownward, GoToColumn, WindowTop, WindowMiddle, WindowBottom,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct NextWordStart { #[serde(default)] ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct NextWordEnd { #[serde(default)] ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct PreviousWordStart { #[serde(default)] ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct PreviousWordEnd { #[serde(default)] ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct NextSubwordStart { #[serde(default)] pub(crate) ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct NextSubwordEnd { #[serde(default)] pub(crate) ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct PreviousSubwordStart { #[serde(default)] pub(crate) ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct PreviousSubwordEnd { #[serde(default)] pub(crate) ignore_punctuation: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct Up { #[serde(default)] pub(crate) display_lines: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub(crate) struct Down { #[serde(default)] pub(crate) display_lines: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct FirstNonWhitespace { #[serde(default)] display_lines: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]struct EndOfLine { #[serde(default)] display_lines: bool,} #[derive(Clone, Deserialize, PartialEq)]#[serde(rename_all = "camelCase")]pub struct StartOfLine { #[serde(default)] pub(crate) display_lines: bool,} impl_actions!( vim, [ StartOfLine, EndOfLine, FirstNonWhitespace, Down, Up, NextWordStart, NextWordEnd, PreviousWordStart, PreviousWordEnd, NextSubwordStart, NextSubwordEnd, PreviousSubwordStart, PreviousSubwordEnd, ]); actions!( vim, [ Left, Backspace, Right, Space, CurrentLine, StartOfParagraph, EndOfParagraph, StartOfDocument, EndOfDocument, Matching, NextLineStart, StartOfLineDownward, EndOfLineDownward, GoToColumn, RepeatFind, RepeatFindReversed, WindowTop, WindowMiddle, WindowBottom, ]); pub fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) { workspace.register_action(|_: &mut Workspace, _: &Left, cx: _| motion(Motion::Left, cx)); workspace .register_action(|_: &mut Workspace, _: &Backspace, cx: _| motion(Motion::Backspace, cx)); workspace.register_action(|_: &mut Workspace, action: &Down, cx: _| { motion( Motion::Down { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &Up, cx: _| { motion( Motion::Up { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx)); workspace.register_action(|_: &mut Workspace, _: &Space, cx: _| motion(Motion::Space, cx)); workspace.register_action(|_: &mut Workspace, action: &FirstNonWhitespace, cx: _| { motion( Motion::FirstNonWhitespace { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &StartOfLine, cx: _| { motion( Motion::StartOfLine { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &EndOfLine, cx: _| { motion( Motion::EndOfLine { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, _: &CurrentLine, cx: _| { motion(Motion::CurrentLine, cx) }); workspace.register_action(|_: &mut Workspace, _: &StartOfParagraph, cx: _| { motion(Motion::StartOfParagraph, cx) }); workspace.register_action(|_: &mut Workspace, _: &EndOfParagraph, cx: _| { motion(Motion::EndOfParagraph, cx) }); workspace.register_action(|_: &mut Workspace, _: &StartOfDocument, cx: _| { motion(Motion::StartOfDocument, cx) }); workspace.register_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| { motion(Motion::EndOfDocument, cx) }); workspace .register_action(|_: &mut Workspace, _: &Matching, cx: _| motion(Motion::Matching, cx)); workspace.register_action( |_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| { motion(Motion::NextWordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextWordEnd { ignore_punctuation }: &NextWordEnd, cx: _| { motion(Motion::NextWordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousWordStart { ignore_punctuation }: &PreviousWordStart, cx: _| { motion(Motion::PreviousWordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousWordEnd { ignore_punctuation }, cx: _| { motion(Motion::PreviousWordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextSubwordStart { ignore_punctuation }: &NextSubwordStart, cx: _| { motion(Motion::NextSubwordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextSubwordEnd { ignore_punctuation }: &NextSubwordEnd, cx: _| { motion(Motion::NextSubwordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousSubwordStart { ignore_punctuation }: &PreviousSubwordStart, cx: _| { motion(Motion::PreviousSubwordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousSubwordEnd { ignore_punctuation }, cx: _| { motion(Motion::PreviousSubwordEnd { ignore_punctuation }, cx) }, ); workspace.register_action(|_: &mut Workspace, &NextLineStart, cx: _| { motion(Motion::NextLineStart, cx) }); workspace.register_action(|_: &mut Workspace, &StartOfLineDownward, cx: _| { motion(Motion::StartOfLineDownward, cx) }); workspace.register_action(|_: &mut Workspace, &EndOfLineDownward, cx: _| { motion(Motion::EndOfLineDownward, cx) }); workspace .register_action(|_: &mut Workspace, &GoToColumn, cx: _| motion(Motion::GoToColumn, cx)); workspace.register_action(|_: &mut Workspace, _: &RepeatFind, cx: _| { if let Some(last_find) = Vim::read(cx) .workspace_state .last_find .clone() .map(Box::new) { motion(Motion::RepeatFind { last_find }, cx); } }); workspace.register_action(|_: &mut Workspace, _: &RepeatFindReversed, cx: _| { if let Some(last_find) = Vim::read(cx) .workspace_state .last_find .clone() .map(Box::new) { motion(Motion::RepeatFindReversed { last_find }, cx); } }); workspace.register_action(|_: &mut Workspace, &WindowTop, cx: _| motion(Motion::WindowTop, cx)); workspace.register_action(|_: &mut Workspace, &WindowMiddle, cx: _| { motion(Motion::WindowMiddle, cx) }); workspace.register_action(|_: &mut Workspace, &WindowBottom, cx: _| { motion(Motion::WindowBottom, 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));} // Motion handling is specified here:// https://github.com/vim/vim/blob/master/runtime/doc/motion.txtimpl Motion { pub fn linewise(&self) -> bool { use Motion::*; match self { Down { .. } | Up { .. } | StartOfDocument | EndOfDocument | CurrentLine | NextLineStart | StartOfLineDownward | StartOfParagraph | WindowTop | WindowMiddle | WindowBottom | EndOfParagraph => true, EndOfLine { .. } | Matching | FindForward { .. } | Left | Backspace | Right | Space | StartOfLine { .. } | EndOfLineDownward | GoToColumn | NextWordStart { .. } | NextWordEnd { .. } | PreviousWordStart { .. } | PreviousWordEnd { .. } | NextSubwordStart { .. } | NextSubwordEnd { .. } | PreviousSubwordStart { .. } | PreviousSubwordEnd { .. } | FirstNonWhitespace { .. } | FindBackward { .. } | RepeatFind { .. } | RepeatFindReversed { .. } => false, } } pub fn infallible(&self) -> bool { use Motion::*; match self { StartOfDocument | EndOfDocument | CurrentLine => true, Down { .. } | Up { .. } | EndOfLine { .. } | Matching | FindForward { .. } | RepeatFind { .. } | Left | Backspace | Right | Space | StartOfLine { .. } | StartOfParagraph | EndOfParagraph | StartOfLineDownward | EndOfLineDownward | GoToColumn | NextWordStart { .. } | NextWordEnd { .. } | PreviousWordStart { .. } | PreviousWordEnd { .. } | NextSubwordStart { .. } | NextSubwordEnd { .. } | PreviousSubwordStart { .. } | PreviousSubwordEnd { .. } | FirstNonWhitespace { .. } | FindBackward { .. } | RepeatFindReversed { .. } | WindowTop | WindowMiddle | WindowBottom | NextLineStart => false, } } pub fn inclusive(&self) -> bool { use Motion::*; match self { Down { .. } | Up { .. } | StartOfDocument | EndOfDocument | CurrentLine | EndOfLine { .. } | EndOfLineDownward | Matching | FindForward { .. } | WindowTop | WindowMiddle | WindowBottom | NextWordEnd { .. } | PreviousWordEnd { .. } | NextSubwordEnd { .. } | PreviousSubwordEnd { .. } | NextLineStart => true, LeftLines 1–500 of 2108. Load more
use editor::{ display_map::{DisplaySnapshot, FoldPoint, ToDisplayPoint}, movement::{ self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails, }, Bias, DisplayPoint, ToOffset, }; use gpui::{actions, impl_actions, px, ViewContext, WindowContext}; use language::{char_kind, CharKind, Point, Selection, SelectionGoal}; use serde::Deserialize; use workspace::Workspace; use crate::{ normal::normal_motion, state::{Mode, Operator}, utils::coerce_punctuation, visual::visual_motion, Vim, }; #[derive(Clone, Debug, PartialEq, Eq)] pub enum Motion { Left, Backspace, Down { display_lines: bool, }, Up { display_lines: bool, }, Right, Space, NextWordStart { ignore_punctuation: bool, }, NextWordEnd { ignore_punctuation: bool, }, PreviousWordStart { ignore_punctuation: bool, }, PreviousWordEnd { ignore_punctuation: bool, }, NextSubwordStart { ignore_punctuation: bool, }, NextSubwordEnd { ignore_punctuation: bool, }, PreviousSubwordStart { ignore_punctuation: bool, }, PreviousSubwordEnd { 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, mode: FindRange, smartcase: bool, }, FindBackward { after: bool, char: char, mode: FindRange, smartcase: bool, }, RepeatFind { last_find: Box<Motion>, }, RepeatFindReversed { last_find: Box<Motion>, }, NextLineStart, StartOfLineDownward, EndOfLineDownward, GoToColumn, WindowTop, WindowMiddle, WindowBottom, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct NextWordStart { #[serde(default)] ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct NextWordEnd { #[serde(default)] ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct PreviousWordStart { #[serde(default)] ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct PreviousWordEnd { #[serde(default)] ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct NextSubwordStart { #[serde(default)] pub(crate) ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct NextSubwordEnd { #[serde(default)] pub(crate) ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct PreviousSubwordStart { #[serde(default)] pub(crate) ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct PreviousSubwordEnd { #[serde(default)] pub(crate) ignore_punctuation: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct Up { #[serde(default)] pub(crate) display_lines: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub(crate) struct Down { #[serde(default)] pub(crate) display_lines: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct FirstNonWhitespace { #[serde(default)] display_lines: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] struct EndOfLine { #[serde(default)] display_lines: bool, } #[derive(Clone, Deserialize, PartialEq)] #[serde(rename_all = "camelCase")] pub struct StartOfLine { #[serde(default)] pub(crate) display_lines: bool, } impl_actions!( vim, [ StartOfLine, EndOfLine, FirstNonWhitespace, Down, Up, NextWordStart, NextWordEnd, PreviousWordStart, PreviousWordEnd, NextSubwordStart, NextSubwordEnd, PreviousSubwordStart, PreviousSubwordEnd, ] ); actions!( vim, [ Left, Backspace, Right, Space, CurrentLine, StartOfParagraph, EndOfParagraph, StartOfDocument, EndOfDocument, Matching, NextLineStart, StartOfLineDownward, EndOfLineDownward, GoToColumn, RepeatFind, RepeatFindReversed, WindowTop, WindowMiddle, WindowBottom, ] ); pub fn register(workspace: &mut Workspace, _: &mut ViewContext<Workspace>) { workspace.register_action(|_: &mut Workspace, _: &Left, cx: _| motion(Motion::Left, cx)); workspace .register_action(|_: &mut Workspace, _: &Backspace, cx: _| motion(Motion::Backspace, cx)); workspace.register_action(|_: &mut Workspace, action: &Down, cx: _| { motion( Motion::Down { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &Up, cx: _| { motion( Motion::Up { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, _: &Right, cx: _| motion(Motion::Right, cx)); workspace.register_action(|_: &mut Workspace, _: &Space, cx: _| motion(Motion::Space, cx)); workspace.register_action(|_: &mut Workspace, action: &FirstNonWhitespace, cx: _| { motion( Motion::FirstNonWhitespace { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &StartOfLine, cx: _| { motion( Motion::StartOfLine { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, action: &EndOfLine, cx: _| { motion( Motion::EndOfLine { display_lines: action.display_lines, }, cx, ) }); workspace.register_action(|_: &mut Workspace, _: &CurrentLine, cx: _| { motion(Motion::CurrentLine, cx) }); workspace.register_action(|_: &mut Workspace, _: &StartOfParagraph, cx: _| { motion(Motion::StartOfParagraph, cx) }); workspace.register_action(|_: &mut Workspace, _: &EndOfParagraph, cx: _| { motion(Motion::EndOfParagraph, cx) }); workspace.register_action(|_: &mut Workspace, _: &StartOfDocument, cx: _| { motion(Motion::StartOfDocument, cx) }); workspace.register_action(|_: &mut Workspace, _: &EndOfDocument, cx: _| { motion(Motion::EndOfDocument, cx) }); workspace .register_action(|_: &mut Workspace, _: &Matching, cx: _| motion(Motion::Matching, cx)); workspace.register_action( |_: &mut Workspace, &NextWordStart { ignore_punctuation }: &NextWordStart, cx: _| { motion(Motion::NextWordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextWordEnd { ignore_punctuation }: &NextWordEnd, cx: _| { motion(Motion::NextWordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousWordStart { ignore_punctuation }: &PreviousWordStart, cx: _| { motion(Motion::PreviousWordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousWordEnd { ignore_punctuation }, cx: _| { motion(Motion::PreviousWordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextSubwordStart { ignore_punctuation }: &NextSubwordStart, cx: _| { motion(Motion::NextSubwordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &NextSubwordEnd { ignore_punctuation }: &NextSubwordEnd, cx: _| { motion(Motion::NextSubwordEnd { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousSubwordStart { ignore_punctuation }: &PreviousSubwordStart, cx: _| { motion(Motion::PreviousSubwordStart { ignore_punctuation }, cx) }, ); workspace.register_action( |_: &mut Workspace, &PreviousSubwordEnd { ignore_punctuation }, cx: _| { motion(Motion::PreviousSubwordEnd { ignore_punctuation }, cx) }, ); workspace.register_action(|_: &mut Workspace, &NextLineStart, cx: _| { motion(Motion::NextLineStart, cx) }); workspace.register_action(|_: &mut Workspace, &StartOfLineDownward, cx: _| { motion(Motion::StartOfLineDownward, cx) }); workspace.register_action(|_: &mut Workspace, &EndOfLineDownward, cx: _| { motion(Motion::EndOfLineDownward, cx) }); workspace .register_action(|_: &mut Workspace, &GoToColumn, cx: _| motion(Motion::GoToColumn, cx)); workspace.register_action(|_: &mut Workspace, _: &RepeatFind, cx: _| { if let Some(last_find) = Vim::read(cx) .workspace_state .last_find .clone() .map(Box::new) { motion(Motion::RepeatFind { last_find }, cx); } }); workspace.register_action(|_: &mut Workspace, _: &RepeatFindReversed, cx: _| { if let Some(last_find) = Vim::read(cx) .workspace_state .last_find .clone() .map(Box::new) { motion(Motion::RepeatFindReversed { last_find }, cx); } }); workspace.register_action(|_: &mut Workspace, &WindowTop, cx: _| motion(Motion::WindowTop, cx)); workspace.register_action(|_: &mut Workspace, &WindowMiddle, cx: _| { motion(Motion::WindowMiddle, cx) }); workspace.register_action(|_: &mut Workspace, &WindowBottom, cx: _| { motion(Motion::WindowBottom, 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)); } // 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 | WindowTop | WindowMiddle | WindowBottom | EndOfParagraph => true, EndOfLine { .. } | Matching | FindForward { .. } | Left | Backspace | Right | Space | StartOfLine { .. } | EndOfLineDownward | GoToColumn | NextWordStart { .. } | NextWordEnd { .. } | PreviousWordStart { .. } | PreviousWordEnd { .. } | NextSubwordStart { .. } | NextSubwordEnd { .. } | PreviousSubwordStart { .. } | PreviousSubwordEnd { .. } | FirstNonWhitespace { .. } | FindBackward { .. } | RepeatFind { .. } | RepeatFindReversed { .. } => false, } } pub fn infallible(&self) -> bool { use Motion::*; match self { StartOfDocument | EndOfDocument | CurrentLine => true, Down { .. } | Up { .. } | EndOfLine { .. } | Matching | FindForward { .. } | RepeatFind { .. } | Left | Backspace | Right | Space | StartOfLine { .. } | StartOfParagraph | EndOfParagraph | StartOfLineDownward | EndOfLineDownward | GoToColumn | NextWordStart { .. } | NextWordEnd { .. } | PreviousWordStart { .. } | PreviousWordEnd { .. } | NextSubwordStart { .. } | NextSubwordEnd { .. } | PreviousSubwordStart { .. } | PreviousSubwordEnd { .. } | FirstNonWhitespace { .. } | FindBackward { .. } | RepeatFindReversed { .. } | WindowTop | WindowMiddle | WindowBottom | NextLineStart => false, } } pub fn inclusive(&self) -> bool { use Motion::*; match self { Down { .. } | Up { .. } | StartOfDocument | EndOfDocument | CurrentLine | EndOfLine { .. } | EndOfLineDownward | Matching | FindForward { .. } | WindowTop | WindowMiddle | WindowBottom | NextWordEnd { .. } | PreviousWordEnd { .. } | NextSubwordEnd { .. } | PreviousSubwordEnd { .. } | NextLineStart => true, Left