Skip to main content

steer_tui/tui/handlers/
text_manipulation.rs

1use crate::error::Result;
2use crate::tui::Tui;
3use ratatui::crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
4use tui_textarea::{CursorMove, Input};
5
6impl Tui {
7    /// Common text manipulation handler used by both Simple mode and Vim insert mode
8    pub fn handle_text_manipulation(&mut self, key: KeyEvent) -> Result<bool> {
9        match (key.code, key.modifiers) {
10            // Basic navigation
11            (KeyCode::Left, KeyModifiers::NONE) => {
12                self.input_panel_state
13                    .textarea
14                    .move_cursor(CursorMove::Back);
15                Ok(true)
16            }
17            (KeyCode::Right, KeyModifiers::NONE) => {
18                self.input_panel_state
19                    .textarea
20                    .move_cursor(CursorMove::Forward);
21                Ok(true)
22            }
23            (KeyCode::Up, KeyModifiers::NONE) => {
24                self.input_panel_state.textarea.move_cursor(CursorMove::Up);
25                Ok(true)
26            }
27            (KeyCode::Down, KeyModifiers::NONE) => {
28                self.input_panel_state
29                    .textarea
30                    .move_cursor(CursorMove::Down);
31                Ok(true)
32            }
33
34            // Word navigation (Alt/Option + arrows)
35            (KeyCode::Left, KeyModifiers::ALT) => {
36                self.input_panel_state
37                    .textarea
38                    .move_cursor(CursorMove::WordBack);
39                Ok(true)
40            }
41            (KeyCode::Right, KeyModifiers::ALT) => {
42                self.input_panel_state
43                    .textarea
44                    .move_cursor(CursorMove::WordForward);
45                Ok(true)
46            }
47
48            // Line navigation (Cmd/Ctrl + arrows, Home/End, Ctrl+A/Ctrl+E)
49            (KeyCode::Left, m)
50                if m.contains(KeyModifiers::CONTROL) || m.contains(KeyModifiers::SUPER) =>
51            {
52                self.input_panel_state
53                    .textarea
54                    .move_cursor(CursorMove::Head);
55                Ok(true)
56            }
57            (KeyCode::Right, m)
58                if m.contains(KeyModifiers::CONTROL) || m.contains(KeyModifiers::SUPER) =>
59            {
60                self.input_panel_state.textarea.move_cursor(CursorMove::End);
61                Ok(true)
62            }
63            (KeyCode::Home, _) => {
64                self.input_panel_state
65                    .textarea
66                    .move_cursor(CursorMove::Head);
67                Ok(true)
68            }
69            (KeyCode::End, _) => {
70                self.input_panel_state.textarea.move_cursor(CursorMove::End);
71                Ok(true)
72            }
73            (KeyCode::Char('a'), m) if m.contains(KeyModifiers::CONTROL) => {
74                self.input_panel_state
75                    .textarea
76                    .move_cursor(CursorMove::Head);
77                Ok(true)
78            }
79            (KeyCode::Char('e'), m) if m.contains(KeyModifiers::CONTROL) => {
80                self.input_panel_state.textarea.move_cursor(CursorMove::End);
81                Ok(true)
82            }
83
84            (KeyCode::Backspace, KeyModifiers::NONE) => {
85                if self.handle_atomic_backspace_delete(false) {
86                    Ok(true)
87                } else {
88                    Ok(false)
89                }
90            }
91            (KeyCode::Delete, KeyModifiers::NONE) => {
92                if self.handle_atomic_backspace_delete(true) {
93                    Ok(true)
94                } else {
95                    Ok(false)
96                }
97            }
98
99            // Text deletion
100            (KeyCode::Char('u'), KeyModifiers::CONTROL) => {
101                self.input_panel_state.textarea.delete_line_by_head();
102                Ok(true)
103            }
104            (KeyCode::Char('k'), KeyModifiers::CONTROL) => {
105                self.input_panel_state.textarea.delete_line_by_end();
106                Ok(true)
107            }
108            (KeyCode::Backspace, m)
109                if m.contains(KeyModifiers::SUPER) || m.contains(KeyModifiers::CONTROL) =>
110            {
111                self.input_panel_state.textarea.delete_line_by_head();
112                Ok(true)
113            }
114            (KeyCode::Delete, m)
115                if m.contains(KeyModifiers::SUPER) || m.contains(KeyModifiers::CONTROL) =>
116            {
117                self.input_panel_state.textarea.delete_line_by_end();
118                Ok(true)
119            }
120
121            // Word deletion
122            (KeyCode::Backspace, KeyModifiers::ALT) => {
123                self.input_panel_state.textarea.delete_word();
124                Ok(true)
125            }
126
127            (KeyCode::Char('v'), KeyModifiers::CONTROL) => {
128                Ok(self.try_attach_image_from_clipboard())
129            }
130
131            // Multi-line support
132            (KeyCode::Enter, m)
133                if m.contains(KeyModifiers::SHIFT)
134                    || m.contains(KeyModifiers::ALT)
135                    || m.contains(KeyModifiers::CONTROL) =>
136            {
137                self.input_panel_state
138                    .handle_input(Input::from(KeyEvent::new(
139                        KeyCode::Char('\n'),
140                        KeyModifiers::empty(),
141                    )));
142                Ok(true)
143            }
144            (KeyCode::Char('j'), KeyModifiers::CONTROL) => {
145                self.input_panel_state
146                    .handle_input(Input::from(KeyEvent::new(
147                        KeyCode::Char('\n'),
148                        KeyModifiers::empty(),
149                    )));
150                Ok(true)
151            }
152
153            // Not handled by text manipulation
154            _ => Ok(false),
155        }
156    }
157}