summaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/input/mod.rs
blob: 2fb7deaf762ee89a37d91046cf82a87cd7e114aa (plain)
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
//! The way terminal input is handled.

pub mod actions;
pub mod command;
pub mod config;
pub mod keybinds;
pub mod layout;
pub mod mouse;
pub mod options;
pub mod plugins;
pub mod theme;

use crate::envs;
use termwiz::input::{InputEvent, InputParser, KeyCode, KeyEvent, Modifiers};
use zellij_tile::{
    data::{InputMode, Key, ModeInfo, PluginCapabilities},
    prelude::{CharOrArrow, Direction, Style},
};

/// Creates a [`ModeInfo`] struct indicating the current [`InputMode`] and its keybinds
/// (as pairs of [`String`]s).
pub fn get_mode_info(mode: InputMode, style: Style, capabilities: PluginCapabilities) -> ModeInfo {
    let keybinds = match mode {
        InputMode::Normal | InputMode::Locked | InputMode::Prompt => Vec::new(),
        InputMode::Resize => vec![
            ("←↓↑→".to_string(), "Resize".to_string()),
            ("+-".to_string(), "Increase/Decrease size".to_string()),
        ],
        InputMode::Move => vec![
            ("←↓↑→".to_string(), "Move".to_string()),
            ("n/Tab".to_string(), "Next Pane".to_string()),
        ],
        InputMode::Pane => vec![
            ("←↓↑→".to_string(), "Move focus".to_string()),
            ("n".to_string(), "New".to_string()),
            ("d".to_string(), "Down split".to_string()),
            ("r".to_string(), "Right split".to_string()),
            ("x".to_string(), "Close".to_string()),
            ("f".to_string(), "Fullscreen".to_string()),
            ("z".to_string(), "Frames".to_string()),
            ("c".to_string(), "Rename".to_string()),
            ("w".to_string(), "Floating Toggle".to_string()),
            ("e".to_string(), "Embed Pane".to_string()),
            ("p".to_string(), "Next".to_string()),
        ],
        InputMode::Tab => vec![
            ("←↓↑→".to_string(), "Move focus".to_string()),
            ("n".to_string(), "New".to_string()),
            ("x".to_string(), "Close".to_string()),
            ("r".to_string(), "Rename".to_string()),
            ("s".to_string(), "Sync".to_string()),
            ("Tab".to_string(), "Toggle".to_string()),
        ],
        InputMode::Scroll => vec![
            ("↓↑".to_string(), "Scroll".to_string()),
            ("PgUp/PgDn".to_string(), "Scroll Page".to_string()),
            ("u/d".to_string(), "Scroll Half Page".to_string()),
        ],
        InputMode::RenameTab => vec![("Enter".to_string(), "when done".to_string())],
        InputMode::RenamePane => vec![("Enter".to_string(), "when done".to_string())],
        InputMode::Session => vec![("d".to_string(), "Detach".to_string())],
        InputMode::Tmux => vec![
            ("←↓↑→".to_string(), "Move focus".to_string()),
            ("\"".to_string(), "Split Down".to_string()),
            ("%".to_string(), "Split Right".to_string()),
            ("z".to_string(), "Fullscreen".to_string()),
            ("c".to_string(), "New Tab".to_string()),
            (",".to_string(), "Rename Tab".to_string()),
            ("p".to_string(), "Previous Tab".to_string()),
            ("n".to_string(), "Next Tab".to_string()),
        ],
    };

    let session_name = envs::get_session_name().ok();

    ModeInfo {
        mode,
        keybinds,
        style,
        capabilities,
        session_name,
    }
}

pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> {
    let mut ret = vec![];
    let mut input_parser = InputParser::new(); // this is the termwiz InputParser
    let maybe_more = false;
    let parse_input_event = |input_event: InputEvent| {
        if let InputEvent::Key(key_event) = input_event {
            ret.push(cast_termwiz_key(key_event, input_bytes));
        }
    };
    input_parser.parse(input_bytes, parse_input_event, maybe_more);
    ret
}

// FIXME: This is an absolutely cursed function that should be destroyed as soon
// as an alternative that doesn't touch zellij-tile can be developed...
pub fn cast_termwiz_key(event: KeyEvent, raw_bytes: &[u8]) -> Key {
    let modifiers = event.modifiers;

    // *** THIS IS WHERE WE SHOULD WORK AROUND ISSUES WITH TERMWIZ ***
    if raw_bytes == [8] {
        return Key::Ctrl('h');
    };

    match event.key {
        KeyCode::Char(c) => {
            if modifiers.contains(Modifiers::CTRL) {
                Key::Ctrl(c.to_lowercase().next().unwrap_or_default())
            } else if modifiers.contains(Modifiers::ALT) {
                Key::Alt(CharOrArrow::Char(c))
            } else {
                Key::Char(c)
            }
        }
        KeyCode::Backspace => Key::Backspace,
        KeyCode::LeftArrow | KeyCode::ApplicationLeftArrow => {
            if modifiers.contains(Modifiers::ALT) {
                Key::Alt(CharOrArrow::Direction(Direction::Left))
            } else {
                Key::Left
            }
        }
        KeyCode::RightArrow | KeyCode::ApplicationRightArrow => {
            if modifiers.contains(Modifiers::ALT) {
                Key::Alt(CharOrArrow::Direction(Direction::Right))
            } else {
                Key::Right
            }
        }
        KeyCode::UpArrow | KeyCode::ApplicationUpArrow => {
            if modifiers.contains(Modifiers::ALT) {
                //Key::AltPlusUpArrow
                Key::Alt(CharOrArrow::Direction(Direction::Up))
            } else {
                Key::Up
            }
        }
        KeyCode::DownArrow | KeyCode::ApplicationDownArrow => {
            if modifiers.contains(Modifiers::ALT) {
                Key::Alt(CharOrArrow::Direction(Direction::Down))
            } else {
                Key::Down
            }
        }
        KeyCode::Home => Key::Home,
        KeyCode::End => Key::End,
        KeyCode::PageUp => Key::PageUp,
        KeyCode::PageDown => Key::PageDown,
        KeyCode::Tab => Key::BackTab, // TODO: ???
        KeyCode::Delete => Key::Delete,
        KeyCode::Insert => Key::Insert,
        KeyCode::Function(n) => Key::F(n),
        KeyCode::Escape => Key::Esc,
        KeyCode::Enter => Key::Char('\n'),
        _ => Key::Esc, // there are other keys we can implement here, but we might need additional terminal support to implement them, not just exhausting this enum
    }
}