vim.rs

   1//! Vim support for Zed.
   2
   3#[cfg(test)]
   4mod test;
   5
   6mod change_list;
   7mod command;
   8mod digraph;
   9mod helix;
  10mod indent;
  11mod insert;
  12mod mode_indicator;
  13mod motion;
  14mod normal;
  15mod object;
  16mod replace;
  17mod rewrap;
  18mod state;
  19mod surrounds;
  20mod visual;
  21
  22use crate::normal::paste::Paste as VimPaste;
  23use collections::HashMap;
  24use editor::{
  25    Anchor, Bias, Editor, EditorEvent, EditorSettings, HideMouseCursorOrigin, MultiBufferOffset,
  26    SelectionEffects, ToPoint,
  27    actions::Paste,
  28    movement::{self, FindRange},
  29};
  30use gpui::{
  31    Action, App, AppContext, Axis, Context, Entity, EventEmitter, KeyContext, KeystrokeEvent,
  32    Render, Subscription, Task, WeakEntity, Window, actions,
  33};
  34use insert::{NormalBefore, TemporaryNormal};
  35use language::{
  36    CharKind, CharScopeContext, CursorShape, Point, Selection, SelectionGoal, TransactionId,
  37};
  38pub use mode_indicator::ModeIndicator;
  39use motion::Motion;
  40use normal::search::SearchSubmit;
  41use object::Object;
  42use schemars::JsonSchema;
  43use serde::Deserialize;
  44use settings::RegisterSetting;
  45pub use settings::{
  46    ModeContent, Settings, SettingsStore, UseSystemClipboard, update_settings_file,
  47};
  48use state::{Mode, Operator, RecordedSelection, SearchState, VimGlobals};
  49use std::{mem, ops::Range, sync::Arc};
  50use surrounds::SurroundsType;
  51use theme::ThemeSettings;
  52use ui::{IntoElement, SharedString, px};
  53use vim_mode_setting::HelixModeSetting;
  54use vim_mode_setting::VimModeSetting;
  55use workspace::{self, Pane, Workspace};
  56
  57use crate::{
  58    normal::{GoToPreviousTab, GoToTab},
  59    state::ReplayableAction,
  60};
  61
  62/// Number is used to manage vim's count. Pushing a digit
  63/// multiplies the current value by 10 and adds the digit.
  64#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  65#[action(namespace = vim)]
  66struct Number(usize);
  67
  68#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  69#[action(namespace = vim)]
  70struct SelectRegister(String);
  71
  72#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  73#[action(namespace = vim)]
  74#[serde(deny_unknown_fields)]
  75struct PushObject {
  76    around: bool,
  77}
  78
  79#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  80#[action(namespace = vim)]
  81#[serde(deny_unknown_fields)]
  82struct PushFindForward {
  83    before: bool,
  84    multiline: bool,
  85}
  86
  87#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  88#[action(namespace = vim)]
  89#[serde(deny_unknown_fields)]
  90struct PushFindBackward {
  91    after: bool,
  92    multiline: bool,
  93}
  94
  95#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
  96#[action(namespace = vim)]
  97#[serde(deny_unknown_fields)]
  98/// Selects the next object.
  99struct PushHelixNext {
 100    around: bool,
 101}
 102
 103#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 104#[action(namespace = vim)]
 105#[serde(deny_unknown_fields)]
 106/// Selects the previous object.
 107struct PushHelixPrevious {
 108    around: bool,
 109}
 110
 111#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 112#[action(namespace = vim)]
 113#[serde(deny_unknown_fields)]
 114struct PushSneak {
 115    first_char: Option<char>,
 116}
 117
 118#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 119#[action(namespace = vim)]
 120#[serde(deny_unknown_fields)]
 121struct PushSneakBackward {
 122    first_char: Option<char>,
 123}
 124
 125#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 126#[action(namespace = vim)]
 127#[serde(deny_unknown_fields)]
 128struct PushAddSurrounds;
 129
 130#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 131#[action(namespace = vim)]
 132#[serde(deny_unknown_fields)]
 133struct PushChangeSurrounds {
 134    target: Option<Object>,
 135}
 136
 137#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 138#[action(namespace = vim)]
 139#[serde(deny_unknown_fields)]
 140struct PushJump {
 141    line: bool,
 142}
 143
 144#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 145#[action(namespace = vim)]
 146#[serde(deny_unknown_fields)]
 147struct PushDigraph {
 148    first_char: Option<char>,
 149}
 150
 151#[derive(Clone, Deserialize, JsonSchema, PartialEq, Action)]
 152#[action(namespace = vim)]
 153#[serde(deny_unknown_fields)]
 154struct PushLiteral {
 155    prefix: Option<String>,
 156}
 157
 158actions!(
 159    vim,
 160    [
 161        /// Switches to normal mode.
 162        SwitchToNormalMode,
 163        /// Switches to insert mode.
 164        SwitchToInsertMode,
 165        /// Switches to replace mode.
 166        SwitchToReplaceMode,
 167        /// Switches to visual mode.
 168        SwitchToVisualMode,
 169        /// Switches to visual line mode.
 170        SwitchToVisualLineMode,
 171        /// Switches to visual block mode.
 172        SwitchToVisualBlockMode,
 173        /// Switches to Helix-style normal mode.
 174        SwitchToHelixNormalMode,
 175        /// Clears any pending operators.
 176        ClearOperators,
 177        /// Clears the exchange register.
 178        ClearExchange,
 179        /// Inserts a tab character.
 180        Tab,
 181        /// Inserts a newline.
 182        Enter,
 183        /// Selects inner text object.
 184        InnerObject,
 185        /// Maximizes the current pane.
 186        MaximizePane,
 187        /// Resets all pane sizes to default.
 188        ResetPaneSizes,
 189        /// Resizes the pane to the right.
 190        ResizePaneRight,
 191        /// Resizes the pane to the left.
 192        ResizePaneLeft,
 193        /// Resizes the pane upward.
 194        ResizePaneUp,
 195        /// Resizes the pane downward.
 196        ResizePaneDown,
 197        /// Starts a change operation.
 198        PushChange,
 199        /// Starts a delete operation.
 200        PushDelete,
 201        /// Exchanges text regions.
 202        Exchange,
 203        /// Starts a yank operation.
 204        PushYank,
 205        /// Starts a replace operation.
 206        PushReplace,
 207        /// Deletes surrounding characters.
 208        PushDeleteSurrounds,
 209        /// Sets a mark at the current position.
 210        PushMark,
 211        /// Toggles the marks view.
 212        ToggleMarksView,
 213        /// Starts a forced motion.
 214        PushForcedMotion,
 215        /// Starts an indent operation.
 216        PushIndent,
 217        /// Starts an outdent operation.
 218        PushOutdent,
 219        /// Starts an auto-indent operation.
 220        PushAutoIndent,
 221        /// Starts a rewrap operation.
 222        PushRewrap,
 223        /// Starts a shell command operation.
 224        PushShellCommand,
 225        /// Converts to lowercase.
 226        PushLowercase,
 227        /// Converts to uppercase.
 228        PushUppercase,
 229        /// Toggles case.
 230        PushOppositeCase,
 231        /// Applies ROT13 encoding.
 232        PushRot13,
 233        /// Applies ROT47 encoding.
 234        PushRot47,
 235        /// Toggles the registers view.
 236        ToggleRegistersView,
 237        /// Selects a register.
 238        PushRegister,
 239        /// Starts recording to a register.
 240        PushRecordRegister,
 241        /// Replays a register.
 242        PushReplayRegister,
 243        /// Replaces with register contents.
 244        PushReplaceWithRegister,
 245        /// Toggles comments.
 246        PushToggleComments,
 247        /// Selects (count) next menu item
 248        MenuSelectNext,
 249        /// Selects (count) previous menu item
 250        MenuSelectPrevious,
 251        /// Clears count or toggles project panel focus
 252        ToggleProjectPanelFocus,
 253        /// Starts a match operation.
 254        PushHelixMatch,
 255        /// Adds surrounding characters in Helix mode.
 256        PushHelixSurroundAdd,
 257        /// Replaces surrounding characters in Helix mode.
 258        PushHelixSurroundReplace,
 259        /// Deletes surrounding characters in Helix mode.
 260        PushHelixSurroundDelete,
 261    ]
 262);
 263
 264// in the workspace namespace so it's not filtered out when vim is disabled.
 265actions!(
 266    workspace,
 267    [
 268        /// Toggles Vim mode on or off.
 269        ToggleVimMode,
 270        /// Toggles Helix mode on or off.
 271        ToggleHelixMode,
 272    ]
 273);
 274
 275/// Initializes the `vim` crate.
 276pub fn init(cx: &mut App) {
 277    VimGlobals::register(cx);
 278
 279    cx.observe_new(Vim::register).detach();
 280
 281    cx.observe_new(|workspace: &mut Workspace, _, _| {
 282        workspace.register_action(|workspace, _: &ToggleVimMode, _, cx| {
 283            let fs = workspace.app_state().fs.clone();
 284            let currently_enabled = VimModeSetting::get_global(cx).0;
 285            update_settings_file(fs, cx, move |setting, _| {
 286                setting.vim_mode = Some(!currently_enabled);
 287                if let Some(helix_mode) = &mut setting.helix_mode {
 288                    *helix_mode = false;
 289                }
 290            })
 291        });
 292
 293        workspace.register_action(|workspace, _: &ToggleHelixMode, _, cx| {
 294            let fs = workspace.app_state().fs.clone();
 295            let currently_enabled = HelixModeSetting::get_global(cx).0;
 296            update_settings_file(fs, cx, move |setting, _| {
 297                setting.helix_mode = Some(!currently_enabled);
 298                if let Some(vim_mode) = &mut setting.vim_mode {
 299                    *vim_mode = false;
 300                }
 301            })
 302        });
 303
 304        workspace.register_action(|_, _: &MenuSelectNext, window, cx| {
 305            let count = Vim::take_count(cx).unwrap_or(1);
 306
 307            for _ in 0..count {
 308                window.dispatch_action(menu::SelectNext.boxed_clone(), cx);
 309            }
 310        });
 311
 312        workspace.register_action(|_, _: &MenuSelectPrevious, window, cx| {
 313            let count = Vim::take_count(cx).unwrap_or(1);
 314
 315            for _ in 0..count {
 316                window.dispatch_action(menu::SelectPrevious.boxed_clone(), cx);
 317            }
 318        });
 319
 320        workspace.register_action(|_, _: &ToggleProjectPanelFocus, window, cx| {
 321            if Vim::take_count(cx).is_none() {
 322                window.dispatch_action(zed_actions::project_panel::ToggleFocus.boxed_clone(), cx);
 323            }
 324        });
 325
 326        workspace.register_action(|workspace, n: &Number, window, cx| {
 327            let vim = workspace
 328                .focused_pane(window, cx)
 329                .read(cx)
 330                .active_item()
 331                .and_then(|item| item.act_as::<Editor>(cx))
 332                .and_then(|editor| editor.read(cx).addon::<VimAddon>().cloned());
 333            if let Some(vim) = vim {
 334                let digit = n.0;
 335                vim.entity.update(cx, |_, cx| {
 336                    cx.defer_in(window, move |vim, window, cx| {
 337                        vim.push_count_digit(digit, window, cx)
 338                    })
 339                });
 340            } else {
 341                let count = Vim::globals(cx).pre_count.unwrap_or(0);
 342                Vim::globals(cx).pre_count = Some(
 343                    count
 344                        .checked_mul(10)
 345                        .and_then(|c| c.checked_add(n.0))
 346                        .unwrap_or(count),
 347                );
 348            };
 349        });
 350
 351        workspace.register_action(|_, _: &zed_actions::vim::OpenDefaultKeymap, _, cx| {
 352            cx.emit(workspace::Event::OpenBundledFile {
 353                text: settings::vim_keymap(),
 354                title: "Default Vim Bindings",
 355                language: "JSON",
 356            });
 357        });
 358
 359        workspace.register_action(|workspace, _: &ResetPaneSizes, _, cx| {
 360            workspace.reset_pane_sizes(cx);
 361        });
 362
 363        workspace.register_action(|workspace, _: &MaximizePane, window, cx| {
 364            let pane = workspace.active_pane();
 365            let Some(size) = workspace.bounding_box_for_pane(pane) else {
 366                return;
 367            };
 368
 369            let theme = ThemeSettings::get_global(cx);
 370            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 371
 372            let desired_size = if let Some(count) = Vim::take_count(cx) {
 373                height * count
 374            } else {
 375                px(10000.)
 376            };
 377            workspace.resize_pane(Axis::Vertical, desired_size - size.size.height, window, cx)
 378        });
 379
 380        workspace.register_action(|workspace, _: &ResizePaneRight, window, cx| {
 381            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 382            Vim::take_forced_motion(cx);
 383            let theme = ThemeSettings::get_global(cx);
 384            let font_id = window.text_system().resolve_font(&theme.buffer_font);
 385            let Ok(width) = window
 386                .text_system()
 387                .advance(font_id, theme.buffer_font_size(cx), 'm')
 388            else {
 389                return;
 390            };
 391            workspace.resize_pane(Axis::Horizontal, width.width * count, window, cx);
 392        });
 393
 394        workspace.register_action(|workspace, _: &ResizePaneLeft, window, cx| {
 395            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 396            Vim::take_forced_motion(cx);
 397            let theme = ThemeSettings::get_global(cx);
 398            let font_id = window.text_system().resolve_font(&theme.buffer_font);
 399            let Ok(width) = window
 400                .text_system()
 401                .advance(font_id, theme.buffer_font_size(cx), 'm')
 402            else {
 403                return;
 404            };
 405            workspace.resize_pane(Axis::Horizontal, -width.width * count, window, cx);
 406        });
 407
 408        workspace.register_action(|workspace, _: &ResizePaneUp, window, cx| {
 409            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 410            Vim::take_forced_motion(cx);
 411            let theme = ThemeSettings::get_global(cx);
 412            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 413            workspace.resize_pane(Axis::Vertical, height * count, window, cx);
 414        });
 415
 416        workspace.register_action(|workspace, _: &ResizePaneDown, window, cx| {
 417            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 418            Vim::take_forced_motion(cx);
 419            let theme = ThemeSettings::get_global(cx);
 420            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 421            workspace.resize_pane(Axis::Vertical, -height * count, window, cx);
 422        });
 423
 424        workspace.register_action(|workspace, _: &SearchSubmit, window, cx| {
 425            let vim = workspace
 426                .focused_pane(window, cx)
 427                .read(cx)
 428                .active_item()
 429                .and_then(|item| item.act_as::<Editor>(cx))
 430                .and_then(|editor| editor.read(cx).addon::<VimAddon>().cloned());
 431            let Some(vim) = vim else { return };
 432            vim.entity.update(cx, |_, cx| {
 433                cx.defer_in(window, |vim, window, cx| vim.search_submit(window, cx))
 434            })
 435        });
 436        workspace.register_action(|_, _: &GoToTab, window, cx| {
 437            let count = Vim::take_count(cx);
 438            Vim::take_forced_motion(cx);
 439
 440            if let Some(tab_index) = count {
 441                // <count>gt goes to tab <count> (1-based).
 442                let zero_based_index = tab_index.saturating_sub(1);
 443                window.dispatch_action(
 444                    workspace::pane::ActivateItem(zero_based_index).boxed_clone(),
 445                    cx,
 446                );
 447            } else {
 448                // If no count is provided, go to the next tab.
 449                window.dispatch_action(workspace::pane::ActivateNextItem.boxed_clone(), cx);
 450            }
 451        });
 452
 453        workspace.register_action(|workspace, _: &GoToPreviousTab, window, cx| {
 454            let count = Vim::take_count(cx);
 455            Vim::take_forced_motion(cx);
 456
 457            if let Some(count) = count {
 458                // gT with count goes back that many tabs with wraparound (not the same as gt!).
 459                let pane = workspace.active_pane().read(cx);
 460                let item_count = pane.items().count();
 461                if item_count > 0 {
 462                    let current_index = pane.active_item_index();
 463                    let target_index = (current_index as isize - count as isize)
 464                        .rem_euclid(item_count as isize)
 465                        as usize;
 466                    window.dispatch_action(
 467                        workspace::pane::ActivateItem(target_index).boxed_clone(),
 468                        cx,
 469                    );
 470                }
 471            } else {
 472                // No count provided, go to the previous tab.
 473                window.dispatch_action(workspace::pane::ActivatePreviousItem.boxed_clone(), cx);
 474            }
 475        });
 476    })
 477    .detach();
 478}
 479
 480#[derive(Clone)]
 481pub(crate) struct VimAddon {
 482    pub(crate) entity: Entity<Vim>,
 483}
 484
 485impl editor::Addon for VimAddon {
 486    fn extend_key_context(&self, key_context: &mut KeyContext, cx: &App) {
 487        self.entity.read(cx).extend_key_context(key_context, cx)
 488    }
 489
 490    fn to_any(&self) -> &dyn std::any::Any {
 491        self
 492    }
 493}
 494
 495/// The state pertaining to Vim mode.
 496pub(crate) struct Vim {
 497    pub(crate) mode: Mode,
 498    pub last_mode: Mode,
 499    pub temp_mode: bool,
 500    pub status_label: Option<SharedString>,
 501    pub exit_temporary_mode: bool,
 502
 503    operator_stack: Vec<Operator>,
 504    pub(crate) replacements: Vec<(Range<editor::Anchor>, String)>,
 505
 506    pub(crate) stored_visual_mode: Option<(Mode, Vec<bool>)>,
 507
 508    pub(crate) current_tx: Option<TransactionId>,
 509    pub(crate) current_anchor: Option<Selection<Anchor>>,
 510    pub(crate) undo_modes: HashMap<TransactionId, Mode>,
 511    pub(crate) undo_last_line_tx: Option<TransactionId>,
 512
 513    selected_register: Option<char>,
 514    pub search: SearchState,
 515
 516    editor: WeakEntity<Editor>,
 517
 518    last_command: Option<String>,
 519    running_command: Option<Task<()>>,
 520    _subscriptions: Vec<Subscription>,
 521}
 522
 523// Hack: Vim intercepts events dispatched to a window and updates the view in response.
 524// This means it needs a VisualContext. The easiest way to satisfy that constraint is
 525// to make Vim a "View" that is just never actually rendered.
 526impl Render for Vim {
 527    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
 528        gpui::Empty
 529    }
 530}
 531
 532enum VimEvent {
 533    Focused,
 534}
 535impl EventEmitter<VimEvent> for Vim {}
 536
 537impl Vim {
 538    /// The namespace for Vim actions.
 539    const NAMESPACE: &'static str = "vim";
 540
 541    pub fn new(window: &mut Window, cx: &mut Context<Editor>) -> Entity<Self> {
 542        let editor = cx.entity();
 543
 544        let initial_vim_mode = VimSettings::get_global(cx).default_mode;
 545        let (mode, last_mode) = if HelixModeSetting::get_global(cx).0 {
 546            let initial_helix_mode = match initial_vim_mode {
 547                Mode::Normal => Mode::HelixNormal,
 548                Mode::Insert => Mode::Insert,
 549                // Otherwise, we panic with a note that we should never get there due to the
 550                // possible values of VimSettings::get_global(cx).default_mode being either Mode::Normal or Mode::Insert.
 551                _ => unreachable!("Invalid default mode"),
 552            };
 553            (initial_helix_mode, Mode::HelixNormal)
 554        } else {
 555            (initial_vim_mode, Mode::Normal)
 556        };
 557
 558        cx.new(|cx| Vim {
 559            mode,
 560            last_mode,
 561            temp_mode: false,
 562            exit_temporary_mode: false,
 563            operator_stack: Vec::new(),
 564            replacements: Vec::new(),
 565
 566            stored_visual_mode: None,
 567            current_tx: None,
 568            undo_last_line_tx: None,
 569            current_anchor: None,
 570            undo_modes: HashMap::default(),
 571
 572            status_label: None,
 573            selected_register: None,
 574            search: SearchState::default(),
 575
 576            last_command: None,
 577            running_command: None,
 578
 579            editor: editor.downgrade(),
 580            _subscriptions: vec![
 581                cx.observe_keystrokes(Self::observe_keystrokes),
 582                cx.subscribe_in(&editor, window, |this, _, event, window, cx| {
 583                    this.handle_editor_event(event, window, cx)
 584                }),
 585            ],
 586        })
 587    }
 588
 589    fn register(editor: &mut Editor, window: Option<&mut Window>, cx: &mut Context<Editor>) {
 590        let Some(window) = window else {
 591            return;
 592        };
 593
 594        if !editor.use_modal_editing() {
 595            return;
 596        }
 597
 598        let mut was_enabled = Vim::enabled(cx);
 599        let mut was_toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 600        cx.observe_global_in::<SettingsStore>(window, move |editor, window, cx| {
 601            let enabled = Vim::enabled(cx);
 602            let toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 603            if enabled && was_enabled && (toggle != was_toggle) {
 604                if toggle {
 605                    let is_relative = editor
 606                        .addon::<VimAddon>()
 607                        .map(|vim| vim.entity.read(cx).mode != Mode::Insert);
 608                    editor.set_relative_line_number(is_relative, cx)
 609                } else {
 610                    editor.set_relative_line_number(None, cx)
 611                }
 612            }
 613            was_toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 614            if was_enabled == enabled {
 615                return;
 616            }
 617            was_enabled = enabled;
 618            if enabled {
 619                Self::activate(editor, window, cx)
 620            } else {
 621                Self::deactivate(editor, cx)
 622            }
 623        })
 624        .detach();
 625        if was_enabled {
 626            Self::activate(editor, window, cx)
 627        }
 628    }
 629
 630    fn activate(editor: &mut Editor, window: &mut Window, cx: &mut Context<Editor>) {
 631        let vim = Vim::new(window, cx);
 632
 633        if !editor.mode().is_full() {
 634            vim.update(cx, |vim, _| {
 635                vim.mode = Mode::Insert;
 636            });
 637        }
 638
 639        editor.register_addon(VimAddon {
 640            entity: vim.clone(),
 641        });
 642
 643        vim.update(cx, |_, cx| {
 644            Vim::action(editor, cx, |vim, _: &SwitchToNormalMode, window, cx| {
 645                vim.switch_mode(Mode::Normal, false, window, cx)
 646            });
 647
 648            Vim::action(editor, cx, |vim, _: &SwitchToInsertMode, window, cx| {
 649                vim.switch_mode(Mode::Insert, false, window, cx)
 650            });
 651
 652            Vim::action(editor, cx, |vim, _: &SwitchToReplaceMode, window, cx| {
 653                vim.switch_mode(Mode::Replace, false, window, cx)
 654            });
 655
 656            Vim::action(editor, cx, |vim, _: &SwitchToVisualMode, window, cx| {
 657                vim.switch_mode(Mode::Visual, false, window, cx)
 658            });
 659
 660            Vim::action(editor, cx, |vim, _: &SwitchToVisualLineMode, window, cx| {
 661                vim.switch_mode(Mode::VisualLine, false, window, cx)
 662            });
 663
 664            Vim::action(
 665                editor,
 666                cx,
 667                |vim, _: &SwitchToVisualBlockMode, window, cx| {
 668                    vim.switch_mode(Mode::VisualBlock, false, window, cx)
 669                },
 670            );
 671
 672            Vim::action(
 673                editor,
 674                cx,
 675                |vim, _: &SwitchToHelixNormalMode, window, cx| {
 676                    vim.switch_mode(Mode::HelixNormal, true, window, cx)
 677                },
 678            );
 679            Vim::action(editor, cx, |_, _: &PushForcedMotion, _, cx| {
 680                Vim::globals(cx).forced_motion = true;
 681            });
 682            Vim::action(editor, cx, |vim, action: &PushObject, window, cx| {
 683                vim.push_operator(
 684                    Operator::Object {
 685                        around: action.around,
 686                    },
 687                    window,
 688                    cx,
 689                )
 690            });
 691
 692            Vim::action(editor, cx, |vim, action: &PushFindForward, window, cx| {
 693                vim.push_operator(
 694                    Operator::FindForward {
 695                        before: action.before,
 696                        multiline: action.multiline,
 697                    },
 698                    window,
 699                    cx,
 700                )
 701            });
 702
 703            Vim::action(editor, cx, |vim, action: &PushFindBackward, window, cx| {
 704                vim.push_operator(
 705                    Operator::FindBackward {
 706                        after: action.after,
 707                        multiline: action.multiline,
 708                    },
 709                    window,
 710                    cx,
 711                )
 712            });
 713
 714            Vim::action(editor, cx, |vim, action: &PushSneak, window, cx| {
 715                vim.push_operator(
 716                    Operator::Sneak {
 717                        first_char: action.first_char,
 718                    },
 719                    window,
 720                    cx,
 721                )
 722            });
 723
 724            Vim::action(editor, cx, |vim, action: &PushSneakBackward, window, cx| {
 725                vim.push_operator(
 726                    Operator::SneakBackward {
 727                        first_char: action.first_char,
 728                    },
 729                    window,
 730                    cx,
 731                )
 732            });
 733
 734            Vim::action(editor, cx, |vim, _: &PushAddSurrounds, window, cx| {
 735                vim.push_operator(Operator::AddSurrounds { target: None }, window, cx)
 736            });
 737
 738            Vim::action(
 739                editor,
 740                cx,
 741                |vim, action: &PushChangeSurrounds, window, cx| {
 742                    vim.push_operator(
 743                        Operator::ChangeSurrounds {
 744                            target: action.target,
 745                            opening: false,
 746                        },
 747                        window,
 748                        cx,
 749                    )
 750                },
 751            );
 752
 753            Vim::action(editor, cx, |vim, action: &PushJump, window, cx| {
 754                vim.push_operator(Operator::Jump { line: action.line }, window, cx)
 755            });
 756
 757            Vim::action(editor, cx, |vim, action: &PushDigraph, window, cx| {
 758                vim.push_operator(
 759                    Operator::Digraph {
 760                        first_char: action.first_char,
 761                    },
 762                    window,
 763                    cx,
 764                )
 765            });
 766
 767            Vim::action(editor, cx, |vim, action: &PushLiteral, window, cx| {
 768                vim.push_operator(
 769                    Operator::Literal {
 770                        prefix: action.prefix.clone(),
 771                    },
 772                    window,
 773                    cx,
 774                )
 775            });
 776
 777            Vim::action(editor, cx, |vim, _: &PushChange, window, cx| {
 778                vim.push_operator(Operator::Change, window, cx)
 779            });
 780
 781            Vim::action(editor, cx, |vim, _: &PushDelete, window, cx| {
 782                vim.push_operator(Operator::Delete, window, cx)
 783            });
 784
 785            Vim::action(editor, cx, |vim, _: &PushYank, window, cx| {
 786                vim.push_operator(Operator::Yank, window, cx)
 787            });
 788
 789            Vim::action(editor, cx, |vim, _: &PushReplace, window, cx| {
 790                vim.push_operator(Operator::Replace, window, cx)
 791            });
 792
 793            Vim::action(editor, cx, |vim, _: &PushDeleteSurrounds, window, cx| {
 794                vim.push_operator(Operator::DeleteSurrounds, window, cx)
 795            });
 796
 797            Vim::action(editor, cx, |vim, _: &PushMark, window, cx| {
 798                vim.push_operator(Operator::Mark, window, cx)
 799            });
 800
 801            Vim::action(editor, cx, |vim, _: &PushIndent, window, cx| {
 802                vim.push_operator(Operator::Indent, window, cx)
 803            });
 804
 805            Vim::action(editor, cx, |vim, _: &PushOutdent, window, cx| {
 806                vim.push_operator(Operator::Outdent, window, cx)
 807            });
 808
 809            Vim::action(editor, cx, |vim, _: &PushAutoIndent, window, cx| {
 810                vim.push_operator(Operator::AutoIndent, window, cx)
 811            });
 812
 813            Vim::action(editor, cx, |vim, _: &PushRewrap, window, cx| {
 814                vim.push_operator(Operator::Rewrap, window, cx)
 815            });
 816
 817            Vim::action(editor, cx, |vim, _: &PushShellCommand, window, cx| {
 818                vim.push_operator(Operator::ShellCommand, window, cx)
 819            });
 820
 821            Vim::action(editor, cx, |vim, _: &PushLowercase, window, cx| {
 822                vim.push_operator(Operator::Lowercase, window, cx)
 823            });
 824
 825            Vim::action(editor, cx, |vim, _: &PushUppercase, window, cx| {
 826                vim.push_operator(Operator::Uppercase, window, cx)
 827            });
 828
 829            Vim::action(editor, cx, |vim, _: &PushOppositeCase, window, cx| {
 830                vim.push_operator(Operator::OppositeCase, window, cx)
 831            });
 832
 833            Vim::action(editor, cx, |vim, _: &PushRot13, window, cx| {
 834                vim.push_operator(Operator::Rot13, window, cx)
 835            });
 836
 837            Vim::action(editor, cx, |vim, _: &PushRot47, window, cx| {
 838                vim.push_operator(Operator::Rot47, window, cx)
 839            });
 840
 841            Vim::action(editor, cx, |vim, _: &PushRegister, window, cx| {
 842                vim.push_operator(Operator::Register, window, cx)
 843            });
 844
 845            Vim::action(editor, cx, |vim, _: &PushRecordRegister, window, cx| {
 846                vim.push_operator(Operator::RecordRegister, window, cx)
 847            });
 848
 849            Vim::action(editor, cx, |vim, _: &PushReplayRegister, window, cx| {
 850                vim.push_operator(Operator::ReplayRegister, window, cx)
 851            });
 852
 853            Vim::action(
 854                editor,
 855                cx,
 856                |vim, _: &PushReplaceWithRegister, window, cx| {
 857                    vim.push_operator(Operator::ReplaceWithRegister, window, cx)
 858                },
 859            );
 860
 861            Vim::action(editor, cx, |vim, _: &Exchange, window, cx| {
 862                if vim.mode.is_visual() {
 863                    vim.exchange_visual(window, cx)
 864                } else {
 865                    vim.push_operator(Operator::Exchange, window, cx)
 866                }
 867            });
 868
 869            Vim::action(editor, cx, |vim, _: &ClearExchange, window, cx| {
 870                vim.clear_exchange(window, cx)
 871            });
 872
 873            Vim::action(editor, cx, |vim, _: &PushToggleComments, window, cx| {
 874                vim.push_operator(Operator::ToggleComments, window, cx)
 875            });
 876
 877            Vim::action(editor, cx, |vim, _: &ClearOperators, window, cx| {
 878                vim.clear_operator(window, cx)
 879            });
 880            Vim::action(editor, cx, |vim, n: &Number, window, cx| {
 881                vim.push_count_digit(n.0, window, cx);
 882            });
 883            Vim::action(editor, cx, |vim, _: &Tab, window, cx| {
 884                vim.input_ignored(" ".into(), window, cx)
 885            });
 886            Vim::action(
 887                editor,
 888                cx,
 889                |vim, action: &editor::actions::AcceptEditPrediction, window, cx| {
 890                    vim.update_editor(cx, |_, editor, cx| {
 891                        editor.accept_edit_prediction(action, window, cx);
 892                    });
 893                    // In non-insertion modes, predictions will be hidden and instead a jump will be
 894                    // displayed (and performed by `accept_edit_prediction`). This switches to
 895                    // insert mode so that the prediction is displayed after the jump.
 896                    match vim.mode {
 897                        Mode::Replace => {}
 898                        _ => vim.switch_mode(Mode::Insert, true, window, cx),
 899                    };
 900                },
 901            );
 902            Vim::action(editor, cx, |vim, _: &Enter, window, cx| {
 903                vim.input_ignored("\n".into(), window, cx)
 904            });
 905            Vim::action(editor, cx, |vim, _: &PushHelixMatch, window, cx| {
 906                vim.push_operator(Operator::HelixMatch, window, cx)
 907            });
 908            Vim::action(editor, cx, |vim, action: &PushHelixNext, window, cx| {
 909                vim.push_operator(
 910                    Operator::HelixNext {
 911                        around: action.around,
 912                    },
 913                    window,
 914                    cx,
 915                );
 916            });
 917            Vim::action(editor, cx, |vim, action: &PushHelixPrevious, window, cx| {
 918                vim.push_operator(
 919                    Operator::HelixPrevious {
 920                        around: action.around,
 921                    },
 922                    window,
 923                    cx,
 924                );
 925            });
 926
 927            Vim::action(
 928                editor,
 929                cx,
 930                |vim, _: &editor::actions::Paste, window, cx| match vim.mode {
 931                    Mode::Replace => vim.paste_replace(window, cx),
 932                    Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
 933                        vim.selected_register.replace('+');
 934                        vim.paste(&VimPaste::default(), window, cx);
 935                    }
 936                    _ => {
 937                        vim.update_editor(cx, |_, editor, cx| editor.paste(&Paste, window, cx));
 938                    }
 939                },
 940            );
 941
 942            normal::register(editor, cx);
 943            insert::register(editor, cx);
 944            helix::register(editor, cx);
 945            motion::register(editor, cx);
 946            command::register(editor, cx);
 947            replace::register(editor, cx);
 948            indent::register(editor, cx);
 949            rewrap::register(editor, cx);
 950            object::register(editor, cx);
 951            visual::register(editor, cx);
 952            change_list::register(editor, cx);
 953            digraph::register(editor, cx);
 954
 955            if editor.is_focused(window) {
 956                cx.defer_in(window, |vim, window, cx| {
 957                    vim.focused(false, window, cx);
 958                })
 959            }
 960        })
 961    }
 962
 963    fn deactivate(editor: &mut Editor, cx: &mut Context<Editor>) {
 964        editor.set_cursor_shape(
 965            EditorSettings::get_global(cx)
 966                .cursor_shape
 967                .unwrap_or_default(),
 968            cx,
 969        );
 970        editor.set_clip_at_line_ends(false, cx);
 971        editor.set_collapse_matches(false);
 972        editor.set_input_enabled(true);
 973        editor.set_autoindent(true);
 974        editor.selections.set_line_mode(false);
 975        editor.unregister_addon::<VimAddon>();
 976        editor.set_relative_line_number(None, cx);
 977        if let Some(vim) = Vim::globals(cx).focused_vim()
 978            && vim.entity_id() == cx.entity().entity_id()
 979        {
 980            Vim::globals(cx).focused_vim = None;
 981        }
 982    }
 983
 984    /// Register an action on the editor.
 985    pub fn action<A: Action>(
 986        editor: &mut Editor,
 987        cx: &mut Context<Vim>,
 988        f: impl Fn(&mut Vim, &A, &mut Window, &mut Context<Vim>) + 'static,
 989    ) {
 990        let subscription = editor.register_action(cx.listener(f));
 991        cx.on_release(|_, _| drop(subscription)).detach();
 992    }
 993
 994    pub fn editor(&self) -> Option<Entity<Editor>> {
 995        self.editor.upgrade()
 996    }
 997
 998    pub fn workspace(&self, window: &mut Window) -> Option<Entity<Workspace>> {
 999        window.root::<Workspace>().flatten()
1000    }
1001
1002    pub fn pane(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Entity<Pane>> {
1003        self.workspace(window)
1004            .map(|workspace| workspace.read(cx).focused_pane(window, cx))
1005    }
1006
1007    pub fn enabled(cx: &mut App) -> bool {
1008        VimModeSetting::get_global(cx).0 || HelixModeSetting::get_global(cx).0
1009    }
1010
1011    /// Called whenever an keystroke is typed so vim can observe all actions
1012    /// and keystrokes accordingly.
1013    fn observe_keystrokes(
1014        &mut self,
1015        keystroke_event: &KeystrokeEvent,
1016        window: &mut Window,
1017        cx: &mut Context<Self>,
1018    ) {
1019        if self.exit_temporary_mode {
1020            self.exit_temporary_mode = false;
1021            // Don't switch to insert mode if the action is temporary_normal.
1022            if let Some(action) = keystroke_event.action.as_ref()
1023                && action.as_any().downcast_ref::<TemporaryNormal>().is_some()
1024            {
1025                return;
1026            }
1027            self.switch_mode(Mode::Insert, false, window, cx)
1028        }
1029        if let Some(action) = keystroke_event.action.as_ref() {
1030            // Keystroke is handled by the vim system, so continue forward
1031            if action.name().starts_with("vim::") {
1032                self.update_editor(cx, |_, editor, cx| {
1033                    editor.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx)
1034                });
1035
1036                return;
1037            }
1038        } else if window.has_pending_keystrokes() || keystroke_event.keystroke.is_ime_in_progress()
1039        {
1040            return;
1041        }
1042
1043        if let Some(operator) = self.active_operator() {
1044            match operator {
1045                Operator::Literal { prefix } => {
1046                    self.handle_literal_keystroke(
1047                        keystroke_event,
1048                        prefix.unwrap_or_default(),
1049                        window,
1050                        cx,
1051                    );
1052                }
1053                _ if !operator.is_waiting(self.mode) => {
1054                    self.clear_operator(window, cx);
1055                    self.stop_recording_immediately(Box::new(ClearOperators), cx)
1056                }
1057                _ => {}
1058            }
1059        }
1060    }
1061
1062    fn handle_editor_event(
1063        &mut self,
1064        event: &EditorEvent,
1065        window: &mut Window,
1066        cx: &mut Context<Self>,
1067    ) {
1068        match event {
1069            EditorEvent::Focused => self.focused(true, window, cx),
1070            EditorEvent::Blurred => self.blurred(window, cx),
1071            EditorEvent::SelectionsChanged { local: true } => {
1072                self.local_selections_changed(window, cx);
1073            }
1074            EditorEvent::InputIgnored { text } => {
1075                self.input_ignored(text.clone(), window, cx);
1076                Vim::globals(cx).observe_insertion(text, None)
1077            }
1078            EditorEvent::InputHandled {
1079                text,
1080                utf16_range_to_replace: range_to_replace,
1081            } => Vim::globals(cx).observe_insertion(text, range_to_replace.clone()),
1082            EditorEvent::TransactionBegun { transaction_id } => {
1083                self.transaction_begun(*transaction_id, window, cx)
1084            }
1085            EditorEvent::TransactionUndone { transaction_id } => {
1086                self.transaction_undone(transaction_id, window, cx)
1087            }
1088            EditorEvent::Edited { .. } => self.push_to_change_list(window, cx),
1089            EditorEvent::FocusedIn => self.sync_vim_settings(window, cx),
1090            EditorEvent::CursorShapeChanged => self.cursor_shape_changed(window, cx),
1091            EditorEvent::PushedToNavHistory {
1092                anchor,
1093                is_deactivate,
1094            } => {
1095                self.update_editor(cx, |vim, editor, cx| {
1096                    let mark = if *is_deactivate {
1097                        "\"".to_string()
1098                    } else {
1099                        "'".to_string()
1100                    };
1101                    vim.set_mark(mark, vec![*anchor], editor.buffer(), window, cx);
1102                });
1103            }
1104            _ => {}
1105        }
1106    }
1107
1108    fn push_operator(&mut self, operator: Operator, window: &mut Window, cx: &mut Context<Self>) {
1109        if operator.starts_dot_recording() {
1110            self.start_recording(cx);
1111        }
1112        // Since these operations can only be entered with pre-operators,
1113        // we need to clear the previous operators when pushing,
1114        // so that the current stack is the most correct
1115        if matches!(
1116            operator,
1117            Operator::AddSurrounds { .. }
1118                | Operator::ChangeSurrounds { .. }
1119                | Operator::DeleteSurrounds
1120                | Operator::Exchange
1121        ) {
1122            self.operator_stack.clear();
1123        };
1124        self.operator_stack.push(operator);
1125        self.sync_vim_settings(window, cx);
1126    }
1127
1128    pub fn switch_mode(
1129        &mut self,
1130        mode: Mode,
1131        leave_selections: bool,
1132        window: &mut Window,
1133        cx: &mut Context<Self>,
1134    ) {
1135        if self.temp_mode && mode == Mode::Normal {
1136            self.temp_mode = false;
1137            self.switch_mode(Mode::Normal, leave_selections, window, cx);
1138            self.switch_mode(Mode::Insert, false, window, cx);
1139            return;
1140        } else if self.temp_mode
1141            && !matches!(mode, Mode::Visual | Mode::VisualLine | Mode::VisualBlock)
1142        {
1143            self.temp_mode = false;
1144        }
1145
1146        let last_mode = self.mode;
1147        let prior_mode = self.last_mode;
1148        let prior_tx = self.current_tx;
1149        self.status_label.take();
1150        self.last_mode = last_mode;
1151        self.mode = mode;
1152        self.operator_stack.clear();
1153        self.selected_register.take();
1154        self.cancel_running_command(window, cx);
1155        if mode == Mode::Normal || mode != last_mode {
1156            self.current_tx.take();
1157            self.current_anchor.take();
1158            self.update_editor(cx, |_, editor, _| {
1159                editor.clear_selection_drag_state();
1160            });
1161        }
1162        Vim::take_forced_motion(cx);
1163        if mode != Mode::Insert && mode != Mode::Replace {
1164            Vim::take_count(cx);
1165        }
1166
1167        // Sync editor settings like clip mode
1168        self.sync_vim_settings(window, cx);
1169
1170        if VimSettings::get_global(cx).toggle_relative_line_numbers
1171            && self.mode != self.last_mode
1172            && (self.mode == Mode::Insert || self.last_mode == Mode::Insert)
1173        {
1174            self.update_editor(cx, |vim, editor, cx| {
1175                let is_relative = vim.mode != Mode::Insert;
1176                editor.set_relative_line_number(Some(is_relative), cx)
1177            });
1178        }
1179        if HelixModeSetting::get_global(cx).0 {
1180            if self.mode == Mode::Normal {
1181                self.mode = Mode::HelixNormal
1182            } else if self.mode == Mode::Visual {
1183                self.mode = Mode::HelixSelect
1184            }
1185        }
1186
1187        if leave_selections {
1188            return;
1189        }
1190
1191        if !mode.is_visual() && last_mode.is_visual() {
1192            self.create_visual_marks(last_mode, window, cx);
1193        }
1194
1195        // Adjust selections
1196        self.update_editor(cx, |vim, editor, cx| {
1197            if last_mode != Mode::VisualBlock && last_mode.is_visual() && mode == Mode::VisualBlock
1198            {
1199                vim.visual_block_motion(true, editor, window, cx, |_, point, goal| {
1200                    Some((point, goal))
1201                })
1202            }
1203            if (last_mode == Mode::Insert || last_mode == Mode::Replace)
1204                && let Some(prior_tx) = prior_tx
1205            {
1206                editor.group_until_transaction(prior_tx, cx)
1207            }
1208
1209            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1210                // we cheat with visual block mode and use multiple cursors.
1211                // the cost of this cheat is we need to convert back to a single
1212                // cursor whenever vim would.
1213                if last_mode == Mode::VisualBlock
1214                    && (mode != Mode::VisualBlock && mode != Mode::Insert)
1215                {
1216                    let tail = s.oldest_anchor().tail();
1217                    let head = s.newest_anchor().head();
1218                    s.select_anchor_ranges(vec![tail..head]);
1219                } else if last_mode == Mode::Insert
1220                    && prior_mode == Mode::VisualBlock
1221                    && mode != Mode::VisualBlock
1222                {
1223                    let pos = s.first_anchor().head();
1224                    s.select_anchor_ranges(vec![pos..pos])
1225                }
1226
1227                let snapshot = s.display_snapshot();
1228                if let Some(pending) = s.pending_anchor_mut()
1229                    && pending.reversed
1230                    && mode.is_visual()
1231                    && !last_mode.is_visual()
1232                {
1233                    let mut end = pending.end.to_point(&snapshot.buffer_snapshot());
1234                    end = snapshot
1235                        .buffer_snapshot()
1236                        .clip_point(end + Point::new(0, 1), Bias::Right);
1237                    pending.end = snapshot.buffer_snapshot().anchor_before(end);
1238                }
1239
1240                s.move_with(|map, selection| {
1241                    if last_mode.is_visual() && !mode.is_visual() {
1242                        let mut point = selection.head();
1243                        if !selection.reversed && !selection.is_empty() {
1244                            point = movement::left(map, selection.head());
1245                        } else if selection.is_empty() {
1246                            point = map.clip_point(point, Bias::Left);
1247                        }
1248                        selection.collapse_to(point, selection.goal)
1249                    } else if !last_mode.is_visual() && mode.is_visual() && selection.is_empty() {
1250                        selection.end = movement::right(map, selection.start);
1251                    }
1252                });
1253            })
1254        });
1255    }
1256
1257    pub fn take_count(cx: &mut App) -> Option<usize> {
1258        let global_state = cx.global_mut::<VimGlobals>();
1259        if global_state.dot_replaying {
1260            return global_state.recorded_count;
1261        }
1262
1263        let count = if global_state.post_count.is_none() && global_state.pre_count.is_none() {
1264            return None;
1265        } else {
1266            Some(
1267                global_state.post_count.take().unwrap_or(1)
1268                    * global_state.pre_count.take().unwrap_or(1),
1269            )
1270        };
1271
1272        if global_state.dot_recording {
1273            global_state.recording_count = count;
1274        }
1275        count
1276    }
1277
1278    pub fn take_forced_motion(cx: &mut App) -> bool {
1279        let global_state = cx.global_mut::<VimGlobals>();
1280        let forced_motion = global_state.forced_motion;
1281        global_state.forced_motion = false;
1282        forced_motion
1283    }
1284
1285    pub fn cursor_shape(&self, cx: &mut App) -> CursorShape {
1286        let cursor_shape = VimSettings::get_global(cx).cursor_shape;
1287        match self.mode {
1288            Mode::Normal => {
1289                if let Some(operator) = self.operator_stack.last() {
1290                    match operator {
1291                        // Navigation operators -> Block cursor
1292                        Operator::FindForward { .. }
1293                        | Operator::FindBackward { .. }
1294                        | Operator::Mark
1295                        | Operator::Jump { .. }
1296                        | Operator::Register
1297                        | Operator::RecordRegister
1298                        | Operator::ReplayRegister => CursorShape::Block,
1299
1300                        // All other operators -> Underline cursor
1301                        _ => CursorShape::Underline,
1302                    }
1303                } else {
1304                    cursor_shape.normal.unwrap_or(CursorShape::Block)
1305                }
1306            }
1307            Mode::HelixNormal => cursor_shape.normal.unwrap_or(CursorShape::Block),
1308            Mode::Replace => cursor_shape.replace.unwrap_or(CursorShape::Underline),
1309            Mode::Visual | Mode::VisualLine | Mode::VisualBlock | Mode::HelixSelect => {
1310                cursor_shape.visual.unwrap_or(CursorShape::Block)
1311            }
1312            Mode::Insert => cursor_shape.insert.unwrap_or({
1313                let editor_settings = EditorSettings::get_global(cx);
1314                editor_settings.cursor_shape.unwrap_or_default()
1315            }),
1316        }
1317    }
1318
1319    pub fn editor_input_enabled(&self) -> bool {
1320        match self.mode {
1321            Mode::Insert => {
1322                if let Some(operator) = self.operator_stack.last() {
1323                    !operator.is_waiting(self.mode)
1324                } else {
1325                    true
1326                }
1327            }
1328            Mode::Normal
1329            | Mode::HelixNormal
1330            | Mode::Replace
1331            | Mode::Visual
1332            | Mode::VisualLine
1333            | Mode::VisualBlock
1334            | Mode::HelixSelect => false,
1335        }
1336    }
1337
1338    pub fn should_autoindent(&self) -> bool {
1339        !(self.mode == Mode::Insert && self.last_mode == Mode::VisualBlock)
1340    }
1341
1342    pub fn clip_at_line_ends(&self) -> bool {
1343        match self.mode {
1344            Mode::Insert
1345            | Mode::Visual
1346            | Mode::VisualLine
1347            | Mode::VisualBlock
1348            | Mode::Replace
1349            | Mode::HelixNormal
1350            | Mode::HelixSelect => false,
1351            Mode::Normal => true,
1352        }
1353    }
1354
1355    pub fn extend_key_context(&self, context: &mut KeyContext, cx: &App) {
1356        let mut mode = match self.mode {
1357            Mode::Normal => "normal",
1358            Mode::Visual | Mode::VisualLine | Mode::VisualBlock => "visual",
1359            Mode::Insert => "insert",
1360            Mode::Replace => "replace",
1361            Mode::HelixNormal => "helix_normal",
1362            Mode::HelixSelect => "helix_select",
1363        }
1364        .to_string();
1365
1366        let mut operator_id = "none";
1367
1368        let active_operator = self.active_operator();
1369        if active_operator.is_none() && cx.global::<VimGlobals>().pre_count.is_some()
1370            || active_operator.is_some() && cx.global::<VimGlobals>().post_count.is_some()
1371        {
1372            context.add("VimCount");
1373        }
1374
1375        if let Some(active_operator) = active_operator {
1376            if active_operator.is_waiting(self.mode) {
1377                if matches!(active_operator, Operator::Literal { .. }) {
1378                    mode = "literal".to_string();
1379                } else {
1380                    mode = "waiting".to_string();
1381                }
1382            } else {
1383                operator_id = active_operator.id();
1384                mode = "operator".to_string();
1385            }
1386        }
1387
1388        if mode == "normal"
1389            || mode == "visual"
1390            || mode == "operator"
1391            || mode == "helix_normal"
1392            || mode == "helix_select"
1393        {
1394            context.add("VimControl");
1395        }
1396        context.set("vim_mode", mode);
1397        context.set("vim_operator", operator_id);
1398    }
1399
1400    fn focused(&mut self, preserve_selection: bool, window: &mut Window, cx: &mut Context<Self>) {
1401        let Some(editor) = self.editor() else {
1402            return;
1403        };
1404        let newest_selection_empty = editor.update(cx, |editor, cx| {
1405            editor
1406                .selections
1407                .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
1408                .is_empty()
1409        });
1410        let editor = editor.read(cx);
1411        let editor_mode = editor.mode();
1412
1413        if editor_mode.is_full()
1414            && !newest_selection_empty
1415            && self.mode == Mode::Normal
1416            // When following someone, don't switch vim mode.
1417            && editor.leader_id().is_none()
1418        {
1419            if preserve_selection {
1420                self.switch_mode(Mode::Visual, true, window, cx);
1421            } else {
1422                self.update_editor(cx, |_, editor, cx| {
1423                    editor.set_clip_at_line_ends(false, cx);
1424                    editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1425                        s.move_with(|_, selection| {
1426                            selection.collapse_to(selection.start, selection.goal)
1427                        })
1428                    });
1429                });
1430            }
1431        }
1432
1433        cx.emit(VimEvent::Focused);
1434        self.sync_vim_settings(window, cx);
1435
1436        if VimSettings::get_global(cx).toggle_relative_line_numbers {
1437            if let Some(old_vim) = Vim::globals(cx).focused_vim() {
1438                if old_vim.entity_id() != cx.entity().entity_id() {
1439                    old_vim.update(cx, |vim, cx| {
1440                        vim.update_editor(cx, |_, editor, cx| {
1441                            editor.set_relative_line_number(None, cx)
1442                        });
1443                    });
1444
1445                    self.update_editor(cx, |vim, editor, cx| {
1446                        let is_relative = vim.mode != Mode::Insert;
1447                        editor.set_relative_line_number(Some(is_relative), cx)
1448                    });
1449                }
1450            } else {
1451                self.update_editor(cx, |vim, editor, cx| {
1452                    let is_relative = vim.mode != Mode::Insert;
1453                    editor.set_relative_line_number(Some(is_relative), cx)
1454                });
1455            }
1456        }
1457        Vim::globals(cx).focused_vim = Some(cx.entity().downgrade());
1458    }
1459
1460    fn blurred(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1461        self.stop_recording_immediately(NormalBefore.boxed_clone(), cx);
1462        self.store_visual_marks(window, cx);
1463        self.clear_operator(window, cx);
1464        self.update_editor(cx, |vim, editor, cx| {
1465            if vim.cursor_shape(cx) == CursorShape::Block {
1466                editor.set_cursor_shape(CursorShape::Hollow, cx);
1467            }
1468        });
1469    }
1470
1471    fn cursor_shape_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
1472        self.update_editor(cx, |vim, editor, cx| {
1473            editor.set_cursor_shape(vim.cursor_shape(cx), cx);
1474        });
1475    }
1476
1477    fn update_editor<S>(
1478        &mut self,
1479        cx: &mut Context<Self>,
1480        update: impl FnOnce(&mut Self, &mut Editor, &mut Context<Editor>) -> S,
1481    ) -> Option<S> {
1482        let editor = self.editor.upgrade()?;
1483        Some(editor.update(cx, |editor, cx| update(self, editor, cx)))
1484    }
1485
1486    fn editor_selections(&mut self, _: &mut Window, cx: &mut Context<Self>) -> Vec<Range<Anchor>> {
1487        self.update_editor(cx, |_, editor, _| {
1488            editor
1489                .selections
1490                .disjoint_anchors_arc()
1491                .iter()
1492                .map(|selection| selection.tail()..selection.head())
1493                .collect()
1494        })
1495        .unwrap_or_default()
1496    }
1497
1498    fn editor_cursor_word(
1499        &mut self,
1500        window: &mut Window,
1501        cx: &mut Context<Self>,
1502    ) -> Option<String> {
1503        self.update_editor(cx, |_, editor, cx| {
1504            let snapshot = &editor.snapshot(window, cx);
1505            let selection = editor
1506                .selections
1507                .newest::<MultiBufferOffset>(&snapshot.display_snapshot);
1508
1509            let snapshot = snapshot.buffer_snapshot();
1510            let (range, kind) =
1511                snapshot.surrounding_word(selection.start, Some(CharScopeContext::Completion));
1512            if kind == Some(CharKind::Word) {
1513                let text: String = snapshot.text_for_range(range).collect();
1514                if !text.trim().is_empty() {
1515                    return Some(text);
1516                }
1517            }
1518
1519            None
1520        })
1521        .unwrap_or_default()
1522    }
1523
1524    /// When doing an action that modifies the buffer, we start recording so that `.`
1525    /// will replay the action.
1526    pub fn start_recording(&mut self, cx: &mut Context<Self>) {
1527        Vim::update_globals(cx, |globals, cx| {
1528            if !globals.dot_replaying {
1529                globals.dot_recording = true;
1530                globals.recording_actions = Default::default();
1531                globals.recording_count = None;
1532
1533                let selections = self.editor().map(|editor| {
1534                    editor.update(cx, |editor, cx| {
1535                        let snapshot = editor.display_snapshot(cx);
1536
1537                        (
1538                            editor.selections.oldest::<Point>(&snapshot),
1539                            editor.selections.newest::<Point>(&snapshot),
1540                        )
1541                    })
1542                });
1543
1544                if let Some((oldest, newest)) = selections {
1545                    globals.recorded_selection = match self.mode {
1546                        Mode::Visual if newest.end.row == newest.start.row => {
1547                            RecordedSelection::SingleLine {
1548                                cols: newest.end.column - newest.start.column,
1549                            }
1550                        }
1551                        Mode::Visual => RecordedSelection::Visual {
1552                            rows: newest.end.row - newest.start.row,
1553                            cols: newest.end.column,
1554                        },
1555                        Mode::VisualLine => RecordedSelection::VisualLine {
1556                            rows: newest.end.row - newest.start.row,
1557                        },
1558                        Mode::VisualBlock => RecordedSelection::VisualBlock {
1559                            rows: newest.end.row.abs_diff(oldest.start.row),
1560                            cols: newest.end.column.abs_diff(oldest.start.column),
1561                        },
1562                        _ => RecordedSelection::None,
1563                    }
1564                } else {
1565                    globals.recorded_selection = RecordedSelection::None;
1566                }
1567            }
1568        })
1569    }
1570
1571    pub fn stop_replaying(&mut self, cx: &mut Context<Self>) {
1572        let globals = Vim::globals(cx);
1573        globals.dot_replaying = false;
1574        if let Some(replayer) = globals.replayer.take() {
1575            replayer.stop();
1576        }
1577    }
1578
1579    /// When finishing an action that modifies the buffer, stop recording.
1580    /// as you usually call this within a keystroke handler we also ensure that
1581    /// the current action is recorded.
1582    pub fn stop_recording(&mut self, cx: &mut Context<Self>) {
1583        let globals = Vim::globals(cx);
1584        if globals.dot_recording {
1585            globals.stop_recording_after_next_action = true;
1586        }
1587        self.exit_temporary_mode = self.temp_mode;
1588    }
1589
1590    /// Stops recording actions immediately rather than waiting until after the
1591    /// next action to stop recording.
1592    ///
1593    /// This doesn't include the current action.
1594    pub fn stop_recording_immediately(&mut self, action: Box<dyn Action>, cx: &mut Context<Self>) {
1595        let globals = Vim::globals(cx);
1596        if globals.dot_recording {
1597            globals
1598                .recording_actions
1599                .push(ReplayableAction::Action(action.boxed_clone()));
1600            globals.recorded_actions = mem::take(&mut globals.recording_actions);
1601            globals.recorded_count = globals.recording_count.take();
1602            globals.dot_recording = false;
1603            globals.stop_recording_after_next_action = false;
1604        }
1605        self.exit_temporary_mode = self.temp_mode;
1606    }
1607
1608    /// Explicitly record one action (equivalents to start_recording and stop_recording)
1609    pub fn record_current_action(&mut self, cx: &mut Context<Self>) {
1610        self.start_recording(cx);
1611        self.stop_recording(cx);
1612    }
1613
1614    fn push_count_digit(&mut self, number: usize, window: &mut Window, cx: &mut Context<Self>) {
1615        if self.active_operator().is_some() {
1616            let post_count = Vim::globals(cx).post_count.unwrap_or(0);
1617
1618            Vim::globals(cx).post_count = Some(
1619                post_count
1620                    .checked_mul(10)
1621                    .and_then(|post_count| post_count.checked_add(number))
1622                    .filter(|post_count| *post_count < isize::MAX as usize)
1623                    .unwrap_or(post_count),
1624            )
1625        } else {
1626            let pre_count = Vim::globals(cx).pre_count.unwrap_or(0);
1627
1628            Vim::globals(cx).pre_count = Some(
1629                pre_count
1630                    .checked_mul(10)
1631                    .and_then(|pre_count| pre_count.checked_add(number))
1632                    .filter(|pre_count| *pre_count < isize::MAX as usize)
1633                    .unwrap_or(pre_count),
1634            )
1635        }
1636        // update the keymap so that 0 works
1637        self.sync_vim_settings(window, cx)
1638    }
1639
1640    fn select_register(&mut self, register: Arc<str>, window: &mut Window, cx: &mut Context<Self>) {
1641        if register.chars().count() == 1 {
1642            self.selected_register
1643                .replace(register.chars().next().unwrap());
1644        }
1645        self.operator_stack.clear();
1646        self.sync_vim_settings(window, cx);
1647    }
1648
1649    fn maybe_pop_operator(&mut self) -> Option<Operator> {
1650        self.operator_stack.pop()
1651    }
1652
1653    fn pop_operator(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Operator {
1654        let popped_operator = self.operator_stack.pop()
1655            .expect("Operator popped when no operator was on the stack. This likely means there is an invalid keymap config");
1656        self.sync_vim_settings(window, cx);
1657        popped_operator
1658    }
1659
1660    fn clear_operator(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1661        Vim::take_count(cx);
1662        Vim::take_forced_motion(cx);
1663        self.selected_register.take();
1664        self.operator_stack.clear();
1665        self.sync_vim_settings(window, cx);
1666    }
1667
1668    fn active_operator(&self) -> Option<Operator> {
1669        self.operator_stack.last().cloned()
1670    }
1671
1672    fn transaction_begun(
1673        &mut self,
1674        transaction_id: TransactionId,
1675        _window: &mut Window,
1676        _: &mut Context<Self>,
1677    ) {
1678        let mode = if (self.mode == Mode::Insert
1679            || self.mode == Mode::Replace
1680            || self.mode == Mode::Normal)
1681            && self.current_tx.is_none()
1682        {
1683            self.current_tx = Some(transaction_id);
1684            self.last_mode
1685        } else {
1686            self.mode
1687        };
1688        if mode == Mode::VisualLine || mode == Mode::VisualBlock {
1689            self.undo_modes.insert(transaction_id, mode);
1690        }
1691    }
1692
1693    fn transaction_undone(
1694        &mut self,
1695        transaction_id: &TransactionId,
1696        window: &mut Window,
1697        cx: &mut Context<Self>,
1698    ) {
1699        match self.mode {
1700            Mode::VisualLine | Mode::VisualBlock | Mode::Visual | Mode::HelixSelect => {
1701                self.update_editor(cx, |vim, editor, cx| {
1702                    let original_mode = vim.undo_modes.get(transaction_id);
1703                    editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1704                        match original_mode {
1705                            Some(Mode::VisualLine) => {
1706                                s.move_with(|map, selection| {
1707                                    selection.collapse_to(
1708                                        map.prev_line_boundary(selection.start.to_point(map)).1,
1709                                        SelectionGoal::None,
1710                                    )
1711                                });
1712                            }
1713                            Some(Mode::VisualBlock) => {
1714                                let mut first = s.first_anchor();
1715                                first.collapse_to(first.start, first.goal);
1716                                s.select_anchors(vec![first]);
1717                            }
1718                            _ => {
1719                                s.move_with(|map, selection| {
1720                                    selection.collapse_to(
1721                                        map.clip_at_line_end(selection.start),
1722                                        selection.goal,
1723                                    );
1724                                });
1725                            }
1726                        }
1727                    });
1728                });
1729                self.switch_mode(Mode::Normal, true, window, cx)
1730            }
1731            Mode::Normal => {
1732                self.update_editor(cx, |_, editor, cx| {
1733                    editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
1734                        s.move_with(|map, selection| {
1735                            selection
1736                                .collapse_to(map.clip_at_line_end(selection.end), selection.goal)
1737                        })
1738                    })
1739                });
1740            }
1741            Mode::Insert | Mode::Replace | Mode::HelixNormal => {}
1742        }
1743    }
1744
1745    fn local_selections_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1746        let Some(editor) = self.editor() else { return };
1747
1748        if editor.read(cx).leader_id().is_some() {
1749            return;
1750        }
1751
1752        let newest = editor.read(cx).selections.newest_anchor().clone();
1753        let is_multicursor = editor.read(cx).selections.count() > 1;
1754        if self.mode == Mode::Insert && self.current_tx.is_some() {
1755            if self.current_anchor.is_none() {
1756                self.current_anchor = Some(newest);
1757            } else if self.current_anchor.as_ref().unwrap() != &newest
1758                && let Some(tx_id) = self.current_tx.take()
1759            {
1760                self.update_editor(cx, |_, editor, cx| {
1761                    editor.group_until_transaction(tx_id, cx)
1762                });
1763            }
1764        } else if self.mode == Mode::Normal && newest.start != newest.end {
1765            if matches!(newest.goal, SelectionGoal::HorizontalRange { .. }) {
1766                self.switch_mode(Mode::VisualBlock, false, window, cx);
1767            } else {
1768                self.switch_mode(Mode::Visual, false, window, cx)
1769            }
1770        } else if newest.start == newest.end
1771            && !is_multicursor
1772            && [Mode::Visual, Mode::VisualLine, Mode::VisualBlock].contains(&self.mode)
1773        {
1774            self.switch_mode(Mode::Normal, false, window, cx);
1775        }
1776    }
1777
1778    fn input_ignored(&mut self, text: Arc<str>, window: &mut Window, cx: &mut Context<Self>) {
1779        if text.is_empty() {
1780            return;
1781        }
1782
1783        match self.active_operator() {
1784            Some(Operator::FindForward { before, multiline }) => {
1785                let find = Motion::FindForward {
1786                    before,
1787                    char: text.chars().next().unwrap(),
1788                    mode: if multiline {
1789                        FindRange::MultiLine
1790                    } else {
1791                        FindRange::SingleLine
1792                    },
1793                    smartcase: VimSettings::get_global(cx).use_smartcase_find,
1794                };
1795                Vim::globals(cx).last_find = Some(find.clone());
1796                self.motion(find, window, cx)
1797            }
1798            Some(Operator::FindBackward { after, multiline }) => {
1799                let find = Motion::FindBackward {
1800                    after,
1801                    char: text.chars().next().unwrap(),
1802                    mode: if multiline {
1803                        FindRange::MultiLine
1804                    } else {
1805                        FindRange::SingleLine
1806                    },
1807                    smartcase: VimSettings::get_global(cx).use_smartcase_find,
1808                };
1809                Vim::globals(cx).last_find = Some(find.clone());
1810                self.motion(find, window, cx)
1811            }
1812            Some(Operator::Sneak { first_char }) => {
1813                if let Some(first_char) = first_char {
1814                    if let Some(second_char) = text.chars().next() {
1815                        let sneak = Motion::Sneak {
1816                            first_char,
1817                            second_char,
1818                            smartcase: VimSettings::get_global(cx).use_smartcase_find,
1819                        };
1820                        Vim::globals(cx).last_find = Some(sneak.clone());
1821                        self.motion(sneak, window, cx)
1822                    }
1823                } else {
1824                    let first_char = text.chars().next();
1825                    self.pop_operator(window, cx);
1826                    self.push_operator(Operator::Sneak { first_char }, window, cx);
1827                }
1828            }
1829            Some(Operator::SneakBackward { first_char }) => {
1830                if let Some(first_char) = first_char {
1831                    if let Some(second_char) = text.chars().next() {
1832                        let sneak = Motion::SneakBackward {
1833                            first_char,
1834                            second_char,
1835                            smartcase: VimSettings::get_global(cx).use_smartcase_find,
1836                        };
1837                        Vim::globals(cx).last_find = Some(sneak.clone());
1838                        self.motion(sneak, window, cx)
1839                    }
1840                } else {
1841                    let first_char = text.chars().next();
1842                    self.pop_operator(window, cx);
1843                    self.push_operator(Operator::SneakBackward { first_char }, window, cx);
1844                }
1845            }
1846            Some(Operator::Replace) => match self.mode {
1847                Mode::Normal => self.normal_replace(text, window, cx),
1848                Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
1849                    self.visual_replace(text, window, cx)
1850                }
1851                Mode::HelixNormal => self.helix_replace(&text, window, cx),
1852                _ => self.clear_operator(window, cx),
1853            },
1854            Some(Operator::Digraph { first_char }) => {
1855                if let Some(first_char) = first_char {
1856                    if let Some(second_char) = text.chars().next() {
1857                        self.insert_digraph(first_char, second_char, window, cx);
1858                    }
1859                } else {
1860                    let first_char = text.chars().next();
1861                    self.pop_operator(window, cx);
1862                    self.push_operator(Operator::Digraph { first_char }, window, cx);
1863                }
1864            }
1865            Some(Operator::Literal { prefix }) => {
1866                self.handle_literal_input(prefix.unwrap_or_default(), &text, window, cx)
1867            }
1868            Some(Operator::AddSurrounds { target }) => match self.mode {
1869                Mode::Normal => {
1870                    if let Some(target) = target {
1871                        self.add_surrounds(text, target, window, cx);
1872                        self.clear_operator(window, cx);
1873                    }
1874                }
1875                Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
1876                    self.add_surrounds(text, SurroundsType::Selection, window, cx);
1877                    self.clear_operator(window, cx);
1878                }
1879                _ => self.clear_operator(window, cx),
1880            },
1881            Some(Operator::ChangeSurrounds { target, opening }) => match self.mode {
1882                Mode::Normal => {
1883                    if let Some(target) = target {
1884                        self.change_surrounds(text, target, opening, window, cx);
1885                        self.clear_operator(window, cx);
1886                    }
1887                }
1888                _ => self.clear_operator(window, cx),
1889            },
1890            Some(Operator::DeleteSurrounds) => match self.mode {
1891                Mode::Normal => {
1892                    self.delete_surrounds(text, window, cx);
1893                    self.clear_operator(window, cx);
1894                }
1895                _ => self.clear_operator(window, cx),
1896            },
1897            Some(Operator::HelixSurroundAdd) => match self.mode {
1898                Mode::HelixNormal | Mode::HelixSelect => {
1899                    self.update_editor(cx, |_, editor, cx| {
1900                        editor.change_selections(Default::default(), window, cx, |s| {
1901                            s.move_with(|map, selection| {
1902                                if selection.is_empty() {
1903                                    selection.end = movement::right(map, selection.start);
1904                                }
1905                            });
1906                        });
1907                    });
1908                    self.helix_surround_add(&text, window, cx);
1909                    self.switch_mode(Mode::HelixNormal, false, window, cx);
1910                    self.clear_operator(window, cx);
1911                }
1912                _ => self.clear_operator(window, cx),
1913            },
1914            Some(Operator::HelixSurroundReplace {
1915                replaced_char: Some(old),
1916            }) => match self.mode {
1917                Mode::HelixNormal | Mode::HelixSelect => {
1918                    if let Some(new_char) = text.chars().next() {
1919                        self.helix_surround_replace(old, new_char, window, cx);
1920                    }
1921                    self.clear_operator(window, cx);
1922                }
1923                _ => self.clear_operator(window, cx),
1924            },
1925            Some(Operator::HelixSurroundReplace {
1926                replaced_char: None,
1927            }) => match self.mode {
1928                Mode::HelixNormal | Mode::HelixSelect => {
1929                    if let Some(ch) = text.chars().next() {
1930                        self.pop_operator(window, cx);
1931                        self.push_operator(
1932                            Operator::HelixSurroundReplace {
1933                                replaced_char: Some(ch),
1934                            },
1935                            window,
1936                            cx,
1937                        );
1938                    }
1939                }
1940                _ => self.clear_operator(window, cx),
1941            },
1942            Some(Operator::HelixSurroundDelete) => match self.mode {
1943                Mode::HelixNormal | Mode::HelixSelect => {
1944                    if let Some(ch) = text.chars().next() {
1945                        self.helix_surround_delete(ch, window, cx);
1946                    }
1947                    self.clear_operator(window, cx);
1948                }
1949                _ => self.clear_operator(window, cx),
1950            },
1951            Some(Operator::Mark) => self.create_mark(text, window, cx),
1952            Some(Operator::RecordRegister) => {
1953                self.record_register(text.chars().next().unwrap(), window, cx)
1954            }
1955            Some(Operator::ReplayRegister) => {
1956                self.replay_register(text.chars().next().unwrap(), window, cx)
1957            }
1958            Some(Operator::Register) => match self.mode {
1959                Mode::Insert => {
1960                    self.update_editor(cx, |_, editor, cx| {
1961                        if let Some(register) = Vim::update_globals(cx, |globals, cx| {
1962                            globals.read_register(text.chars().next(), Some(editor), cx)
1963                        }) {
1964                            editor.do_paste(
1965                                &register.text.to_string(),
1966                                register.clipboard_selections,
1967                                false,
1968                                window,
1969                                cx,
1970                            )
1971                        }
1972                    });
1973                    self.clear_operator(window, cx);
1974                }
1975                _ => {
1976                    self.select_register(text, window, cx);
1977                }
1978            },
1979            Some(Operator::Jump { line }) => self.jump(text, line, true, window, cx),
1980            _ => {
1981                if self.mode == Mode::Replace {
1982                    self.multi_replace(text, window, cx)
1983                }
1984
1985                if self.mode == Mode::Normal {
1986                    self.update_editor(cx, |_, editor, cx| {
1987                        editor.accept_edit_prediction(
1988                            &editor::actions::AcceptEditPrediction {},
1989                            window,
1990                            cx,
1991                        );
1992                    });
1993                }
1994            }
1995        }
1996    }
1997
1998    fn sync_vim_settings(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1999        self.update_editor(cx, |vim, editor, cx| {
2000            editor.set_cursor_shape(vim.cursor_shape(cx), cx);
2001            editor.set_clip_at_line_ends(vim.clip_at_line_ends(), cx);
2002            let collapse_matches = !HelixModeSetting::get_global(cx).0;
2003            editor.set_collapse_matches(collapse_matches);
2004            editor.set_input_enabled(vim.editor_input_enabled());
2005            editor.set_autoindent(vim.should_autoindent());
2006            editor.set_cursor_offset_on_selection(vim.mode.is_visual());
2007            editor
2008                .selections
2009                .set_line_mode(matches!(vim.mode, Mode::VisualLine));
2010
2011            let hide_edit_predictions = !matches!(vim.mode, Mode::Insert | Mode::Replace);
2012            editor.set_edit_predictions_hidden_for_vim_mode(hide_edit_predictions, window, cx);
2013        });
2014        cx.notify()
2015    }
2016}
2017
2018#[derive(RegisterSetting)]
2019struct VimSettings {
2020    pub default_mode: Mode,
2021    pub toggle_relative_line_numbers: bool,
2022    pub use_system_clipboard: settings::UseSystemClipboard,
2023    pub use_smartcase_find: bool,
2024    pub custom_digraphs: HashMap<String, Arc<str>>,
2025    pub highlight_on_yank_duration: u64,
2026    pub cursor_shape: CursorShapeSettings,
2027}
2028
2029/// The settings for cursor shape.
2030#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2031pub struct CursorShapeSettings {
2032    /// Cursor shape for the normal mode.
2033    ///
2034    /// Default: block
2035    pub normal: Option<CursorShape>,
2036    /// Cursor shape for the replace mode.
2037    ///
2038    /// Default: underline
2039    pub replace: Option<CursorShape>,
2040    /// Cursor shape for the visual mode.
2041    ///
2042    /// Default: block
2043    pub visual: Option<CursorShape>,
2044    /// Cursor shape for the insert mode.
2045    ///
2046    /// The default value follows the primary cursor_shape.
2047    pub insert: Option<CursorShape>,
2048}
2049
2050impl From<settings::CursorShapeSettings> for CursorShapeSettings {
2051    fn from(settings: settings::CursorShapeSettings) -> Self {
2052        Self {
2053            normal: settings.normal.map(Into::into),
2054            replace: settings.replace.map(Into::into),
2055            visual: settings.visual.map(Into::into),
2056            insert: settings.insert.map(Into::into),
2057        }
2058    }
2059}
2060
2061impl From<settings::ModeContent> for Mode {
2062    fn from(mode: ModeContent) -> Self {
2063        match mode {
2064            ModeContent::Normal => Self::Normal,
2065            ModeContent::Insert => Self::Insert,
2066        }
2067    }
2068}
2069
2070impl Settings for VimSettings {
2071    fn from_settings(content: &settings::SettingsContent) -> Self {
2072        let vim = content.vim.clone().unwrap();
2073        Self {
2074            default_mode: vim.default_mode.unwrap().into(),
2075            toggle_relative_line_numbers: vim.toggle_relative_line_numbers.unwrap(),
2076            use_system_clipboard: vim.use_system_clipboard.unwrap(),
2077            use_smartcase_find: vim.use_smartcase_find.unwrap(),
2078            custom_digraphs: vim.custom_digraphs.unwrap(),
2079            highlight_on_yank_duration: vim.highlight_on_yank_duration.unwrap(),
2080            cursor_shape: vim.cursor_shape.unwrap().into(),
2081        }
2082    }
2083}