Skip to main content

indigo_core/mode/
insert.rs

1#![allow(clippy::enum_glob_use)]
2
3use crate::{
4    editor::Editor,
5    key::{KeyCode, KeyModifiers},
6    keymap::{Keymap, KeymapResult, keymap},
7    mode::{Mode, normal},
8};
9use std::sync::LazyLock;
10
11#[cfg(feature = "arbitrary")]
12use arbitrary::Arbitrary;
13
14#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
15#[derive(Debug)]
16pub enum Action {
17    EnterNormalMode,
18    DeleteBefore,
19    DeleteAfter,
20    InsertChar(char),
21}
22
23pub static KEYMAP: LazyLock<Keymap<Vec<Action>>> = LazyLock::new(|| {
24    use Action::*;
25    keymap! { Vec<Action>;
26        "<esc>" => vec![EnterNormalMode], /// Exit insert mode
27        "<tab>" => vec![InsertChar('\t')], /// Insert tab
28        "<ret>" => vec![InsertChar('\n')], /// Insert newline
29        "<bs>" => vec![DeleteBefore], /// Delete before cursor
30        "<del>" => vec![DeleteAfter], /// Delete after cursor
31        keys => {
32            if let [key] = keys
33                && let KeyCode::Char(c) = key.code
34                && key.modifiers.difference(KeyModifiers::SHIFT).is_empty()
35            {
36                KeymapResult::Fallback(vec![InsertChar(char::from(c))])
37            } else {
38                KeymapResult::Unmapped
39            }
40        } /// Insert character
41    }
42});
43
44pub fn handle_actions(editor: &mut Editor, actions: &[Action]) {
45    for action in actions {
46        handle_action(editor, action);
47    }
48}
49
50pub fn handle_action(editor: &mut Editor, action: &Action) {
51    match action {
52        Action::EnterNormalMode => normal::enter(editor),
53        Action::DeleteBefore => delete_before(editor),
54        Action::DeleteAfter => delete_after(editor),
55        Action::InsertChar(c) => insert_char(editor, *c),
56    }
57}
58
59pub fn handle_keys(editor: &mut Editor) -> bool {
60    match KEYMAP.get_keys(&editor.pending_keys) {
61        KeymapResult::Mapped(actions) => {
62            editor.pending_keys.clear();
63            handle_actions(editor, actions);
64            true
65        }
66        KeymapResult::Fallback(actions) => {
67            editor.pending_keys.clear();
68            handle_actions(editor, &actions);
69            true
70        }
71        KeymapResult::Unmapped => {
72            editor.pending_keys.clear();
73            false
74        }
75        KeymapResult::Pending => true,
76    }
77}
78
79pub fn enter(editor: &mut Editor) {
80    if editor.focused_buffer().text.readonly {
81        editor.message = Some(Err(String::from("Buffer is readonly")));
82        editor.count = None;
83        return;
84    }
85    let mut window = editor.focused_window_mut();
86    window
87        .selection_move()
88        .for_each_move(|mut range| range.collapse());
89    window.scroll_to_selection();
90    editor.mode = Mode::Insert;
91    editor.count = None;
92}
93
94fn delete_before(editor: &mut Editor) {
95    let mut window = editor.focused_window_mut();
96    window.selection_edit().delete_before();
97    window.scroll_to_selection();
98    editor.count = None;
99}
100
101fn delete_after(editor: &mut Editor) {
102    let mut window = editor.focused_window_mut();
103    window.selection_edit().delete_after();
104    window.scroll_to_selection();
105    editor.count = None;
106}
107
108fn insert_char(editor: &mut Editor, char: char) {
109    let mut window = editor.focused_window_mut();
110    window.selection_edit().insert_char(char);
111    window.scroll_to_selection();
112    editor.count = None;
113}
114
115pub fn paste(editor: &mut Editor, text: &str) {
116    let mut window = editor.focused_window_mut();
117    window.selection_edit().insert(text);
118    window.scroll_to_selection();
119    editor.count = None;
120}