pepper/
mode.rs

1use crate::{
2    client::ClientHandle,
3    editor::{Editor, EditorContext, EditorFlow, KeysIterator},
4    plugin::PluginHandle,
5};
6
7mod command;
8mod insert;
9mod normal;
10pub(crate) mod picker;
11pub(crate) mod readline;
12
13pub(crate) trait ModeState {
14    fn on_enter(editor: &mut Editor);
15    fn on_exit(editor: &mut Editor);
16    fn on_keys(
17        ctx: &mut EditorContext,
18        client_handle: ClientHandle,
19        keys: &mut KeysIterator,
20    ) -> Option<EditorFlow>;
21}
22
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub enum ModeKind {
25    Normal,
26    Insert,
27    Command,
28    ReadLine,
29    Picker,
30    Plugin,
31}
32
33impl Default for ModeKind {
34    fn default() -> Self {
35        Self::Normal
36    }
37}
38
39#[derive(Default)]
40pub struct Mode {
41    kind: ModeKind,
42
43    pub normal_state: normal::State,
44    pub insert_state: insert::State,
45    pub command_state: command::State,
46    pub readline_state: readline::State,
47    pub picker_state: picker::State,
48    pub plugin_handle: Option<PluginHandle>,
49}
50
51impl Mode {
52    pub fn kind(&self) -> ModeKind {
53        self.kind
54    }
55
56    pub(crate) fn change_to(editor: &mut Editor, next: ModeKind) {
57        if editor.mode.kind == next {
58            return;
59        }
60
61        match editor.mode.kind {
62            ModeKind::Normal => normal::State::on_exit(editor),
63            ModeKind::Insert => insert::State::on_exit(editor),
64            ModeKind::Command => command::State::on_exit(editor),
65            ModeKind::ReadLine => readline::State::on_exit(editor),
66            ModeKind::Picker => picker::State::on_exit(editor),
67            ModeKind::Plugin => editor.mode.plugin_handle = None,
68        }
69
70        editor.mode.kind = next;
71
72        match editor.mode.kind {
73            ModeKind::Normal => normal::State::on_enter(editor),
74            ModeKind::Insert => insert::State::on_enter(editor),
75            ModeKind::Command => command::State::on_enter(editor),
76            ModeKind::ReadLine => readline::State::on_enter(editor),
77            ModeKind::Picker => picker::State::on_enter(editor),
78            ModeKind::Plugin => (),
79        }
80    }
81
82    pub(crate) fn on_keys(
83        ctx: &mut EditorContext,
84        client_handle: ClientHandle,
85        keys: &mut KeysIterator,
86    ) -> Option<EditorFlow> {
87        match ctx.editor.mode.kind {
88            ModeKind::Normal => normal::State::on_keys(ctx, client_handle, keys),
89            ModeKind::Insert => insert::State::on_keys(ctx, client_handle, keys),
90            ModeKind::Command => command::State::on_keys(ctx, client_handle, keys),
91            ModeKind::ReadLine => readline::State::on_keys(ctx, client_handle, keys),
92            ModeKind::Picker => picker::State::on_keys(ctx, client_handle, keys),
93            ModeKind::Plugin => match ctx.editor.mode.plugin_handle {
94                Some(plugin_handle) => {
95                    let on_keys = ctx.plugins.get(plugin_handle).on_keys;
96                    on_keys(plugin_handle, ctx, client_handle, keys)
97                }
98                None => {
99                    Mode::change_to(&mut ctx.editor, ModeKind::default());
100                    None
101                }
102            },
103        }
104    }
105}