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}