1use crate::complete::Completer;
2use crate::event::*;
3use crate::Editor;
4use std::io::{self, ErrorKind, Write};
5use termion::event::Key;
6
7pub trait KeyMap: Default {
8 fn handle_key_core<W: Write>(&mut self, key: Key, editor: &mut Editor<'_, W>)
9 -> io::Result<()>;
10
11 fn init<W: Write>(&mut self, _editor: &mut Editor<'_, W>) {}
12
13 fn handle_key<W: Write, C: Completer>(
14 &mut self,
15 mut key: Key,
16 editor: &mut Editor<'_, W>,
17 handler: &mut C,
18 ) -> io::Result<bool> {
19 let mut done = false;
20
21 handler.on_event(Event::new(editor, EventKind::BeforeKey(key)));
22
23 let is_empty = editor.current_buffer().is_empty();
24
25 if key == Key::Ctrl('h') {
26 key = Key::Backspace;
28 }
29
30 match key {
31 Key::Ctrl('c') => {
32 editor.handle_newline()?;
33 return Err(io::Error::new(ErrorKind::Interrupted, "ctrl-c"));
34 }
35 Key::Ctrl('d') if is_empty => {
37 editor.handle_newline()?;
38 return Err(io::Error::new(ErrorKind::UnexpectedEof, "ctrl-d"));
39 }
40 Key::Char('\t') => editor.complete(handler)?,
41 Key::Char('\n') => {
42 done = editor.handle_newline()?;
43 }
44 Key::Ctrl('f') if editor.is_currently_showing_autosuggestion() => {
45 editor.accept_autosuggestion()?;
46 }
47 Key::Ctrl('r') => {
48 editor.search(false)?;
49 }
50 Key::Ctrl('s') => {
51 editor.search(true)?;
52 }
53 Key::Right
54 if editor.is_currently_showing_autosuggestion()
55 && editor.cursor_is_at_end_of_line() =>
56 {
57 editor.accept_autosuggestion()?;
58 }
59 _ => {
60 self.handle_key_core(key, editor)?;
61 editor.skip_completions_hint();
62 }
63 };
64
65 handler.on_event(Event::new(editor, EventKind::AfterKey(key)));
66
67 editor.flush()?;
68
69 Ok(done)
70 }
71}
72
73pub mod vi;
74pub use vi::Vi;
75
76pub mod emacs;
77pub use emacs::Emacs;
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::editor::Prompt;
83 use crate::Context;
84 use std::io::ErrorKind;
85 use termion::event::Key::*;
86
87 #[derive(Default)]
88 struct TestKeyMap;
89
90 impl KeyMap for TestKeyMap {
91 fn handle_key_core<W: Write>(&mut self, _: Key, _: &mut Editor<'_, W>) -> io::Result<()> {
92 Ok(())
93 }
94 }
95
96 struct EmptyCompleter;
97
98 impl Completer for EmptyCompleter {
99 fn completions(&mut self, _start: &str) -> Vec<String> {
100 Vec::default()
101 }
102 }
103
104 #[test]
105 fn ctrl_d_empty() {
107 let mut context = Context::new();
108 let out = Vec::new();
109 let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
110 let mut map = TestKeyMap;
111
112 let res = map.handle_key(Ctrl('d'), &mut ed, &mut EmptyCompleter);
113 assert_eq!(res.is_err(), true);
114 assert_eq!(res.err().unwrap().kind(), ErrorKind::UnexpectedEof);
115 }
116
117 #[test]
118 fn ctrl_d_non_empty() {
120 let mut context = Context::new();
121 let out = Vec::new();
122 let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
123 let mut map = TestKeyMap;
124 ed.insert_str_after_cursor("not empty").unwrap();
125
126 let res = map.handle_key(Ctrl('d'), &mut ed, &mut EmptyCompleter);
127 assert_eq!(res.is_ok(), true);
128 }
129
130 #[test]
131 fn ctrl_c() {
133 let mut context = Context::new();
134 let out = Vec::new();
135 let mut ed = Editor::new(out, Prompt::from("prompt"), None, &mut context).unwrap();
136 let mut map = TestKeyMap;
137
138 let res = map.handle_key(Ctrl('c'), &mut ed, &mut EmptyCompleter);
139 assert_eq!(res.is_err(), true);
140 assert_eq!(res.err().unwrap().kind(), ErrorKind::Interrupted);
141 }
142}