state.rs

  1use gpui::keymap::Context;
  2use language::CursorShape;
  3use serde::{Deserialize, Serialize};
  4
  5#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize, Serialize)]
  6pub enum Mode {
  7    Normal,
  8    Insert,
  9    Visual { line: bool },
 10}
 11
 12impl Default for Mode {
 13    fn default() -> Self {
 14        Self::Normal
 15    }
 16}
 17
 18#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
 19pub enum Namespace {
 20    G,
 21}
 22
 23#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
 24pub enum Operator {
 25    Number(usize),
 26    Namespace(Namespace),
 27    Change,
 28    Delete,
 29    Yank,
 30    Object { around: bool },
 31}
 32
 33#[derive(Default)]
 34pub struct VimState {
 35    pub mode: Mode,
 36    pub operator_stack: Vec<Operator>,
 37}
 38
 39impl VimState {
 40    pub fn cursor_shape(&self) -> CursorShape {
 41        match self.mode {
 42            Mode::Normal => {
 43                if self.operator_stack.is_empty() {
 44                    CursorShape::Block
 45                } else {
 46                    CursorShape::Underscore
 47                }
 48            }
 49            Mode::Visual { .. } => CursorShape::Block,
 50            Mode::Insert => CursorShape::Bar,
 51        }
 52    }
 53
 54    pub fn vim_controlled(&self) -> bool {
 55        !matches!(self.mode, Mode::Insert)
 56    }
 57
 58    pub fn clip_at_line_end(&self) -> bool {
 59        !matches!(self.mode, Mode::Insert | Mode::Visual { .. })
 60    }
 61
 62    pub fn empty_selections_only(&self) -> bool {
 63        !matches!(self.mode, Mode::Visual { .. })
 64    }
 65
 66    pub fn keymap_context_layer(&self) -> Context {
 67        let mut context = Context::default();
 68        context.map.insert(
 69            "vim_mode".to_string(),
 70            match self.mode {
 71                Mode::Normal => "normal",
 72                Mode::Visual { .. } => "visual",
 73                Mode::Insert => "insert",
 74            }
 75            .to_string(),
 76        );
 77
 78        if self.vim_controlled() {
 79            context.set.insert("VimControl".to_string());
 80        }
 81
 82        let active_operator = self.operator_stack.last();
 83        if matches!(active_operator, Some(Operator::Object { .. })) {
 84            context.set.insert("VimObject".to_string());
 85        }
 86
 87        Operator::set_context(active_operator, &mut context);
 88
 89        context
 90    }
 91}
 92
 93impl Operator {
 94    pub fn set_context(operator: Option<&Operator>, context: &mut Context) {
 95        let operator_context = match operator {
 96            Some(Operator::Number(_)) => "n",
 97            Some(Operator::Namespace(Namespace::G)) => "g",
 98            Some(Operator::Object { around: false }) => "i",
 99            Some(Operator::Object { around: true }) => "a",
100            Some(Operator::Change) => "c",
101            Some(Operator::Delete) => "d",
102            Some(Operator::Yank) => "y",
103
104            None => "none",
105        }
106        .to_owned();
107
108        context
109            .map
110            .insert("vim_operator".to_string(), operator_context);
111    }
112}