diff options
| author | Brooks Rady <b.j.rady@gmail.com> | 2021-03-26 13:20:06 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-03-26 13:20:06 +0000 |
| commit | d818661c727a59312e1a43432e84fbeec79fc145 (patch) | |
| tree | e8ab04124ee7f5c87cd88be63c1867c7d9b2289c /src/common/input | |
| parent | fix(render): various rendering issues (#238) (diff) | |
| parent | Fix some overzealous format!() removals and a stray comment (diff) | |
| download | sl0ppij-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.rs | 5 | ||||
| -rw-r--r-- | src/common/input/handler.rs | 128 | ||||
| -rw-r--r-- | src/common/input/keybinds.rs | 14 |
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 |
