Initial implementation of the update callback + upstream termion

This commit is contained in:
Brooks J Rady 2021-03-23 19:52:59 +00:00
parent 9bc7a268ce
commit ac55e59047
10 changed files with 104 additions and 22 deletions

23
Cargo.lock generated
View File

@ -1269,12 +1269,6 @@ dependencies = [
"num_cpus", "num_cpus",
] ]
[[package]]
name = "redox_syscall"
version = "0.1.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.2.5" version = "0.2.5"
@ -1290,7 +1284,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f" checksum = "8440d8acb4fd3d277125b4bd01a6f38aee8d814b3b5fc09b3f2b825d37d3fe8f"
dependencies = [ dependencies = [
"redox_syscall 0.2.5", "redox_syscall",
] ]
[[package]] [[package]]
@ -1300,7 +1294,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"redox_syscall 0.2.5", "redox_syscall",
] ]
[[package]] [[package]]
@ -1621,7 +1615,7 @@ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"libc", "libc",
"rand", "rand",
"redox_syscall 0.2.5", "redox_syscall",
"remove_dir_all", "remove_dir_all",
"winapi", "winapi",
] ]
@ -1637,16 +1631,15 @@ dependencies = [
] ]
[[package]] [[package]]
name = "termion_temporary_zellij_fork" name = "termion"
version = "1.6.0" version = "1.5.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "65175afb01727f72d690bc8b2a2ac411c0243ec43988b7bd96d428301197bed0" checksum = "077185e2eac69c3f8379a4298e1e07cd36beb962290d4a51199acf0fdc10607e"
dependencies = [ dependencies = [
"libc", "libc",
"numtoa", "numtoa",
"redox_syscall 0.1.57", "redox_syscall",
"redox_termios", "redox_termios",
"serde",
] ]
[[package]] [[package]]
@ -2269,7 +2262,7 @@ dependencies = [
"strip-ansi-escapes", "strip-ansi-escapes",
"structopt", "structopt",
"strum", "strum",
"termion_temporary_zellij_fork", "termion",
"termios", "termios",
"toml", "toml",
"unicode-truncate", "unicode-truncate",

View File

@ -27,7 +27,7 @@ signal-hook = "0.1.10"
strip-ansi-escapes = "0.1.0" strip-ansi-escapes = "0.1.0"
structopt = "0.3" structopt = "0.3"
# termion = { git = "https://gitlab.com/TheLostLambda/termion.git", version = "1.6.0", features = ["serde"] } # termion = { git = "https://gitlab.com/TheLostLambda/termion.git", version = "1.6.0", features = ["serde"] }
termion = { package = "termion_temporary_zellij_fork", version = "1.6.0", features = ["serde"]} termion = "1.5.0"
termios = "0.3" termios = "0.3"
unicode-truncate = "0.2.0" unicode-truncate = "0.2.0"
unicode-width = "0.1.8" unicode-width = "0.1.8"

View File

@ -278,6 +278,7 @@ use crate::wasm_vm::PluginInstruction;
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq)]
pub enum PluginContext { pub enum PluginContext {
Load, Load,
Update,
Render, Render,
Input, Input,
GlobalInput, GlobalInput,
@ -290,6 +291,7 @@ impl From<&PluginInstruction> for PluginContext {
fn from(plugin_instruction: &PluginInstruction) -> Self { fn from(plugin_instruction: &PluginInstruction) -> Self {
match *plugin_instruction { match *plugin_instruction {
PluginInstruction::Load(..) => PluginContext::Load, PluginInstruction::Load(..) => PluginContext::Load,
PluginInstruction::Update(_) => PluginContext::Update,
PluginInstruction::Render(..) => PluginContext::Render, PluginInstruction::Render(..) => PluginContext::Render,
PluginInstruction::Input(..) => PluginContext::Input, PluginInstruction::Input(..) => PluginContext::Input,
PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput, PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput,

View File

@ -11,7 +11,7 @@ use crate::wasm_vm::{NaughtyEventType, PluginInputType, PluginInstruction};
use crate::CommandIsExecuting; use crate::CommandIsExecuting;
use termion::input::TermReadEventsAndRaw; use termion::input::TermReadEventsAndRaw;
use zellij_tile::data::{Help, InputMode}; use zellij_tile::data::{Event, Help, InputMode, Key};
use super::keybinds::key_to_actions; use super::keybinds::key_to_actions;
@ -61,6 +61,7 @@ impl InputHandler {
'input_loop: loop { 'input_loop: loop {
//@@@ I think this should actually just iterate over stdin directly //@@@ I think this should actually just iterate over stdin directly
let stdin_buffer = self.os_input.read_from_stdin(); let stdin_buffer = self.os_input.read_from_stdin();
// FIXME: Kill me someday (soon)
drop( drop(
self.send_plugin_instructions self.send_plugin_instructions
.send(PluginInstruction::GlobalInput(stdin_buffer.clone())), .send(PluginInstruction::GlobalInput(stdin_buffer.clone())),
@ -69,6 +70,11 @@ impl InputHandler {
match key_result { match key_result {
Ok((event, raw_bytes)) => match event { Ok((event, raw_bytes)) => match event {
termion::event::Event::Key(key) => { termion::event::Event::Key(key) => {
let key = cast_termion_key(key);
drop(
self.send_plugin_instructions
.send(PluginInstruction::Update(Event::KeyPress(key))),
);
// FIXME this explicit break is needed because the current test // FIXME this explicit break is needed because the current test
// framework relies on it to not create dead threads that loop // framework relies on it to not create dead threads that loop
// and eat up CPUs. Do not remove until the test framework has // and eat up CPUs. Do not remove until the test framework has
@ -320,3 +326,31 @@ pub fn input_loop(
) )
.handle_input(); .handle_input();
} }
// 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!")
}
}
}

View File

@ -5,7 +5,6 @@ use super::actions::{Action, Direction};
use std::collections::HashMap; use std::collections::HashMap;
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use termion::event::Key;
use zellij_tile::data::*; use zellij_tile::data::*;
type Keybinds = HashMap<InputMode, ModeKeybinds>; type Keybinds = HashMap<InputMode, ModeKeybinds>;

View File

@ -40,7 +40,7 @@ use wasm_vm::{
}; };
use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
use wasmer_wasi::{Pipe, WasiState}; use wasmer_wasi::{Pipe, WasiState};
use zellij_tile::data::InputMode; use zellij_tile::data::{InputMode, Key};
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub enum ApiCommand { pub enum ApiCommand {
@ -456,6 +456,33 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
.collect(); .collect();
move || loop { move || loop {
// FIXME: This 100% *must* be destroyed before this makes in into main!!!!!!!!!!!
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!")
}
}
}
let (event, mut err_ctx) = receive_plugin_instructions let (event, mut err_ctx) = receive_plugin_instructions
.recv() .recv()
.expect("failed to receive event on channel"); .expect("failed to receive event on channel");
@ -522,6 +549,17 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
pid_tx.send(plugin_id).unwrap(); pid_tx.send(plugin_id).unwrap();
plugin_id += 1; plugin_id += 1;
} }
PluginInstruction::Update(event) => {
for (instance, plugin_env) in plugin_map.values() {
let update = instance.exports.get_function("update").unwrap();
wasi_write_string(
&plugin_env.wasi_env,
&serde_json::to_string(&event).unwrap(),
);
update.call(&[]).unwrap();
}
}
PluginInstruction::Render(buf_tx, pid, rows, cols) => { PluginInstruction::Render(buf_tx, pid, rows, cols) => {
let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
@ -555,6 +593,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let handle_key = let handle_key =
instance.exports.get_function("handle_key").unwrap(); instance.exports.get_function("handle_key").unwrap();
for key in input_bytes.keys().flatten() { for key in input_bytes.keys().flatten() {
let key = cast_termion_key(key);
wasi_write_string( wasi_write_string(
&plugin_env.wasi_env, &plugin_env.wasi_env,
&serde_json::to_string(&key).unwrap(), &serde_json::to_string(&key).unwrap(),
@ -572,6 +611,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
.get_function(handler_map.get(&event).unwrap()) .get_function(handler_map.get(&event).unwrap())
.unwrap(); .unwrap();
for key in input_bytes.keys().flatten() { for key in input_bytes.keys().flatten() {
let key = cast_termion_key(key);
wasi_write_string( wasi_write_string(
&plugin_env.wasi_env, &plugin_env.wasi_env,
&serde_json::to_string(&key).unwrap(), &serde_json::to_string(&key).unwrap(),
@ -589,6 +629,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let handler = let handler =
instance.exports.get_function("handle_global_key").unwrap(); instance.exports.get_function("handle_global_key").unwrap();
for key in input_bytes.keys().flatten() { for key in input_bytes.keys().flatten() {
let key = cast_termion_key(key);
wasi_write_string( wasi_write_string(
&plugin_env.wasi_env, &plugin_env.wasi_env,
&serde_json::to_string(&key).unwrap(), &serde_json::to_string(&key).unwrap(),

View File

@ -9,7 +9,7 @@ use std::{
}; };
use wasmer::{imports, Function, ImportObject, Store, WasmerEnv}; use wasmer::{imports, Function, ImportObject, Store, WasmerEnv};
use wasmer_wasi::WasiEnv; use wasmer_wasi::WasiEnv;
use zellij_tile::data::{EventType, TabInfo}; use zellij_tile::data::{Event, EventType, TabInfo};
use super::{ use super::{
input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, input::handler::get_help, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction,
@ -30,6 +30,7 @@ pub enum PluginInputType {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PluginInstruction { pub enum PluginInstruction {
Load(Sender<u32>, PathBuf, Vec<NaughtyEventType>), Load(Sender<u32>, PathBuf, Vec<NaughtyEventType>),
Update(Event),
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
Input(PluginInputType, Vec<u8>), // plugin id, input bytes Input(PluginInputType, Vec<u8>), // plugin id, input bytes
GlobalInput(Vec<u8>), // input bytes GlobalInput(Vec<u8>), // input bytes

View File

@ -23,7 +23,7 @@ pub enum Key {
Esc, Esc,
} }
#[derive(Debug, EnumDiscriminants, ToString, Serialize, Deserialize)] #[derive(Debug, Clone, EnumDiscriminants, ToString, Serialize, Deserialize)]
#[strum_discriminants(derive(Hash, Serialize, Deserialize))] #[strum_discriminants(derive(Hash, Serialize, Deserialize))]
#[strum_discriminants(name(EventType))] #[strum_discriminants(name(EventType))]
pub enum Event { pub enum Event {

View File

@ -7,6 +7,7 @@ use data::*;
#[allow(unused_variables)] #[allow(unused_variables)]
pub trait ZellijTile { pub trait ZellijTile {
fn load(&mut self) {} fn load(&mut self) {}
fn update(&mut self, event: Event) {}
fn render(&mut self, rows: usize, cols: usize) {} fn render(&mut self, rows: usize, cols: usize) {}
// FIXME: Everything below this line should be purged // FIXME: Everything below this line should be purged
fn handle_key(&mut self, key: Key) {} fn handle_key(&mut self, key: Key) {}
@ -28,6 +29,15 @@ macro_rules! register_tile {
}); });
} }
#[no_mangle]
pub fn update() {
STATE.with(|state| {
state
.borrow_mut()
.update($crate::shim::deserialize_from_stdin().unwrap());
});
}
#[no_mangle] #[no_mangle]
pub fn render(rows: i32, cols: i32) { pub fn render(rows: i32, cols: i32) {
STATE.with(|state| { STATE.with(|state| {

View File

@ -45,7 +45,9 @@ pub fn get_tabs() -> Vec<TabInfo> {
deserialize_from_stdin().unwrap_or_default() deserialize_from_stdin().unwrap_or_default()
} }
fn deserialize_from_stdin<T: DeserializeOwned>() -> Option<T> { #[doc(hidden)]
// FIXME: Make this just return T and do a .unwrap() at the end; also naming?
pub fn deserialize_from_stdin<T: DeserializeOwned>() -> Option<T> {
let mut json = String::new(); let mut json = String::new();
io::stdin().read_line(&mut json).unwrap(); io::stdin().read_line(&mut json).unwrap();
serde_json::from_str(&json).ok() serde_json::from_str(&json).ok()