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,
10 VisualLine,
11}
12
13impl Default for Mode {
14 fn default() -> Self {
15 Self::Normal
16 }
17}
18
19#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
20pub enum Namespace {
21 G,
22}
23
24#[derive(Copy, Clone, Debug, PartialEq, Eq, Deserialize)]
25pub enum Operator {
26 Namespace(Namespace),
27 Change,
28 Delete,
29 Yank,
30}
31
32#[derive(Default)]
33pub struct VimState {
34 pub mode: Mode,
35 pub operator_stack: Vec<Operator>,
36}
37
38impl VimState {
39 pub fn cursor_shape(&self) -> CursorShape {
40 match self.mode {
41 Mode::Normal | Mode::Visual | Mode::VisualLine => CursorShape::Block,
42 Mode::Insert => CursorShape::Bar,
43 }
44 }
45
46 pub fn vim_controlled(&self) -> bool {
47 !matches!(self.mode, Mode::Insert)
48 }
49
50 pub fn empty_selections_only(&self) -> bool {
51 self.mode != Mode::Visual && self.mode != Mode::VisualLine
52 }
53
54 pub fn keymap_context_layer(&self) -> Context {
55 let mut context = Context::default();
56 context.map.insert(
57 "vim_mode".to_string(),
58 match self.mode {
59 Mode::Normal => "normal",
60 Mode::Visual => "visual",
61 Mode::VisualLine => "visual_line",
62 Mode::Insert => "insert",
63 }
64 .to_string(),
65 );
66
67 if self.vim_controlled() {
68 context.set.insert("VimControl".to_string());
69 }
70
71 if let Some(operator) = &self.operator_stack.last() {
72 operator.set_context(&mut context);
73 }
74 context
75 }
76}
77
78impl Operator {
79 pub fn set_context(&self, context: &mut Context) {
80 let operator_context = match self {
81 Operator::Namespace(Namespace::G) => "g",
82 Operator::Change => "c",
83 Operator::Delete => "d",
84 Operator::Yank => "y",
85 }
86 .to_owned();
87
88 context
89 .map
90 .insert("vim_operator".to_string(), operator_context.to_string());
91 }
92}