Detailed changes
@@ -2284,11 +2284,15 @@
"use_smartcase_find": false,
"highlight_on_yank_duration": 200,
"custom_digraphs": {},
- // Cursor shape for the each mode.
- // Specify the mode as the key and the shape as the value.
- // The mode can be one of the following: "normal", "replace", "insert", "visual".
+ // Cursor shape for each mode.
// The shape can be one of the following: "block", "bar", "underline", "hollow".
- "cursor_shape": {},
+ "cursor_shape": {
+ "normal": "block",
+ "replace": "underline",
+ "visual": "block",
+ // Set to "inherit" to use the editor's cursor_shape.
+ "insert": "inherit",
+ },
},
// Which-key popup settings
"which_key": {
@@ -687,7 +687,19 @@ pub struct VimSettingsContent {
pub cursor_shape: Option<CursorShapeSettings>,
}
-#[derive(Copy, Clone, Default, Serialize, Deserialize, JsonSchema, MergeFrom, PartialEq, Debug)]
+#[derive(
+ Copy,
+ Clone,
+ Default,
+ Serialize,
+ Deserialize,
+ JsonSchema,
+ MergeFrom,
+ PartialEq,
+ Debug,
+ strum::VariantArray,
+ strum::VariantNames,
+)]
#[serde(rename_all = "snake_case")]
pub enum ModeContent {
#[default]
@@ -696,7 +708,19 @@ pub enum ModeContent {
}
/// Controls when to use system clipboard.
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[derive(
+ Copy,
+ Clone,
+ Debug,
+ Serialize,
+ Deserialize,
+ PartialEq,
+ Eq,
+ JsonSchema,
+ MergeFrom,
+ strum::VariantArray,
+ strum::VariantNames,
+)]
#[serde(rename_all = "snake_case")]
pub enum UseSystemClipboard {
/// Don't use system clipboard.
@@ -707,9 +731,39 @@ pub enum UseSystemClipboard {
OnYank,
}
+/// Cursor shape configuration for insert mode in Vim.
+#[derive(
+ Copy,
+ Clone,
+ Debug,
+ Serialize,
+ Deserialize,
+ PartialEq,
+ Eq,
+ JsonSchema,
+ MergeFrom,
+ strum::VariantArray,
+ strum::VariantNames,
+)]
+#[serde(rename_all = "snake_case")]
+pub enum VimInsertModeCursorShape {
+ /// Inherit cursor shape from the editor's base cursor_shape setting.
+ Inherit,
+ /// Vertical bar cursor.
+ Bar,
+ /// Block cursor that surrounds the character.
+ Block,
+ /// Underline cursor.
+ Underline,
+ /// Hollow box cursor.
+ Hollow,
+}
+
/// The settings for cursor shape.
#[with_fallible_options]
-#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom)]
+#[derive(
+ Copy, Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq, JsonSchema, MergeFrom,
+)]
pub struct CursorShapeSettings {
/// Cursor shape for the normal mode.
///
@@ -726,7 +780,7 @@ pub struct CursorShapeSettings {
/// Cursor shape for the insert mode.
///
/// The default value follows the primary cursor_shape.
- pub insert: Option<CursorShape>,
+ pub insert: Option<VimInsertModeCursorShape>,
}
/// Settings specific to journaling
@@ -2414,6 +2414,227 @@ fn editor_page() -> SettingsPage {
]
}
+ fn vim_settings_section() -> [SettingsPageItem; 11] {
+ [
+ SettingsPageItem::SectionHeader("Vim"),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Default Mode",
+ description: "The default mode when Vim starts.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.default_mode"),
+ pick: |settings_content| settings_content.vim.as_ref()?.default_mode.as_ref(),
+ write: |settings_content, value| {
+ settings_content.vim.get_or_insert_default().default_mode = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Toggle Relative Line Numbers",
+ description: "Toggle relative line numbers in Vim mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.toggle_relative_line_numbers"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .toggle_relative_line_numbers
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .toggle_relative_line_numbers = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use System Clipboard",
+ description: "Controls when to use system clipboard in Vim mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.use_system_clipboard"),
+ pick: |settings_content| {
+ settings_content.vim.as_ref()?.use_system_clipboard.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .use_system_clipboard = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Use Smartcase Find",
+ description: "Enable smartcase searching in Vim mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.use_smartcase_find"),
+ pick: |settings_content| {
+ settings_content.vim.as_ref()?.use_smartcase_find.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .use_smartcase_find = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Highlight on Yank Duration",
+ description: "Duration in milliseconds to highlight yanked text in Vim mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.highlight_on_yank_duration"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .highlight_on_yank_duration
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .highlight_on_yank_duration = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Shape - Normal Mode",
+ description: "Cursor shape for normal mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.cursor_shape.normal"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .cursor_shape
+ .as_ref()?
+ .normal
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .cursor_shape
+ .get_or_insert_default()
+ .normal = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Shape - Insert Mode",
+ description: "Cursor shape for insert mode. Inherit uses the editor's cursor shape.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.cursor_shape.insert"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .cursor_shape
+ .as_ref()?
+ .insert
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .cursor_shape
+ .get_or_insert_default()
+ .insert = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Shape - Replace Mode",
+ description: "Cursor shape for replace mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.cursor_shape.replace"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .cursor_shape
+ .as_ref()?
+ .replace
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .cursor_shape
+ .get_or_insert_default()
+ .replace = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Cursor Shape - Visual Mode",
+ description: "Cursor shape for visual mode.",
+ field: Box::new(SettingField {
+ json_path: Some("vim.cursor_shape.visual"),
+ pick: |settings_content| {
+ settings_content
+ .vim
+ .as_ref()?
+ .cursor_shape
+ .as_ref()?
+ .visual
+ .as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content
+ .vim
+ .get_or_insert_default()
+ .cursor_shape
+ .get_or_insert_default()
+ .visual = value;
+ },
+ }),
+ metadata: None,
+ files: USER,
+ }),
+ SettingsPageItem::SettingItem(SettingItem {
+ title: "Custom Digraphs",
+ description: "Custom digraph mappings for Vim mode.",
+ field: Box::new(
+ SettingField {
+ json_path: Some("vim.custom_digraphs"),
+ pick: |settings_content| {
+ settings_content.vim.as_ref()?.custom_digraphs.as_ref()
+ },
+ write: |settings_content, value| {
+ settings_content.vim.get_or_insert_default().custom_digraphs = value;
+ },
+ }
+ .unimplemented(),
+ ),
+ metadata: None,
+ files: USER,
+ }),
+ ]
+ }
+
let items = concat_sections!(
auto_save_section(),
which_key_section(),
@@ -2426,6 +2647,7 @@ fn editor_page() -> SettingsPage {
scrollbar_section(),
minimap_section(),
toolbar_section(),
+ vim_settings_section(),
language_settings_data(),
);
@@ -493,6 +493,9 @@ fn init_renderers(cx: &mut App) {
.add_basic_renderer::<settings::DisplayIn>(render_dropdown)
.add_basic_renderer::<settings::MinimapThumb>(render_dropdown)
.add_basic_renderer::<settings::MinimapThumbBorder>(render_dropdown)
+ .add_basic_renderer::<settings::ModeContent>(render_dropdown)
+ .add_basic_renderer::<settings::UseSystemClipboard>(render_dropdown)
+ .add_basic_renderer::<settings::VimInsertModeCursorShape>(render_dropdown)
.add_basic_renderer::<settings::SteppingGranularity>(render_dropdown)
.add_basic_renderer::<settings::NotifyWhenAgentWaiting>(render_dropdown)
.add_basic_renderer::<settings::NotifyWhenAgentWaiting>(render_dropdown)
@@ -1322,18 +1322,21 @@ impl Vim {
_ => CursorShape::Underline,
}
} else {
- cursor_shape.normal.unwrap_or(CursorShape::Block)
+ cursor_shape.normal
}
}
- Mode::HelixNormal => cursor_shape.normal.unwrap_or(CursorShape::Block),
- Mode::Replace => cursor_shape.replace.unwrap_or(CursorShape::Underline),
+ Mode::HelixNormal => cursor_shape.normal,
+ Mode::Replace => cursor_shape.replace,
Mode::Visual | Mode::VisualLine | Mode::VisualBlock | Mode::HelixSelect => {
- cursor_shape.visual.unwrap_or(CursorShape::Block)
+ cursor_shape.visual
}
- Mode::Insert => cursor_shape.insert.unwrap_or({
- let editor_settings = EditorSettings::get_global(cx);
- editor_settings.cursor_shape.unwrap_or_default()
- }),
+ Mode::Insert => match cursor_shape.insert {
+ InsertModeCursorShape::Explicit(shape) => shape,
+ InsertModeCursorShape::Inherit => {
+ let editor_settings = EditorSettings::get_global(cx);
+ editor_settings.cursor_shape.unwrap_or_default()
+ }
+ },
}
}
@@ -2047,34 +2050,65 @@ struct VimSettings {
pub cursor_shape: CursorShapeSettings,
}
+/// Cursor shape configuration for insert mode.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum InsertModeCursorShape {
+ /// Inherit cursor shape from the editor's base cursor_shape setting.
+ /// This allows users to set their preferred editor cursor and have
+ /// it automatically apply to vim insert mode.
+ Inherit,
+ /// Use an explicit cursor shape for insert mode.
+ Explicit(CursorShape),
+}
+
/// The settings for cursor shape.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CursorShapeSettings {
/// Cursor shape for the normal mode.
///
/// Default: block
- pub normal: Option<CursorShape>,
+ pub normal: CursorShape,
/// Cursor shape for the replace mode.
///
/// Default: underline
- pub replace: Option<CursorShape>,
+ pub replace: CursorShape,
/// Cursor shape for the visual mode.
///
/// Default: block
- pub visual: Option<CursorShape>,
+ pub visual: CursorShape,
/// Cursor shape for the insert mode.
///
- /// The default value follows the primary cursor_shape.
- pub insert: Option<CursorShape>,
+ /// Default: Inherit (follows editor.cursor_shape)
+ pub insert: InsertModeCursorShape,
+}
+
+impl From<settings::VimInsertModeCursorShape> for InsertModeCursorShape {
+ fn from(shape: settings::VimInsertModeCursorShape) -> Self {
+ match shape {
+ settings::VimInsertModeCursorShape::Inherit => InsertModeCursorShape::Inherit,
+ settings::VimInsertModeCursorShape::Bar => {
+ InsertModeCursorShape::Explicit(CursorShape::Bar)
+ }
+ settings::VimInsertModeCursorShape::Block => {
+ InsertModeCursorShape::Explicit(CursorShape::Block)
+ }
+ settings::VimInsertModeCursorShape::Underline => {
+ InsertModeCursorShape::Explicit(CursorShape::Underline)
+ }
+ settings::VimInsertModeCursorShape::Hollow => {
+ InsertModeCursorShape::Explicit(CursorShape::Hollow)
+ }
+ }
+ }
}
impl From<settings::CursorShapeSettings> for CursorShapeSettings {
fn from(settings: settings::CursorShapeSettings) -> Self {
Self {
- normal: settings.normal.map(Into::into),
- replace: settings.replace.map(Into::into),
- visual: settings.visual.map(Into::into),
- insert: settings.insert.map(Into::into),
+ normal: settings.normal.unwrap().into(),
+ replace: settings.replace.unwrap().into(),
+ visual: settings.visual.unwrap().into(),
+ insert: settings.insert.unwrap().into(),
}
}
}