feat(plugin): added the get_plugin_ids() query function

This commit is contained in:
Brooks Rady 2021-04-27 15:34:26 +01:00 committed by GitHub
commit 9f567f721e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 71 additions and 34 deletions

View File

@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* Doesn't quit anymore on single `q` press while in tab mode (https://github.com/zellij-org/zellij/pull/342) * Doesn't quit anymore on single `q` press while in tab mode (https://github.com/zellij-org/zellij/pull/342)
* Completions are not assets anymore, but commands `option --generate-completion [shell]` (https://github.com/zellij-org/zellij/pull/369) * Completions are not assets anymore, but commands `option --generate-completion [shell]` (https://github.com/zellij-org/zellij/pull/369)
* Fixes in the default configuration `default.yaml` file. Adds initial tmux-compat keybindings `tmux.yaml` (https://github.com/zellij-org/zellij/pull/362) * Fixes in the default configuration `default.yaml` file. Adds initial tmux-compat keybindings `tmux.yaml` (https://github.com/zellij-org/zellij/pull/362)
* Added the `get_plugin_ids()` query function to the plugin API (https://github.com/zellij-org/zellij/pull/392)
## [0.5.1] - 2021-04-23 ## [0.5.1] - 2021-04-23
* Change config to flag (https://github.com/zellij-org/zellij/pull/300) * Change config to flag (https://github.com/zellij-org/zellij/pull/300)

2
Cargo.lock generated
View File

@ -2217,7 +2217,7 @@ dependencies = [
[[package]] [[package]]
name = "zellij-tile" name = "zellij-tile"
version = "1.0.0" version = "1.1.0"
dependencies = [ dependencies = [
"serde", "serde",
"serde_json", "serde_json",

View File

@ -36,7 +36,7 @@ lazy_static = "1.4.0"
wasmer = "1.0.0" wasmer = "1.0.0"
wasmer-wasi = "1.0.0" wasmer-wasi = "1.0.0"
interprocess = "1.0.1" interprocess = "1.0.1"
zellij-tile = { path = "zellij-tile/", version = "1.0.0" } zellij-tile = { path = "zellij-tile/", version = "1.1.0" }
[dependencies.async-std] [dependencies.async-std]
version = "1.3.0" version = "1.3.0"

View File

@ -40,8 +40,7 @@ use pty_bus::{PtyBus, PtyInstruction};
use screen::{Screen, ScreenInstruction}; use screen::{Screen, ScreenInstruction};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use utils::consts::ZELLIJ_IPC_PIPE; use utils::consts::ZELLIJ_IPC_PIPE;
use wasm_vm::PluginEnv; use wasm_vm::{wasi_stdout, wasi_write_json, zellij_exports, PluginEnv, PluginInstruction};
use wasm_vm::{wasi_stdout, wasi_write_string, zellij_imports, PluginInstruction};
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::{EventType, ModeInfo}; use zellij_tile::data::{EventType, ModeInfo};
@ -506,7 +505,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
subscriptions: Arc::new(Mutex::new(HashSet::new())), subscriptions: Arc::new(Mutex::new(HashSet::new())),
}; };
let zellij = zellij_imports(&store, &plugin_env); let zellij = zellij_exports(&store, &plugin_env);
let instance = Instance::new(&module, &zellij.chain_back(wasi)).unwrap(); let instance = Instance::new(&module, &zellij.chain_back(wasi)).unwrap();
let start = instance.exports.get_function("_start").unwrap(); let start = instance.exports.get_function("_start").unwrap();
@ -525,10 +524,7 @@ pub fn start(mut os_input: Box<dyn OsApi>, opts: CliArgs) {
let event_type = EventType::from_str(&event.to_string()).unwrap(); let event_type = EventType::from_str(&event.to_string()).unwrap();
if (pid.is_none() || pid == Some(i)) && subs.contains(&event_type) { if (pid.is_none() || pid == Some(i)) && subs.contains(&event_type) {
let update = instance.exports.get_function("update").unwrap(); let update = instance.exports.get_function("update").unwrap();
wasi_write_string( wasi_write_json(&plugin_env.wasi_env, &event);
&plugin_env.wasi_env,
&serde_json::to_string(&event).unwrap(),
);
update.call(&[]).unwrap(); update.call(&[]).unwrap();
} }
} }

View File

@ -1,11 +1,13 @@
use serde::Serialize;
use std::{ use std::{
collections::HashSet, collections::HashSet,
path::PathBuf, path::PathBuf,
process,
sync::{mpsc::Sender, Arc, Mutex}, sync::{mpsc::Sender, Arc, Mutex},
}; };
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::{Event, EventType}; use zellij_tile::data::{Event, EventType, PluginIds};
use super::{ use super::{
pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, PaneId, SenderWithContext, pty_bus::PtyInstruction, screen::ScreenInstruction, AppInstruction, PaneId, SenderWithContext,
@ -32,17 +34,27 @@ pub struct PluginEnv {
// Plugin API --------------------------------------------------------------------------------------------------------- // Plugin API ---------------------------------------------------------------------------------------------------------
pub fn zellij_imports(store: &Store, plugin_env: &PluginEnv) -> ImportObject { pub fn zellij_exports(store: &Store, plugin_env: &PluginEnv) -> ImportObject {
imports! { macro_rules! zellij_export {
"zellij" => { ($($host_function:ident),+ $(,)?) => {
"host_subscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_subscribe), imports! {
"host_unsubscribe" => Function::new_native_with_env(store, plugin_env.clone(), host_unsubscribe), "zellij" => {
"host_open_file" => Function::new_native_with_env(store, plugin_env.clone(), host_open_file), $(stringify!($host_function) =>
"host_set_invisible_borders" => Function::new_native_with_env(store, plugin_env.clone(), host_set_invisible_borders), Function::new_native_with_env(store, plugin_env.clone(), $host_function),)+
"host_set_max_height" => Function::new_native_with_env(store, plugin_env.clone(), host_set_max_height), }
"host_set_selectable" => Function::new_native_with_env(store, plugin_env.clone(), host_set_selectable), }
} }
} }
zellij_export! {
host_subscribe,
host_unsubscribe,
host_set_invisible_borders,
host_set_max_height,
host_set_selectable,
host_get_plugin_ids,
host_open_file,
}
} }
fn host_subscribe(plugin_env: &PluginEnv) { fn host_subscribe(plugin_env: &PluginEnv) {
@ -57,14 +69,6 @@ fn host_unsubscribe(plugin_env: &PluginEnv) {
subscriptions.retain(|k| !old.contains(k)); subscriptions.retain(|k| !old.contains(k));
} }
fn host_open_file(plugin_env: &PluginEnv) {
let path = PathBuf::from(wasi_stdout(&plugin_env.wasi_env).lines().next().unwrap());
plugin_env
.send_pty_instructions
.send(PtyInstruction::SpawnTerminal(Some(path)))
.unwrap();
}
fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) { fn host_set_selectable(plugin_env: &PluginEnv, selectable: i32) {
let selectable = selectable != 0; let selectable = selectable != 0;
plugin_env plugin_env
@ -98,6 +102,22 @@ fn host_set_invisible_borders(plugin_env: &PluginEnv, invisible_borders: i32) {
.unwrap() .unwrap()
} }
fn host_get_plugin_ids(plugin_env: &PluginEnv) {
let ids = PluginIds {
plugin_id: plugin_env.plugin_id,
zellij_pid: process::id(),
};
wasi_write_json(&plugin_env.wasi_env, &ids);
}
fn host_open_file(plugin_env: &PluginEnv) {
let path = PathBuf::from(wasi_stdout(&plugin_env.wasi_env).lines().next().unwrap());
plugin_env
.send_pty_instructions
.send(PtyInstruction::SpawnTerminal(Some(path)))
.unwrap();
}
// Helper Functions --------------------------------------------------------------------------------------------------- // Helper Functions ---------------------------------------------------------------------------------------------------
// FIXME: Unwrap city // FIXME: Unwrap city
@ -114,3 +134,7 @@ pub fn wasi_write_string(wasi_env: &WasiEnv, buf: &str) {
let wasi_file = state.fs.stdin_mut().unwrap().as_mut().unwrap(); let wasi_file = state.fs.stdin_mut().unwrap().as_mut().unwrap();
writeln!(wasi_file, "{}\r", buf).unwrap(); writeln!(wasi_file, "{}\r", buf).unwrap();
} }
pub fn wasi_write_json(wasi_env: &WasiEnv, object: &impl Serialize) {
wasi_write_string(wasi_env, &serde_json::to_string(&object).unwrap());
}

View File

@ -1,6 +1,6 @@
[package] [package]
name = "zellij-tile" name = "zellij-tile"
version = "1.0.0" version = "1.1.0"
authors = ["Brooks J Rady <b.j.rady@gmail.com>"] authors = ["Brooks J Rady <b.j.rady@gmail.com>"]
edition = "2018" edition = "2018"
description = "A small client-side library for writing Zellij plugins" description = "A small client-side library for writing Zellij plugins"

View File

@ -23,9 +23,12 @@ pub enum Key {
Esc, Esc,
} }
#[derive(Debug, Clone, EnumDiscriminants, ToString, Serialize, Deserialize)] #[derive(
Debug, Clone, PartialEq, Eq, Hash, EnumDiscriminants, ToString, Serialize, Deserialize,
)]
#[strum_discriminants(derive(EnumString, Hash, Serialize, Deserialize))] #[strum_discriminants(derive(EnumString, Hash, Serialize, Deserialize))]
#[strum_discriminants(name(EventType))] #[strum_discriminants(name(EventType))]
#[non_exhaustive]
pub enum Event { pub enum Event {
ModeUpdate(ModeInfo), ModeUpdate(ModeInfo),
TabUpdate(Vec<TabInfo>), TabUpdate(Vec<TabInfo>),
@ -68,17 +71,23 @@ impl Default for InputMode {
/// Represents the contents of the help message that is printed in the status bar, /// 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 /// which indicates the current [`InputMode`] and what the keybinds for that mode
/// are. Related to the default `status-bar` plugin. /// are. Related to the default `status-bar` plugin.
#[derive(Default, Debug, Clone, Serialize, Deserialize)] #[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ModeInfo { pub struct ModeInfo {
pub mode: InputMode, pub mode: InputMode,
// FIXME: This should probably return Keys and Actions, then sort out strings plugin-side // FIXME: This should probably return Keys and Actions, then sort out strings plugin-side
pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description> pub keybinds: Vec<(String, String)>, // <shortcut> => <shortcut description>
} }
#[derive(Debug, Default, Clone, Deserialize, Serialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct TabInfo { pub struct TabInfo {
/* subset of fields to publish to plugins */ /* subset of fields to publish to plugins */
pub position: usize, pub position: usize,
pub name: String, pub name: String,
pub active: bool, pub active: bool,
} }
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)]
pub struct PluginIds {
pub plugin_id: u32,
pub zellij_pid: u32,
}

View File

@ -21,12 +21,18 @@ pub fn set_max_height(max_height: i32) {
unsafe { host_set_max_height(max_height) }; unsafe { host_set_max_height(max_height) };
} }
pub fn set_selectable(selectable: bool) {
unsafe { host_set_selectable(if selectable { 1 } else { 0 }) };
}
pub fn set_invisible_borders(invisible_borders: bool) { pub fn set_invisible_borders(invisible_borders: bool) {
unsafe { host_set_invisible_borders(if invisible_borders { 1 } else { 0 }) }; unsafe { host_set_invisible_borders(if invisible_borders { 1 } else { 0 }) };
} }
pub fn set_selectable(selectable: bool) { // Query Functions
unsafe { host_set_selectable(if selectable { 1 } else { 0 }) }; pub fn get_plugin_ids() -> PluginIds {
unsafe { host_get_plugin_ids() };
object_from_stdin()
} }
// Host Functions // Host Functions
@ -49,8 +55,9 @@ pub fn object_from_stdin<T: DeserializeOwned>() -> T {
extern "C" { extern "C" {
fn host_subscribe(); fn host_subscribe();
fn host_unsubscribe(); fn host_unsubscribe();
fn host_open_file();
fn host_set_max_height(max_height: i32); fn host_set_max_height(max_height: i32);
fn host_set_selectable(selectable: i32); fn host_set_selectable(selectable: i32);
fn host_set_invisible_borders(invisible_borders: i32); fn host_set_invisible_borders(invisible_borders: i32);
fn host_get_plugin_ids();
fn host_open_file();
} }