mirror of
https://github.com/zellij-org/zellij.git
synced 2024-11-23 08:57:14 +03:00
Move most key handling to the update() + event system
This commit is contained in:
parent
ac55e59047
commit
23df8e447a
@ -10,6 +10,41 @@ register_tile!(State);
|
||||
impl ZellijTile for State {
|
||||
fn load(&mut self) {
|
||||
refresh_directory(self);
|
||||
subscribe(&[EventType::KeyPress]);
|
||||
}
|
||||
|
||||
fn update(&mut self, event: Event) {
|
||||
if let Event::KeyPress(key) = event {
|
||||
match key {
|
||||
Key::Up | Key::Char('k') => {
|
||||
*self.selected_mut() = self.selected().saturating_sub(1);
|
||||
}
|
||||
Key::Down | Key::Char('j') => {
|
||||
let next = self.selected().saturating_add(1);
|
||||
*self.selected_mut() = min(self.files.len() - 1, next);
|
||||
}
|
||||
Key::Right | Key::Char('\n') | Key::Char('l') => {
|
||||
match self.files[self.selected()].clone() {
|
||||
FsEntry::Dir(p, _) => {
|
||||
self.path = p;
|
||||
refresh_directory(self);
|
||||
}
|
||||
FsEntry::File(p, _) => open_file(&p),
|
||||
}
|
||||
}
|
||||
Key::Left | Key::Char('h') => {
|
||||
self.path.pop();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
Key::Char('.') => {
|
||||
self.toggle_hidden_files();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn render(&mut self, rows: usize, cols: usize) {
|
||||
@ -38,38 +73,6 @@ impl ZellijTile for State {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_key(&mut self, key: Key) {
|
||||
match key {
|
||||
Key::Up | Key::Char('k') => {
|
||||
*self.selected_mut() = self.selected().saturating_sub(1);
|
||||
}
|
||||
Key::Down | Key::Char('j') => {
|
||||
let next = self.selected().saturating_add(1);
|
||||
*self.selected_mut() = min(self.files.len() - 1, next);
|
||||
}
|
||||
Key::Right | Key::Char('\n') | Key::Char('l') => {
|
||||
match self.files[self.selected()].clone() {
|
||||
FsEntry::Dir(p, _) => {
|
||||
self.path = p;
|
||||
refresh_directory(self);
|
||||
}
|
||||
FsEntry::File(p, _) => open_file(&p),
|
||||
}
|
||||
}
|
||||
Key::Left | Key::Char('h') => {
|
||||
self.path.pop();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
Key::Char('.') => {
|
||||
self.toggle_hidden_files();
|
||||
refresh_directory(self);
|
||||
}
|
||||
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_directory(state: &mut State) {
|
||||
|
@ -1,11 +1,11 @@
|
||||
//! `Tab`s holds multiple panes. It tracks their coordinates (x/y) and size,
|
||||
//! as well as how they should be resized
|
||||
|
||||
use crate::common::{AppInstruction, SenderWithContext};
|
||||
use crate::common::{input::handler::parse_keys, AppInstruction, SenderWithContext};
|
||||
use crate::layout::Layout;
|
||||
use crate::panes::{PaneId, PositionAndSize, TerminalPane};
|
||||
use crate::pty_bus::{PtyInstruction, VteEvent};
|
||||
use crate::wasm_vm::{PluginInputType, PluginInstruction};
|
||||
use crate::wasm_vm::PluginInstruction;
|
||||
use crate::{boundaries::Boundaries, panes::PluginPane};
|
||||
use crate::{os_input_output::OsApi, utils::shared::pad_to_size};
|
||||
use std::os::unix::io::RawFd;
|
||||
@ -14,6 +14,7 @@ use std::{
|
||||
collections::{BTreeMap, HashSet},
|
||||
};
|
||||
use std::{io::Write, sync::mpsc::channel};
|
||||
use zellij_tile::data::Event;
|
||||
|
||||
const CURSOR_HEIGHT_WIDTH_RATIO: usize = 4; // this is not accurate and kind of a magic number, TODO: look into this
|
||||
const MIN_TERMINAL_HEIGHT: usize = 2;
|
||||
@ -553,12 +554,11 @@ impl Tab {
|
||||
.expect("failed to drain terminal");
|
||||
}
|
||||
Some(PaneId::Plugin(pid)) => {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Input(
|
||||
PluginInputType::Normal(pid),
|
||||
input_bytes,
|
||||
))
|
||||
.unwrap();
|
||||
for key in parse_keys(&input_bytes) {
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Update(Some(pid), Event::KeyPress(key)))
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -281,7 +281,6 @@ pub enum PluginContext {
|
||||
Update,
|
||||
Render,
|
||||
Input,
|
||||
GlobalInput,
|
||||
Unload,
|
||||
Quit,
|
||||
Tabs,
|
||||
@ -291,10 +290,9 @@ impl From<&PluginInstruction> for PluginContext {
|
||||
fn from(plugin_instruction: &PluginInstruction) -> Self {
|
||||
match *plugin_instruction {
|
||||
PluginInstruction::Load(..) => PluginContext::Load,
|
||||
PluginInstruction::Update(_) => PluginContext::Update,
|
||||
PluginInstruction::Update(..) => PluginContext::Update,
|
||||
PluginInstruction::Render(..) => PluginContext::Render,
|
||||
PluginInstruction::Input(..) => PluginContext::Input,
|
||||
PluginInstruction::GlobalInput(_) => PluginContext::GlobalInput,
|
||||
PluginInstruction::Unload(_) => PluginContext::Unload,
|
||||
PluginInstruction::Quit => PluginContext::Quit,
|
||||
PluginInstruction::UpdateTabs(..) => PluginContext::Tabs,
|
||||
|
@ -10,8 +10,8 @@ use crate::screen::ScreenInstruction;
|
||||
use crate::wasm_vm::{NaughtyEventType, PluginInputType, PluginInstruction};
|
||||
use crate::CommandIsExecuting;
|
||||
|
||||
use termion::input::TermReadEventsAndRaw;
|
||||
use zellij_tile::data::{Event, Help, InputMode, Key};
|
||||
use termion::input::{TermRead, TermReadEventsAndRaw};
|
||||
use zellij_tile::data::{Help, InputMode, Key};
|
||||
|
||||
use super::keybinds::key_to_actions;
|
||||
|
||||
@ -61,19 +61,15 @@ impl InputHandler {
|
||||
'input_loop: loop {
|
||||
//@@@ I think this should actually just iterate over stdin directly
|
||||
let stdin_buffer = self.os_input.read_from_stdin();
|
||||
// FIXME: Kill me someday (soon)
|
||||
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 is a bit of a hack to get resizing to work!
|
||||
drop(
|
||||
self.send_plugin_instructions
|
||||
.send(PluginInstruction::Update(Event::KeyPress(key))),
|
||||
self.send_screen_instructions
|
||||
.send(ScreenInstruction::Render),
|
||||
);
|
||||
// FIXME this explicit break is needed because the current test
|
||||
// framework relies on it to not create dead threads that loop
|
||||
@ -327,6 +323,10 @@ 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 {
|
||||
|
@ -17,6 +17,7 @@ use std::{collections::HashMap, fs};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
io::Write,
|
||||
str::FromStr,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
|
||||
@ -40,7 +41,7 @@ use wasm_vm::{
|
||||
};
|
||||
use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
|
||||
use wasmer_wasi::{Pipe, WasiState};
|
||||
use zellij_tile::data::{InputMode, Key};
|
||||
use zellij_tile::data::{EventType, InputMode, Key};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum ApiCommand {
|
||||
@ -549,16 +550,21 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||
pid_tx.send(plugin_id).unwrap();
|
||||
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::Update(pid, event) => {
|
||||
for (&i, (instance, plugin_env)) in &plugin_map {
|
||||
let subs = plugin_env.subscriptions.lock().unwrap();
|
||||
// FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType?
|
||||
let event_type = EventType::from_str(&event.to_string()).unwrap();
|
||||
if pid.is_none() || pid == Some(i) && subs.contains(&event_type) {
|
||||
let update = instance.exports.get_function("update").unwrap();
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&event).unwrap(),
|
||||
);
|
||||
update.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::Render(buf_tx, pid, rows, cols) => {
|
||||
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
|
||||
@ -587,11 +593,15 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||
}
|
||||
// FIXME: Deduplicate this with the callback below!
|
||||
PluginInstruction::Input(input_type, input_bytes) => {
|
||||
match input_type {
|
||||
PluginInputType::Normal(pid) => {
|
||||
let (instance, plugin_env) = plugin_map.get(&pid).unwrap();
|
||||
let handle_key =
|
||||
instance.exports.get_function("handle_key").unwrap();
|
||||
if let PluginInputType::Event(event) = input_type {
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
if !plugin_env.events.contains(&event) {
|
||||
continue;
|
||||
}
|
||||
let handle_key = instance
|
||||
.exports
|
||||
.get_function(handler_map.get(&event).unwrap())
|
||||
.unwrap();
|
||||
for key in input_bytes.keys().flatten() {
|
||||
let key = cast_termion_key(key);
|
||||
wasi_write_string(
|
||||
@ -601,45 +611,9 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
|
||||
handle_key.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
PluginInputType::Event(event) => {
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
if !plugin_env.events.contains(&event) {
|
||||
continue;
|
||||
}
|
||||
let handle_key = instance
|
||||
.exports
|
||||
.get_function(handler_map.get(&event).unwrap())
|
||||
.unwrap();
|
||||
for key in input_bytes.keys().flatten() {
|
||||
let key = cast_termion_key(key);
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handle_key.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::GlobalInput(input_bytes) => {
|
||||
// FIXME: Set up an event subscription system, and timed callbacks
|
||||
for (instance, plugin_env) in plugin_map.values() {
|
||||
let handler =
|
||||
instance.exports.get_function("handle_global_key").unwrap();
|
||||
for key in input_bytes.keys().flatten() {
|
||||
let key = cast_termion_key(key);
|
||||
wasi_write_string(
|
||||
&plugin_env.wasi_env,
|
||||
&serde_json::to_string(&key).unwrap(),
|
||||
);
|
||||
handler.call(&[]).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
drop(send_screen_instructions.send(ScreenInstruction::Render));
|
||||
}
|
||||
PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)),
|
||||
PluginInstruction::Quit => break,
|
||||
}
|
||||
|
@ -30,10 +30,9 @@ pub enum PluginInputType {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PluginInstruction {
|
||||
Load(Sender<u32>, PathBuf, Vec<NaughtyEventType>),
|
||||
Update(Event),
|
||||
Update(Option<u32>, Event), // Focused plugin / broadcast, event data
|
||||
Render(Sender<String>, u32, usize, usize), // String buffer, plugin id, rows, cols
|
||||
Input(PluginInputType, Vec<u8>), // plugin id, input bytes
|
||||
GlobalInput(Vec<u8>), // input bytes
|
||||
Input(PluginInputType, Vec<u8>), // plugin id, input bytes
|
||||
Unload(u32),
|
||||
UpdateTabs(Vec<TabInfo>), // num tabs, active tab
|
||||
Quit,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum_macros::{EnumDiscriminants, EnumIter, ToString};
|
||||
use strum_macros::{EnumDiscriminants, EnumIter, EnumString, ToString};
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub enum Key {
|
||||
@ -24,7 +24,7 @@ pub enum Key {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, EnumDiscriminants, ToString, Serialize, Deserialize)]
|
||||
#[strum_discriminants(derive(Hash, Serialize, Deserialize))]
|
||||
#[strum_discriminants(derive(EnumString, Hash, Serialize, Deserialize))]
|
||||
#[strum_discriminants(name(EventType))]
|
||||
pub enum Event {
|
||||
ModeUpdate(Help), // FIXME: Rename the `Help` struct
|
||||
|
@ -10,8 +10,6 @@ pub trait ZellijTile {
|
||||
fn update(&mut self, event: Event) {}
|
||||
fn render(&mut self, rows: usize, cols: usize) {}
|
||||
// FIXME: Everything below this line should be purged
|
||||
fn handle_key(&mut self, key: Key) {}
|
||||
fn handle_global_key(&mut self, key: Key) {}
|
||||
fn update_tabs(&mut self) {}
|
||||
fn handle_tab_rename_keypress(&mut self, key: Key) {}
|
||||
}
|
||||
@ -45,22 +43,6 @@ macro_rules! register_tile {
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn handle_key() {
|
||||
STATE.with(|state| {
|
||||
state.borrow_mut().handle_key($crate::shim::get_key());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn handle_global_key() {
|
||||
STATE.with(|state| {
|
||||
state
|
||||
.borrow_mut()
|
||||
.handle_global_key($crate::shim::get_key());
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn update_tabs() {
|
||||
STATE.with(|state| {
|
||||
|
Loading…
Reference in New Issue
Block a user