diff --git a/assets/settings/default.json b/assets/settings/default.json index d75e213b52..5aa605644a 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -1296,6 +1296,7 @@ }, // Vim settings "vim": { + "default_mode": "normal", "toggle_relative_line_numbers": false, "use_system_clipboard": "always", "use_multiline_find": false, diff --git a/crates/vim/src/vim.rs b/crates/vim/src/vim.rs index e3cbcd9c40..d437d980fd 100644 --- a/crates/vim/src/vim.rs +++ b/crates/vim/src/vim.rs @@ -354,7 +354,7 @@ impl Vim { let editor = cx.entity().clone(); cx.new(|cx| Vim { - mode: Mode::Normal, + mode: VimSettings::get_global(cx).default_mode, last_mode: Mode::Normal, temp_mode: false, exit_temporary_mode: false, @@ -1643,6 +1643,7 @@ pub enum UseSystemClipboard { #[derive(Deserialize)] struct VimSettings { + pub default_mode: Mode, pub toggle_relative_line_numbers: bool, pub use_system_clipboard: UseSystemClipboard, pub use_multiline_find: bool, @@ -1653,6 +1654,7 @@ struct VimSettings { #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] struct VimSettingsContent { + pub default_mode: Option, pub toggle_relative_line_numbers: Option, pub use_system_clipboard: Option, pub use_multiline_find: Option, @@ -1661,12 +1663,62 @@ struct VimSettingsContent { pub highlight_on_yank_duration: Option, } +#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ModeContent { + #[default] + Normal, + Insert, + Replace, + Visual, + VisualLine, + VisualBlock, + HelixNormal, +} + +impl From for Mode { + fn from(mode: ModeContent) -> Self { + match mode { + ModeContent::Normal => Self::Normal, + ModeContent::Insert => Self::Insert, + ModeContent::Replace => Self::Replace, + ModeContent::Visual => Self::Visual, + ModeContent::VisualLine => Self::VisualLine, + ModeContent::VisualBlock => Self::VisualBlock, + ModeContent::HelixNormal => Self::HelixNormal, + } + } +} + impl Settings for VimSettings { const KEY: Option<&'static str> = Some("vim"); type FileContent = VimSettingsContent; fn load(sources: SettingsSources, _: &mut App) -> Result { - sources.json_merge() + let settings: VimSettingsContent = sources.json_merge()?; + + Ok(Self { + default_mode: settings + .default_mode + .ok_or_else(Self::missing_default)? + .into(), + toggle_relative_line_numbers: settings + .toggle_relative_line_numbers + .ok_or_else(Self::missing_default)?, + use_system_clipboard: settings + .use_system_clipboard + .ok_or_else(Self::missing_default)?, + use_multiline_find: settings + .use_multiline_find + .ok_or_else(Self::missing_default)?, + use_smartcase_find: settings + .use_smartcase_find + .ok_or_else(Self::missing_default)?, + custom_digraphs: settings.custom_digraphs.ok_or_else(Self::missing_default)?, + highlight_on_yank_duration: settings + .highlight_on_yank_duration + .ok_or_else(Self::missing_default)?, + }) } } diff --git a/docs/src/vim.md b/docs/src/vim.md index a84c8636fe..8df0edd4cc 100644 --- a/docs/src/vim.md +++ b/docs/src/vim.md @@ -451,6 +451,7 @@ You can change the following settings to modify vim mode's behavior: | Property | Description | Default Value | | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | +| default_mode | The default mode to start in. One of "normal", "insert", "replace", "visual", "visual_line", "visual_block", "helix_normal". | "normal" | | use_system_clipboard | Determines how system clipboard is used:
  • "always": use for all operations
  • "never": only use when explicitly specified
  • "on_yank": use for yank operations
| "always" | | use_multiline_find | If `true`, `f` and `t` motions extend across multiple lines. | false | | use_smartcase_find | If `true`, `f` and `t` motions are case-insensitive when the target letter is lowercase. | false |