1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
use crate::{
    client::{ClientHandle, ClientManager},
    command::CommandOperation,
    editor::{Editor, KeysIterator},
    platform::Platform,
};

mod command;
mod insert;
mod normal;
pub mod picker;
pub mod read_line;

pub enum ModeOperation {
    Pending,
    Suspend,
    Quit,
    QuitAll,
}
impl From<CommandOperation> for ModeOperation {
    fn from(op: CommandOperation) -> Self {
        match op {
            CommandOperation::Suspend => ModeOperation::Suspend,
            CommandOperation::Quit => ModeOperation::Quit,
            CommandOperation::QuitAll => ModeOperation::QuitAll,
        }
    }
}

pub struct ModeContext<'a> {
    pub editor: &'a mut Editor,
    pub platform: &'a mut Platform,
    pub clients: &'a mut ClientManager,
    pub client_handle: ClientHandle,
}

pub trait ModeState {
    fn on_enter(ctx: &mut ModeContext);
    fn on_exit(ctx: &mut ModeContext);
    fn on_client_keys(ctx: &mut ModeContext, keys: &mut KeysIterator) -> Option<ModeOperation>;
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ModeKind {
    Normal,
    Insert,
    Command,
    ReadLine,
    Picker,
}

impl Default for ModeKind {
    fn default() -> Self {
        Self::Normal
    }
}

#[derive(Default)]
pub struct Mode {
    kind: ModeKind,

    pub normal_state: normal::State,
    pub insert_state: insert::State,
    pub command_state: command::State,
    pub read_line_state: read_line::State,
    pub picker_state: picker::State,
}

impl Mode {
    pub fn kind(&self) -> ModeKind {
        self.kind
    }

    pub fn change_to(ctx: &mut ModeContext, next: ModeKind) {
        if ctx.editor.mode.kind == next {
            return;
        }

        match ctx.editor.mode.kind {
            ModeKind::Normal => normal::State::on_exit(ctx),
            ModeKind::Insert => insert::State::on_exit(ctx),
            ModeKind::Command => command::State::on_exit(ctx),
            ModeKind::ReadLine => read_line::State::on_exit(ctx),
            ModeKind::Picker => picker::State::on_exit(ctx),
        }

        ctx.editor.mode.kind = next;

        match ctx.editor.mode.kind {
            ModeKind::Normal => normal::State::on_enter(ctx),
            ModeKind::Insert => insert::State::on_enter(ctx),
            ModeKind::Command => command::State::on_enter(ctx),
            ModeKind::ReadLine => read_line::State::on_enter(ctx),
            ModeKind::Picker => picker::State::on_enter(ctx),
        }
    }

    pub fn on_client_keys(ctx: &mut ModeContext, keys: &mut KeysIterator) -> Option<ModeOperation> {
        match ctx.editor.mode.kind {
            ModeKind::Normal => normal::State::on_client_keys(ctx, keys),
            ModeKind::Insert => insert::State::on_client_keys(ctx, keys),
            ModeKind::Command => command::State::on_client_keys(ctx, keys),
            ModeKind::ReadLine => read_line::State::on_client_keys(ctx, keys),
            ModeKind::Picker => picker::State::on_client_keys(ctx, keys),
        }
    }
}