mal/handlers/
input.rs

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        // Delete everything after the cursor including selected character
10        Key::Ctrl('k') => {
11            app.input.drain(app.input_idx..app.input.len());
12        }
13
14        // Delete everything before the cursor not including selected character
15        Key::Ctrl('u') => {
16            app.input.drain(..app.input_idx);
17            app.input_idx = 0;
18            app.input_cursor_position = 0;
19        }
20
21        // Deletes everything in input
22        Key::Ctrl('l') => {
23            app.input = vec![];
24            app.input_idx = 0;
25            app.input_cursor_position = 0;
26        }
27        // Delete word before cursor
28        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        // Move cursor to the end of the input
48        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        // Move cursor to the start of the input
57        Key::Ctrl('a') => {
58            app.input_idx = 0;
59            app.input_cursor_position = 0;
60        }
61
62        // Move cursor to left
63        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        // Move cursor to right
72        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        // end input mode
81        Key::Esc => {
82            app.active_block = ActiveBlock::DisplayBlock;
83        }
84
85        // Submit search query
86        Key::Enter => {
87            let input_str: String = app.input.iter().collect();
88
89            // Don't do anything if there is no input
90            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            // On searching for a track, clear the playlist selection
101        }
102
103        // add character to input
104        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        // delete character before cursor
111        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        // ! not working ??
120        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}