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 anyhow::Result;
  23use collections::HashMap;
  24use editor::{
  25    movement::{self, FindRange},
  26    Anchor, Bias, Editor, EditorEvent, EditorMode, ToPoint,
  27};
  28use gpui::{
  29    actions, impl_actions, Action, App, AppContext as _, Axis, Context, Entity, EventEmitter,
  30    KeyContext, KeystrokeEvent, Render, Subscription, Task, WeakEntity, Window,
  31};
  32use insert::{NormalBefore, TemporaryNormal};
  33use language::{CursorShape, Point, Selection, SelectionGoal, TransactionId};
  34pub use mode_indicator::ModeIndicator;
  35use motion::Motion;
  36use normal::search::SearchSubmit;
  37use object::Object;
  38use schemars::JsonSchema;
  39use serde::Deserialize;
  40use serde_derive::Serialize;
  41use settings::{update_settings_file, Settings, SettingsSources, SettingsStore};
  42use state::{Mode, Operator, RecordedSelection, SearchState, VimGlobals};
  43use std::{mem, ops::Range, sync::Arc};
  44use surrounds::SurroundsType;
  45use theme::ThemeSettings;
  46use ui::{px, IntoElement, SharedString};
  47use vim_mode_setting::VimModeSetting;
  48use workspace::{self, Pane, Workspace};
  49
  50use crate::state::ReplayableAction;
  51
  52/// Number is used to manage vim's count. Pushing a digit
  53/// multiplies the current value by 10 and adds the digit.
  54#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  55struct Number(usize);
  56
  57#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  58struct SelectRegister(String);
  59
  60#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  61#[serde(deny_unknown_fields)]
  62struct PushObject {
  63    around: bool,
  64}
  65
  66#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  67#[serde(deny_unknown_fields)]
  68struct PushFindForward {
  69    before: bool,
  70}
  71
  72#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  73#[serde(deny_unknown_fields)]
  74struct PushFindBackward {
  75    after: bool,
  76}
  77
  78#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  79#[serde(deny_unknown_fields)]
  80struct PushSneak {
  81    first_char: Option<char>,
  82}
  83
  84#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  85#[serde(deny_unknown_fields)]
  86struct PushSneakBackward {
  87    first_char: Option<char>,
  88}
  89
  90#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  91#[serde(deny_unknown_fields)]
  92struct PushAddSurrounds {}
  93
  94#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
  95#[serde(deny_unknown_fields)]
  96struct PushChangeSurrounds {
  97    target: Option<Object>,
  98}
  99
 100#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
 101#[serde(deny_unknown_fields)]
 102struct PushJump {
 103    line: bool,
 104}
 105
 106#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
 107#[serde(deny_unknown_fields)]
 108struct PushDigraph {
 109    first_char: Option<char>,
 110}
 111
 112#[derive(Clone, Deserialize, JsonSchema, PartialEq)]
 113#[serde(deny_unknown_fields)]
 114struct PushLiteral {
 115    prefix: Option<String>,
 116}
 117
 118actions!(
 119    vim,
 120    [
 121        SwitchToNormalMode,
 122        SwitchToInsertMode,
 123        SwitchToReplaceMode,
 124        SwitchToVisualMode,
 125        SwitchToVisualLineMode,
 126        SwitchToVisualBlockMode,
 127        SwitchToHelixNormalMode,
 128        ClearOperators,
 129        Tab,
 130        Enter,
 131        InnerObject,
 132        MaximizePane,
 133        OpenDefaultKeymap,
 134        ResetPaneSizes,
 135        ResizePaneRight,
 136        ResizePaneLeft,
 137        ResizePaneUp,
 138        ResizePaneDown,
 139        PushChange,
 140        PushDelete,
 141        PushYank,
 142        PushReplace,
 143        PushDeleteSurrounds,
 144        PushMark,
 145        PushIndent,
 146        PushOutdent,
 147        PushAutoIndent,
 148        PushRewrap,
 149        PushShellCommand,
 150        PushLowercase,
 151        PushUppercase,
 152        PushOppositeCase,
 153        PushRegister,
 154        PushRecordRegister,
 155        PushReplayRegister,
 156        PushReplaceWithRegister,
 157        PushToggleComments,
 158    ]
 159);
 160
 161// in the workspace namespace so it's not filtered out when vim is disabled.
 162actions!(workspace, [ToggleVimMode,]);
 163
 164impl_actions!(
 165    vim,
 166    [
 167        Number,
 168        SelectRegister,
 169        PushObject,
 170        PushFindForward,
 171        PushFindBackward,
 172        PushSneak,
 173        PushSneakBackward,
 174        PushAddSurrounds,
 175        PushChangeSurrounds,
 176        PushJump,
 177        PushDigraph,
 178        PushLiteral
 179    ]
 180);
 181
 182/// Initializes the `vim` crate.
 183pub fn init(cx: &mut App) {
 184    vim_mode_setting::init(cx);
 185    VimSettings::register(cx);
 186    VimGlobals::register(cx);
 187
 188    cx.observe_new(Vim::register).detach();
 189
 190    cx.observe_new(|workspace: &mut Workspace, _, _| {
 191        workspace.register_action(|workspace, _: &ToggleVimMode, _, cx| {
 192            let fs = workspace.app_state().fs.clone();
 193            let currently_enabled = Vim::enabled(cx);
 194            update_settings_file::<VimModeSetting>(fs, cx, move |setting, _| {
 195                *setting = Some(!currently_enabled)
 196            })
 197        });
 198
 199        workspace.register_action(|_, _: &OpenDefaultKeymap, _, cx| {
 200            cx.emit(workspace::Event::OpenBundledFile {
 201                text: settings::vim_keymap(),
 202                title: "Default Vim Bindings",
 203                language: "JSON",
 204            });
 205        });
 206
 207        workspace.register_action(|workspace, _: &ResetPaneSizes, _, cx| {
 208            workspace.reset_pane_sizes(cx);
 209        });
 210
 211        workspace.register_action(|workspace, _: &MaximizePane, window, cx| {
 212            let pane = workspace.active_pane();
 213            let Some(size) = workspace.bounding_box_for_pane(&pane) else {
 214                return;
 215            };
 216
 217            let theme = ThemeSettings::get_global(cx);
 218            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 219
 220            let desired_size = if let Some(count) = Vim::take_count(cx) {
 221                height * count
 222            } else {
 223                px(10000.)
 224            };
 225            workspace.resize_pane(Axis::Vertical, desired_size - size.size.height, window, cx)
 226        });
 227
 228        workspace.register_action(|workspace, _: &ResizePaneRight, window, cx| {
 229            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 230            let theme = ThemeSettings::get_global(cx);
 231            let Ok(font_id) = window.text_system().font_id(&theme.buffer_font) else {
 232                return;
 233            };
 234            let Ok(width) = window
 235                .text_system()
 236                .advance(font_id, theme.buffer_font_size(cx), 'm')
 237            else {
 238                return;
 239            };
 240            workspace.resize_pane(Axis::Horizontal, width.width * count, window, cx);
 241        });
 242
 243        workspace.register_action(|workspace, _: &ResizePaneLeft, window, cx| {
 244            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 245            let theme = ThemeSettings::get_global(cx);
 246            let Ok(font_id) = window.text_system().font_id(&theme.buffer_font) else {
 247                return;
 248            };
 249            let Ok(width) = window
 250                .text_system()
 251                .advance(font_id, theme.buffer_font_size(cx), 'm')
 252            else {
 253                return;
 254            };
 255            workspace.resize_pane(Axis::Horizontal, -width.width * count, window, cx);
 256        });
 257
 258        workspace.register_action(|workspace, _: &ResizePaneUp, window, cx| {
 259            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 260            let theme = ThemeSettings::get_global(cx);
 261            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 262            workspace.resize_pane(Axis::Vertical, height * count, window, cx);
 263        });
 264
 265        workspace.register_action(|workspace, _: &ResizePaneDown, window, cx| {
 266            let count = Vim::take_count(cx).unwrap_or(1) as f32;
 267            let theme = ThemeSettings::get_global(cx);
 268            let height = theme.buffer_font_size(cx) * theme.buffer_line_height.value();
 269            workspace.resize_pane(Axis::Vertical, -height * count, window, cx);
 270        });
 271
 272        workspace.register_action(|workspace, _: &SearchSubmit, window, cx| {
 273            let vim = workspace
 274                .focused_pane(window, cx)
 275                .read(cx)
 276                .active_item()
 277                .and_then(|item| item.act_as::<Editor>(cx))
 278                .and_then(|editor| editor.read(cx).addon::<VimAddon>().cloned());
 279            let Some(vim) = vim else { return };
 280            vim.entity.update(cx, |_, cx| {
 281                cx.defer_in(window, |vim, window, cx| vim.search_submit(window, cx))
 282            })
 283        });
 284    })
 285    .detach();
 286}
 287
 288#[derive(Clone)]
 289pub(crate) struct VimAddon {
 290    pub(crate) entity: Entity<Vim>,
 291}
 292
 293impl editor::Addon for VimAddon {
 294    fn extend_key_context(&self, key_context: &mut KeyContext, cx: &App) {
 295        self.entity.read(cx).extend_key_context(key_context, cx)
 296    }
 297
 298    fn to_any(&self) -> &dyn std::any::Any {
 299        self
 300    }
 301}
 302
 303/// The state pertaining to Vim mode.
 304pub(crate) struct Vim {
 305    pub(crate) mode: Mode,
 306    pub last_mode: Mode,
 307    pub temp_mode: bool,
 308    pub status_label: Option<SharedString>,
 309    pub exit_temporary_mode: bool,
 310
 311    operator_stack: Vec<Operator>,
 312    pub(crate) replacements: Vec<(Range<editor::Anchor>, String)>,
 313
 314    pub(crate) marks: HashMap<String, Vec<Anchor>>,
 315    pub(crate) stored_visual_mode: Option<(Mode, Vec<bool>)>,
 316    pub(crate) change_list: Vec<Vec<Anchor>>,
 317    pub(crate) change_list_position: Option<usize>,
 318
 319    pub(crate) current_tx: Option<TransactionId>,
 320    pub(crate) current_anchor: Option<Selection<Anchor>>,
 321    pub(crate) undo_modes: HashMap<TransactionId, Mode>,
 322
 323    selected_register: Option<char>,
 324    pub search: SearchState,
 325
 326    editor: WeakEntity<Editor>,
 327
 328    last_command: Option<String>,
 329    running_command: Option<Task<()>>,
 330    _subscriptions: Vec<Subscription>,
 331}
 332
 333// Hack: Vim intercepts events dispatched to a window and updates the view in response.
 334// This means it needs a VisualContext. The easiest way to satisfy that constraint is
 335// to make Vim a "View" that is just never actually rendered.
 336impl Render for Vim {
 337    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
 338        gpui::Empty
 339    }
 340}
 341
 342enum VimEvent {
 343    Focused,
 344}
 345impl EventEmitter<VimEvent> for Vim {}
 346
 347impl Vim {
 348    /// The namespace for Vim actions.
 349    const NAMESPACE: &'static str = "vim";
 350
 351    pub fn new(window: &mut Window, cx: &mut Context<Editor>) -> Entity<Self> {
 352        let editor = cx.entity().clone();
 353
 354        cx.new(|cx| Vim {
 355            mode: Mode::Normal,
 356            last_mode: Mode::Normal,
 357            temp_mode: false,
 358            exit_temporary_mode: false,
 359            operator_stack: Vec::new(),
 360            replacements: Vec::new(),
 361
 362            marks: HashMap::default(),
 363            stored_visual_mode: None,
 364            change_list: Vec::new(),
 365            change_list_position: None,
 366            current_tx: None,
 367            current_anchor: None,
 368            undo_modes: HashMap::default(),
 369
 370            status_label: None,
 371            selected_register: None,
 372            search: SearchState::default(),
 373
 374            last_command: None,
 375            running_command: None,
 376
 377            editor: editor.downgrade(),
 378            _subscriptions: vec![
 379                cx.observe_keystrokes(Self::observe_keystrokes),
 380                cx.subscribe_in(&editor, window, |this, _, event, window, cx| {
 381                    this.handle_editor_event(event, window, cx)
 382                }),
 383            ],
 384        })
 385    }
 386
 387    fn register(editor: &mut Editor, window: Option<&mut Window>, cx: &mut Context<Editor>) {
 388        let Some(window) = window else {
 389            return;
 390        };
 391
 392        if !editor.use_modal_editing() {
 393            return;
 394        }
 395
 396        let mut was_enabled = Vim::enabled(cx);
 397        let mut was_toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 398        cx.observe_global_in::<SettingsStore>(window, move |editor, window, cx| {
 399            let enabled = Vim::enabled(cx);
 400            let toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 401            if enabled && was_enabled && (toggle != was_toggle) {
 402                if toggle {
 403                    let is_relative = editor
 404                        .addon::<VimAddon>()
 405                        .map(|vim| vim.entity.read(cx).mode != Mode::Insert);
 406                    editor.set_relative_line_number(is_relative, cx)
 407                } else {
 408                    editor.set_relative_line_number(None, cx)
 409                }
 410            }
 411            was_toggle = VimSettings::get_global(cx).toggle_relative_line_numbers;
 412            if was_enabled == enabled {
 413                return;
 414            }
 415            was_enabled = enabled;
 416            if enabled {
 417                Self::activate(editor, window, cx)
 418            } else {
 419                Self::deactivate(editor, cx)
 420            }
 421        })
 422        .detach();
 423        if was_enabled {
 424            Self::activate(editor, window, cx)
 425        }
 426    }
 427
 428    fn activate(editor: &mut Editor, window: &mut Window, cx: &mut Context<Editor>) {
 429        let vim = Vim::new(window, cx);
 430
 431        editor.register_addon(VimAddon {
 432            entity: vim.clone(),
 433        });
 434
 435        vim.update(cx, |_, cx| {
 436            Vim::action(editor, cx, |vim, _: &SwitchToNormalMode, window, cx| {
 437                vim.switch_mode(Mode::Normal, false, window, cx)
 438            });
 439
 440            Vim::action(editor, cx, |vim, _: &SwitchToInsertMode, window, cx| {
 441                vim.switch_mode(Mode::Insert, false, window, cx)
 442            });
 443
 444            Vim::action(editor, cx, |vim, _: &SwitchToReplaceMode, window, cx| {
 445                vim.switch_mode(Mode::Replace, false, window, cx)
 446            });
 447
 448            Vim::action(editor, cx, |vim, _: &SwitchToVisualMode, window, cx| {
 449                vim.switch_mode(Mode::Visual, false, window, cx)
 450            });
 451
 452            Vim::action(editor, cx, |vim, _: &SwitchToVisualLineMode, window, cx| {
 453                vim.switch_mode(Mode::VisualLine, false, window, cx)
 454            });
 455
 456            Vim::action(
 457                editor,
 458                cx,
 459                |vim, _: &SwitchToVisualBlockMode, window, cx| {
 460                    vim.switch_mode(Mode::VisualBlock, false, window, cx)
 461                },
 462            );
 463
 464            Vim::action(
 465                editor,
 466                cx,
 467                |vim, _: &SwitchToHelixNormalMode, window, cx| {
 468                    vim.switch_mode(Mode::HelixNormal, false, window, cx)
 469                },
 470            );
 471
 472            Vim::action(editor, cx, |vim, action: &PushObject, window, cx| {
 473                vim.push_operator(
 474                    Operator::Object {
 475                        around: action.around,
 476                    },
 477                    window,
 478                    cx,
 479                )
 480            });
 481
 482            Vim::action(editor, cx, |vim, action: &PushFindForward, window, cx| {
 483                vim.push_operator(
 484                    Operator::FindForward {
 485                        before: action.before,
 486                    },
 487                    window,
 488                    cx,
 489                )
 490            });
 491
 492            Vim::action(editor, cx, |vim, action: &PushFindBackward, window, cx| {
 493                vim.push_operator(
 494                    Operator::FindBackward {
 495                        after: action.after,
 496                    },
 497                    window,
 498                    cx,
 499                )
 500            });
 501
 502            Vim::action(editor, cx, |vim, action: &PushSneak, window, cx| {
 503                vim.push_operator(
 504                    Operator::Sneak {
 505                        first_char: action.first_char,
 506                    },
 507                    window,
 508                    cx,
 509                )
 510            });
 511
 512            Vim::action(editor, cx, |vim, action: &PushSneakBackward, window, cx| {
 513                vim.push_operator(
 514                    Operator::SneakBackward {
 515                        first_char: action.first_char,
 516                    },
 517                    window,
 518                    cx,
 519                )
 520            });
 521
 522            Vim::action(editor, cx, |vim, _: &PushAddSurrounds, window, cx| {
 523                vim.push_operator(Operator::AddSurrounds { target: None }, window, cx)
 524            });
 525
 526            Vim::action(
 527                editor,
 528                cx,
 529                |vim, action: &PushChangeSurrounds, window, cx| {
 530                    vim.push_operator(
 531                        Operator::ChangeSurrounds {
 532                            target: action.target,
 533                        },
 534                        window,
 535                        cx,
 536                    )
 537                },
 538            );
 539
 540            Vim::action(editor, cx, |vim, action: &PushJump, window, cx| {
 541                vim.push_operator(Operator::Jump { line: action.line }, window, cx)
 542            });
 543
 544            Vim::action(editor, cx, |vim, action: &PushDigraph, window, cx| {
 545                vim.push_operator(
 546                    Operator::Digraph {
 547                        first_char: action.first_char,
 548                    },
 549                    window,
 550                    cx,
 551                )
 552            });
 553
 554            Vim::action(editor, cx, |vim, action: &PushLiteral, window, cx| {
 555                vim.push_operator(
 556                    Operator::Literal {
 557                        prefix: action.prefix.clone(),
 558                    },
 559                    window,
 560                    cx,
 561                )
 562            });
 563
 564            Vim::action(editor, cx, |vim, _: &PushChange, window, cx| {
 565                vim.push_operator(Operator::Change, window, cx)
 566            });
 567
 568            Vim::action(editor, cx, |vim, _: &PushDelete, window, cx| {
 569                vim.push_operator(Operator::Delete, window, cx)
 570            });
 571
 572            Vim::action(editor, cx, |vim, _: &PushYank, window, cx| {
 573                vim.push_operator(Operator::Yank, window, cx)
 574            });
 575
 576            Vim::action(editor, cx, |vim, _: &PushReplace, window, cx| {
 577                vim.push_operator(Operator::Replace, window, cx)
 578            });
 579
 580            Vim::action(editor, cx, |vim, _: &PushDeleteSurrounds, window, cx| {
 581                vim.push_operator(Operator::DeleteSurrounds, window, cx)
 582            });
 583
 584            Vim::action(editor, cx, |vim, _: &PushMark, window, cx| {
 585                vim.push_operator(Operator::Mark, window, cx)
 586            });
 587
 588            Vim::action(editor, cx, |vim, _: &PushIndent, window, cx| {
 589                vim.push_operator(Operator::Indent, window, cx)
 590            });
 591
 592            Vim::action(editor, cx, |vim, _: &PushOutdent, window, cx| {
 593                vim.push_operator(Operator::Outdent, window, cx)
 594            });
 595
 596            Vim::action(editor, cx, |vim, _: &PushAutoIndent, window, cx| {
 597                vim.push_operator(Operator::AutoIndent, window, cx)
 598            });
 599
 600            Vim::action(editor, cx, |vim, _: &PushRewrap, window, cx| {
 601                vim.push_operator(Operator::Rewrap, window, cx)
 602            });
 603
 604            Vim::action(editor, cx, |vim, _: &PushShellCommand, window, cx| {
 605                vim.push_operator(Operator::ShellCommand, window, cx)
 606            });
 607
 608            Vim::action(editor, cx, |vim, _: &PushLowercase, window, cx| {
 609                vim.push_operator(Operator::Lowercase, window, cx)
 610            });
 611
 612            Vim::action(editor, cx, |vim, _: &PushUppercase, window, cx| {
 613                vim.push_operator(Operator::Uppercase, window, cx)
 614            });
 615
 616            Vim::action(editor, cx, |vim, _: &PushOppositeCase, window, cx| {
 617                vim.push_operator(Operator::OppositeCase, window, cx)
 618            });
 619
 620            Vim::action(editor, cx, |vim, _: &PushRegister, window, cx| {
 621                vim.push_operator(Operator::Register, window, cx)
 622            });
 623
 624            Vim::action(editor, cx, |vim, _: &PushRecordRegister, window, cx| {
 625                vim.push_operator(Operator::RecordRegister, window, cx)
 626            });
 627
 628            Vim::action(editor, cx, |vim, _: &PushReplayRegister, window, cx| {
 629                vim.push_operator(Operator::ReplayRegister, window, cx)
 630            });
 631
 632            Vim::action(
 633                editor,
 634                cx,
 635                |vim, _: &PushReplaceWithRegister, window, cx| {
 636                    vim.push_operator(Operator::ReplaceWithRegister, window, cx)
 637                },
 638            );
 639
 640            Vim::action(editor, cx, |vim, _: &PushToggleComments, window, cx| {
 641                vim.push_operator(Operator::ToggleComments, window, cx)
 642            });
 643
 644            Vim::action(editor, cx, |vim, _: &ClearOperators, window, cx| {
 645                vim.clear_operator(window, cx)
 646            });
 647            Vim::action(editor, cx, |vim, n: &Number, window, cx| {
 648                vim.push_count_digit(n.0, window, cx);
 649            });
 650            Vim::action(editor, cx, |vim, _: &Tab, window, cx| {
 651                vim.input_ignored(" ".into(), window, cx)
 652            });
 653            Vim::action(
 654                editor,
 655                cx,
 656                |vim, action: &editor::AcceptEditPrediction, window, cx| {
 657                    vim.update_editor(window, cx, |_, editor, window, cx| {
 658                        editor.accept_edit_prediction(action, window, cx);
 659                    });
 660                    // In non-insertion modes, predictions will be hidden and instead a jump will be
 661                    // displayed (and performed by `accept_edit_prediction`). This switches to
 662                    // insert mode so that the prediction is displayed after the jump.
 663                    match vim.mode {
 664                        Mode::Replace => {}
 665                        _ => vim.switch_mode(Mode::Insert, true, window, cx),
 666                    };
 667                },
 668            );
 669            Vim::action(editor, cx, |vim, _: &Enter, window, cx| {
 670                vim.input_ignored("\n".into(), window, cx)
 671            });
 672
 673            normal::register(editor, cx);
 674            insert::register(editor, cx);
 675            helix::register(editor, cx);
 676            motion::register(editor, cx);
 677            command::register(editor, cx);
 678            replace::register(editor, cx);
 679            indent::register(editor, cx);
 680            rewrap::register(editor, cx);
 681            object::register(editor, cx);
 682            visual::register(editor, cx);
 683            change_list::register(editor, cx);
 684            digraph::register(editor, cx);
 685
 686            cx.defer_in(window, |vim, window, cx| {
 687                vim.focused(false, window, cx);
 688            })
 689        })
 690    }
 691
 692    fn deactivate(editor: &mut Editor, cx: &mut Context<Editor>) {
 693        editor.set_cursor_shape(CursorShape::Bar, cx);
 694        editor.set_clip_at_line_ends(false, cx);
 695        editor.set_collapse_matches(false);
 696        editor.set_input_enabled(true);
 697        editor.set_autoindent(true);
 698        editor.selections.line_mode = false;
 699        editor.unregister_addon::<VimAddon>();
 700        editor.set_relative_line_number(None, cx);
 701        if let Some(vim) = Vim::globals(cx).focused_vim() {
 702            if vim.entity_id() == cx.entity().entity_id() {
 703                Vim::globals(cx).focused_vim = None;
 704            }
 705        }
 706    }
 707
 708    /// Register an action on the editor.
 709    pub fn action<A: Action>(
 710        editor: &mut Editor,
 711        cx: &mut Context<Vim>,
 712        f: impl Fn(&mut Vim, &A, &mut Window, &mut Context<Vim>) + 'static,
 713    ) {
 714        let subscription = editor.register_action(cx.listener(f));
 715        cx.on_release(|_, _| drop(subscription)).detach();
 716    }
 717
 718    pub fn editor(&self) -> Option<Entity<Editor>> {
 719        self.editor.upgrade()
 720    }
 721
 722    pub fn workspace(&self, window: &mut Window) -> Option<Entity<Workspace>> {
 723        window.root::<Workspace>().flatten()
 724    }
 725
 726    pub fn pane(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Entity<Pane>> {
 727        self.workspace(window)
 728            .map(|workspace| workspace.read(cx).focused_pane(window, cx))
 729    }
 730
 731    pub fn enabled(cx: &mut App) -> bool {
 732        VimModeSetting::get_global(cx).0
 733    }
 734
 735    /// Called whenever an keystroke is typed so vim can observe all actions
 736    /// and keystrokes accordingly.
 737    fn observe_keystrokes(
 738        &mut self,
 739        keystroke_event: &KeystrokeEvent,
 740        window: &mut Window,
 741        cx: &mut Context<Self>,
 742    ) {
 743        if self.exit_temporary_mode {
 744            self.exit_temporary_mode = false;
 745            // Don't switch to insert mode if the action is temporary_normal.
 746            if let Some(action) = keystroke_event.action.as_ref() {
 747                if action.as_any().downcast_ref::<TemporaryNormal>().is_some() {
 748                    return;
 749                }
 750            }
 751            self.switch_mode(Mode::Insert, false, window, cx)
 752        }
 753        if let Some(action) = keystroke_event.action.as_ref() {
 754            // Keystroke is handled by the vim system, so continue forward
 755            if action.name().starts_with("vim::") {
 756                return;
 757            }
 758        } else if window.has_pending_keystrokes() || keystroke_event.keystroke.is_ime_in_progress()
 759        {
 760            return;
 761        }
 762
 763        if let Some(operator) = self.active_operator() {
 764            match operator {
 765                Operator::Literal { prefix } => {
 766                    self.handle_literal_keystroke(
 767                        keystroke_event,
 768                        prefix.unwrap_or_default(),
 769                        window,
 770                        cx,
 771                    );
 772                }
 773                _ if !operator.is_waiting(self.mode) => {
 774                    self.clear_operator(window, cx);
 775                    self.stop_recording_immediately(Box::new(ClearOperators), cx)
 776                }
 777                _ => {}
 778            }
 779        }
 780    }
 781
 782    fn handle_editor_event(
 783        &mut self,
 784        event: &EditorEvent,
 785        window: &mut Window,
 786        cx: &mut Context<Self>,
 787    ) {
 788        match event {
 789            EditorEvent::Focused => self.focused(true, window, cx),
 790            EditorEvent::Blurred => self.blurred(window, cx),
 791            EditorEvent::SelectionsChanged { local: true } => {
 792                self.local_selections_changed(window, cx);
 793            }
 794            EditorEvent::InputIgnored { text } => {
 795                self.input_ignored(text.clone(), window, cx);
 796                Vim::globals(cx).observe_insertion(text, None)
 797            }
 798            EditorEvent::InputHandled {
 799                text,
 800                utf16_range_to_replace: range_to_replace,
 801            } => Vim::globals(cx).observe_insertion(text, range_to_replace.clone()),
 802            EditorEvent::TransactionBegun { transaction_id } => {
 803                self.transaction_begun(*transaction_id, window, cx)
 804            }
 805            EditorEvent::TransactionUndone { transaction_id } => {
 806                self.transaction_undone(transaction_id, window, cx)
 807            }
 808            EditorEvent::Edited { .. } => self.push_to_change_list(window, cx),
 809            EditorEvent::FocusedIn => self.sync_vim_settings(window, cx),
 810            EditorEvent::CursorShapeChanged => self.cursor_shape_changed(window, cx),
 811            _ => {}
 812        }
 813    }
 814
 815    fn push_operator(&mut self, operator: Operator, window: &mut Window, cx: &mut Context<Self>) {
 816        if matches!(
 817            operator,
 818            Operator::Change
 819                | Operator::Delete
 820                | Operator::Replace
 821                | Operator::Indent
 822                | Operator::Outdent
 823                | Operator::AutoIndent
 824                | Operator::Lowercase
 825                | Operator::Uppercase
 826                | Operator::OppositeCase
 827                | Operator::ToggleComments
 828                | Operator::ReplaceWithRegister
 829        ) {
 830            self.start_recording(cx)
 831        };
 832        // Since these operations can only be entered with pre-operators,
 833        // we need to clear the previous operators when pushing,
 834        // so that the current stack is the most correct
 835        if matches!(
 836            operator,
 837            Operator::AddSurrounds { .. }
 838                | Operator::ChangeSurrounds { .. }
 839                | Operator::DeleteSurrounds
 840        ) {
 841            self.operator_stack.clear();
 842            if let Operator::AddSurrounds { target: None } = operator {
 843                self.start_recording(cx);
 844            }
 845        };
 846        self.operator_stack.push(operator);
 847        self.sync_vim_settings(window, cx);
 848    }
 849
 850    pub fn switch_mode(
 851        &mut self,
 852        mode: Mode,
 853        leave_selections: bool,
 854        window: &mut Window,
 855        cx: &mut Context<Self>,
 856    ) {
 857        if self.temp_mode && mode == Mode::Normal {
 858            self.temp_mode = false;
 859            self.switch_mode(Mode::Normal, leave_selections, window, cx);
 860            self.switch_mode(Mode::Insert, false, window, cx);
 861            return;
 862        } else if self.temp_mode
 863            && !matches!(mode, Mode::Visual | Mode::VisualLine | Mode::VisualBlock)
 864        {
 865            self.temp_mode = false;
 866        }
 867
 868        let last_mode = self.mode;
 869        let prior_mode = self.last_mode;
 870        let prior_tx = self.current_tx;
 871        self.status_label.take();
 872        self.last_mode = last_mode;
 873        self.mode = mode;
 874        self.operator_stack.clear();
 875        self.selected_register.take();
 876        self.cancel_running_command(window, cx);
 877        if mode == Mode::Normal || mode != last_mode {
 878            self.current_tx.take();
 879            self.current_anchor.take();
 880        }
 881        if mode != Mode::Insert && mode != Mode::Replace {
 882            Vim::take_count(cx);
 883        }
 884
 885        // Sync editor settings like clip mode
 886        self.sync_vim_settings(window, cx);
 887
 888        if VimSettings::get_global(cx).toggle_relative_line_numbers
 889            && self.mode != self.last_mode
 890            && (self.mode == Mode::Insert || self.last_mode == Mode::Insert)
 891        {
 892            self.update_editor(window, cx, |vim, editor, _, cx| {
 893                let is_relative = vim.mode != Mode::Insert;
 894                editor.set_relative_line_number(Some(is_relative), cx)
 895            });
 896        }
 897
 898        if leave_selections {
 899            return;
 900        }
 901
 902        if !mode.is_visual() && last_mode.is_visual() {
 903            self.create_visual_marks(last_mode, window, cx);
 904        }
 905
 906        // Adjust selections
 907        self.update_editor(window, cx, |vim, editor, window, cx| {
 908            if last_mode != Mode::VisualBlock && last_mode.is_visual() && mode == Mode::VisualBlock
 909            {
 910                vim.visual_block_motion(true, editor, window, cx, |_, point, goal| {
 911                    Some((point, goal))
 912                })
 913            }
 914            if last_mode == Mode::Insert || last_mode == Mode::Replace {
 915                if let Some(prior_tx) = prior_tx {
 916                    editor.group_until_transaction(prior_tx, cx)
 917                }
 918            }
 919
 920            editor.change_selections(None, window, cx, |s| {
 921                // we cheat with visual block mode and use multiple cursors.
 922                // the cost of this cheat is we need to convert back to a single
 923                // cursor whenever vim would.
 924                if last_mode == Mode::VisualBlock
 925                    && (mode != Mode::VisualBlock && mode != Mode::Insert)
 926                {
 927                    let tail = s.oldest_anchor().tail();
 928                    let head = s.newest_anchor().head();
 929                    s.select_anchor_ranges(vec![tail..head]);
 930                } else if last_mode == Mode::Insert
 931                    && prior_mode == Mode::VisualBlock
 932                    && mode != Mode::VisualBlock
 933                {
 934                    let pos = s.first_anchor().head();
 935                    s.select_anchor_ranges(vec![pos..pos])
 936                }
 937
 938                let snapshot = s.display_map();
 939                if let Some(pending) = s.pending.as_mut() {
 940                    if pending.selection.reversed && mode.is_visual() && !last_mode.is_visual() {
 941                        let mut end = pending.selection.end.to_point(&snapshot.buffer_snapshot);
 942                        end = snapshot
 943                            .buffer_snapshot
 944                            .clip_point(end + Point::new(0, 1), Bias::Right);
 945                        pending.selection.end = snapshot.buffer_snapshot.anchor_before(end);
 946                    }
 947                }
 948
 949                s.move_with(|map, selection| {
 950                    if last_mode.is_visual() && !mode.is_visual() {
 951                        let mut point = selection.head();
 952                        if !selection.reversed && !selection.is_empty() {
 953                            point = movement::left(map, selection.head());
 954                        }
 955                        selection.collapse_to(point, selection.goal)
 956                    } else if !last_mode.is_visual() && mode.is_visual() && selection.is_empty() {
 957                        selection.end = movement::right(map, selection.start);
 958                    }
 959                });
 960            })
 961        });
 962    }
 963
 964    pub fn take_count(cx: &mut App) -> Option<usize> {
 965        let global_state = cx.global_mut::<VimGlobals>();
 966        if global_state.dot_replaying {
 967            return global_state.recorded_count;
 968        }
 969
 970        let count = if global_state.post_count.is_none() && global_state.pre_count.is_none() {
 971            return None;
 972        } else {
 973            Some(
 974                global_state.post_count.take().unwrap_or(1)
 975                    * global_state.pre_count.take().unwrap_or(1),
 976            )
 977        };
 978
 979        if global_state.dot_recording {
 980            global_state.recorded_count = count;
 981        }
 982        count
 983    }
 984
 985    pub fn cursor_shape(&self) -> CursorShape {
 986        match self.mode {
 987            Mode::Normal => {
 988                if let Some(operator) = self.operator_stack.last() {
 989                    match operator {
 990                        // Navigation operators -> Block cursor
 991                        Operator::FindForward { .. }
 992                        | Operator::FindBackward { .. }
 993                        | Operator::Mark
 994                        | Operator::Jump { .. }
 995                        | Operator::Register
 996                        | Operator::RecordRegister
 997                        | Operator::ReplayRegister => CursorShape::Block,
 998
 999                        // All other operators -> Underline cursor
1000                        _ => CursorShape::Underline,
1001                    }
1002                } else {
1003                    // No operator active -> Block cursor
1004                    CursorShape::Block
1005                }
1006            }
1007            Mode::Replace => CursorShape::Underline,
1008            Mode::HelixNormal | Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
1009                CursorShape::Block
1010            }
1011            Mode::Insert => CursorShape::Bar,
1012        }
1013    }
1014
1015    pub fn editor_input_enabled(&self) -> bool {
1016        match self.mode {
1017            Mode::Insert => {
1018                if let Some(operator) = self.operator_stack.last() {
1019                    !operator.is_waiting(self.mode)
1020                } else {
1021                    true
1022                }
1023            }
1024            Mode::Normal
1025            | Mode::HelixNormal
1026            | Mode::Replace
1027            | Mode::Visual
1028            | Mode::VisualLine
1029            | Mode::VisualBlock => false,
1030        }
1031    }
1032
1033    pub fn should_autoindent(&self) -> bool {
1034        !(self.mode == Mode::Insert && self.last_mode == Mode::VisualBlock)
1035    }
1036
1037    pub fn clip_at_line_ends(&self) -> bool {
1038        match self.mode {
1039            Mode::Insert
1040            | Mode::Visual
1041            | Mode::VisualLine
1042            | Mode::VisualBlock
1043            | Mode::Replace
1044            | Mode::HelixNormal => false,
1045            Mode::Normal => true,
1046        }
1047    }
1048
1049    pub fn extend_key_context(&self, context: &mut KeyContext, cx: &App) {
1050        let mut mode = match self.mode {
1051            Mode::Normal => "normal",
1052            Mode::Visual | Mode::VisualLine | Mode::VisualBlock => "visual",
1053            Mode::Insert => "insert",
1054            Mode::Replace => "replace",
1055            Mode::HelixNormal => "helix_normal",
1056        }
1057        .to_string();
1058
1059        let mut operator_id = "none";
1060
1061        let active_operator = self.active_operator();
1062        if active_operator.is_none() && cx.global::<VimGlobals>().pre_count.is_some()
1063            || active_operator.is_some() && cx.global::<VimGlobals>().post_count.is_some()
1064        {
1065            context.add("VimCount");
1066        }
1067
1068        if let Some(active_operator) = active_operator {
1069            if active_operator.is_waiting(self.mode) {
1070                if matches!(active_operator, Operator::Literal { .. }) {
1071                    mode = "literal".to_string();
1072                } else {
1073                    mode = "waiting".to_string();
1074                }
1075            } else {
1076                operator_id = active_operator.id();
1077                mode = "operator".to_string();
1078            }
1079        }
1080
1081        if mode == "normal" || mode == "visual" || mode == "operator" {
1082            context.add("VimControl");
1083        }
1084        context.set("vim_mode", mode);
1085        context.set("vim_operator", operator_id);
1086    }
1087
1088    fn focused(&mut self, preserve_selection: bool, window: &mut Window, cx: &mut Context<Self>) {
1089        let Some(editor) = self.editor() else {
1090            return;
1091        };
1092        let newest_selection_empty = editor.update(cx, |editor, cx| {
1093            editor.selections.newest::<usize>(cx).is_empty()
1094        });
1095        let editor = editor.read(cx);
1096        let editor_mode = editor.mode();
1097
1098        if editor_mode == EditorMode::Full
1099                && !newest_selection_empty
1100                && self.mode == Mode::Normal
1101                // When following someone, don't switch vim mode.
1102                && editor.leader_peer_id().is_none()
1103        {
1104            if preserve_selection {
1105                self.switch_mode(Mode::Visual, true, window, cx);
1106            } else {
1107                self.update_editor(window, cx, |_, editor, window, cx| {
1108                    editor.set_clip_at_line_ends(false, cx);
1109                    editor.change_selections(None, window, cx, |s| {
1110                        s.move_with(|_, selection| {
1111                            selection.collapse_to(selection.start, selection.goal)
1112                        })
1113                    });
1114                });
1115            }
1116        }
1117
1118        cx.emit(VimEvent::Focused);
1119        self.sync_vim_settings(window, cx);
1120
1121        if VimSettings::get_global(cx).toggle_relative_line_numbers {
1122            if let Some(old_vim) = Vim::globals(cx).focused_vim() {
1123                if old_vim.entity_id() != cx.entity().entity_id() {
1124                    old_vim.update(cx, |vim, cx| {
1125                        vim.update_editor(window, cx, |_, editor, _, cx| {
1126                            editor.set_relative_line_number(None, cx)
1127                        });
1128                    });
1129
1130                    self.update_editor(window, cx, |vim, editor, _, cx| {
1131                        let is_relative = vim.mode != Mode::Insert;
1132                        editor.set_relative_line_number(Some(is_relative), cx)
1133                    });
1134                }
1135            } else {
1136                self.update_editor(window, cx, |vim, editor, _, cx| {
1137                    let is_relative = vim.mode != Mode::Insert;
1138                    editor.set_relative_line_number(Some(is_relative), cx)
1139                });
1140            }
1141        }
1142        Vim::globals(cx).focused_vim = Some(cx.entity().downgrade());
1143    }
1144
1145    fn blurred(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1146        self.stop_recording_immediately(NormalBefore.boxed_clone(), cx);
1147        self.store_visual_marks(window, cx);
1148        self.clear_operator(window, cx);
1149        self.update_editor(window, cx, |vim, editor, _, cx| {
1150            if vim.cursor_shape() == CursorShape::Block {
1151                editor.set_cursor_shape(CursorShape::Hollow, cx);
1152            }
1153        });
1154    }
1155
1156    fn cursor_shape_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1157        self.update_editor(window, cx, |vim, editor, _, cx| {
1158            editor.set_cursor_shape(vim.cursor_shape(), cx);
1159        });
1160    }
1161
1162    fn update_editor<S>(
1163        &mut self,
1164        window: &mut Window,
1165        cx: &mut Context<Self>,
1166        update: impl FnOnce(&mut Self, &mut Editor, &mut Window, &mut Context<Editor>) -> S,
1167    ) -> Option<S> {
1168        let editor = self.editor.upgrade()?;
1169        Some(editor.update(cx, |editor, cx| update(self, editor, window, cx)))
1170    }
1171
1172    fn editor_selections(
1173        &mut self,
1174        window: &mut Window,
1175        cx: &mut Context<Self>,
1176    ) -> Vec<Range<Anchor>> {
1177        self.update_editor(window, cx, |_, editor, _, _| {
1178            editor
1179                .selections
1180                .disjoint_anchors()
1181                .iter()
1182                .map(|selection| selection.tail()..selection.head())
1183                .collect()
1184        })
1185        .unwrap_or_default()
1186    }
1187
1188    /// When doing an action that modifies the buffer, we start recording so that `.`
1189    /// will replay the action.
1190    pub fn start_recording(&mut self, cx: &mut Context<Self>) {
1191        Vim::update_globals(cx, |globals, cx| {
1192            if !globals.dot_replaying {
1193                globals.dot_recording = true;
1194                globals.recording_actions = Default::default();
1195                globals.recorded_count = None;
1196
1197                let selections = self.editor().map(|editor| {
1198                    editor.update(cx, |editor, cx| {
1199                        (
1200                            editor.selections.oldest::<Point>(cx),
1201                            editor.selections.newest::<Point>(cx),
1202                        )
1203                    })
1204                });
1205
1206                if let Some((oldest, newest)) = selections {
1207                    globals.recorded_selection = match self.mode {
1208                        Mode::Visual if newest.end.row == newest.start.row => {
1209                            RecordedSelection::SingleLine {
1210                                cols: newest.end.column - newest.start.column,
1211                            }
1212                        }
1213                        Mode::Visual => RecordedSelection::Visual {
1214                            rows: newest.end.row - newest.start.row,
1215                            cols: newest.end.column,
1216                        },
1217                        Mode::VisualLine => RecordedSelection::VisualLine {
1218                            rows: newest.end.row - newest.start.row,
1219                        },
1220                        Mode::VisualBlock => RecordedSelection::VisualBlock {
1221                            rows: newest.end.row.abs_diff(oldest.start.row),
1222                            cols: newest.end.column.abs_diff(oldest.start.column),
1223                        },
1224                        _ => RecordedSelection::None,
1225                    }
1226                } else {
1227                    globals.recorded_selection = RecordedSelection::None;
1228                }
1229            }
1230        })
1231    }
1232
1233    pub fn stop_replaying(&mut self, cx: &mut Context<Self>) {
1234        let globals = Vim::globals(cx);
1235        globals.dot_replaying = false;
1236        if let Some(replayer) = globals.replayer.take() {
1237            replayer.stop();
1238        }
1239    }
1240
1241    /// When finishing an action that modifies the buffer, stop recording.
1242    /// as you usually call this within a keystroke handler we also ensure that
1243    /// the current action is recorded.
1244    pub fn stop_recording(&mut self, cx: &mut Context<Self>) {
1245        let globals = Vim::globals(cx);
1246        if globals.dot_recording {
1247            globals.stop_recording_after_next_action = true;
1248        }
1249        self.exit_temporary_mode = self.temp_mode;
1250    }
1251
1252    /// Stops recording actions immediately rather than waiting until after the
1253    /// next action to stop recording.
1254    ///
1255    /// This doesn't include the current action.
1256    pub fn stop_recording_immediately(&mut self, action: Box<dyn Action>, cx: &mut Context<Self>) {
1257        let globals = Vim::globals(cx);
1258        if globals.dot_recording {
1259            globals
1260                .recording_actions
1261                .push(ReplayableAction::Action(action.boxed_clone()));
1262            globals.recorded_actions = mem::take(&mut globals.recording_actions);
1263            globals.dot_recording = false;
1264            globals.stop_recording_after_next_action = false;
1265        }
1266        self.exit_temporary_mode = self.temp_mode;
1267    }
1268
1269    /// Explicitly record one action (equivalents to start_recording and stop_recording)
1270    pub fn record_current_action(&mut self, cx: &mut Context<Self>) {
1271        self.start_recording(cx);
1272        self.stop_recording(cx);
1273    }
1274
1275    fn push_count_digit(&mut self, number: usize, window: &mut Window, cx: &mut Context<Self>) {
1276        if self.active_operator().is_some() {
1277            let post_count = Vim::globals(cx).post_count.unwrap_or(0);
1278
1279            Vim::globals(cx).post_count = Some(
1280                post_count
1281                    .checked_mul(10)
1282                    .and_then(|post_count| post_count.checked_add(number))
1283                    .unwrap_or(post_count),
1284            )
1285        } else {
1286            let pre_count = Vim::globals(cx).pre_count.unwrap_or(0);
1287
1288            Vim::globals(cx).pre_count = Some(
1289                pre_count
1290                    .checked_mul(10)
1291                    .and_then(|pre_count| pre_count.checked_add(number))
1292                    .unwrap_or(pre_count),
1293            )
1294        }
1295        // update the keymap so that 0 works
1296        self.sync_vim_settings(window, cx)
1297    }
1298
1299    fn select_register(&mut self, register: Arc<str>, window: &mut Window, cx: &mut Context<Self>) {
1300        if register.chars().count() == 1 {
1301            self.selected_register
1302                .replace(register.chars().next().unwrap());
1303        }
1304        self.operator_stack.clear();
1305        self.sync_vim_settings(window, cx);
1306    }
1307
1308    fn maybe_pop_operator(&mut self) -> Option<Operator> {
1309        self.operator_stack.pop()
1310    }
1311
1312    fn pop_operator(&mut self, window: &mut Window, cx: &mut Context<Self>) -> Operator {
1313        let popped_operator = self.operator_stack.pop()
1314            .expect("Operator popped when no operator was on the stack. This likely means there is an invalid keymap config");
1315        self.sync_vim_settings(window, cx);
1316        popped_operator
1317    }
1318
1319    fn clear_operator(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1320        Vim::take_count(cx);
1321        self.selected_register.take();
1322        self.operator_stack.clear();
1323        self.sync_vim_settings(window, cx);
1324    }
1325
1326    fn active_operator(&self) -> Option<Operator> {
1327        self.operator_stack.last().cloned()
1328    }
1329
1330    fn transaction_begun(
1331        &mut self,
1332        transaction_id: TransactionId,
1333        _window: &mut Window,
1334        _: &mut Context<Self>,
1335    ) {
1336        let mode = if (self.mode == Mode::Insert
1337            || self.mode == Mode::Replace
1338            || self.mode == Mode::Normal)
1339            && self.current_tx.is_none()
1340        {
1341            self.current_tx = Some(transaction_id);
1342            self.last_mode
1343        } else {
1344            self.mode
1345        };
1346        if mode == Mode::VisualLine || mode == Mode::VisualBlock {
1347            self.undo_modes.insert(transaction_id, mode);
1348        }
1349    }
1350
1351    fn transaction_undone(
1352        &mut self,
1353        transaction_id: &TransactionId,
1354        window: &mut Window,
1355        cx: &mut Context<Self>,
1356    ) {
1357        match self.mode {
1358            Mode::VisualLine | Mode::VisualBlock | Mode::Visual => {
1359                self.update_editor(window, cx, |vim, editor, window, cx| {
1360                    let original_mode = vim.undo_modes.get(transaction_id);
1361                    editor.change_selections(None, window, cx, |s| match original_mode {
1362                        Some(Mode::VisualLine) => {
1363                            s.move_with(|map, selection| {
1364                                selection.collapse_to(
1365                                    map.prev_line_boundary(selection.start.to_point(map)).1,
1366                                    SelectionGoal::None,
1367                                )
1368                            });
1369                        }
1370                        Some(Mode::VisualBlock) => {
1371                            let mut first = s.first_anchor();
1372                            first.collapse_to(first.start, first.goal);
1373                            s.select_anchors(vec![first]);
1374                        }
1375                        _ => {
1376                            s.move_with(|map, selection| {
1377                                selection.collapse_to(
1378                                    map.clip_at_line_end(selection.start),
1379                                    selection.goal,
1380                                );
1381                            });
1382                        }
1383                    });
1384                });
1385                self.switch_mode(Mode::Normal, true, window, cx)
1386            }
1387            Mode::Normal => {
1388                self.update_editor(window, cx, |_, editor, window, cx| {
1389                    editor.change_selections(None, window, cx, |s| {
1390                        s.move_with(|map, selection| {
1391                            selection
1392                                .collapse_to(map.clip_at_line_end(selection.end), selection.goal)
1393                        })
1394                    })
1395                });
1396            }
1397            Mode::Insert | Mode::Replace | Mode::HelixNormal => {}
1398        }
1399    }
1400
1401    fn local_selections_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1402        let Some(editor) = self.editor() else { return };
1403
1404        if editor.read(cx).leader_peer_id().is_some() {
1405            return;
1406        }
1407
1408        let newest = editor.read(cx).selections.newest_anchor().clone();
1409        let is_multicursor = editor.read(cx).selections.count() > 1;
1410        if self.mode == Mode::Insert && self.current_tx.is_some() {
1411            if self.current_anchor.is_none() {
1412                self.current_anchor = Some(newest);
1413            } else if self.current_anchor.as_ref().unwrap() != &newest {
1414                if let Some(tx_id) = self.current_tx.take() {
1415                    self.update_editor(window, cx, |_, editor, _, cx| {
1416                        editor.group_until_transaction(tx_id, cx)
1417                    });
1418                }
1419            }
1420        } else if self.mode == Mode::Normal && newest.start != newest.end {
1421            if matches!(newest.goal, SelectionGoal::HorizontalRange { .. }) {
1422                self.switch_mode(Mode::VisualBlock, false, window, cx);
1423            } else {
1424                self.switch_mode(Mode::Visual, false, window, cx)
1425            }
1426        } else if newest.start == newest.end
1427            && !is_multicursor
1428            && [Mode::Visual, Mode::VisualLine, Mode::VisualBlock].contains(&self.mode)
1429        {
1430            self.switch_mode(Mode::Normal, true, window, cx);
1431        }
1432    }
1433
1434    fn input_ignored(&mut self, text: Arc<str>, window: &mut Window, cx: &mut Context<Self>) {
1435        if text.is_empty() {
1436            return;
1437        }
1438
1439        match self.active_operator() {
1440            Some(Operator::FindForward { before }) => {
1441                let find = Motion::FindForward {
1442                    before,
1443                    char: text.chars().next().unwrap(),
1444                    mode: if VimSettings::get_global(cx).use_multiline_find {
1445                        FindRange::MultiLine
1446                    } else {
1447                        FindRange::SingleLine
1448                    },
1449                    smartcase: VimSettings::get_global(cx).use_smartcase_find,
1450                };
1451                Vim::globals(cx).last_find = Some(find.clone());
1452                self.motion(find, window, cx)
1453            }
1454            Some(Operator::FindBackward { after }) => {
1455                let find = Motion::FindBackward {
1456                    after,
1457                    char: text.chars().next().unwrap(),
1458                    mode: if VimSettings::get_global(cx).use_multiline_find {
1459                        FindRange::MultiLine
1460                    } else {
1461                        FindRange::SingleLine
1462                    },
1463                    smartcase: VimSettings::get_global(cx).use_smartcase_find,
1464                };
1465                Vim::globals(cx).last_find = Some(find.clone());
1466                self.motion(find, window, cx)
1467            }
1468            Some(Operator::Sneak { first_char }) => {
1469                if let Some(first_char) = first_char {
1470                    if let Some(second_char) = text.chars().next() {
1471                        let sneak = Motion::Sneak {
1472                            first_char,
1473                            second_char,
1474                            smartcase: VimSettings::get_global(cx).use_smartcase_find,
1475                        };
1476                        Vim::globals(cx).last_find = Some((&sneak).clone());
1477                        self.motion(sneak, window, cx)
1478                    }
1479                } else {
1480                    let first_char = text.chars().next();
1481                    self.pop_operator(window, cx);
1482                    self.push_operator(Operator::Sneak { first_char }, window, cx);
1483                }
1484            }
1485            Some(Operator::SneakBackward { first_char }) => {
1486                if let Some(first_char) = first_char {
1487                    if let Some(second_char) = text.chars().next() {
1488                        let sneak = Motion::SneakBackward {
1489                            first_char,
1490                            second_char,
1491                            smartcase: VimSettings::get_global(cx).use_smartcase_find,
1492                        };
1493                        Vim::globals(cx).last_find = Some((&sneak).clone());
1494                        self.motion(sneak, window, cx)
1495                    }
1496                } else {
1497                    let first_char = text.chars().next();
1498                    self.pop_operator(window, cx);
1499                    self.push_operator(Operator::SneakBackward { first_char }, window, cx);
1500                }
1501            }
1502            Some(Operator::Replace) => match self.mode {
1503                Mode::Normal => self.normal_replace(text, window, cx),
1504                Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
1505                    self.visual_replace(text, window, cx)
1506                }
1507                _ => self.clear_operator(window, cx),
1508            },
1509            Some(Operator::Digraph { first_char }) => {
1510                if let Some(first_char) = first_char {
1511                    if let Some(second_char) = text.chars().next() {
1512                        self.insert_digraph(first_char, second_char, window, cx);
1513                    }
1514                } else {
1515                    let first_char = text.chars().next();
1516                    self.pop_operator(window, cx);
1517                    self.push_operator(Operator::Digraph { first_char }, window, cx);
1518                }
1519            }
1520            Some(Operator::Literal { prefix }) => {
1521                self.handle_literal_input(prefix.unwrap_or_default(), &text, window, cx)
1522            }
1523            Some(Operator::AddSurrounds { target }) => match self.mode {
1524                Mode::Normal => {
1525                    if let Some(target) = target {
1526                        self.add_surrounds(text, target, window, cx);
1527                        self.clear_operator(window, cx);
1528                    }
1529                }
1530                Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
1531                    self.add_surrounds(text, SurroundsType::Selection, window, cx);
1532                    self.clear_operator(window, cx);
1533                }
1534                _ => self.clear_operator(window, cx),
1535            },
1536            Some(Operator::ChangeSurrounds { target }) => match self.mode {
1537                Mode::Normal => {
1538                    if let Some(target) = target {
1539                        self.change_surrounds(text, target, window, cx);
1540                        self.clear_operator(window, cx);
1541                    }
1542                }
1543                _ => self.clear_operator(window, cx),
1544            },
1545            Some(Operator::DeleteSurrounds) => match self.mode {
1546                Mode::Normal => {
1547                    self.delete_surrounds(text, window, cx);
1548                    self.clear_operator(window, cx);
1549                }
1550                _ => self.clear_operator(window, cx),
1551            },
1552            Some(Operator::Mark) => self.create_mark(text, false, window, cx),
1553            Some(Operator::RecordRegister) => {
1554                self.record_register(text.chars().next().unwrap(), window, cx)
1555            }
1556            Some(Operator::ReplayRegister) => {
1557                self.replay_register(text.chars().next().unwrap(), window, cx)
1558            }
1559            Some(Operator::Register) => match self.mode {
1560                Mode::Insert => {
1561                    self.update_editor(window, cx, |_, editor, window, cx| {
1562                        if let Some(register) = Vim::update_globals(cx, |globals, cx| {
1563                            globals.read_register(text.chars().next(), Some(editor), cx)
1564                        }) {
1565                            editor.do_paste(
1566                                &register.text.to_string(),
1567                                register.clipboard_selections.clone(),
1568                                false,
1569                                window,
1570                                cx,
1571                            )
1572                        }
1573                    });
1574                    self.clear_operator(window, cx);
1575                }
1576                _ => {
1577                    self.select_register(text, window, cx);
1578                }
1579            },
1580            Some(Operator::Jump { line }) => self.jump(text, line, window, cx),
1581            _ => {
1582                if self.mode == Mode::Replace {
1583                    self.multi_replace(text, window, cx)
1584                }
1585
1586                if self.mode == Mode::Normal {
1587                    self.update_editor(window, cx, |_, editor, window, cx| {
1588                        editor.accept_edit_prediction(
1589                            &editor::actions::AcceptEditPrediction {},
1590                            window,
1591                            cx,
1592                        );
1593                    });
1594                }
1595            }
1596        }
1597    }
1598
1599    fn sync_vim_settings(&mut self, window: &mut Window, cx: &mut Context<Self>) {
1600        self.update_editor(window, cx, |vim, editor, window, cx| {
1601            editor.set_cursor_shape(vim.cursor_shape(), cx);
1602            editor.set_clip_at_line_ends(vim.clip_at_line_ends(), cx);
1603            editor.set_collapse_matches(true);
1604            editor.set_input_enabled(vim.editor_input_enabled());
1605            editor.set_autoindent(vim.should_autoindent());
1606            editor.selections.line_mode = matches!(vim.mode, Mode::VisualLine);
1607
1608            let hide_inline_completions = match vim.mode {
1609                Mode::Insert | Mode::Replace => false,
1610                _ => true,
1611            };
1612            editor.set_inline_completions_hidden_for_vim_mode(hide_inline_completions, window, cx);
1613        });
1614        cx.notify()
1615    }
1616}
1617
1618/// Controls when to use system clipboard.
1619#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
1620#[serde(rename_all = "snake_case")]
1621pub enum UseSystemClipboard {
1622    /// Don't use system clipboard.
1623    Never,
1624    /// Use system clipboard.
1625    Always,
1626    /// Use system clipboard for yank operations.
1627    OnYank,
1628}
1629
1630#[derive(Deserialize)]
1631struct VimSettings {
1632    pub toggle_relative_line_numbers: bool,
1633    pub use_system_clipboard: UseSystemClipboard,
1634    pub use_multiline_find: bool,
1635    pub use_smartcase_find: bool,
1636    pub custom_digraphs: HashMap<String, Arc<str>>,
1637    pub highlight_on_yank_duration: u64,
1638}
1639
1640#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
1641struct VimSettingsContent {
1642    pub toggle_relative_line_numbers: Option<bool>,
1643    pub use_system_clipboard: Option<UseSystemClipboard>,
1644    pub use_multiline_find: Option<bool>,
1645    pub use_smartcase_find: Option<bool>,
1646    pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
1647    pub highlight_on_yank_duration: Option<u64>,
1648}
1649
1650impl Settings for VimSettings {
1651    const KEY: Option<&'static str> = Some("vim");
1652
1653    type FileContent = VimSettingsContent;
1654
1655    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
1656        sources.json_merge()
1657    }
1658}