Skip to content

Commit

Permalink
Support tiny commands in keymap config (#410)
Browse files Browse the repository at this point in the history
* Support tiny commands in keymap config

Allows the user to specify a config of this sort:

```yaml
key_map:
  ctrl_d:
    run_command: quit
```

Fixes #403.
  • Loading branch information
nthnd authored Aug 5, 2023
1 parent 308ba7e commit 66a1014
Show file tree
Hide file tree
Showing 7 changed files with 50 additions and 16 deletions.
2 changes: 1 addition & 1 deletion crates/libtiny_tui/src/exit_dialogue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ impl ExitDialogue {
}
}

pub(crate) fn keypressed(&self, key_action: KeyAction) -> WidgetRet {
pub(crate) fn keypressed(&self, key_action: &KeyAction) -> WidgetRet {
match key_action {
KeyAction::Input('y') | KeyAction::InputSend => WidgetRet::Abort,
_ => WidgetRet::Remove,
Expand Down
23 changes: 12 additions & 11 deletions crates/libtiny_tui/src/input_area/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ impl InputArea {
}
}

pub(crate) fn keypressed(&mut self, key_action: KeyAction) -> WidgetRet {
pub(crate) fn keypressed(&mut self, key_action: &KeyAction) -> WidgetRet {
match key_action {
KeyAction::InputSend => {
if self.current_buffer_len() > 0 {
Expand Down Expand Up @@ -330,10 +330,11 @@ impl InputArea {
}
KeyAction::Input(ch) => {
self.modify();
self.buffer.insert(self.cursor as usize, ch);
self.buffer.insert(self.cursor as usize, *ch);
self.inc_cursor();
WidgetRet::KeyHandled
}
KeyAction::RunCommand(cmd) => WidgetRet::Command(cmd.to_owned()),
_ => WidgetRet::KeyIgnored,
}
}
Expand Down Expand Up @@ -777,18 +778,18 @@ mod tests {
#[test]
fn text_field_bug() {
let mut text_field = InputArea::new(10, 50);
text_field.keypressed(KeyAction::Input('a'));
text_field.keypressed(KeyAction::Input(' '));
text_field.keypressed(KeyAction::Input('b'));
text_field.keypressed(KeyAction::Input(' '));
text_field.keypressed(KeyAction::Input('c'));
text_field.keypressed(KeyAction::InputSend);
text_field.keypressed(KeyAction::InputPrevEntry);
text_field.keypressed(&KeyAction::Input('a'));
text_field.keypressed(&KeyAction::Input(' '));
text_field.keypressed(&KeyAction::Input('b'));
text_field.keypressed(&KeyAction::Input(' '));
text_field.keypressed(&KeyAction::Input('c'));
text_field.keypressed(&KeyAction::InputSend);
text_field.keypressed(&KeyAction::InputPrevEntry);
// this panics:
text_field.keypressed(KeyAction::InputMoveWordLeft);
text_field.keypressed(&KeyAction::InputMoveWordLeft);
// a b ^c
assert_eq!(text_field.cursor, 4);
text_field.keypressed(KeyAction::InputMoveWordRight);
text_field.keypressed(&KeyAction::InputMoveWordRight);
assert_eq!(text_field.cursor, 5);
}

Expand Down
11 changes: 9 additions & 2 deletions crates/libtiny_tui/src/key_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use term_input::{Arrow, FKey, Key};
#[derive(Debug, PartialEq)]
pub(crate) struct KeyMap(HashMap<Key, KeyAction>);

#[derive(Debug, Copy, Clone, Deserialize, PartialEq)]
#[derive(Debug, Clone, Deserialize, PartialEq)]
#[serde(rename_all = "snake_case")]
pub(crate) enum KeyAction {
Cancel,
Expand All @@ -31,6 +31,7 @@ pub(crate) enum KeyAction {
MessagesScrollBottom,

Input(char),
RunCommand(String),
InputAutoComplete,
InputNextEntry,
InputPrevEntry,
Expand Down Expand Up @@ -67,6 +68,7 @@ impl Display for KeyAction {
KeyAction::MessagesScrollTop => "messages_scroll_top",
KeyAction::MessagesScrollBottom => "messages_scroll_bottom",
KeyAction::Input(c) => return writeln!(f, "input_{}", c),
KeyAction::RunCommand(string) => return writeln!(f, "run_command_{}", string),
KeyAction::InputAutoComplete => "input_auto_complete",
KeyAction::InputNextEntry => "input_next_entry",
KeyAction::InputPrevEntry => "input_prev_entry",
Expand Down Expand Up @@ -150,7 +152,7 @@ impl KeyMap {
}

pub(crate) fn load(&mut self, key_map: &KeyMap) {
self.0.extend(key_map.0.iter())
self.0.extend(key_map.0.clone().into_iter())
}
}

Expand Down Expand Up @@ -357,13 +359,18 @@ fn deser_keymap() {
tab_goto: 1
a:
input: b
b:
run_command: clear
"#;
let mut expect = KeyMap(HashMap::new());
expect
.0
.insert(Key::Ctrl('a'), KeyAction::InputMoveCursStart);
expect.0.insert(Key::Ctrl('e'), KeyAction::TabGoto('1'));
expect.0.insert(Key::Char('a'), KeyAction::Input('b'));
expect
.0
.insert(Key::Char('b'), KeyAction::RunCommand("clear".to_string()));

let key_map: KeyMap = serde_yaml::from_str(s).unwrap();
assert_eq!(expect, key_map);
Expand Down
14 changes: 14 additions & 0 deletions crates/libtiny_tui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,20 @@ async fn input_handler<S>(
return;
}
TUIRet::KeyHandled | TUIRet::KeyIgnored(_) | TUIRet::EventIgnored(_) => {}
TUIRet::KeyCommand { cmd, from } => {
let result = tui.borrow_mut().try_handle_cmd(&cmd, &from);
match result {
CmdResult::Ok => {}
CmdResult::Continue => {
snd_ev.try_send(Event::Cmd { cmd, source: from }).unwrap()
}
CmdResult::Quit(msg) => {
snd_ev.try_send(Event::Abort { msg }).unwrap();
let _ = snd_abort.try_send(());
return;
}
}
}
TUIRet::Input { msg, from } => {
if msg[0] == '/' {
// Handle TUI commands, send others to downstream
Expand Down
2 changes: 1 addition & 1 deletion crates/libtiny_tui/src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ impl MessagingUI {
self.msg_area.draw(tb, colors, pos_x, pos_y);
}

pub(crate) fn keypressed(&mut self, key_action: KeyAction) -> WidgetRet {
pub(crate) fn keypressed(&mut self, key_action: &KeyAction) -> WidgetRet {
match key_action {
KeyAction::Exit => {
self.toggle_exit_dialogue();
Expand Down
11 changes: 10 additions & 1 deletion crates/libtiny_tui/src/tui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ pub(crate) enum TUIRet {
KeyIgnored(Key),
EventIgnored(Event),

KeyCommand {
cmd: String,
from: MsgSource,
},

/// INVARIANT: The vec will have at least one char.
// Can't make MsgSource a ref because of this weird error:
// https://users.rust-lang.org/t/borrow-checker-bug/5165
Expand Down Expand Up @@ -670,9 +675,13 @@ impl TUI {
});

if let Some(key_action) = key_action {
match self.tabs[self.active_idx].widget.keypressed(key_action) {
match self.tabs[self.active_idx].widget.keypressed(&key_action) {
WidgetRet::KeyHandled => TUIRet::KeyHandled,
WidgetRet::KeyIgnored => self.handle_keypress(key, key_action, rcv_editor_ret),
WidgetRet::Command(cmd) => TUIRet::KeyCommand {
cmd,
from: self.tabs[self.active_idx].src.clone(),
},
WidgetRet::Input(input) => TUIRet::Input {
msg: input,
from: self.tabs[self.active_idx].src.clone(),
Expand Down
3 changes: 3 additions & 0 deletions crates/libtiny_tui/src/widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ pub(crate) enum WidgetRet {
/// An input is submitted.
Input(Vec<char>),

/// A command is ran
Command(String),

/// Remove the widget. E.g. close the tab, hide the dialogue etc.
Remove,

Expand Down

0 comments on commit 66a1014

Please sign in to comment.