aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/input/keybinds.rs
blob: 4b676037de89f8b6f96388f69bf48657eb56f08c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
//! Mapping of inputs to sequences of actions.

use super::actions::{Action, Direction};
use super::handler::InputMode;

use std::collections::HashMap;

use strum::IntoEnumIterator;
use termion::event::Key;

type Keybinds = HashMap<InputMode, ModeKeybinds>;
type ModeKeybinds = HashMap<Key, Vec<Action>>;

/// Populates the default hashmap of keybinds.
/// @@@khs26 What about an input config file?
pub fn get_default_keybinds() -> Result<Keybinds, String> {
    let mut defaults = Keybinds::new();

    for mode in InputMode::iter() {
        defaults.insert(mode, get_defaults_for_mode(&mode)?);
    }

    Ok(defaults)
}

/// Returns the default keybinds for a givent [`InputMode`].
fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
    let mut defaults = ModeKeybinds::new();

    match *mode {
        InputMode::Normal => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Locked)],
            );
            defaults.insert(Key::Ctrl('p'), vec![Action::SwitchToMode(InputMode::Pane)]);
            defaults.insert(
                Key::Ctrl('r'),
                vec![Action::SwitchToMode(InputMode::Resize)],
            );
            defaults.insert(Key::Ctrl('t'), vec![Action::SwitchToMode(InputMode::Tab)]);
            defaults.insert(
                Key::Ctrl('s'),
                vec![Action::SwitchToMode(InputMode::Scroll)],
            );
            defaults.insert(Key::Ctrl('q'), vec![Action::Quit]);
        }
        InputMode::Locked => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
        }
        InputMode::Resize => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Locked)],
            );
            defaults.insert(Key::Ctrl('p'), vec![Action::SwitchToMode(InputMode::Pane)]);
            defaults.insert(
                Key::Ctrl('r'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(Key::Ctrl('t'), vec![Action::SwitchToMode(InputMode::Tab)]);
            defaults.insert(
                Key::Ctrl('s'),
                vec![Action::SwitchToMode(InputMode::Scroll)],
            );
            defaults.insert(Key::Ctrl('q'), vec![Action::Quit]);
            defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Normal)]);
            defaults.insert(
                Key::Char('\n'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Char(' '),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );

            defaults.insert(Key::Char('h'), vec![Action::Resize(Direction::Left)]);
            defaults.insert(Key::Char('j'), vec![Action::Resize(Direction::Down)]);
            defaults.insert(Key::Char('k'), vec![Action::Resize(Direction::Up)]);
            defaults.insert(Key::Char('l'), vec![Action::Resize(Direction::Right)]);

            defaults.insert(Key::Left, vec![Action::Resize(Direction::Left)]);
            defaults.insert(Key::Down, vec![Action::Resize(Direction::Down)]);
            defaults.insert(Key::Up, vec![Action::Resize(Direction::Up)]);
            defaults.insert(Key::Right, vec![Action::Resize(Direction::Right)]);
        }
        InputMode::Pane => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Locked)],
            );
            defaults.insert(
                Key::Ctrl('p'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Ctrl('r'),
                vec![Action::SwitchToMode(InputMode::Resize)],
            );
            defaults.insert(Key::Ctrl('t'), vec![Action::SwitchToMode(InputMode::Tab)]);
            defaults.insert(
                Key::Ctrl('s'),
                vec![Action::SwitchToMode(InputMode::Scroll)],
            );
            defaults.insert(Key::Ctrl('q'), vec![Action::Quit]);
            defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Normal)]);
            defaults.insert(
                Key::Char('\n'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Char(' '),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );

            defaults.insert(Key::Char('h'), vec![Action::MoveFocus(Direction::Left)]);
            defaults.insert(Key::Char('j'), vec![Action::MoveFocus(Direction::Down)]);
            defaults.insert(Key::Char('k'), vec![Action::MoveFocus(Direction::Up)]);
            defaults.insert(Key::Char('l'), vec![Action::MoveFocus(Direction::Right)]);

            defaults.insert(Key::Left, vec![Action::MoveFocus(Direction::Left)]);
            defaults.insert(Key::Down, vec![Action::MoveFocus(Direction::Down)]);
            defaults.insert(Key::Up, vec![Action::MoveFocus(Direction::Up)]);
            defaults.insert(Key::Right, vec![Action::MoveFocus(Direction::Right)]);

            defaults.insert(Key::Char('p'), vec![Action::SwitchFocus(Direction::Right)]);
            defaults.insert(Key::Char('n'), vec![Action::NewPane(None)]);
            defaults.insert(Key::Char('d'), vec![Action::NewPane(Some(Direction::Down))]);
            defaults.insert(
                Key::Char('r'),
                vec![Action::NewPane(Some(Direction::Right))],
            );
            defaults.insert(Key::Char('x'), vec![Action::CloseFocus]);
            defaults.insert(Key::Char('f'), vec![Action::ToggleFocusFullscreen]);
        }
        InputMode::Tab => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Locked)],
            );
            defaults.insert(Key::Ctrl('p'), vec![Action::SwitchToMode(InputMode::Pane)]);
            defaults.insert(
                Key::Ctrl('r'),
                vec![Action::SwitchToMode(InputMode::Resize)],
            );
            defaults.insert(
                Key::Ctrl('t'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Ctrl('s'),
                vec![Action::SwitchToMode(InputMode::Scroll)],
            );
            defaults.insert(Key::Ctrl('q'), vec![Action::Quit]);
            defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Normal)]);
            defaults.insert(
                Key::Char('\n'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Char(' '),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );

            defaults.insert(Key::Char('h'), vec![Action::GoToPreviousTab]);
            defaults.insert(Key::Char('j'), vec![Action::GoToNextTab]);
            defaults.insert(Key::Char('k'), vec![Action::GoToPreviousTab]);
            defaults.insert(Key::Char('l'), vec![Action::GoToNextTab]);

            defaults.insert(Key::Left, vec![Action::GoToPreviousTab]);
            defaults.insert(Key::Down, vec![Action::GoToNextTab]);
            defaults.insert(Key::Up, vec![Action::GoToPreviousTab]);
            defaults.insert(Key::Right, vec![Action::GoToNextTab]);

            defaults.insert(Key::Char('n'), vec![Action::NewTab]);
            defaults.insert(Key::Char('x'), vec![Action::CloseTab]);

            defaults.insert(
                Key::Char('r'),
                vec![
                    Action::SwitchToMode(InputMode::RenameTab),
                    Action::TabNameInput(vec![0]),
                ],
            );
            defaults.insert(Key::Char('q'), vec![Action::Quit]);
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            for i in '1'..='9' {
                defaults.insert(Key::Char(i), vec![Action::GoToTab(i.to_digit(10).unwrap())]);
            }
        }
        InputMode::Scroll => {
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Locked)],
            );
            defaults.insert(Key::Ctrl('p'), vec![Action::SwitchToMode(InputMode::Pane)]);
            defaults.insert(
                Key::Ctrl('r'),
                vec![Action::SwitchToMode(InputMode::Resize)],
            );
            defaults.insert(Key::Ctrl('t'), vec![Action::SwitchToMode(InputMode::Tab)]);
            defaults.insert(
                Key::Ctrl('s'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(Key::Ctrl('q'), vec![Action::Quit]);
            defaults.insert(Key::Esc, vec![Action::SwitchToMode(InputMode::Normal)]);
            defaults.insert(
                Key::Char('\n'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Char(' '),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );

            defaults.insert(Key::Char('j'), vec![Action::ScrollDown]);
            defaults.insert(Key::Char('k'), vec![Action::ScrollUp]);

            defaults.insert(Key::Down, vec![Action::ScrollDown]);
            defaults.insert(Key::Up, vec![Action::ScrollUp]);
        }
        InputMode::RenameTab => {
            defaults.insert(
                Key::Char('\n'),
                vec![Action::SaveTabName, Action::SwitchToMode(InputMode::Tab)],
            );
            defaults.insert(
                Key::Ctrl('g'),
                vec![Action::SwitchToMode(InputMode::Normal)],
            );
            defaults.insert(
                Key::Esc,
                vec![
                    Action::TabNameInput(vec![0x1b]),
                    Action::SwitchToMode(InputMode::Tab),
                ],
            );
        }
    }

    Ok(defaults)
}

/// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current
/// [`InputMode`] and [`Keybinds`].
pub fn key_to_actions(
    key: &Key,
    input: Vec<u8>,
    mode: &InputMode,
    keybinds: &Keybinds,
) -> Vec<Action> {
    let mode_keybind_or_action = |action: Action| {
        keybinds
            .get(mode)
            .unwrap_or_else(|| unreachable!("Unrecognized mode: {:?}", mode))
            .get(key)
            .cloned()
            .unwrap_or_else(|| vec![action])
    };
    match *mode {
        InputMode::Normal | InputMode::Locked => mode_keybind_or_action(Action::Write(input)),
        InputMode::RenameTab => mode_keybind_or_action(Action::TabNameInput(input)),
        _ => mode_keybind_or_action(Action::NoOp),
    }
}