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 => {
41 if self.operator_stack.is_empty() {
42 CursorShape::Block
43 } else {
44 CursorShape::Underscore
45 }
46 }
47 Mode::Visual { .. } => CursorShape::Block,
48 Mode::Insert => CursorShape::Bar,
49 }
50 }
51
52 pub fn vim_controlled(&self) -> bool {
53 !matches!(self.mode, Mode::Insert)
54 }
55
56 pub fn clip_at_line_end(&self) -> bool {
57 !matches!(self.mode, Mode::Insert | Mode::Visual { .. })
58 }
59
60 pub fn empty_selections_only(&self) -> bool {
61 !matches!(self.mode, Mode::Visual { .. })
62 }
63
64 pub fn keymap_context_layer(&self) -> Context {
65 let mut context = Context::default();
66 context.map.insert(
67 "vim_mode".to_string(),
68 match self.mode {
69 Mode::Normal => "normal",
70 Mode::Visual { .. } => "visual",
71 Mode::Insert => "insert",
72 }
73 .to_string(),
74 );
75
76 if self.vim_controlled() {
77 context.set.insert("VimControl".to_string());
78 }
79
80 Operator::set_context(self.operator_stack.last(), &mut context);
81
82 context
83 }
84}
85
86impl Operator {
87 pub fn set_context(operator: Option<&Operator>, context: &mut Context) {
88 let operator_context = match operator {
89 Some(Operator::Namespace(Namespace::G)) => "g",
90 Some(Operator::Change) => "c",
91 Some(Operator::Delete) => "d",
92 Some(Operator::Yank) => "y",
93 None => "none",
94 }
95 .to_owned();
96
97 context
98 .map
99 .insert("vim_operator".to_string(), operator_context);
100 }
101}