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