Conrad Irwinfix vim panics (#8245)351c8c92 years agoHistory
1734 lines · 53.3 KB · Rust
RawDownload
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 },    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 },    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 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,        PreviousWordStart,        PreviousWordEnd,        NextWordEnd,        NextWordStart    ]); 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, &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)    });    workspace.register_action(        |_: &mut Workspace, &PreviousWordEnd { ignore_punctuation }, cx: _| {            motion(Motion::PreviousWordEnd { ignore_punctuation }, 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 { .. }            | NextWordEnd { .. }            | Matching            | FindForward { .. }            | Left            | Backspace            | Right            | Space            | StartOfLine { .. }            | EndOfLineDownward            | GoToColumn            | NextWordStart { .. }            | PreviousWordStart { .. }            | PreviousWordEnd { .. }            | FirstNonWhitespace { .. }            | FindBackward { .. }            | RepeatFind { .. }            | RepeatFindReversed { .. } => false,        }    }     pub fn infallible(&self) -> bool {        use Motion::*;        match self {            StartOfDocument | EndOfDocument | CurrentLine => true,            Down { .. }            | Up { .. }            | EndOfLine { .. }            | NextWordEnd { .. }            | Matching            | FindForward { .. }            | RepeatFind { .. }            | Left            | Backspace            | Right            | Space            | StartOfLine { .. }            | StartOfParagraph            | EndOfParagraph            | StartOfLineDownward            | EndOfLineDownward            | GoToColumn            | NextWordStart { .. }            | PreviousWordStart { .. }            | FirstNonWhitespace { .. }            | FindBackward { .. }            | RepeatFindReversed { .. }            | WindowTop            | WindowMiddle            | WindowBottom            | PreviousWordEnd { .. }            | NextLineStart => false,        }    }     pub fn inclusive(&self) -> bool {        use Motion::*;        match self {            Down { .. }            | Up { .. }            | StartOfDocument            | EndOfDocument            | CurrentLine            | EndOfLine { .. }            | EndOfLineDownward            | NextWordEnd { .. }            | Matching            | FindForward { .. }            | WindowTop            | WindowMiddle            | WindowBottom            | PreviousWordEnd { .. }            | NextLineStart => true,            Left            | Backspace            | Right            | Space            | StartOfLine { .. }            | StartOfLineDownward            | StartOfParagraph            | EndOfParagraph            | GoToColumn            | NextWordStart { .. }            | PreviousWordStart { .. }            | FirstNonWhitespace { .. }            | FindBackward { .. } => false,            RepeatFind { last_find: motion } | RepeatFindReversed { last_find: motion } => {                motion.inclusive()            }        }    }     pub fn move_point(        &self,        map: &DisplaySnapshot,        point: DisplayPoint,        goal: SelectionGoal,        maybe_times: Option<usize>,        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),            Space => (space(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,            ),            PreviousWordEnd { ignore_punctuation } => (                previous_word_end(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),            // t f            FindForward { before, char } => {                return find_forward(map, point, *before, *char, times)                    .map(|new_point| (new_point, SelectionGoal::None))            }            // T F            FindBackward { after, char } => (                find_backward(map, point, *after, *char, times),                SelectionGoal::None,            ),            // ; -- repeat the last find done with t, f, T, F            RepeatFind { last_find } => match **last_find {                Motion::FindForward { before, char } => {                    let mut new_point = find_forward(map, point, before, char, times);                    if new_point == Some(point) {                        new_point = find_forward(map, point, before, char, times + 1);                    } 

Lines 1–500 of 1734.