use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::time::Duration;
pub mod defaults;
pub mod leader;
pub mod stack;
pub use defaults::{
default_copy_mode_table, default_resize_mode_table, default_search_mode_table, KeyTableRegistry,
};
pub use leader::{LeaderKeyConfig, LeaderKeyState};
pub use stack::{KeyTableActivation, KeyTableStack};
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct KeyTable {
pub name: String,
pub bindings: HashMap<KeyCombo, KeyAction>,
}
impl KeyTable {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
bindings: HashMap::new(),
}
}
pub fn bind(&mut self, combo: KeyCombo, action: KeyAction) {
self.bindings.insert(combo, action);
}
pub fn get(&self, combo: &KeyCombo) -> Option<&KeyAction> {
self.bindings.get(combo)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct KeyCombo {
pub key: KeyCode,
pub mods: KeyModifiers,
}
impl KeyCombo {
pub fn new(key: KeyCode, mods: KeyModifiers) -> Self {
Self { key, mods }
}
pub fn key(key: KeyCode) -> Self {
Self {
key,
mods: KeyModifiers::NONE,
}
}
pub fn ctrl(key: KeyCode) -> Self {
Self {
key,
mods: KeyModifiers::CTRL,
}
}
pub fn shift(key: KeyCode) -> Self {
Self {
key,
mods: KeyModifiers::SHIFT,
}
}
pub fn alt(key: KeyCode) -> Self {
Self {
key,
mods: KeyModifiers::ALT,
}
}
pub fn super_key(key: KeyCode) -> Self {
Self {
key,
mods: KeyModifiers::SUPER,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum KeyCode {
KeyA,
KeyB,
KeyC,
KeyD,
KeyE,
KeyF,
KeyG,
KeyH,
KeyI,
KeyJ,
KeyK,
KeyL,
KeyM,
KeyN,
KeyO,
KeyP,
KeyQ,
KeyR,
KeyS,
KeyT,
KeyU,
KeyV,
KeyW,
KeyX,
KeyY,
KeyZ,
Digit0,
Digit1,
Digit2,
Digit3,
Digit4,
Digit5,
Digit6,
Digit7,
Digit8,
Digit9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
Escape,
Enter,
Tab,
Backspace,
Space,
Slash,
Left,
Right,
Up,
Down,
Home,
End,
PageUp,
PageDown,
Insert,
Delete,
ControlLeft,
ControlRight,
AltLeft,
AltRight,
ShiftLeft,
ShiftRight,
SuperLeft,
SuperRight,
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct KeyModifiers: u8 {
const NONE = 0;
const CTRL = 1 << 0;
const ALT = 1 << 1;
const SHIFT = 1 << 2;
const SUPER = 1 << 3;
const LEADER = 1 << 4;
}
}
impl KeyModifiers {
pub fn ctrl(self) -> bool {
self.contains(KeyModifiers::CTRL)
}
pub fn alt(self) -> bool {
self.contains(KeyModifiers::ALT)
}
pub fn shift(self) -> bool {
self.contains(KeyModifiers::SHIFT)
}
pub fn super_key(self) -> bool {
self.contains(KeyModifiers::SUPER)
}
pub fn leader(self) -> bool {
self.contains(KeyModifiers::LEADER)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ActivateKeyTableMode {
Persistent,
OneShot,
Timeout(Duration),
UntilAction(Box<KeyAction>),
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum KeyAction {
ActivateKeyTable {
name: String,
mode: ActivateKeyTableMode,
replace_current: bool,
},
PopKeyTable,
ClearKeyTableStack,
ActivatePaneDirection(Direction),
AdjustPaneSize { direction: Direction, amount: i32 },
SplitPane { direction: SplitDirection },
ClosePane,
ZoomPane,
ActivateTab(i32),
ActivateTabRelative(i32),
SpawnTab,
CloseTab,
MoveTab(i32),
SpawnWindow,
CloseWindow,
ToggleFullscreen,
SendString(String),
SendKey { key: KeyCode, mods: KeyModifiers },
ScrollByPage(i32),
ScrollByLine(i32),
ScrollToTop,
ScrollToBottom,
ClearScrollback,
Copy,
Paste,
CopyTo(ClipboardKind),
PasteFrom(ClipboardKind),
ActivateCopyMode,
ActivateSearchMode,
CopyMode(CopyModeAction),
Search(SearchAction),
EmitEvent { event: String, args: Vec<String> },
RunCommand(String),
Noop,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Direction {
Left,
Right,
Up,
Down,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum SplitDirection {
Horizontal,
Vertical,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ClipboardKind {
Primary,
Clipboard,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum CopyModeAction {
MoveLeft,
MoveRight,
MoveUp,
MoveDown,
MoveWordForward,
MoveWordBackward,
MoveToLineStart,
MoveToLineEnd,
MoveToTop,
MoveToBottom,
ToggleSelection,
ToggleLineSelection,
ToggleBlockSelection,
SearchForward,
SearchBackward,
NextMatch,
PrevMatch,
CopyAndExit,
Exit,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum SearchAction {
Confirm,
Cancel,
NextMatch,
PrevMatch,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_key_modifiers_flags() {
let mods = KeyModifiers::CTRL | KeyModifiers::SHIFT;
assert!(mods.ctrl());
assert!(mods.shift());
assert!(!mods.alt());
assert!(!mods.super_key());
assert!(!mods.leader());
}
#[test]
fn test_key_modifiers_none() {
let mods = KeyModifiers::NONE;
assert!(!mods.ctrl());
assert!(!mods.alt());
assert!(!mods.shift());
assert!(!mods.super_key());
assert!(!mods.leader());
}
#[test]
fn test_key_combo_equality() {
let combo1 = KeyCombo::new(KeyCode::KeyH, KeyModifiers::CTRL);
let combo2 = KeyCombo::new(KeyCode::KeyH, KeyModifiers::CTRL);
let combo3 = KeyCombo::new(KeyCode::KeyH, KeyModifiers::ALT);
assert_eq!(combo1, combo2);
assert_ne!(combo1, combo3);
}
#[test]
fn test_key_table_binding() {
let mut table = KeyTable::new("test");
let combo = KeyCombo::new(KeyCode::KeyH, KeyModifiers::NONE);
let action = KeyAction::Noop;
table.bind(combo.clone(), action.clone());
assert_eq!(table.get(&combo), Some(&action));
}
#[test]
fn test_key_combo_hash() {
use std::collections::HashSet;
let mut set = HashSet::new();
let combo = KeyCombo::new(KeyCode::KeyA, KeyModifiers::CTRL);
set.insert(combo.clone());
assert!(set.contains(&combo));
}
}