1use crate::app::{ActiveBlock, ActiveDisplayBlock, App};
2use crate::event::Key;
3use crate::network::IoEvent;
4use std::convert::TryInto;
5use unicode_width::{UnicodeWidthChar, UnicodeWidthStr};
6
7pub fn handler(key: Key, app: &mut App) {
8 match key {
9 Key::Ctrl('k') => {
11 app.input.drain(app.input_idx..app.input.len());
12 }
13
14 Key::Ctrl('u') => {
16 app.input.drain(..app.input_idx);
17 app.input_idx = 0;
18 app.input_cursor_position = 0;
19 }
20
21 Key::Ctrl('l') => {
23 app.input = vec![];
24 app.input_idx = 0;
25 app.input_cursor_position = 0;
26 }
27 Key::Ctrl('w') => {
29 if app.input_cursor_position == 0 {
30 return;
31 }
32 let word_end = match app.input[..app.input_idx].iter().rposition(|&x| x != ' ') {
33 Some(index) => index + 1,
34 None => 0,
35 };
36 let word_start = match app.input[..word_end].iter().rposition(|&x| x == ' ') {
37 Some(index) => index + 1,
38 None => 0,
39 };
40 let deleted: String = app.input[word_start..app.input_idx].iter().collect();
41 let deleted_len: u16 = UnicodeWidthStr::width(deleted.as_str()).try_into().unwrap();
42 app.input.drain(word_start..app.input_idx);
43 app.input_idx = word_start;
44 app.input_cursor_position -= deleted_len;
45 }
46
47 Key::Ctrl('e') => {
49 app.input_idx = app.input.len();
50 let input_string: String = app.input.iter().collect();
51 app.input_cursor_position = UnicodeWidthStr::width(input_string.as_str())
52 .try_into()
53 .unwrap();
54 }
55
56 Key::Ctrl('a') => {
58 app.input_idx = 0;
59 app.input_cursor_position = 0;
60 }
61
62 Key::Left | Key::Ctrl('b') => {
64 if !app.input.is_empty() && app.input_idx > 0 {
65 let last_c = app.input[app.input_idx - 1];
66 app.input_idx -= 1;
67 app.input_cursor_position -= compute_character_width(last_c);
68 }
69 }
70
71 Key::Right | Key::Ctrl('f') => {
73 if app.input_idx < app.input.len() {
74 let next_c = app.input[app.input_idx];
75 app.input_idx += 1;
76 app.input_cursor_position += compute_character_width(next_c);
77 }
78 }
79
80 Key::Esc => {
82 app.active_block = ActiveBlock::DisplayBlock;
83 }
84
85 Key::Enter => {
87 let input_str: String = app.input.iter().collect();
88
89 if input_str.is_empty() {
91 return;
92 }
93 app.active_display_block = ActiveDisplayBlock::Loading;
94 app.active_block = ActiveBlock::DisplayBlock;
95 app.reset_result_index();
96 app.display_block_title = format!("Search Results: {}", input_str).to_string();
97
98 app.dispatch(IoEvent::GetSearchResults(input_str.clone()));
99
100 }
102
103 Key::Char(c) => {
105 app.input.insert(app.input_idx, c);
106 app.input_idx += 1;
107 app.input_cursor_position += compute_character_width(c);
108 }
109
110 Key::Backspace | Key::Ctrl('h') => {
112 if !app.input.is_empty() && app.input_idx > 0 {
113 let last_c = app.input.remove(app.input_idx - 1);
114 app.input_idx -= 1;
115 app.input_cursor_position -= compute_character_width(last_c);
116 }
117 }
118
119 Key::Delete | Key::Ctrl('d') => {
121 if !app.input.is_empty() && app.input_idx < app.input.len() {
122 app.input.remove(app.input_idx);
123 }
124 }
125
126 _ => {}
127 }
128}
129
130fn compute_character_width(character: char) -> u16 {
131 UnicodeWidthChar::width(character)
132 .unwrap()
133 .try_into()
134 .unwrap()
135}