1use editor::CursorShape;
2use gpui::keymap::Context;
3use serde::Deserialize;
4
5#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
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 Namespace(Namespace),
26 Change,
27 Delete,
28 Yank,
29}
30
31#[derive(Default)]
32pub struct VimState {
33 pub mode: Mode,
34 pub operator_stack: Vec<Operator>,
35}
36
37impl VimState {
38 pub fn cursor_shape(&self) -> CursorShape {
39 match self.mode {
40 Mode::Normal | Mode::Visual { .. } => CursorShape::Block,
41 Mode::Insert => CursorShape::Bar,
42 }
43 }
44
45 pub fn vim_controlled(&self) -> bool {
46 !matches!(self.mode, Mode::Insert)
47 }
48
49 pub fn clip_at_line_end(&self) -> bool {
50 match self.mode {
51 Mode::Insert | Mode::Visual { .. } => false,
52 _ => true,
53 }
54 }
55
56 pub fn empty_selections_only(&self) -> bool {
57 !matches!(self.mode, Mode::Visual { .. })
58 }
59
60 pub fn keymap_context_layer(&self) -> Context {
61 let mut context = Context::default();
62 context.map.insert(
63 "vim_mode".to_string(),
64 match self.mode {
65 Mode::Normal => "normal",
66 Mode::Visual { .. } => "visual",
67 Mode::Insert => "insert",
68 }
69 .to_string(),
70 );
71
72 if self.vim_controlled() {
73 context.set.insert("VimControl".to_string());
74 }
75
76 if let Some(operator) = &self.operator_stack.last() {
77 operator.set_context(&mut context);
78 }
79 context
80 }
81}
82
83impl Operator {
84 pub fn set_context(&self, context: &mut Context) {
85 let operator_context = match self {
86 Operator::Namespace(Namespace::G) => "g",
87 Operator::Change => "c",
88 Operator::Delete => "d",
89 Operator::Yank => "y",
90 }
91 .to_owned();
92
93 context
94 .map
95 .insert("vim_operator".to_string(), operator_context.to_string());
96 }
97}