1use std::fmt;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
6pub enum Mode {
7 #[default]
8 Normal,
9 Insert,
10 Visual,
11 VisualLine,
12 Command,
14}
15
16impl Mode {
17 pub fn label(self) -> &'static str {
19 match self {
20 Mode::Normal => "NORMAL",
21 Mode::Insert => "INSERT",
22 Mode::Visual => "VISUAL",
23 Mode::VisualLine => "V-LINE",
24 Mode::Command => "COMMAND",
25 }
26 }
27
28 pub fn takes_counts(self) -> bool {
30 matches!(self, Mode::Normal | Mode::Visual | Mode::VisualLine)
31 }
32
33 pub fn is_text_entry(self) -> bool {
35 matches!(self, Mode::Insert | Mode::Command)
36 }
37
38 pub fn is_visual(self) -> bool {
39 matches!(self, Mode::Visual | Mode::VisualLine)
40 }
41}
42
43impl fmt::Display for Mode {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 f.write_str(self.label())
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn only_normal_and_visual_take_counts() {
55 assert!(Mode::Normal.takes_counts());
56 assert!(Mode::Visual.takes_counts());
57 assert!(Mode::VisualLine.takes_counts());
58 assert!(!Mode::Insert.takes_counts());
59 assert!(!Mode::Command.takes_counts());
60 }
61
62 #[test]
63 fn text_entry_modes_are_not_count_modes() {
64 for m in [
65 Mode::Normal,
66 Mode::Insert,
67 Mode::Visual,
68 Mode::VisualLine,
69 Mode::Command,
70 ] {
71 assert!(
72 !(m.takes_counts() && m.is_text_entry()),
73 "{m} cannot be both"
74 );
75 }
76 }
77}