vim_mode_setting.rs

  1//! Contains the [`VimModeSetting`] and [`HelixModeSetting`] used to enable/disable Vim and Helix modes.
  2//!
  3//! This is in its own crate as we want other crates to be able to enable or
  4//! disable Vim/Helix modes without having to depend on the `vim` crate in its
  5//! entirety.
  6
  7use anyhow::Result;
  8use gpui::App;
  9use schemars::JsonSchema;
 10use serde::de::Error;
 11use serde::{Deserialize, Deserializer, Serialize, Serializer};
 12use settings::{Settings, SettingsSources};
 13use std::fmt::Display;
 14
 15/// Initializes the `vim_mode_setting` crate.
 16pub fn init(cx: &mut App) {
 17    EditorModeSetting::register(cx);
 18}
 19
 20/// Whether or not to enable Vim mode.
 21///
 22/// Default: `EditMode::Default`
 23pub struct EditorModeSetting(pub EditorMode);
 24
 25#[derive(Copy, Clone, Debug, PartialEq, Eq, JsonSchema, Default)]
 26pub enum EditorMode {
 27    #[default]
 28    Default,
 29    Vim(ModalMode),
 30    Helix(ModalMode),
 31}
 32
 33impl<'de> Deserialize<'de> for EditorMode {
 34    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
 35    where
 36        D: Deserializer<'de>,
 37    {
 38        let s = String::deserialize(deserializer)?;
 39        match s.as_str() {
 40            "default" => Ok(EditorMode::Default),
 41            "vim" => Ok(EditorMode::Vim(ModalMode::Normal)),
 42            "vim_normal" => Ok(EditorMode::Vim(ModalMode::Normal)),
 43            "vim_insert" => Ok(EditorMode::Vim(ModalMode::Insert)),
 44            "vim_replace" => Ok(EditorMode::Vim(ModalMode::Replace)),
 45            "vim_visual" => Ok(EditorMode::Vim(ModalMode::Visual)),
 46            "vim_visual_line" => Ok(EditorMode::Vim(ModalMode::VisualLine)),
 47            "vim_visual_block" => Ok(EditorMode::Vim(ModalMode::VisualBlock)),
 48            "helix_experimental" => Ok(EditorMode::Helix(ModalMode::HelixNormal)),
 49            _ => Err(D::Error::custom(format!("Unknown editor mode: {}", s))),
 50        }
 51    }
 52}
 53
 54impl Serialize for EditorMode {
 55    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 56    where
 57        S: Serializer,
 58    {
 59        let s = match self {
 60            EditorMode::Default => "default",
 61            EditorMode::Vim(ModalMode::Normal) => "vim",
 62            EditorMode::Vim(ModalMode::Insert) => "vim_insert",
 63            EditorMode::Vim(ModalMode::Replace) => "vim_replace",
 64            EditorMode::Vim(ModalMode::Visual) => "vim_visual",
 65            EditorMode::Vim(ModalMode::VisualLine) => "vim_visual_line",
 66            EditorMode::Vim(ModalMode::VisualBlock) => "vim_visual_block",
 67            EditorMode::Helix(ModalMode::HelixNormal) => "helix_experimental",
 68            _ => return Err(serde::ser::Error::custom("unsupported editor mode variant")),
 69        };
 70        serializer.serialize_str(s)
 71    }
 72}
 73
 74#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
 75pub enum ModalMode {
 76    Normal,
 77    Insert,
 78    Replace,
 79    Visual,
 80    VisualLine,
 81    VisualBlock,
 82    HelixNormal,
 83}
 84
 85impl Display for ModalMode {
 86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 87        match self {
 88            ModalMode::Normal => write!(f, "NORMAL"),
 89            ModalMode::Insert => write!(f, "INSERT"),
 90            ModalMode::Replace => write!(f, "REPLACE"),
 91            ModalMode::Visual => write!(f, "VISUAL"),
 92            ModalMode::VisualLine => write!(f, "VISUAL LINE"),
 93            ModalMode::VisualBlock => write!(f, "VISUAL BLOCK"),
 94            ModalMode::HelixNormal => write!(f, "HELIX NORMAL"),
 95        }
 96    }
 97}
 98
 99impl ModalMode {
100    pub fn is_visual(&self) -> bool {
101        match self {
102            Self::Visual | Self::VisualLine | Self::VisualBlock => true,
103            Self::Normal | Self::Insert | Self::Replace | Self::HelixNormal => false,
104        }
105    }
106}
107
108impl Default for ModalMode {
109    fn default() -> Self {
110        Self::Normal
111    }
112}
113
114impl Settings for EditorModeSetting {
115    const KEY: Option<&'static str> = Some("editor_mode");
116
117    type FileContent = Option<EditorMode>;
118
119    fn load(sources: SettingsSources<Self::FileContent>, _: &mut App) -> Result<Self> {
120        Ok(Self(
121            sources
122                .user
123                .or(sources.server)
124                .copied()
125                .flatten()
126                .unwrap_or(sources.default.ok_or_else(Self::missing_default)?),
127        ))
128    }
129
130    fn import_from_vscode(_vscode: &settings::VsCodeSettings, _current: &mut Self::FileContent) {
131        // TODO: could possibly check if any of the `vim.<foo>` keys are set?
132    }
133}
134
135impl EditorMode {
136    pub fn is_modal(&self) -> bool {
137        matches!(self, EditorMode::Vim(_) | EditorMode::Helix(_))
138    }
139
140    pub fn vim() -> EditorMode {
141        EditorMode::Vim(ModalMode::default())
142    }
143}