vim: Add cursor shape settings for each vim mode (#28636)

Closes #4495

Release Notes:

- vim: add cursor shape settings for each vim mode

---

Add cursor shape settings for each vim mode to enable users to specify
them.

Example of `settings.json`:

```json
{
  "vim_mode": true,
  "vim": {
    "cursor_shape": {
      "normal": "hollow",
      "insert": "bar",
      "replace": "block",
      "visual": "underline"
    }
  }
}
```

After this change is applied,

- The cursor shape specified by the user for each mode is used.
- In insert mode, the `vim > cursor_shape > insert` setting takes
precedence over the primary `cursor_shape` setting.
- If `vim > cursor_shape > insert` is not set, the primary
`cursor_shape` will be used in insert mode.
- The cursor shape will remain unchanged before and after this update
when the user does not set the `vim > cursor_shape` setting.

Video:


[screen-record.webm](https://github.com/user-attachments/assets/b87461a1-6b3a-4a77-a607-a340f106def5)
This commit is contained in:
Gaku Kanematsu 2025-04-22 09:42:04 +09:00 committed by GitHub
parent 70c51b513b
commit c15382c4d8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 38 additions and 8 deletions

View file

@ -1023,6 +1023,7 @@ impl Vim {
}
pub fn cursor_shape(&self, cx: &mut App) -> CursorShape {
let cursor_shape = VimSettings::get_global(cx).cursor_shape;
match self.mode {
Mode::Normal => {
if let Some(operator) = self.operator_stack.last() {
@ -1040,18 +1041,18 @@ impl Vim {
_ => CursorShape::Underline,
}
} else {
// No operator active -> Block cursor
CursorShape::Block
cursor_shape.normal.unwrap_or(CursorShape::Block)
}
}
Mode::Replace => CursorShape::Underline,
Mode::HelixNormal | Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
CursorShape::Block
Mode::HelixNormal => cursor_shape.normal.unwrap_or(CursorShape::Block),
Mode::Replace => cursor_shape.replace.unwrap_or(CursorShape::Underline),
Mode::Visual | Mode::VisualLine | Mode::VisualBlock => {
cursor_shape.visual.unwrap_or(CursorShape::Block)
}
Mode::Insert => {
Mode::Insert => cursor_shape.insert.unwrap_or({
let editor_settings = EditorSettings::get_global(cx);
editor_settings.cursor_shape.unwrap_or_default()
}
}),
}
}
@ -1693,6 +1694,27 @@ pub enum UseSystemClipboard {
OnYank,
}
/// The settings for cursor shape.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
struct CursorShapeSettings {
/// Cursor shape for the normal mode.
///
/// Default: block
pub normal: Option<CursorShape>,
/// Cursor shape for the replace mode.
///
/// Default: underline
pub replace: Option<CursorShape>,
/// Cursor shape for the visual mode.
///
/// Default: block
pub visual: Option<CursorShape>,
/// Cursor shape for the insert mode.
///
/// The default value follows the primary cursor_shape.
pub insert: Option<CursorShape>,
}
#[derive(Deserialize)]
struct VimSettings {
pub default_mode: Mode,
@ -1702,6 +1724,7 @@ struct VimSettings {
pub use_smartcase_find: bool,
pub custom_digraphs: HashMap<String, Arc<str>>,
pub highlight_on_yank_duration: u64,
pub cursor_shape: CursorShapeSettings,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
@ -1713,6 +1736,7 @@ struct VimSettingsContent {
pub use_smartcase_find: Option<bool>,
pub custom_digraphs: Option<HashMap<String, Arc<str>>>,
pub highlight_on_yank_duration: Option<u64>,
pub cursor_shape: Option<CursorShapeSettings>,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
@ -1771,6 +1795,7 @@ impl Settings for VimSettings {
highlight_on_yank_duration: settings
.highlight_on_yank_duration
.ok_or_else(Self::missing_default)?,
cursor_shape: settings.cursor_shape.ok_or_else(Self::missing_default)?,
})
}
}