2294 lines · 71.5 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, RowExt, ToOffset,};use gpui::{actions, impl_actions, px, ViewContext, WindowContext};use language::{char_kind, CharKind, Point, Selection, SelectionGoal};use multi_buffer::MultiBufferRow;use serde::Deserialize;use std::ops::Range;use workspace::Workspace; use crate::{    normal::{mark, normal_motion},    state::{Mode, Operator},    surrounds::SurroundsType,    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,     // we don't have a good way to run a search syncronously, 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,        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 search_motion(m: Motion, cx: &mut WindowContext) {    if let Motion::ZedSearchResult {        prior_selections, ..    } = &m    {        match Vim::read(cx).state().mode {            Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {                if !prior_selections.is_empty() {                    Vim::update(cx, |vim, cx| {                        vim.update_active_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 Vim::read(cx).active_operator().is_none() {                    return;                }            }        }    }     motion(m, 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 active_operator = Vim::read(cx).active_operator();    let mut waiting_operator: Option<Operator> = None;    match Vim::read(cx).state().mode {        Mode::Normal | Mode::Replace => {            if active_operator == Some(Operator::AddSurrounds { target: None }) {                waiting_operator = Some(Operator::AddSurrounds {                    target: Some(SurroundsType::Motion(motion)),                });            } else {                normal_motion(motion.clone(), active_operator.clone(), count, cx)            }        }        Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {            visual_motion(motion.clone(), count, cx)        }        Mode::Insert => {            // Shouldn't execute a motion in insert mode. Ignoring        }    }    Vim::update(cx, |vim, cx| {        vim.clear_operator(cx);        if let Some(operator) = waiting_operator {            vim.push_operator(operator, cx);            vim.update_state(|state| state.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            | StartOfLineDownward            | StartOfParagraph            | WindowTop            | WindowMiddle            | WindowBottom            | Jump { line: true, .. }            | EndOfParagraph => true,            EndOfLine { .. }            | Matching            | FindForward { .. }            | Left            | Backspace            | Right            | Space            | StartOfLine { .. }            | EndOfLineDownward            | GoToColumn            | NextWordStart { .. }            | NextWordEnd { .. }            | PreviousWordStart { .. }            | PreviousWordEnd { .. }            | NextSubwordStart { .. }            | NextSubwordEnd { .. }            | PreviousSubwordStart { .. }            | PreviousSubwordEnd { .. }            | FirstNonWhitespace { .. }            | FindBackward { .. }            | RepeatFind { .. }            | RepeatFindReversed { .. }            | Jump { line: false, .. }

Lines 1–500 of 2294.