Skip to main content

escriba_core/
mode.rs

1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4/// Editor modes — vim-inspired with a small ceiling.
5///
6/// More modes (operator-pending, replace, insert-visual) are phase-2 add-ons
7/// layered through pending state, not new enum variants.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
9pub enum Mode {
10    #[default]
11    Normal,
12    Insert,
13    Visual,
14    VisualLine,
15    Command,
16}
17
18impl Mode {
19    #[must_use]
20    pub const fn as_str(self) -> &'static str {
21        match self {
22            Self::Normal => "NORMAL",
23            Self::Insert => "INSERT",
24            Self::Visual => "VISUAL",
25            Self::VisualLine => "V-LINE",
26            Self::Command => "COMMAND",
27        }
28    }
29
30    #[must_use]
31    pub const fn is_insertish(self) -> bool {
32        matches!(self, Self::Insert | Self::Command)
33    }
34
35    #[must_use]
36    pub const fn is_visualish(self) -> bool {
37        matches!(self, Self::Visual | Self::VisualLine)
38    }
39}
40
41/// A one-shot transition request — emitted by the keymap, consumed by the
42/// editor loop.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
44pub struct ModeTransition {
45    pub from: Mode,
46    pub to: Mode,
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn default_is_normal() {
55        assert_eq!(Mode::default(), Mode::Normal);
56    }
57
58    #[test]
59    fn classifiers() {
60        assert!(Mode::Insert.is_insertish());
61        assert!(Mode::Command.is_insertish());
62        assert!(!Mode::Normal.is_insertish());
63        assert!(Mode::Visual.is_visualish());
64        assert!(Mode::VisualLine.is_visualish());
65    }
66
67    #[test]
68    fn display_labels() {
69        assert_eq!(Mode::Normal.as_str(), "NORMAL");
70        assert_eq!(Mode::Insert.as_str(), "INSERT");
71    }
72}