Skip to main content

hjkl_vim/
insert.rs

1//! Phase 6.6d: insert-mode FSM body relocated from `hjkl-engine::vim`.
2//!
3//! Dispatched by [`crate::dispatch_input`] before the deprecated
4//! `Editor::step_input` shim. The engine keeps an in-engine duplicate
5//! body in `vim::step` (`Mode::Insert` arm) for back-compat with the
6//! deprecated shim path until Phase 6.6h.
7use hjkl_engine::{Host, Input, Key};
8
9/// Drive the insert-mode FSM for one keystroke.
10///
11/// Returns `true` (consumed) unconditionally — every key inside insert mode
12/// is swallowed regardless of whether it produced a visible effect.
13pub fn step_insert<H: Host>(
14    ed: &mut hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
15    input: Input,
16) -> bool {
17    // `Ctrl-R {reg}` paste — the previous keystroke armed the wait. Any
18    // non-char key cancels (matches vim, which beeps on selectors like
19    // Esc and re-emits the literal text otherwise).
20    if ed.insert_pending_register() {
21        ed.set_insert_pending_register(false);
22        if let Key::Char(c) = input.key
23            && !input.ctrl
24        {
25            ed.insert_paste_register(c);
26        }
27        return true;
28    }
29
30    if input.key == Key::Esc {
31        ed.leave_insert_to_normal();
32        return true;
33    }
34
35    // Ctrl-prefixed insert-mode shortcuts — thin dispatcher to public Editor methods.
36    if input.ctrl {
37        match input.key {
38            Key::Char('w') => {
39                ed.insert_ctrl_w();
40                return true;
41            }
42            Key::Char('u') => {
43                ed.insert_ctrl_u();
44                return true;
45            }
46            Key::Char('h') => {
47                ed.insert_ctrl_h();
48                return true;
49            }
50            Key::Char('o') => {
51                ed.insert_ctrl_o_arm();
52                return true;
53            }
54            Key::Char('r') => {
55                ed.insert_ctrl_r_arm();
56                return true;
57            }
58            Key::Char('t') => {
59                ed.insert_ctrl_t();
60                return true;
61            }
62            Key::Char('d') => {
63                ed.insert_ctrl_d();
64                return true;
65            }
66            _ => {}
67        }
68    }
69
70    // Widen the session's visited row window *before* handling the key
71    // so navigation-only keystrokes (arrow keys) still extend the range.
72    let (row, _) = ed.cursor();
73    if let Some(session) = ed.insert_session_mut() {
74        session.row_min = session.row_min.min(row);
75        session.row_max = session.row_max.max(row);
76    }
77    let mutated = handle_insert_key(ed, input);
78    if mutated {
79        ed.mark_content_dirty();
80        let (row, _) = ed.cursor();
81        if let Some(session) = ed.insert_session_mut() {
82            session.row_min = session.row_min.min(row);
83            session.row_max = session.row_max.max(row);
84        }
85    }
86    true
87}
88
89/// Insert-mode key dispatcher — thin shim that routes each key to the
90/// corresponding public `Editor::*` method (Phase 6.6a). Returns `true`
91/// when the buffer mutated (editing keys), `false` for navigation-only keys.
92pub(crate) fn handle_insert_key<H: Host>(
93    ed: &mut hjkl_engine::Editor<hjkl_buffer::Buffer, H>,
94    input: Input,
95) -> bool {
96    use hjkl_engine::InsertDir;
97    match input.key {
98        Key::Char(c) => {
99            ed.insert_char(c);
100            true
101        }
102        Key::Enter => {
103            ed.insert_newline();
104            true
105        }
106        Key::Tab => {
107            ed.insert_tab();
108            true
109        }
110        Key::Backspace => {
111            ed.insert_backspace();
112            true
113        }
114        Key::Delete => {
115            ed.insert_delete();
116            true
117        }
118        Key::Left => {
119            ed.insert_arrow(InsertDir::Left);
120            false
121        }
122        Key::Right => {
123            ed.insert_arrow(InsertDir::Right);
124            false
125        }
126        Key::Up => {
127            ed.insert_arrow(InsertDir::Up);
128            false
129        }
130        Key::Down => {
131            ed.insert_arrow(InsertDir::Down);
132            false
133        }
134        Key::Home => {
135            ed.insert_home();
136            false
137        }
138        Key::End => {
139            ed.insert_end();
140            false
141        }
142        Key::PageUp => {
143            let h = ed.viewport_height_value();
144            ed.insert_pageup(h);
145            false
146        }
147        Key::PageDown => {
148            let h = ed.viewport_height_value();
149            ed.insert_pagedown(h);
150            false
151        }
152        // F-keys, mouse scroll, copy/cut/paste virtual keys, Null —
153        // no insert-mode behaviour.
154        _ => false,
155    }
156}