minime/editor/
keybindings.rs

1use crate::{editor::Editor, renderer::Renderer, Result};
2
3use crossterm::event::{read, Event, KeyCode, KeyEvent, KeyModifiers};
4
5/// Generic keybinding trait.
6pub trait Keybinding {
7    /// Read a key from the environment and act upon the editor.
8    fn read(&self, editor: &mut Editor<impl Renderer>) -> Result<bool>;
9}
10
11/// Default keybindings for the editor.
12pub struct NormalKeybinding;
13
14impl Keybinding for NormalKeybinding {
15    fn read(&self, editor: &mut Editor<impl Renderer>) -> Result<bool> {
16        let key_event = read()?;
17        match key_event {
18            Event::Key(k) => Self::process_key_event(editor, k),
19            _ => Ok(true),
20        }
21    }
22}
23
24impl NormalKeybinding {
25    fn process_key_event(editor: &mut Editor<impl Renderer>, event: KeyEvent) -> Result<bool> {
26        let code = event.code;
27        let ln_count = editor.line_count();
28        // let mut cursor = editor.cursor();
29        let shifted = event.modifiers.contains(KeyModifiers::SHIFT);
30        let alt = event.modifiers.contains(KeyModifiers::ALT);
31        let control = event.modifiers.contains(KeyModifiers::CONTROL);
32
33        match code {
34            // KeyCode::Down if shifted => editor.move_to_bottom(),
35            // KeyCode::Up if control => editor.move_to_top(),
36            // KeyCode::PageDown => editor.move_to_bottom(),
37            // KeyCode::PageUp => editor.move_to_top(),
38            KeyCode::Down => editor.move_down(shifted),
39            KeyCode::Up => editor.move_up(shifted),
40            KeyCode::Left => editor.move_left(shifted),
41            KeyCode::Right => editor.move_right(shifted),
42
43            KeyCode::Home => {
44                let leading_spaces = editor
45                    .curr_ln_chars()
46                    .take_while(|c| c.is_whitespace())
47                    .count();
48                if editor.focus.col == leading_spaces {
49                    editor.move_to_col(0, shifted);
50                } else {
51                    editor.move_to_col(leading_spaces, shifted);
52                }
53            }
54            KeyCode::End => editor.move_to_line_end(shifted),
55
56            KeyCode::Backspace => editor.backspace(),
57            KeyCode::Char('h') if control => editor.backspace(),
58            KeyCode::Delete => editor.delete(),
59
60            #[cfg(feature = "unstable")]
61            KeyCode::Char('c') if control => {
62                if let Ok(mut clipboard) = arboard::Clipboard::new() {
63                    if let Some(txt) = editor.curr_sel() {
64                        clipboard.set_text(txt.to_string()).unwrap();
65                    } else {
66                        clipboard.set_text(editor.curr_ln().to_string()).unwrap();
67                    }
68                }
69            }
70            #[cfg(feature = "unstable")]
71            KeyCode::Char('x') if control => {
72                if let Ok(mut clipboard) = arboard::Clipboard::new() {
73                    if let Some(txt) = editor.curr_sel() {
74                        clipboard.set_text(txt.to_string()).unwrap();
75                        editor.delete();
76                    } else {
77                        clipboard.set_text(editor.remove_line(editor.focus.ln)).unwrap();
78                    }
79                }
80            }
81            #[cfg(feature = "unstable")]
82            KeyCode::Char('v') if control => {
83                if let Ok(mut clipboard) = arboard::Clipboard::new() {
84                    if let Ok(txt) = clipboard.get_text() {
85                        editor.insert_str(&txt);
86                    }
87                }
88            }
89            
90            KeyCode::Tab => {
91                editor.clamp();
92                let soft = 4 - editor.focus.col % 4;
93                for _ in 0..soft {
94                    editor.insert_char(0, ' ');
95                }
96                editor.focus.col += soft;
97            }
98            KeyCode::BackTab => {
99                editor.clamp();
100
101                let leading_spaces = editor
102                    .curr_ln_chars()
103                    .take(4)
104                    .take_while(|c| c.is_whitespace())
105                    .count();
106
107                editor.delete_ln_range(0, leading_spaces);
108            }
109            KeyCode::Esc => return Ok(false),
110            KeyCode::Enter => {
111                if !alt && editor.curr_ln_len() == 0 && editor.focus.ln + 1 == ln_count {
112                    return Ok(false);
113                } else {
114                    editor.type_char('\n');
115                }
116            }
117            KeyCode::Char(c) => editor.type_char(c),
118            _ => { /* ignored */ }
119        }
120        Ok(true)
121    }
122}
123
124#[doc(hidden)]
125pub struct DebugKeybinding;
126
127impl Keybinding for DebugKeybinding {
128    fn read(&self, editor: &mut Editor<impl Renderer>) -> Result<bool> {
129        let key_event = read()?;
130        match key_event {
131            Event::Key(k) => Self::process_key_event(editor, k),
132            _ => Ok(true),
133        }
134    }
135}
136
137impl DebugKeybinding {
138    fn process_key_event(editor: &mut Editor<impl Renderer>, event: KeyEvent) -> Result<bool> {
139        let code = event.code;
140        match code {
141            KeyCode::Esc => return Ok(false),
142            _ => editor.insert_str(&format!("{:#?}", event)),
143        }
144        Ok(true)
145    }
146}