2474 lines · 75.7 KB · Rust
RawDownload
use editor::{    display_map::{DisplayRow, DisplaySnapshot, FoldPoint, ToDisplayPoint},    movement::{        self, find_boundary, find_preceding_boundary_display_point, FindRange, TextLayoutDetails,    },    scroll::Autoscroll,    Anchor, Bias, DisplayPoint, Editor, RowExt, ToOffset,};use gpui::{actions, impl_actions, px, ViewContext};use language::{CharKind, Point, Selection, SelectionGoal};use multi_buffer::MultiBufferRow;use serde::Deserialize;use std::ops::Range; use crate::{    normal::mark,    state::{Mode, Operator},    surrounds::SurroundsType,    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,    },    SentenceBackward,    SentenceForward,    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,    PreviousLineStart,    StartOfLineDownward,    EndOfLineDownward,    GoToColumn,    WindowTop,    WindowMiddle,    WindowBottom,     // we don't have a good way to run a search synchronously, so    // we handle search motions by running the search async and then    // calling back into motion with this    ZedSearchResult {        prior_selections: Vec<Range<Anchor>>,        new_selections: Vec<Range<Anchor>>,    },    Jump {        anchor: Anchor,        line: bool,    },} #[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,        SentenceForward,        SentenceBackward,        StartOfParagraph,        EndOfParagraph,        StartOfDocument,        EndOfDocument,        Matching,        NextLineStart,        PreviousLineStart,        StartOfLineDownward,        EndOfLineDownward,        GoToColumn,        RepeatFind,        RepeatFindReversed,        WindowTop,        WindowMiddle,        WindowBottom,    ]); pub fn register(editor: &mut Editor, cx: &mut ViewContext<Vim>) {    Vim::action(editor, cx, |vim, _: &Left, cx| vim.motion(Motion::Left, cx));    Vim::action(editor, cx, |vim, _: &Backspace, cx| {        vim.motion(Motion::Backspace, cx)    });    Vim::action(editor, cx, |vim, action: &Down, cx| {        vim.motion(            Motion::Down {                display_lines: action.display_lines,            },            cx,        )    });    Vim::action(editor, cx, |vim, action: &Up, cx| {        vim.motion(            Motion::Up {                display_lines: action.display_lines,            },            cx,        )    });    Vim::action(editor, cx, |vim, _: &Right, cx| {        vim.motion(Motion::Right, cx)    });    Vim::action(editor, cx, |vim, _: &Space, cx| {        vim.motion(Motion::Space, cx)    });    Vim::action(editor, cx, |vim, action: &FirstNonWhitespace, cx| {        vim.motion(            Motion::FirstNonWhitespace {                display_lines: action.display_lines,            },            cx,        )    });    Vim::action(editor, cx, |vim, action: &StartOfLine, cx| {        vim.motion(            Motion::StartOfLine {                display_lines: action.display_lines,            },            cx,        )    });    Vim::action(editor, cx, |vim, action: &EndOfLine, cx| {        vim.motion(            Motion::EndOfLine {                display_lines: action.display_lines,            },            cx,        )    });    Vim::action(editor, cx, |vim, _: &CurrentLine, cx| {        vim.motion(Motion::CurrentLine, cx)    });    Vim::action(editor, cx, |vim, _: &StartOfParagraph, cx| {        vim.motion(Motion::StartOfParagraph, cx)    });    Vim::action(editor, cx, |vim, _: &EndOfParagraph, cx| {        vim.motion(Motion::EndOfParagraph, cx)    });     Vim::action(editor, cx, |vim, _: &SentenceForward, cx| {        vim.motion(Motion::SentenceForward, cx)    });    Vim::action(editor, cx, |vim, _: &SentenceBackward, cx| {        vim.motion(Motion::SentenceBackward, cx)    });    Vim::action(editor, cx, |vim, _: &StartOfDocument, cx| {        vim.motion(Motion::StartOfDocument, cx)    });    Vim::action(editor, cx, |vim, _: &EndOfDocument, cx| {        vim.motion(Motion::EndOfDocument, cx)    });    Vim::action(editor, cx, |vim, _: &Matching, cx| {        vim.motion(Motion::Matching, cx)    });     Vim::action(        editor,        cx,        |vim, &NextWordStart { ignore_punctuation }: &NextWordStart, cx| {            vim.motion(Motion::NextWordStart { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &NextWordEnd { ignore_punctuation }: &NextWordEnd, cx| {            vim.motion(Motion::NextWordEnd { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &PreviousWordStart { ignore_punctuation }: &PreviousWordStart, cx| {            vim.motion(Motion::PreviousWordStart { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &PreviousWordEnd { ignore_punctuation }, cx| {            vim.motion(Motion::PreviousWordEnd { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &NextSubwordStart { ignore_punctuation }: &NextSubwordStart, cx| {            vim.motion(Motion::NextSubwordStart { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &NextSubwordEnd { ignore_punctuation }: &NextSubwordEnd, cx| {            vim.motion(Motion::NextSubwordEnd { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &PreviousSubwordStart { ignore_punctuation }: &PreviousSubwordStart, cx| {            vim.motion(Motion::PreviousSubwordStart { ignore_punctuation }, cx)        },    );    Vim::action(        editor,        cx,        |vim, &PreviousSubwordEnd { ignore_punctuation }, cx| {            vim.motion(Motion::PreviousSubwordEnd { ignore_punctuation }, cx)        },    );    Vim::action(editor, cx, |vim, &NextLineStart, cx| {        vim.motion(Motion::NextLineStart, cx)    });    Vim::action(editor, cx, |vim, &PreviousLineStart, cx| {        vim.motion(Motion::PreviousLineStart, cx)    });    Vim::action(editor, cx, |vim, &StartOfLineDownward, cx| {        vim.motion(Motion::StartOfLineDownward, cx)    });    Vim::action(editor, cx, |vim, &EndOfLineDownward, cx| {        vim.motion(Motion::EndOfLineDownward, cx)    });    Vim::action(editor, cx, |vim, &GoToColumn, cx| {        vim.motion(Motion::GoToColumn, cx)    });     Vim::action(editor, cx, |vim, _: &RepeatFind, cx| {        if let Some(last_find) = Vim::globals(cx).last_find.clone().map(Box::new) {            vim.motion(Motion::RepeatFind { last_find }, cx);        }    });     Vim::action(editor, cx, |vim, _: &RepeatFindReversed, cx| {        if let Some(last_find) = Vim::globals(cx).last_find.clone().map(Box::new) {            vim.motion(Motion::RepeatFindReversed { last_find }, cx);        }    });    Vim::action(editor, cx, |vim, &WindowTop, cx| {        vim.motion(Motion::WindowTop, cx)    });    Vim::action(editor, cx, |vim, &WindowMiddle, cx| {        vim.motion(Motion::WindowMiddle, cx)    });    Vim::action(editor, cx, |vim, &WindowBottom, cx| {        vim.motion(Motion::WindowBottom, cx)    });} impl Vim {    pub(crate) fn search_motion(&mut self, m: Motion, cx: &mut ViewContext<Self>) {        if let Motion::ZedSearchResult {            prior_selections, ..        } = &m        {            match self.mode {                Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {                    if !prior_selections.is_empty() {                        self.update_editor(cx, |_, editor, cx| {                            editor.change_selections(Some(Autoscroll::fit()), cx, |s| {                                s.select_ranges(prior_selections.iter().cloned())                            })                        });                    }                }                Mode::Normal | Mode::Replace | Mode::Insert => {                    if self.active_operator().is_none() {                        return;                    }                }            }        }         self.motion(m, cx)    }     pub(crate) fn motion(&mut self, motion: Motion, cx: &mut ViewContext<Self>) {        if let Some(Operator::FindForward { .. }) | Some(Operator::FindBackward { .. }) =            self.active_operator()        {            self.pop_operator(cx);        }         let count = self.take_count(cx);        let active_operator = self.active_operator();        let mut waiting_operator: Option<Operator> = None;        match self.mode {            Mode::Normal | Mode::Replace | Mode::Insert => {                if active_operator == Some(Operator::AddSurrounds { target: None }) {                    waiting_operator = Some(Operator::AddSurrounds {                        target: Some(SurroundsType::Motion(motion)),                    });                } else {                    self.normal_motion(motion.clone(), active_operator.clone(), count, cx)                }            }            Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {                self.visual_motion(motion.clone(), count, cx)            }        }        self.clear_operator(cx);        if let Some(operator) = waiting_operator {            self.push_operator(operator, cx);            self.pre_count = count        }    }} // 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            | PreviousLineStart            | StartOfLineDownward            | SentenceBackward            | SentenceForward            | StartOfParagraph            | EndOfParagraph

Lines 1–500 of 2474.