aboutsummaryrefslogtreecommitdiffstats
path: root/src/common/input
diff options
context:
space:
mode:
authorBrooks Rady <b.j.rady@gmail.com>2021-03-26 13:20:06 +0000
committerGitHub <noreply@github.com>2021-03-26 13:20:06 +0000
commitd818661c727a59312e1a43432e84fbeec79fc145 (patch)
treee8ab04124ee7f5c87cd88be63c1867c7d9b2289c /src/common/input
parentfix(render): various rendering issues (#238) (diff)
parentFix some overzealous format!() removals and a stray comment (diff)
downloadsl0ppij-d818661c727a59312e1a43432e84fbeec79fc145.tar.gz
sl0ppij-d818661c727a59312e1a43432e84fbeec79fc145.tar.xz
sl0ppij-d818661c727a59312e1a43432e84fbeec79fc145.zip
feat(plugin): refactored to a new and more general plugin API
- Changed `init()` to `load()` - Deduplicated structs that are in both `zellij` and `zellij-tile` - WASM thread now keeps a mapping of plugins and event subscriptions - Added host-functions for subscribing and unsubscribing from events - Introduced the `update(event)` callback into the API (which is called to handle plugin events) - Made mode changes send an event to the WASM thread - Removed the `AppInstruction::Get/SetState` calls (and any global state) - Removed the `get_help()` host function - Added an event system for key-presses - Added an event for updating tabs - Ported support for renaming tabs - Removed every plugin callback other than `load()`, `update(event)`, and `draw(rows, cols)` - Removed every WASM thread event other than Load, Draw, Update, Unload, and Quit - Calls render after a plugin is updated - Switched back to upstream `termion` - Loads of lint fixing - Shrunk and simplified the code!
Diffstat (limited to 'src/common/input')
-rw-r--r--src/common/input/actions.rs5
-rw-r--r--src/common/input/handler.rs128
-rw-r--r--src/common/input/keybinds.rs14
3 files changed, 59 insertions, 88 deletions
diff --git a/src/common/input/actions.rs b/src/common/input/actions.rs
index 88a7036f..f4226864 100644
--- a/src/common/input/actions.rs
+++ b/src/common/input/actions.rs
@@ -1,6 +1,6 @@
//! Definition of the actions that can be bound to keys.
-use super::handler;
+use zellij_tile::data::InputMode;
/// The four directions (left, right, up, down).
#[derive(Clone, Debug)]
@@ -19,7 +19,7 @@ pub enum Action {
/// Write to the terminal.
Write(Vec<u8>),
/// Switch to the specified input mode.
- SwitchToMode(handler::InputMode),
+ SwitchToMode(InputMode),
/// Resize focus pane in specified direction.
Resize(Direction),
/// Switch focus to next pane in specified direction.
@@ -49,5 +49,4 @@ pub enum Action {
CloseTab,
GoToTab(u32),
TabNameInput(Vec<u8>),
- SaveTabName,
}
diff --git a/src/common/input/handler.rs b/src/common/input/handler.rs
index 2d5e965f..33f4e5dc 100644
--- a/src/common/input/handler.rs
+++ b/src/common/input/handler.rs
@@ -2,17 +2,16 @@
use super::actions::Action;
use super::keybinds::get_default_keybinds;
-use crate::common::{update_state, AppInstruction, AppState, SenderWithContext, OPENCALLS};
+use crate::common::{AppInstruction, SenderWithContext, OPENCALLS};
use crate::errors::ContextType;
use crate::os_input_output::OsApi;
use crate::pty_bus::PtyInstruction;
use crate::screen::ScreenInstruction;
-use crate::wasm_vm::{EventType, PluginInputType, PluginInstruction};
+use crate::wasm_vm::PluginInstruction;
use crate::CommandIsExecuting;
-use serde::{Deserialize, Serialize};
-use strum_macros::EnumIter;
-use termion::input::TermReadEventsAndRaw;
+use termion::input::{TermRead, TermReadEventsAndRaw};
+use zellij_tile::data::{Event, InputMode, Key, ModeInfo};
use super::keybinds::key_to_actions;
@@ -62,27 +61,21 @@ impl InputHandler {
'input_loop: loop {
//@@@ I think this should actually just iterate over stdin directly
let stdin_buffer = self.os_input.read_from_stdin();
- drop(
- self.send_plugin_instructions
- .send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
- );
for key_result in stdin_buffer.events_and_raw() {
match key_result {
Ok((event, raw_bytes)) => match event {
termion::event::Event::Key(key) => {
+ let key = cast_termion_key(key);
// FIXME this explicit break is needed because the current test
// framework relies on it to not create dead threads that loop
// and eat up CPUs. Do not remove until the test framework has
// been revised. Sorry about this (@categorille)
- if {
- let mut should_break = false;
- for action in
- key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
- {
- should_break |= self.dispatch_action(action);
- }
- should_break
- } {
+ let mut should_break = false;
+ for action in key_to_actions(&key, raw_bytes, &self.mode, &keybinds)
+ {
+ should_break |= self.dispatch_action(action);
+ }
+ if should_break {
break 'input_loop;
}
}
@@ -130,11 +123,14 @@ impl InputHandler {
}
Action::SwitchToMode(mode) => {
self.mode = mode;
- update_state(&self.send_app_instructions, |_| AppState {
- input_mode: self.mode,
- });
+ self.send_plugin_instructions
+ .send(PluginInstruction::Update(
+ None,
+ Event::ModeUpdate(get_mode_info(mode)),
+ ))
+ .unwrap();
self.send_screen_instructions
- .send(ScreenInstruction::ChangeInputMode(self.mode))
+ .send(ScreenInstruction::ChangeInputMode(mode))
.unwrap();
self.send_screen_instructions
.send(ScreenInstruction::Render)
@@ -236,27 +232,10 @@ impl InputHandler {
.unwrap();
}
Action::TabNameInput(c) => {
- self.send_plugin_instructions
- .send(PluginInstruction::Input(
- PluginInputType::Event(EventType::Tab),
- c.clone(),
- ))
- .unwrap();
self.send_screen_instructions
.send(ScreenInstruction::UpdateTabName(c))
.unwrap();
}
- Action::SaveTabName => {
- self.send_plugin_instructions
- .send(PluginInstruction::Input(
- PluginInputType::Event(EventType::Tab),
- vec![b'\n'],
- ))
- .unwrap();
- self.send_screen_instructions
- .send(ScreenInstruction::UpdateTabName(vec![b'\n']))
- .unwrap();
- }
Action::NoOp => {}
}
@@ -272,45 +251,10 @@ impl InputHandler {
}
}
-/// Describes the different input modes, which change the way that keystrokes will be interpreted.
-#[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, EnumIter, Serialize, Deserialize)]
-pub enum InputMode {
- /// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading
- /// to other modes
- Normal,
- /// In `Locked` mode, input is always written to the terminal and all shortcuts are disabled
- /// except the one leading back to normal mode
- Locked,
- /// `Resize` mode allows resizing the different existing panes.
- Resize,
- /// `Pane` mode allows creating and closing panes, as well as moving between them.
- Pane,
- /// `Tab` mode allows creating and closing tabs, as well as moving between them.
- Tab,
- /// `Scroll` mode allows scrolling up and down within a pane.
- Scroll,
- RenameTab,
-}
-
-/// Represents the contents of the help message that is printed in the status bar,
-/// which indicates the current [`InputMode`] and what the keybinds for that mode
-/// are. Related to the default `status-bar` plugin.
-#[derive(Default, Debug, Clone, Serialize, Deserialize)]
-pub struct Help {
- pub mode: InputMode,
- pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description>
-}
-
-impl Default for InputMode {
- fn default() -> InputMode {
- InputMode::Normal
- }
-}
-
/// Creates a [`Help`] struct indicating the current [`InputMode`] and its keybinds
/// (as pairs of [`String`]s).
// TODO this should probably be automatically generated in some way
-pub fn get_help(mode: InputMode) -> Help {
+pub fn get_mode_info(mode: InputMode) -> ModeInfo {
let mut keybinds: Vec<(String, String)> = vec![];
match mode {
InputMode::Normal | InputMode::Locked => {}
@@ -339,7 +283,7 @@ pub fn get_help(mode: InputMode) -> Help {
keybinds.push(("Enter".to_string(), "when done".to_string()));
}
}
- Help { mode, keybinds }
+ ModeInfo { mode, keybinds }
}
/// Entry point to the module. Instantiates an [`InputHandler`] and starts
@@ -362,3 +306,35 @@ pub fn input_loop(
)
.handle_input();
}
+
+pub fn parse_keys(input_bytes: &[u8]) -> Vec<Key> {
+ input_bytes.keys().flatten().map(cast_termion_key).collect()
+}
+
+// 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...
+fn cast_termion_key(event: termion::event::Key) -> Key {
+ match event {
+ termion::event::Key::Backspace => Key::Backspace,
+ termion::event::Key::Left => Key::Left,
+ termion::event::Key::Right => Key::Right,
+ termion::event::Key::Up => Key::Up,
+ termion::event::Key::Down => Key::Down,
+ termion::event::Key::Home => Key::Home,
+ termion::event::Key::End => Key::End,
+ termion::event::Key::PageUp => Key::PageUp,
+ termion::event::Key::PageDown => Key::PageDown,
+ termion::event::Key::BackTab => Key::BackTab,
+ termion::event::Key::Delete => Key::Delete,
+ termion::event::Key::Insert => Key::Insert,
+ termion::event::Key::F(n) => Key::F(n),
+ termion::event::Key::Char(c) => Key::Char(c),
+ termion::event::Key::Alt(c) => Key::Alt(c),
+ termion::event::Key::Ctrl(c) => Key::Ctrl(c),
+ termion::event::Key::Null => Key::Null,
+ termion::event::Key::Esc => Key::Esc,
+ _ => {
+ unimplemented!("Encountered an unknown key!")
+ }
+ }
+}
diff --git a/src/common/input/keybinds.rs b/src/common/input/keybinds.rs
index 4b676037..7b1e8779 100644
--- a/src/common/input/keybinds.rs
+++ b/src/common/input/keybinds.rs
@@ -1,12 +1,11 @@
//! 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;
+use zellij_tile::data::*;
type Keybinds = HashMap<InputMode, ModeKeybinds>;
type ModeKeybinds = HashMap<Key, Vec<Action>>;
@@ -17,14 +16,14 @@ 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)?);
+ 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> {
+fn get_defaults_for_mode(mode: &InputMode) -> ModeKeybinds {
let mut defaults = ModeKeybinds::new();
match *mode {
@@ -227,10 +226,7 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
defaults.insert(Key::Up, vec![Action::ScrollUp]);
}
InputMode::RenameTab => {
- defaults.insert(
- Key::Char('\n'),
- vec![Action::SaveTabName, Action::SwitchToMode(InputMode::Tab)],
- );
+ defaults.insert(Key::Char('\n'), vec![Action::SwitchToMode(InputMode::Tab)]);
defaults.insert(
Key::Ctrl('g'),
vec![Action::SwitchToMode(InputMode::Normal)],
@@ -245,7 +241,7 @@ fn get_defaults_for_mode(mode: &InputMode) -> Result<ModeKeybinds, String> {
}
}
- Ok(defaults)
+ defaults
}
/// Converts a [`Key`] terminal event to a sequence of [`Action`]s according to the current