aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/plugin_api
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2023-08-09 22:26:00 +0200
committerGitHub <noreply@github.com>2023-08-09 22:26:00 +0200
commit1bedfc90021558cb201695444107afe5bddd2c17 (patch)
tree38dd31b5ab112aa9b1c3a54edb07331013bf7d87 /zellij-utils/src/plugin_api
parentdocs(changelog): plug memory leak (diff)
downloadsl0ppij-1bedfc90021558cb201695444107afe5bddd2c17.tar.gz
sl0ppij-1bedfc90021558cb201695444107afe5bddd2c17.tar.xz
sl0ppij-1bedfc90021558cb201695444107afe5bddd2c17.zip
feat(plugins): use protocol buffers for serializing across the wasm boundary (#2686)
* work * almost done with command protobuffers * done translating command data structures * mid transferring of every command to protobuff command * transferred plugin_command.rs, now moving on to shim.rs * plugin command working with protobufs * protobuffers in update * protobuf event tests * various TODOs and comments * fix zellij-tile * clean up prost deps * remove version mismatch error * fix panic * some cleanups * clean up event protobuffers * clean up command protobuffers * clean up various protobufs * refactor protobufs * update comments * some transformation fixes * use protobufs for workers * style(fmt): rustfmt * style(fmt): rustfmt * chore(build): add protoc * chore(build): authenticate protoc
Diffstat (limited to 'zellij-utils/src/plugin_api')
-rw-r--r--zellij-utils/src/plugin_api/action.proto246
-rw-r--r--zellij-utils/src/plugin_api/action.rs1304
-rw-r--r--zellij-utils/src/plugin_api/command.proto9
-rw-r--r--zellij-utils/src/plugin_api/command.rs26
-rw-r--r--zellij-utils/src/plugin_api/event.proto162
-rw-r--r--zellij-utils/src/plugin_api/event.rs1059
-rw-r--r--zellij-utils/src/plugin_api/file.proto9
-rw-r--r--zellij-utils/src/plugin_api/file.rs30
-rw-r--r--zellij-utils/src/plugin_api/input_mode.proto40
-rw-r--r--zellij-utils/src/plugin_api/input_mode.rs69
-rw-r--r--zellij-utils/src/plugin_api/key.proto83
-rw-r--r--zellij-utils/src/plugin_api/key.rs222
-rw-r--r--zellij-utils/src/plugin_api/message.proto9
-rw-r--r--zellij-utils/src/plugin_api/message.rs29
-rw-r--r--zellij-utils/src/plugin_api/mod.rs14
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto175
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs825
-rw-r--r--zellij-utils/src/plugin_api/plugin_ids.proto12
-rw-r--r--zellij-utils/src/plugin_api/plugin_ids.rs35
-rw-r--r--zellij-utils/src/plugin_api/resize.proto24
-rw-r--r--zellij-utils/src/plugin_api/resize.rs130
-rw-r--r--zellij-utils/src/plugin_api/style.proto54
-rw-r--r--zellij-utils/src/plugin_api/style.rs213
23 files changed, 4779 insertions, 0 deletions
diff --git a/zellij-utils/src/plugin_api/action.proto b/zellij-utils/src/plugin_api/action.proto
new file mode 100644
index 00000000..05fa5c6e
--- /dev/null
+++ b/zellij-utils/src/plugin_api/action.proto
@@ -0,0 +1,246 @@
+syntax = "proto3";
+
+import "input_mode.proto";
+import "resize.proto";
+
+package api.action;
+
+message Action {
+ ActionName name = 1;
+ oneof optional_payload {
+ SwitchToModePayload switch_to_mode_payload = 2;
+ WritePayload write_payload = 3;
+ WriteCharsPayload write_chars_payload = 4;
+ SwitchToModePayload switch_mode_for_all_clients_payload = 5;
+ resize.Resize resize_payload = 6;
+ resize.ResizeDirection move_focus_payload = 7;
+ resize.ResizeDirection move_focus_or_tab_payload = 8;
+ MovePanePayload move_pane_payload = 9;
+ DumpScreenPayload dump_screen_payload = 10;
+ ScrollAtPayload scroll_up_at_payload = 11;
+ ScrollAtPayload scroll_down_at_payload = 12;
+ NewPanePayload new_pane_payload = 13;
+ EditFilePayload edit_file_payload = 14;
+ NewFloatingPanePayload new_floating_pane_payload = 15;
+ NewTiledPanePayload new_tiled_pane_payload = 16;
+ bytes pane_name_input_payload = 17;
+ uint32 go_to_tab_payload = 18;
+ GoToTabNamePayload go_to_tab_name_payload = 19;
+ bytes tab_name_input_payload = 20;
+ RunCommandAction run_payload = 21;
+ Position left_click_payload = 22;
+ Position right_click_payload = 23;
+ Position middle_click_payload = 24;
+ LaunchOrFocusPluginPayload launch_or_focus_plugin_payload = 25;
+ Position left_mouse_release_payload = 26;
+ Position right_mouse_release_payload = 27;
+ Position middle_mouse_release_payload = 28;
+ Position mouse_hold_left_payload = 29;
+ Position mouse_hold_right_payload = 30;
+ Position mouse_hold_middle_payload = 31;
+ bytes search_input_payload = 32;
+ SearchDirection search_payload = 33;
+ SearchOption search_toggle_option_payload = 34;
+ NewPluginPanePayload new_tiled_plugin_pane_payload = 35;
+ NewPluginPanePayload new_floating_plugin_pane_payload = 36;
+ string start_or_reload_plugin_payload = 37;
+ uint32 close_terminal_pane_payload = 38;
+ uint32 close_plugin_pane_payload = 39;
+ PaneIdAndShouldFloat focus_terminal_pane_with_id_payload = 40;
+ PaneIdAndShouldFloat focus_plugin_pane_with_id_payload = 41;
+ IdAndName rename_terminal_pane_payload = 42;
+ IdAndName rename_plugin_pane_payload = 43;
+ IdAndName rename_tab_payload = 44;
+ }
+}
+
+message IdAndName {
+ bytes name = 1;
+ uint32 id = 2;
+}
+
+message PaneIdAndShouldFloat {
+ uint32 pane_id = 1;
+ bool should_float_if_hidden = 2;
+}
+
+message NewPluginPanePayload {
+ string plugin_url = 1;
+ optional string pane_name = 2;
+}
+
+enum SearchDirection {
+ Up = 0;
+ Down = 1;
+}
+
+enum SearchOption {
+ CaseSensitivity = 0;
+ WholeWord = 1;
+ Wrap = 2;
+}
+
+message LaunchOrFocusPluginPayload {
+ string plugin_url = 1;
+ bool should_float = 2;
+ optional PluginConfiguration plugin_configuration = 3;
+}
+
+message GoToTabNamePayload {
+ string tab_name = 1;
+ bool create = 2;
+}
+
+message NewFloatingPanePayload {
+ optional RunCommandAction command = 1;
+}
+
+message NewTiledPanePayload {
+ optional RunCommandAction command = 1;
+ optional resize.ResizeDirection direction = 2;
+}
+
+message MovePanePayload {
+ optional resize.ResizeDirection direction = 1;
+}
+
+message EditFilePayload {
+ string file_to_edit = 1;
+ optional uint32 line_number = 2;
+ optional string cwd = 3;
+ optional resize.ResizeDirection direction = 4;
+ bool should_float = 5;
+}
+
+message ScrollAtPayload {
+ Position position = 1;
+}
+
+message NewPanePayload {
+ optional resize.ResizeDirection direction = 1;
+ optional string pane_name = 2;
+}
+
+message SwitchToModePayload {
+ input_mode.InputMode input_mode = 1;
+}
+
+message WritePayload {
+ bytes bytes_to_write = 1;
+}
+
+message WriteCharsPayload {
+ string chars = 1;
+}
+
+message DumpScreenPayload {
+ string file_path = 1;
+ bool include_scrollback = 2;
+}
+
+enum ActionName {
+ Quit = 0;
+ Write = 1;
+ WriteChars = 2;
+ SwitchToMode = 3;
+ SwitchModeForAllClients = 4;
+ Resize = 5;
+ FocusNextPane = 6;
+ FocusPreviousPane = 7;
+ SwitchFocus = 8;
+ MoveFocus = 9;
+ MoveFocusOrTab = 10;
+ MovePane = 11;
+ MovePaneBackwards = 12;
+ ClearScreen = 13;
+ DumpScreen = 14;
+ EditScrollback = 15;
+ ScrollUp = 16;
+ ScrollUpAt = 17;
+ ScrollDown = 18;
+ ScrollDownAt = 19;
+ ScrollToBottom = 20;
+ ScrollToTop = 21;
+ PageScrollUp = 22;
+ PageScrollDown = 23;
+ HalfPageScrollUp = 24;
+ HalfPageScrollDown = 25;
+ ToggleFocusFullscreen = 26;
+ TogglePaneFrames = 27;
+ ToggleActiveSyncTab = 28;
+ NewPane = 29;
+ EditFile = 30;
+ NewFloatingPane = 31;
+ NewTiledPane = 32;
+ TogglePaneEmbedOrFloating = 33;
+ ToggleFloatingPanes = 34;
+ CloseFocus = 35;
+ PaneNameInput = 36;
+ UndoRenamePane = 37;
+ NewTab = 38;
+ NoOp = 39;
+ GoToNextTab = 40;
+ GoToPreviousTab = 41;
+ CloseTab = 42;
+ GoToTab = 43;
+ GoToTabName = 44;
+ ToggleTab = 45;
+ TabNameInput = 46;
+ UndoRenameTab = 47;
+ Run = 48;
+ Detach = 49;
+ LeftClick = 50;
+ RightClick = 51;
+ MiddleClick = 52;
+ LaunchOrFocusPlugin = 53;
+ LeftMouseRelease = 54;
+ RightMouseRelease = 55;
+ MiddleMouseRelease = 56;
+ MouseHoldLeft = 57;
+ MouseHoldRight = 58;
+ MouseHoldMiddle = 59;
+ SearchInput = 60;
+ Search = 61;
+ SearchToggleOption = 62;
+ ToggleMouseMode = 63;
+ PreviousSwapLayout = 64;
+ NextSwapLayout = 65;
+ QueryTabNames = 66;
+ NewTiledPluginPane = 67;
+ NewFloatingPluginPane = 68;
+ StartOrReloadPlugin = 69;
+ CloseTerminalPane = 70;
+ ClosePluginPane = 71;
+ FocusTerminalPaneWithId = 72;
+ FocusPluginPaneWithId = 73;
+ RenameTerminalPane = 74;
+ RenamePluginPane = 75;
+ RenameTab = 76;
+ BreakPane = 77;
+ BreakPaneRight = 78;
+ BreakPaneLeft = 79;
+}
+
+message Position {
+ int64 line = 1;
+ int64 column = 2;
+}
+
+message RunCommandAction {
+ string command = 1;
+ repeated string args = 2;
+ optional string cwd = 3;
+ optional resize.ResizeDirection direction = 4;
+ optional string pane_name = 5;
+ bool hold_on_close = 6;
+ bool hold_on_start = 7;
+}
+
+message PluginConfiguration {
+ repeated NameAndValue name_and_value = 1;
+}
+
+message NameAndValue {
+ string name = 1;
+ string value = 2;
+}
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
new file mode 100644
index 00000000..1a964fa9
--- /dev/null
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -0,0 +1,1304 @@
+pub use super::generated_api::api::{
+ action::{
+ action::OptionalPayload, Action as ProtobufAction, ActionName as ProtobufActionName,
+ DumpScreenPayload, EditFilePayload, GoToTabNamePayload, IdAndName,
+ LaunchOrFocusPluginPayload, MovePanePayload, NameAndValue as ProtobufNameAndValue,
+ NewFloatingPanePayload, NewPanePayload, NewPluginPanePayload, NewTiledPanePayload,
+ PaneIdAndShouldFloat, PluginConfiguration as ProtobufPluginConfiguration,
+ Position as ProtobufPosition, RunCommandAction as ProtobufRunCommandAction,
+ ScrollAtPayload, SearchDirection as ProtobufSearchDirection,
+ SearchOption as ProtobufSearchOption, SwitchToModePayload, WriteCharsPayload, WritePayload,
+ },
+ input_mode::InputMode as ProtobufInputMode,
+ resize::{Resize as ProtobufResize, ResizeDirection as ProtobufResizeDirection},
+};
+use crate::data::{Direction, InputMode, ResizeStrategy};
+use crate::errors::prelude::*;
+use crate::input::actions::Action;
+use crate::input::actions::{SearchDirection, SearchOption};
+use crate::input::command::RunCommandAction;
+use crate::input::layout::{PluginUserConfiguration, RunPlugin, RunPluginLocation};
+use crate::position::Position;
+use url::Url;
+
+use std::collections::BTreeMap;
+use std::convert::TryFrom;
+use std::path::PathBuf;
+
+impl TryFrom<ProtobufAction> for Action {
+ type Error = &'static str;
+ fn try_from(protobuf_action: ProtobufAction) -> Result<Self, &'static str> {
+ match ProtobufActionName::from_i32(protobuf_action.name) {
+ Some(ProtobufActionName::Quit) => match protobuf_action.optional_payload {
+ Some(_) => Err("The Quit Action should not have a payload"),
+ None => Ok(Action::Quit),
+ },
+ Some(ProtobufActionName::Write) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::WritePayload(write_payload)) => {
+ Ok(Action::Write(write_payload.bytes_to_write))
+ },
+ _ => Err("Wrong payload for Action::Write"),
+ },
+ Some(ProtobufActionName::WriteChars) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::WriteCharsPayload(write_chars_payload)) => {
+ Ok(Action::WriteChars(write_chars_payload.chars))
+ },
+ _ => Err("Wrong payload for Action::WriteChars"),
+ },
+ Some(ProtobufActionName::SwitchToMode) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::SwitchToModePayload(switch_to_mode_payload)) => {
+ let input_mode: InputMode =
+ ProtobufInputMode::from_i32(switch_to_mode_payload.input_mode)
+ .ok_or("Malformed input mode for SwitchToMode Action")?
+ .try_into()?;
+ Ok(Action::SwitchToMode(input_mode))
+ },
+ _ => Err("Wrong payload for Action::SwitchToModePayload"),
+ },
+ Some(ProtobufActionName::SwitchModeForAllClients) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::SwitchModeForAllClientsPayload(
+ switch_to_mode_payload,
+ )) => {
+ let input_mode: InputMode =
+ ProtobufInputMode::from_i32(switch_to_mode_payload.input_mode)
+ .ok_or("Malformed input mode for SwitchToMode Action")?
+ .try_into()?;
+ Ok(Action::SwitchModeForAllClients(input_mode))
+ },
+ _ => Err("Wrong payload for Action::SwitchModeForAllClients"),
+ }
+ },
+ Some(ProtobufActionName::Resize) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::ResizePayload(resize_payload)) => {
+ let resize_strategy: ResizeStrategy = resize_payload.try_into()?;
+ Ok(Action::Resize(
+ resize_strategy.resize,
+ resize_strategy.direction,
+ ))
+ },
+ _ => Err("Wrong payload for Action::Resize"),
+ },
+ Some(ProtobufActionName::FocusNextPane) => match protobuf_action.optional_payload {
+ Some(_) => Err("FocusNextPane should not have a payload"),
+ None => Ok(Action::FocusNextPane),
+ },
+ Some(ProtobufActionName::FocusPreviousPane) => match protobuf_action.optional_payload {
+ Some(_) => Err("FocusPreviousPane should not have a payload"),
+ None => Ok(Action::FocusPreviousPane),
+ },
+ Some(ProtobufActionName::SwitchFocus) => match protobuf_action.optional_payload {
+ Some(_) => Err("SwitchFocus should not have a payload"),
+ None => Ok(Action::SwitchFocus),
+ },
+ Some(ProtobufActionName::MoveFocus) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MoveFocusPayload(move_focus_payload)) => {
+ let direction: Direction =
+ ProtobufResizeDirection::from_i32(move_focus_payload)
+ .ok_or("Malformed resize direction for Action::MoveFocus")?
+ .try_into()?;
+ Ok(Action::MoveFocus(direction))
+ },
+ _ => Err("Wrong payload for Action::MoveFocus"),
+ },
+ Some(ProtobufActionName::MoveFocusOrTab) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MoveFocusOrTabPayload(move_focus_or_tab_payload)) => {
+ let direction: Direction =
+ ProtobufResizeDirection::from_i32(move_focus_or_tab_payload)
+ .ok_or("Malformed resize direction for Action::MoveFocusOrTab")?
+ .try_into()?;
+ Ok(Action::MoveFocusOrTab(direction))
+ },
+ _ => Err("Wrong payload for Action::MoveFocusOrTab"),
+ },
+ Some(ProtobufActionName::MovePane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MovePanePayload(payload)) => {
+ let direction: Option<Direction> = payload
+ .direction
+ .and_then(|d| ProtobufResizeDirection::from_i32(d))
+ .and_then(|d| d.try_into().ok());
+ Ok(Action::MovePane(direction))
+ },
+ _ => Err("Wrong payload for Action::MovePane"),
+ },
+ Some(ProtobufActionName::MovePaneBackwards) => match protobuf_action.optional_payload {
+ Some(_) => Err("MovePaneBackwards should not have a payload"),
+ None => Ok(Action::MovePaneBackwards),
+ },
+ Some(ProtobufActionName::ClearScreen) => match protobuf_action.optional_payload {
+ Some(_) => Err("ClearScreen should not have a payload"),
+ None => Ok(Action::ClearScreen),
+ },
+ Some(ProtobufActionName::DumpScreen) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::DumpScreenPayload(payload)) => {
+ let file_path = payload.file_path;
+ let include_scrollback = payload.include_scrollback;
+ Ok(Action::DumpScreen(file_path, include_scrollback))
+ },
+ _ => Err("Wrong payload for Action::DumpScreen"),
+ },
+ Some(ProtobufActionName::EditScrollback) => match protobuf_action.optional_payload {
+ Some(_) => Err("EditScrollback should not have a payload"),
+ None => Ok(Action::EditScrollback),
+ },
+ Some(ProtobufActionName::ScrollUp) => match protobuf_action.optional_payload {
+ Some(_) => Err("ScrollUp should not have a payload"),
+ None => Ok(Action::ScrollUp),
+ },
+ Some(ProtobufActionName::ScrollDown) => match protobuf_action.optional_payload {
+ Some(_) => Err("ScrollDown should not have a payload"),
+ None => Ok(Action::ScrollDown),
+ },
+ Some(ProtobufActionName::ScrollUpAt) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::ScrollUpAtPayload(payload)) => {
+ let position = payload
+ .position
+ .ok_or("ScrollUpAtPayload must have a position")?
+ .try_into()?;
+ Ok(Action::ScrollUpAt(position))
+ },
+ _ => Err("Wrong payload for Action::ScrollUpAt"),
+ },
+ Some(ProtobufActionName::ScrollDownAt) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::ScrollDownAtPayload(payload)) => {
+ let position = payload
+ .position
+ .ok_or("ScrollDownAtPayload must have a position")?
+ .try_into()?;
+ Ok(Action::ScrollDownAt(position))
+ },
+ _ => Err("Wrong payload for Action::ScrollDownAt"),
+ },
+ Some(ProtobufActionName::ScrollToBottom) => match protobuf_action.optional_payload {
+ Some(_) => Err("ScrollToBottom should not have a payload"),
+ None => Ok(Action::ScrollToBottom),
+ },
+ Some(ProtobufActionName::ScrollToTop) => match protobuf_action.optional_payload {
+ Some(_) => Err("ScrollToTop should not have a payload"),
+ None => Ok(Action::ScrollToTop),
+ },
+ Some(ProtobufActionName::PageScrollUp) => match protobuf_action.optional_payload {
+ Some(_) => Err("PageScrollUp should not have a payload"),
+ None => Ok(Action::PageScrollUp),
+ },
+ Some(ProtobufActionName::PageScrollDown) => match protobuf_action.optional_payload {
+ Some(_) => Err("PageScrollDown should not have a payload"),
+ None => Ok(Action::PageScrollDown),
+ },
+ Some(ProtobufActionName::HalfPageScrollUp) => match protobuf_action.optional_payload {
+ Some(_) => Err("HalfPageScrollUp should not have a payload"),
+ None => Ok(Action::HalfPageScrollUp),
+ },
+ Some(ProtobufActionName::HalfPageScrollDown) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("HalfPageScrollDown should not have a payload"),
+ None => Ok(Action::HalfPageScrollDown),
+ }
+ },
+ Some(ProtobufActionName::ToggleFocusFullscreen) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleFocusFullscreen should not have a payload"),
+ None => Ok(Action::ToggleFocusFullscreen),
+ }
+ },
+ Some(ProtobufActionName::TogglePaneFrames) => match protobuf_action.optional_payload {
+ Some(_) => Err("TogglePaneFrames should not have a payload"),
+ None => Ok(Action::TogglePaneFrames),
+ },
+ Some(ProtobufActionName::ToggleActiveSyncTab) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleActiveSyncTab should not have a payload"),
+ None => Ok(Action::ToggleActiveSyncTab),
+ }
+ },
+ Some(ProtobufActionName::NewPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::NewPanePayload(payload)) => {
+ let direction: Option<Direction> = payload
+ .direction
+ .and_then(|d| ProtobufResizeDirection::from_i32(d))
+ .and_then(|d| d.try_into().ok());
+ let pane_name = payload.pane_name;
+ Ok(Action::NewPane(direction, pane_name))
+ },
+ _ => Err("Wrong payload for Action::NewPane"),
+ },
+ Some(ProtobufActionName::EditFile) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::EditFilePayload(payload)) => {
+ let file_to_edit = PathBuf::from(payload.file_to_edit);
+ let line_number: Option<usize> = payload.line_number.map(|l| l as usize);
+ let cwd: Option<PathBuf> = payload.cwd.map(|p| PathBuf::from(p));
+ let direction: Option<Direction> = payload
+ .direction
+ .and_then(|d| ProtobufResizeDirection::from_i32(d))
+ .and_then(|d| d.try_into().ok());
+ let should_float = payload.should_float;
+ Ok(Action::EditFile(
+ file_to_edit,
+ line_number,
+ cwd,
+ direction,
+ should_float,
+ ))
+ },
+ _ => Err("Wrong payload for Action::NewPane"),
+ },
+ Some(ProtobufActionName::NewFloatingPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::NewFloatingPanePayload(payload)) => {
+ if let Some(payload) = payload.command {
+ let pane_name = payload.pane_name.clone();
+ let run_command_action: RunCommandAction = payload.try_into()?;
+ Ok(Action::NewFloatingPane(Some(run_command_action), pane_name))
+ } else {
+ Ok(Action::NewFloatingPane(None, None))
+ }
+ },
+ _ => Err("Wrong payload for Action::NewFloatingPane"),
+ },
+ Some(ProtobufActionName::NewTiledPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::NewTiledPanePayload(payload)) => {
+ let direction: Option<Direction> = payload
+ .direction
+ .and_then(|d| ProtobufResizeDirection::from_i32(d))
+ .and_then(|d| d.try_into().ok());
+ if let Some(payload) = payload.command {
+ let pane_name = payload.pane_name.clone();
+ let run_command_action: RunCommandAction = payload.try_into()?;
+ Ok(Action::NewTiledPane(
+ direction,
+ Some(run_command_action),
+ pane_name,
+ ))
+ } else {
+ Ok(Action::NewTiledPane(direction, None, None))
+ }
+ },
+ _ => Err("Wrong payload for Action::NewTiledPane"),
+ },
+ Some(ProtobufActionName::TogglePaneEmbedOrFloating) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("TogglePaneEmbedOrFloating should not have a payload"),
+ None => Ok(Action::TogglePaneEmbedOrFloating),
+ }
+ },
+ Some(ProtobufActionName::ToggleFloatingPanes) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleFloatingPanes should not have a payload"),
+ None => Ok(Action::ToggleFloatingPanes),
+ }
+ },
+ Some(ProtobufActionName::CloseFocus) => match protobuf_action.optional_payload {
+ Some(_) => Err("CloseFocus should not have a payload"),
+ None => Ok(Action::CloseFocus),
+ },
+ Some(ProtobufActionName::PaneNameInput) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::PaneNameInputPayload(bytes)) => {
+ Ok(Action::PaneNameInput(bytes))
+ },
+ _ => Err("Wrong payload for Action::PaneNameInput"),
+ },
+ Some(ProtobufActionName::UndoRenamePane) => match protobuf_action.optional_payload {
+ Some(_) => Err("UndoRenamePane should not have a payload"),
+ None => Ok(Action::UndoRenamePane),
+ },
+ Some(ProtobufActionName::NewTab) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("NewTab should not have a payload"),
+ None => {
+ // we do not serialize the layouts of this action
+ Ok(Action::NewTab(None, vec![], None, None, None))
+ },
+ }
+ },
+ Some(ProtobufActionName::NoOp) => match protobuf_action.optional_payload {
+ Some(_) => Err("NoOp should not have a payload"),
+ None => Ok(Action::NoOp),
+ },
+ Some(ProtobufActionName::GoToNextTab) => match protobuf_action.optional_payload {
+ Some(_) => Err("GoToNextTab should not have a payload"),
+ None => Ok(Action::GoToNextTab),
+ },
+ Some(ProtobufActionName::GoToPreviousTab) => match protobuf_action.optional_payload {
+ Some(_) => Err("GoToPreviousTab should not have a payload"),
+ None => Ok(Action::GoToPreviousTab),
+ },
+ Some(ProtobufActionName::CloseTab) => match protobuf_action.optional_payload {
+ Some(_) => Err("CloseTab should not have a payload"),
+ None => Ok(Action::CloseTab),
+ },
+ Some(ProtobufActionName::GoToTab) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::GoToTabPayload(index)) => Ok(Action::GoToTab(index)),
+ _ => Err("Wrong payload for Action::GoToTab"),
+ },
+ Some(ProtobufActionName::GoToTabName) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::GoToTabNamePayload(payload)) => {
+ let tab_name = payload.tab_name;
+ let create = payload.create;
+ Ok(Action::GoToTabName(tab_name, create))
+ },
+ _ => Err("Wrong payload for Action::GoToTabName"),
+ },
+ Some(ProtobufActionName::ToggleTab) => match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleTab should not have a payload"),
+ None => Ok(Action::ToggleTab),
+ },
+ Some(ProtobufActionName::TabNameInput) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::TabNameInputPayload(bytes)) => {
+ Ok(Action::TabNameInput(bytes))
+ },
+ _ => Err("Wrong payload for Action::TabNameInput"),
+ },
+ Some(ProtobufActionName::UndoRenameTab) => match protobuf_action.optional_payload {
+ Some(_) => Err("UndoRenameTab should not have a payload"),
+ None => Ok(Action::UndoRenameTab),
+ },
+ Some(ProtobufActionName::Run) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::RunPayload(run_command_action)) => {
+ let run_command_action = run_command_action.try_into()?;
+ Ok(Action::Run(run_command_action))
+ },
+ _ => Err("Wrong payload for Action::Run"),
+ },
+ Some(ProtobufActionName::Detach) => match protobuf_action.optional_payload {
+ Some(_) => Err("Detach should not have a payload"),
+ None => Ok(Action::Detach),
+ },
+ Some(ProtobufActionName::LeftClick) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::LeftClickPayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::LeftClick(position))
+ },
+ _ => Err("Wrong payload for Action::LeftClick"),
+ },
+ Some(ProtobufActionName::RightClick) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::RightClickPayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::RightClick(position))
+ },
+ _ => Err("Wrong payload for Action::RightClick"),
+ },
+ Some(ProtobufActionName::MiddleClick) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MiddleClickPayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::MiddleClick(position))
+ },
+ _ => Err("Wrong payload for Action::MiddleClick"),
+ },
+ Some(ProtobufActionName::LaunchOrFocusPlugin) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::LaunchOrFocusPluginPayload(payload)) => {
+ let run_plugin_location =
+ RunPluginLocation::parse(&payload.plugin_url, None)
+ .map_err(|_| "Malformed LaunchOrFocusPlugin payload")?;
+ let configuration: PluginUserConfiguration = payload
+ .plugin_configuration
+ .and_then(|p| PluginUserConfiguration::try_from(p).ok())
+ .unwrap_or_default();
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: run_plugin_location,
+ configuration,
+ };
+ let should_float = payload.should_float;
+ Ok(Action::LaunchOrFocusPlugin(run_plugin, should_float))
+ },
+ _ => Err("Wrong payload for Action::LaunchOrFocusPlugin"),
+ }
+ },
+ Some(ProtobufActionName::LeftMouseRelease) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::LeftMouseReleasePayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::LeftMouseRelease(position))
+ },
+ _ => Err("Wrong payload for Action::LeftMouseRelease"),
+ },
+ Some(ProtobufActionName::RightMouseRelease) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::RightMouseReleasePayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::RightMouseRelease(position))
+ },
+ _ => Err("Wrong payload for Action::RightMouseRelease"),
+ },
+ Some(ProtobufActionName::MiddleMouseRelease) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::MiddleMouseReleasePayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::MiddleMouseRelease(position))
+ },
+ _ => Err("Wrong payload for Action::MiddleMouseRelease"),
+ }
+ },
+ Some(ProtobufActionName::MouseHoldLeft) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MouseHoldLeftPayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::MouseHoldLeft(position))
+ },
+ _ => Err("Wrong payload for Action::MouseHoldLeft"),
+ },
+ Some(ProtobufActionName::MouseHoldRight) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MouseHoldRightPayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::MouseHoldRight(position))
+ },
+ _ => Err("Wrong payload for Action::MouseHoldRight"),
+ },
+ Some(ProtobufActionName::MouseHoldMiddle) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::MouseHoldMiddlePayload(payload)) => {
+ let position = payload.try_into()?;
+ Ok(Action::MouseHoldMiddle(position))
+ },
+ _ => Err("Wrong payload for Action::MouseHoldMiddle"),
+ },
+ Some(ProtobufActionName::SearchInput) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::SearchInputPayload(payload)) => {
+ Ok(Action::SearchInput(payload))
+ },
+ _ => Err("Wrong payload for Action::SearchInput"),
+ },
+ Some(ProtobufActionName::Search) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::SearchPayload(search_direction)) => Ok(Action::Search(
+ ProtobufSearchDirection::from_i32(search_direction)
+ .ok_or("Malformed payload for Action::Search")?
+ .try_into()?,
+ )),
+ _ => Err("Wrong payload for Action::Search"),
+ },
+ Some(ProtobufActionName::SearchToggleOption) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::SearchToggleOptionPayload(search_option)) => {
+ Ok(Action::SearchToggleOption(
+ ProtobufSearchOption::from_i32(search_option)
+ .ok_or("Malformed payload for Action::SearchToggleOption")?
+ .try_into()?,
+ ))
+ },
+ _ => Err("Wrong payload for Action::SearchToggleOption"),
+ }
+ },
+ Some(ProtobufActionName::ToggleMouseMode) => match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleMouseMode should not have a payload"),
+ None => Ok(Action::ToggleMouseMode),
+ },
+ Some(ProtobufActionName::PreviousSwapLayout) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("PreviousSwapLayout should not have a payload"),
+ None => Ok(Action::PreviousSwapLayout),
+ }
+ },
+ Some(ProtobufActionName::NextSwapLayout) => match protobuf_action.optional_payload {
+ Some(_) => Err("NextSwapLayout should not have a payload"),
+ None => Ok(Action::NextSwapLayout),
+ },
+ Some(ProtobufActionName::QueryTabNames) => match protobuf_action.optional_payload {
+ Some(_) => Err("QueryTabNames should not have a payload"),
+ None => Ok(Action::QueryTabNames),
+ },
+ Some(ProtobufActionName::NewTiledPluginPane) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::NewTiledPluginPanePayload(payload)) => {
+ let run_plugin_location =
+ RunPluginLocation::parse(&payload.plugin_url, None)
+ .map_err(|_| "Malformed NewTiledPluginPane payload")?;
+ let run_plugin = RunPlugin {
+ location: run_plugin_location,
+ _allow_exec_host_cmd: false,
+ configuration: PluginUserConfiguration::default(),
+ };
+ let pane_name = payload.pane_name;
+ Ok(Action::NewTiledPluginPane(run_plugin, pane_name))
+ },
+ _ => Err("Wrong payload for Action::NewTiledPluginPane"),
+ }
+ },
+ Some(ProtobufActionName::NewFloatingPluginPane) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::NewFloatingPluginPanePayload(payload)) => {
+ let run_plugin_location =
+ RunPluginLocation::parse(&payload.plugin_url, None)
+ .map_err(|_| "Malformed NewTiledPluginPane payload")?;
+ let run_plugin = RunPlugin {
+ location: run_plugin_location,
+ _allow_exec_host_cmd: false,
+ configuration: PluginUserConfiguration::default(),
+ };
+ let pane_name = payload.pane_name;
+ Ok(Action::NewFloatingPluginPane(run_plugin, pane_name))
+ },
+ _ => Err("Wrong payload for Action::MiddleClick"),
+ }
+ },
+ Some(ProtobufActionName::StartOrReloadPlugin) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::StartOrReloadPluginPayload(payload)) => {
+ let run_plugin_location = RunPluginLocation::parse(&payload, None)
+ .map_err(|_| "Malformed StartOrReloadPluginPayload payload")?;
+ let run_plugin = RunPlugin {
+ _allow_exec_host_cmd: false,
+ location: run_plugin_location,
+ configuration: PluginUserConfiguration::default(),
+ };
+ Ok(Action::StartOrReloadPlugin(run_plugin))
+ },
+ _ => Err("Wrong payload for Action::StartOrReloadPlugin"),
+ }
+ },
+ Some(ProtobufActionName::CloseTerminalPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::CloseTerminalPanePayload(payload)) => {
+ Ok(Action::CloseTerminalPane(payload))
+ },
+ _ => Err("Wrong payload for Action::CloseTerminalPane"),
+ },
+ Some(ProtobufActionName::ClosePluginPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::ClosePluginPanePayload(payload)) => {
+ Ok(Action::ClosePluginPane(payload))
+ },
+ _ => Err("Wrong payload for Action::ClosePluginPane"),
+ },
+ Some(ProtobufActionName::FocusTerminalPaneWithId) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::FocusTerminalPaneWithIdPayload(payload)) => {
+ let terminal_pane_id = payload.pane_id;
+ let should_float_if_hidden = payload.should_float_if_hidden;
+ Ok(Action::FocusTerminalPaneWithId(
+ terminal_pane_id,
+ should_float_if_hidden,
+ ))
+ },
+ _ => Err("Wrong payload for Action::FocusTerminalPaneWithId"),
+ }
+ },
+ Some(ProtobufActionName::FocusPluginPaneWithId) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::FocusPluginPaneWithIdPayload(payload)) => {
+ let plugin_pane_id = payload.pane_id;
+ let should_float_if_hidden = payload.should_float_if_hidden;
+ Ok(Action::FocusPluginPaneWithId(
+ plugin_pane_id,
+ should_float_if_hidden,
+ ))
+ },
+ _ => Err("Wrong payload for Action::FocusPluginPaneWithId"),
+ }
+ },
+ Some(ProtobufActionName::RenameTerminalPane) => {
+ match protobuf_action.optional_payload {
+ Some(OptionalPayload::RenameTerminalPanePayload(payload)) => {
+ let terminal_pane_id = payload.id;
+ let new_pane_name = payload.name;
+ Ok(Action::RenameTerminalPane(terminal_pane_id, new_pane_name))
+ },
+ _ => Err("Wrong payload for Action::RenameTerminalPane"),
+ }
+ },
+ Some(ProtobufActionName::RenamePluginPane) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::RenamePluginPanePayload(payload)) => {
+ let plugin_pane_id = payload.id;
+ let new_pane_name = payload.name;
+ Ok(Action::RenamePluginPane(plugin_pane_id, new_pane_name))
+ },
+ _ => Err("Wrong payload for Action::RenamePluginPane"),
+ },
+ Some(ProtobufActionName::RenameTab) => match protobuf_action.optional_payload {
+ Some(OptionalPayload::RenameTabPayload(payload)) => {
+ let tab_index = payload.id;
+ let new_tab_name = payload.name;
+ Ok(Action::RenameTab(tab_index, new_tab_name))
+ },
+ _ => Err("Wrong payload for Action::RenameTab"),
+ },
+ Some(ProtobufActionName::BreakPane) => match protobuf_action.optional_payload {
+ Some(_) => Err("BreakPane should not have a payload"),
+ None => Ok(Action::BreakPane),
+ },
+ Some(ProtobufActionName::BreakPaneRight) => match protobuf_action.optional_payload {
+ Some(_) => Err("BreakPaneRight should not have a payload"),
+ None => Ok(Action::BreakPaneRight),
+ },
+ Some(ProtobufActionName::BreakPaneLeft) => match protobuf_action.optional_payload {
+ Some(_) => Err("BreakPaneLeft should not have a payload"),
+ None => Ok(Action::BreakPaneLeft),
+ },
+ _ => Err("Unknown Action"),
+ }
+ }
+}
+
+impl TryFrom<Action> for ProtobufAction {
+ type Error = &'static str;
+ fn try_from(action: Action) -> Result<Self, &'static str> {
+ match action {
+ Action::Quit => Ok(ProtobufAction {
+ name: ProtobufActionName::Quit as i32,
+ optional_payload: None,
+ }),
+ Action::Write(bytes) => Ok(ProtobufAction {
+ name: ProtobufActionName::Write as i32,
+ optional_payload: Some(OptionalPayload::WritePayload(WritePayload {
+ bytes_to_write: bytes,
+ })),
+ }),
+ Action::WriteChars(chars_to_write) => Ok(ProtobufAction {
+ name: ProtobufActionName::WriteChars as i32,
+ optional_payload: Some(OptionalPayload::WriteCharsPayload(WriteCharsPayload {
+ chars: chars_to_write,
+ })),
+ }),
+ Action::SwitchToMode(input_mode) => {
+ let input_mode: ProtobufInputMode = input_mode.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::SwitchToMode as i32,
+ optional_payload: Some(OptionalPayload::SwitchToModePayload(
+ SwitchToModePayload {
+ input_mode: input_mode as i32,
+ },
+ )),
+ })
+ },
+ Action::SwitchModeForAllClients(input_mode) => {
+ let input_mode: ProtobufInputMode = input_mode.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::SwitchModeForAllClients as i32,
+ optional_payload: Some(OptionalPayload::SwitchModeForAllClientsPayload(
+ SwitchToModePayload {
+ input_mode: input_mode as i32,
+ },
+ )),
+ })
+ },
+ Action::Resize(resize, direction) => {
+ let mut resize: ProtobufResize = resize.try_into()?;
+ resize.direction = direction.and_then(|d| {
+ let resize_direction: ProtobufResizeDirection = d.try_into().ok()?;
+ Some(resize_direction as i32)
+ });
+ Ok(ProtobufAction {
+ name: ProtobufActionName::Resize as i32,
+ optional_payload: Some(OptionalPayload::ResizePayload(resize)),
+ })
+ },
+ Action::FocusNextPane => Ok(ProtobufAction {
+ name: ProtobufActionName::FocusNextPane as i32,
+ optional_payload: None,
+ }),
+ Action::FocusPreviousPane => Ok(ProtobufAction {
+ name: ProtobufActionName::FocusPreviousPane as i32,
+ optional_payload: None,
+ }),
+ Action::SwitchFocus => Ok(ProtobufAction {
+ name: ProtobufActionName::SwitchFocus as i32,
+ optional_payload: None,
+ }),
+ Action::MoveFocus(direction) => {
+ let direction: ProtobufResizeDirection = direction.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MoveFocus as i32,
+ optional_payload: Some(OptionalPayload::MoveFocusPayload(direction as i32)),
+ })
+ },
+ Action::MoveFocusOrTab(direction) => {
+ let direction: ProtobufResizeDirection = direction.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MoveFocusOrTab as i32,
+ optional_payload: Some(OptionalPayload::MoveFocusOrTabPayload(
+ direction as i32,
+ )),
+ })
+ },
+ Action::MovePane(direction) => {
+ let direction = direction.and_then(|direction| {
+ let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
+ Some(protobuf_direction as i32)
+ });
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MovePane as i32,
+ optional_payload: Some(OptionalPayload::MovePanePayload(MovePanePayload {
+ direction,
+ })),
+ })
+ },
+ Action::MovePaneBackwards => Ok(ProtobufAction {
+ name: ProtobufActionName::MovePaneBackwards as i32,
+ optional_payload: None,
+ }),
+ Action::ClearScreen => Ok(ProtobufAction {
+ name: ProtobufActionName::ClearScreen as i32,
+ optional_payload: None,
+ }),
+ Action::DumpScreen(file_path, include_scrollback) => Ok(ProtobufAction {
+ name: ProtobufActionName::DumpScreen as i32,
+ optional_payload: Some(OptionalPayload::DumpScreenPayload(DumpScreenPayload {
+ file_path,
+ include_scrollback,
+ })),
+ }),
+ Action::EditScrollback => Ok(ProtobufAction {
+ name: ProtobufActionName::EditScrollback as i32,
+ optional_payload: None,
+ }),
+ Action::ScrollUp => Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollUp as i32,
+ optional_payload: None,
+ }),
+ Action::ScrollUpAt(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollUpAt as i32,
+ optional_payload: Some(OptionalPayload::ScrollUpAtPayload(ScrollAtPayload {
+ position: Some(position),
+ })),
+ })
+ },
+ Action::ScrollDown => Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollDown as i32,
+ optional_payload: None,
+ }),
+ Action::ScrollDownAt(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollDownAt as i32,
+ optional_payload: Some(OptionalPayload::ScrollDownAtPayload(ScrollAtPayload {
+ position: Some(position),
+ })),
+ })
+ },
+ Action::ScrollToBottom => Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollToBottom as i32,
+ optional_payload: None,
+ }),
+ Action::ScrollToTop => Ok(ProtobufAction {
+ name: ProtobufActionName::ScrollToTop as i32,
+ optional_payload: None,
+ }),
+ Action::PageScrollUp => Ok(ProtobufAction {
+ name: ProtobufActionName::PageScrollUp as i32,
+ optional_payload: None,
+ }),
+ Action::PageScrollDown => Ok(ProtobufAction {
+ name: ProtobufActionName::PageScrollDown as i32,
+ optional_payload: None,
+ }),
+ Action::HalfPageScrollUp => Ok(ProtobufAction {
+ name: ProtobufActionName::HalfPageScrollUp as i32,
+ optional_payload: None,
+ }),
+ Action::HalfPageScrollDown => Ok(ProtobufAction {
+ name: ProtobufActionName::HalfPageScrollDown as i32,
+ optional_payload: None,
+ }),
+ Action::ToggleFocusFullscreen => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleFocusFullscreen as i32,
+ optional_payload: None,
+ }),
+ Action::TogglePaneFrames => Ok(ProtobufAction {
+ name: ProtobufActionName::TogglePaneFrames as i32,
+ optional_payload: None,
+ }),
+ Action::ToggleActiveSyncTab => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleActiveSyncTab as i32,
+ optional_payload: None,
+ }),
+ Action::NewPane(direction, new_pane_name) => {
+ let direction = direction.and_then(|direction| {
+ let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
+ Some(protobuf_direction as i32)
+ });
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewPane as i32,
+ optional_payload: Some(OptionalPayload::NewPanePayload(NewPanePayload {
+ direction,
+ pane_name: new_pane_name,
+ })),
+ })
+ },
+ Action::EditFile(path_to_file, line_number, cwd, direction, should_float) => {
+ let file_to_edit = path_to_file.display().to_string();
+ let cwd = cwd.map(|cwd| cwd.display().to_string());
+ let direction: Option<i32> = direction
+ .and_then(|d| ProtobufResizeDirection::try_from(d).ok())
+ .map(|d| d as i32);
+ let line_number = line_number.map(|l| l as u32);
+ Ok(ProtobufAction {
+ name: ProtobufActionName::EditFile as i32,
+ optional_payload: Some(OptionalPayload::EditFilePayload(EditFilePayload {
+ file_to_edit,
+ line_number,
+ should_float,
+ direction,
+ cwd,
+ })),
+ })
+ },
+ Action::NewFloatingPane(run_command_action, pane_name) => {
+ let command = run_command_action.and_then(|r| {
+ let mut protobuf_run_command_action: ProtobufRunCommandAction =
+ r.try_into().ok()?;
+ protobuf_run_command_action.pane_name = pane_name;
+ Some(protobuf_run_command_action)
+ });
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewFloatingPane as i32,
+ optional_payload: Some(OptionalPayload::NewFloatingPanePayload(
+ NewFloatingPanePayload { command },
+ )),
+ })
+ },
+ Action::NewTiledPane(direction, run_command_action, pane_name) => {
+ let direction = direction.and_then(|direction| {
+ let protobuf_direction: ProtobufResizeDirection = direction.try_into().ok()?;
+ Some(protobuf_direction as i32)
+ });
+ let command = run_command_action.and_then(|r| {
+ let mut protobuf_run_command_action: ProtobufRunCommandAction =
+ r.try_into().ok()?;
+ let pane_name = pane_name.and_then(|n| n.try_into().ok());
+ protobuf_run_command_action.pane_name = pane_name;
+ Some(protobuf_run_command_action)
+ });
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewTiledPane as i32,
+ optional_payload: Some(OptionalPayload::NewTiledPanePayload(
+ NewTiledPanePayload { direction, command },
+ )),
+ })
+ },
+ Action::TogglePaneEmbedOrFloating => Ok(ProtobufAction {
+ name: ProtobufActionName::TogglePaneEmbedOrFloating as i32,
+ optional_payload: None,
+ }),
+ Action::ToggleFloatingPanes => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleFloatingPanes as i32,
+ optional_payload: None,
+ }),
+ Action::CloseFocus => Ok(ProtobufAction {
+ name: ProtobufActionName::CloseFocus as i32,
+ optional_payload: None,
+ }),
+ Action::PaneNameInput(bytes) => Ok(ProtobufAction {
+ name: ProtobufActionName::PaneNameInput as i32,
+ optional_payload: Some(OptionalPayload::PaneNameInputPayload(bytes)),
+ }),
+ Action::UndoRenamePane => Ok(ProtobufAction {
+ name: ProtobufActionName::UndoRenamePane as i32,
+ optional_payload: None,
+ }),
+ Action::NewTab(..) => {
+ // we do not serialize the various newtab payloads
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewTab as i32,
+ optional_payload: None,
+ })
+ },
+ Action::GoToNextTab => Ok(ProtobufAction {
+ name: ProtobufActionName::GoToNextTab as i32,
+ optional_payload: None,
+ }),
+ Action::GoToPreviousTab => Ok(ProtobufAction {
+ name: ProtobufActionName::GoToPreviousTab as i32,
+ optional_payload: None,
+ }),
+ Action::CloseTab => Ok(ProtobufAction {
+ name: ProtobufActionName::CloseTab as i32,
+ optional_payload: None,
+ }),
+ Action::GoToTab(tab_index) => Ok(ProtobufAction {
+ name: ProtobufActionName::GoToTab as i32,
+ optional_payload: Some(OptionalPayload::GoToTabPayload(tab_index)),
+ }),
+ Action::GoToTabName(tab_name, create) => Ok(ProtobufAction {
+ name: ProtobufActionName::GoToTabName as i32,
+ optional_payload: Some(OptionalPayload::GoToTabNamePayload(GoToTabNamePayload {
+ tab_name,
+ create,
+ })),
+ }),
+ Action::ToggleTab => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleTab as i32,
+ optional_payload: None,
+ }),
+ Action::TabNameInput(bytes) => Ok(ProtobufAction {
+ name: ProtobufActionName::TabNameInput as i32,
+ optional_payload: Some(OptionalPayload::TabNameInputPayload(bytes)),
+ }),
+ Action::UndoRenameTab => Ok(ProtobufAction {
+ name: ProtobufActionName::UndoRenameTab as i32,
+ optional_payload: None,
+ }),
+ Action::Run(run_command_action) => {
+ let run_command_action: ProtobufRunCommandAction = run_command_action.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::Run as i32,
+ optional_payload: Some(OptionalPayload::RunPayload(run_command_action)),
+ })
+ },
+ Action::Detach => Ok(ProtobufAction {
+ name: ProtobufActionName::Detach as i32,
+ optional_payload: None,
+ }),
+ Action::LeftClick(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::LeftClick as i32,
+ optional_payload: Some(OptionalPayload::LeftClickPayload(position)),
+ })
+ },
+ Action::RightClick(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::RightClick as i32,
+ optional_payload: Some(OptionalPayload::RightClickPayload(position)),
+ })
+ },
+ Action::MiddleClick(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MiddleClick as i32,
+ optional_payload: Some(OptionalPayload::MiddleClickPayload(position)),
+ })
+ },
+ Action::LaunchOrFocusPlugin(run_plugin, should_float) => {
+ let url: Url = Url::from(&run_plugin.location);
+ Ok(ProtobufAction {
+ name: ProtobufActionName::LaunchOrFocusPlugin as i32,
+ optional_payload: Some(OptionalPayload::LaunchOrFocusPluginPayload(
+ LaunchOrFocusPluginPayload {
+ plugin_url: url.into(),
+ should_float,
+ plugin_configuration: Some(run_plugin.configuration.try_into()?),
+ },
+ )),
+ })
+ },
+ Action::LeftMouseRelease(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::LeftMouseRelease as i32,
+ optional_payload: Some(OptionalPayload::LeftMouseReleasePayload(position)),
+ })
+ },
+ Action::RightMouseRelease(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::RightMouseRelease as i32,
+ optional_payload: Some(OptionalPayload::RightMouseReleasePayload(position)),
+ })
+ },
+ Action::MiddleMouseRelease(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MiddleMouseRelease as i32,
+ optional_payload: Some(OptionalPayload::MiddleMouseReleasePayload(position)),
+ })
+ },
+ Action::MouseHoldLeft(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MouseHoldLeft as i32,
+ optional_payload: Some(OptionalPayload::MouseHoldLeftPayload(position)),
+ })
+ },
+ Action::MouseHoldRight(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MouseHoldRight as i32,
+ optional_payload: Some(OptionalPayload::MouseHoldRightPayload(position)),
+ })
+ },
+ Action::MouseHoldMiddle(position) => {
+ let position: ProtobufPosition = position.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::MouseHoldMiddle as i32,
+ optional_payload: Some(OptionalPayload::MouseHoldMiddlePayload(position)),
+ })
+ },
+ Action::SearchInput(bytes) => Ok(ProtobufAction {
+ name: ProtobufActionName::SearchInput as i32,
+ optional_payload: Some(OptionalPayload::SearchInputPayload(bytes)),
+ }),
+ Action::Search(search_direction) => {
+ let search_direction: ProtobufSearchDirection = search_direction.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::Search as i32,
+ optional_payload: Some(OptionalPayload::SearchPayload(search_direction as i32)),
+ })
+ },
+ Action::SearchToggleOption(search_option) => {
+ let search_option: ProtobufSearchOption = search_option.try_into()?;
+ Ok(ProtobufAction {
+ name: ProtobufActionName::SearchToggleOption as i32,
+ optional_payload: Some(OptionalPayload::SearchToggleOptionPayload(
+ search_option as i32,
+ )),
+ })
+ },
+ Action::ToggleMouseMode => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleMouseMode as i32,
+ optional_payload: None,
+ }),
+ Action::PreviousSwapLayout => Ok(ProtobufAction {
+ name: ProtobufActionName::PreviousSwapLayout as i32,
+ optional_payload: None,
+ }),
+ Action::NextSwapLayout => Ok(ProtobufAction {
+ name: ProtobufActionName::NextSwapLayout as i32,
+ optional_payload: None,
+ }),
+ Action::QueryTabNames => Ok(ProtobufAction {
+ name: ProtobufActionName::QueryTabNames as i32,
+ optional_payload: None,
+ }),
+ Action::NewTiledPluginPane(run_plugin, pane_name) => {
+ let plugin_url: Url = Url::from(&run_plugin.location);
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewTiledPluginPane as i32,
+ optional_payload: Some(OptionalPayload::NewTiledPluginPanePayload(
+ NewPluginPanePayload {
+ plugin_url: plugin_url.into(),
+ pane_name,
+ },
+ )),
+ })
+ },
+ Action::NewFloatingPluginPane(run_plugin, pane_name) => {
+ let plugin_url: Url = Url::from(&run_plugin.location);
+ Ok(ProtobufAction {
+ name: ProtobufActionName::NewFloatingPluginPane as i32,
+ optional_payload: Some(OptionalPayload::NewFloatingPluginPanePayload(
+ NewPluginPanePayload {
+ plugin_url: plugin_url.into(),
+ pane_name,
+ },
+ )),
+ })
+ },
+ Action::StartOrReloadPlugin(run_plugin) => {
+ let plugin_url: Url = Url::from(&run_plugin.location);
+ Ok(ProtobufAction {
+ name: ProtobufActionName::StartOrReloadPlugin as i32,
+ optional_payload: Some(OptionalPayload::StartOrReloadPluginPayload(
+ plugin_url.into(),
+ )),
+ })
+ },
+ Action::CloseTerminalPane(terminal_pane_id) => Ok(ProtobufAction {
+ name: ProtobufActionName::CloseTerminalPane as i32,
+ optional_payload: Some(OptionalPayload::CloseTerminalPanePayload(terminal_pane_id)),
+ }),
+ Action::ClosePluginPane(plugin_pane_id) => Ok(ProtobufAction {
+ name: ProtobufActionName::ClosePluginPane as i32,
+ optional_payload: Some(OptionalPayload::ClosePluginPanePayload(plugin_pane_id)),
+ }),
+ Action::FocusTerminalPaneWithId(terminal_pane_id, should_float_if_hidden) => {
+ Ok(ProtobufAction {
+ name: ProtobufActionName::FocusTerminalPaneWithId as i32,
+ optional_payload: Some(OptionalPayload::FocusTerminalPaneWithIdPayload(
+ PaneIdAndShouldFloat {
+ pane_id: terminal_pane_id,
+ should_float_if_hidden,
+ },
+ )),
+ })
+ },
+ Action::FocusPluginPaneWithId(plugin_pane_id, should_float_if_hidden) => {
+ Ok(ProtobufAction {
+ name: ProtobufActionName::FocusPluginPaneWithId as i32,
+ optional_payload: Some(OptionalPayload::FocusPluginPaneWithIdPayload(
+ PaneIdAndShouldFloat {
+ pane_id: plugin_pane_id,
+ should_float_if_hidden,
+ },
+ )),
+ })
+ },
+ Action::RenameTerminalPane(terminal_pane_id, new_name) => Ok(ProtobufAction {
+ name: ProtobufActionName::RenameTerminalPane as i32,
+ optional_payload: Some(OptionalPayload::RenameTerminalPanePayload(IdAndName {
+ name: new_name,
+ id: terminal_pane_id,
+ })),
+ }),
+ Action::RenamePluginPane(plugin_pane_id, new_name) => Ok(ProtobufAction {
+ name: ProtobufActionName::RenamePluginPane as i32,
+ optional_payload: Some(OptionalPayload::RenamePluginPanePayload(IdAndName {
+ name: new_name,
+ id: plugin_pane_id,
+ })),
+ }),
+ Action::RenameTab(tab_index, new_name) => Ok(ProtobufAction {
+ name: ProtobufActionName::RenameTab as i32,
+ optional_payload: Some(OptionalPayload::RenameTabPayload(IdAndName {
+ name: new_name,
+ id: tab_index,
+ })),
+ }),
+ Action::BreakPane => Ok(ProtobufAction {
+ name: ProtobufActionName::BreakPane as i32,
+ optional_payload: None,
+ }),
+ Action::BreakPaneRight => Ok(ProtobufAction {
+ name: ProtobufActionName::BreakPaneRight as i32,
+ optional_payload: None,
+ }),
+ Action::BreakPaneLeft => Ok(ProtobufAction {
+ name: ProtobufActionName::BreakPaneLeft as i32,
+ optional_payload: None,
+ }),
+ Action::NoOp
+ | Action::Confirm
+ | Action::Deny
+ | Action::Copy
+ | Action::SkipConfirm(..) => Err("Unsupported action"),
+ }
+ }
+}
+
+impl TryFrom<ProtobufSearchOption> for SearchOption {
+ type Error = &'static str;
+ fn try_from(protobuf_search_option: ProtobufSearchOption) -> Result<Self, &'static str> {
+ match protobuf_search_option {
+ ProtobufSearchOption::CaseSensitivity => Ok(SearchOption::CaseSensitivity),
+ ProtobufSearchOption::WholeWord => Ok(SearchOption::WholeWord),
+ ProtobufSearchOption::Wrap => Ok(SearchOption::Wrap),
+ }
+ }
+}
+
+impl TryFrom<SearchOption> for ProtobufSearchOption {
+ type Error = &'static str;
+ fn try_from(search_option: SearchOption) -> Result<Self, &'static str> {
+ match search_option {
+ SearchOption::CaseSensitivity => Ok(ProtobufSearchOption::CaseSensitivity),
+ SearchOption::WholeWord => Ok(ProtobufSearchOption::WholeWord),
+ SearchOption::Wrap => Ok(ProtobufSearchOption::Wrap),
+ }
+ }
+}
+
+impl TryFrom<ProtobufSearchDirection> for SearchDirection {
+ type Error = &'static str;
+ fn try_from(protobuf_search_direction: ProtobufSearchDirection) -> Result<Self, &'static str> {
+ match protobuf_search_direction {
+ ProtobufSearchDirection::Up => Ok(SearchDirection::Up),
+ ProtobufSearchDirection::Down => Ok(SearchDirection::Down),
+ }
+ }
+}
+
+impl TryFrom<SearchDirection> for ProtobufSearchDirection {
+ type Error = &'static str;
+ fn try_from(search_direction: SearchDirection) -> Result<Self, &'static str> {
+ match search_direction {
+ SearchDirection::Up => Ok(ProtobufSearchDirection::Up),
+ SearchDirection::Down => Ok(ProtobufSearchDirection::Down),
+ }
+ }
+}
+
+impl TryFrom<ProtobufRunCommandAction> for RunCommandAction {
+ type Error = &'static str;
+ fn try_from(
+ protobuf_run_command_action: ProtobufRunCommandAction,
+ ) -> Result<Self, &'static str> {
+ let command = PathBuf::from(protobuf_run_command_action.command);
+ let args: Vec<String> = protobuf_run_command_action.args;
+ let cwd: Option<PathBuf> = protobuf_run_command_action.cwd.map(|c| PathBuf::from(c));
+ let direction: Option<Direction> = protobuf_run_command_action
+ .direction
+ .and_then(|d| ProtobufResizeDirection::from_i32(d))
+ .and_then(|d| d.try_into().ok());
+ let hold_on_close = protobuf_run_command_action.hold_on_close;
+ let hold_on_start = protobuf_run_command_action.hold_on_start;
+ Ok(RunCommandAction {
+ command,
+ args,
+ cwd,
+ direction,
+ hold_on_close,
+ hold_on_start,
+ })
+ }
+}
+
+impl TryFrom<RunCommandAction> for ProtobufRunCommandAction {
+ type Error = &'static str;
+ fn try_from(run_command_action: RunCommandAction) -> Result<Self, &'static str> {
+ let command = run_command_action.command.display().to_string();
+ let args: Vec<String> = run_command_action.args;
+ let cwd = run_command_action.cwd.map(|c| c.display().to_string());
+ let direction = run_command_action.direction.and_then(|p| {
+ let direction: ProtobufResizeDirection = p.try_into().ok()?;
+ Some(direction as i32)
+ });
+ let hold_on_close = run_command_action.hold_on_close;
+ let hold_on_start = run_command_action.hold_on_start;
+ Ok(ProtobufRunCommandAction {
+ command,
+ args,
+ cwd,
+ direction,
+ hold_on_close,
+ hold_on_start,
+ pane_name: None,
+ })
+ }
+}
+
+impl TryFrom<ProtobufPosition> for Position {
+ type Error = &'static str;
+ fn try_from(protobuf_position: ProtobufPosition) -> Result<Self, &'static str> {
+ Ok(Position::new(
+ protobuf_position.line as i32,
+ protobuf_position.column as u16,
+ ))
+ }
+}
+
+impl TryFrom<Position> for ProtobufPosition {
+ type Error = &'static str;
+ fn try_from(position: Position) -> Result<Self, &'static str> {
+ Ok(ProtobufPosition {
+ line: position.line.0 as i64,
+ column: position.column.0 as i64,
+ })
+ }
+}
+
+impl TryFrom<ProtobufPluginConfiguration> for PluginUserConfiguration {
+ type Error = &'static str;
+ fn try_from(plugin_configuration: ProtobufPluginConfiguration) -> Result<Self, &'static str> {
+ let mut converted = BTreeMap::new();
+ for name_and_value in plugin_configuration.name_and_value {
+ converted.insert(name_and_value.name, name_and_value.value);
+ }
+ Ok(PluginUserConfiguration::new(converted))
+ }
+}
+
+impl TryFrom<PluginUserConfiguration> for ProtobufPluginConfiguration {
+ type Error = &'static str;
+ fn try_from(plugin_configuration: PluginUserConfiguration) -> Result<Self, &'static str> {
+ let mut converted = vec![];
+ for (name, value) in plugin_configuration.inner() {
+ let name_and_value = ProtobufNameAndValue {
+ name: name.to_owned(),
+ value: value.to_owned(),
+ };
+ converted.push(name_and_value);
+ }
+ Ok(ProtobufPluginConfiguration {
+ name_and_value: converted,
+ })
+ }
+}
+
+impl TryFrom<&ProtobufPluginConfiguration> for BTreeMap<String, String> {
+ type Error = &'static str;
+ fn try_from(plugin_configuration: &ProtobufPluginConfiguration) -> Result<Self, &'static str> {
+ let mut converted = BTreeMap::new();
+ for name_and_value in &plugin_configuration.name_and_value {
+ converted.insert(
+ name_and_value.name.to_owned(),
+ name_and_value.value.to_owned(),
+ );
+ }
+ Ok(converted)
+ }
+}
diff --git a/zellij-utils/src/plugin_api/command.proto b/zellij-utils/src/plugin_api/command.proto
new file mode 100644
index 00000000..70402f25
--- /dev/null
+++ b/zellij-utils/src/plugin_api/command.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package api.command;
+
+message Command {
+ string path = 1;
+ repeated string args = 2;
+ optional string cwd = 3;
+}
diff --git a/zellij-utils/src/plugin_api/command.rs b/zellij-utils/src/plugin_api/command.rs
new file mode 100644
index 00000000..2f8bf300
--- /dev/null
+++ b/zellij-utils/src/plugin_api/command.rs
@@ -0,0 +1,26 @@
+pub use super::generated_api::api::command::Command as ProtobufCommand;
+use crate::data::CommandToRun;
+
+use std::convert::TryFrom;
+use std::path::PathBuf;
+
+impl TryFrom<ProtobufCommand> for CommandToRun {
+ type Error = &'static str;
+ fn try_from(protobuf_command: ProtobufCommand) -> Result<Self, &'static str> {
+ let path = PathBuf::from(protobuf_command.path);
+ let args = protobuf_command.args;
+ let cwd = protobuf_command.cwd.map(|c| PathBuf::from(c));
+ Ok(CommandToRun { path, args, cwd })
+ }
+}
+
+impl TryFrom<CommandToRun> for ProtobufCommand {
+ type Error = &'static str;
+ fn try_from(command_to_run: CommandToRun) -> Result<Self, &'static str> {
+ Ok(ProtobufCommand {
+ path: command_to_run.path.display().to_string(),
+ args: command_to_run.args,
+ cwd: command_to_run.cwd.map(|c| c.display().to_string()),
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto
new file mode 100644
index 00000000..95928ae3
--- /dev/null
+++ b/zellij-utils/src/plugin_api/event.proto
@@ -0,0 +1,162 @@
+syntax = "proto3";
+
+import "input_mode.proto";
+import "key.proto";
+import "style.proto";
+import "action.proto";
+
+package api.event;
+
+enum EventType {
+ /// The input mode or relevant metadata changed
+ ModeUpdate = 0;
+ /// The tab state in the app was changed
+ TabUpdate = 1;
+ /// The pane state in the app was changed
+ PaneUpdate = 2;
+ /// A key was pressed while the user is focused on this plugin's pane
+ Key = 3;
+ /// A mouse event happened while the user is focused on this plugin's pane
+ Mouse = 4;
+ /// A timer expired set by the `set_timeout` method exported by `zellij-tile`.
+ Timer = 5;
+ /// Text was copied to the clipboard anywhere in the app
+ CopyToClipboard = 6;
+ /// Failed to copy text to clipboard anywhere in the app
+ SystemClipboardFailure = 7;
+ /// Input was received anywhere in the app
+ InputReceived = 8;
+ /// This plugin became visible or invisible
+ Visible = 9;
+ /// A message from one of the plugin's workers
+ CustomMessage = 10;
+ /// A file was created somewhere in the Zellij CWD folder
+ FileSystemCreate = 11;
+ /// A file was accessed somewhere in the Zellij CWD folder
+ FileSystemRead = 12;
+ /// A file was modified somewhere in the Zellij CWD folder
+ FileSystemUpdate = 13;
+ /// A file was deleted somewhere in the Zellij CWD folder
+ FileSystemDelete = 14;
+}
+
+message EventNameList {
+ repeated EventType event_types = 1;
+}
+
+message Event {
+ EventType name = 1;
+ oneof payload {
+ ModeUpdatePayload mode_update_payload = 2;
+ TabUpdatePayload tab_update_payload = 3;
+ PaneUpdatePayload pane_update_payload = 4;
+ key.Key key_payload = 5;
+ MouseEventPayload mouse_event_payload = 6;
+ float timer_payload = 7;
+ CopyDestination copy_to_clipboard_payload = 8;
+ bool visible_payload = 9;
+ CustomMessagePayload custom_message_payload = 10;
+ FileListPayload file_list_payload = 11;
+ }
+}
+
+message FileListPayload {
+ repeated string paths = 1;
+}
+
+message CustomMessagePayload {
+ string message_name = 1;
+ string payload = 2;
+}
+
+enum CopyDestination {
+ Command = 0;
+ Primary = 1;
+ System = 2;
+}
+
+message MouseEventPayload {
+ MouseEventName mouse_event_name = 1;
+ oneof mouse_event_payload {
+ uint32 line_count = 2;
+ action.Position position = 3;
+ }
+}
+
+enum MouseEventName {
+ MouseScrollUp = 0;
+ MouseScrollDown = 1;
+ MouseLeftClick = 2;
+ MouseRightClick = 3;
+ MouseHold = 4;
+ MouseRelease = 5;
+}
+
+message TabUpdatePayload {
+ repeated TabInfo tab_info = 1;
+}
+
+message PaneUpdatePayload {
+ repeated PaneManifest pane_manifest = 1;
+}
+
+message PaneManifest {
+ uint32 tab_index = 1;
+ repeated PaneInfo panes = 2;
+}
+
+message PaneInfo {
+ uint32 id = 1;
+ bool is_plugin = 2;
+ bool is_focused = 3;
+ bool is_fullscreen = 4;
+ bool is_floating = 5;
+ bool is_suppressed = 6;
+ string title = 7;
+ bool exited = 8;
+ optional int32 exit_status = 9;
+ bool is_held = 10;
+ uint32 pane_x = 11;
+ uint32 pane_content_x = 12;
+ uint32 pane_y = 13;
+ uint32 pane_content_y = 14;
+ uint32 pane_rows = 15;
+ uint32 pane_content_rows = 16;
+ uint32 pane_columns = 17;
+ uint32 pane_content_columns = 18;
+ optional action.Position cursor_coordinates_in_pane = 19;
+ optional string terminal_command = 20;
+ optional string plugin_url = 21;
+ bool is_selectable = 22;
+}
+
+message TabInfo {
+ uint32 position = 1;
+ string name = 2;
+ bool active = 3;
+ uint32 panes_to_hide = 4;
+ bool is_fullscreen_active = 5;
+ bool is_sync_panes_active = 6;
+ bool are_floating_panes_visible = 7;
+ repeated uint32 other_focused_clients = 8;
+ optional string active_swap_layout_name = 9;
+ bool is_swap_layout_dirty = 10;
+}
+
+message ModeUpdatePayload {
+ input_mode.InputMode current_mode = 1;
+ repeated InputModeKeybinds keybinds = 2;
+ style.Style style = 3;
+ bool arrow_fonts_support = 4;
+ optional string session_name = 5;
+}
+
+message InputModeKeybinds {
+ input_mode.InputMode mode = 1;
+ repeated KeyBind key_bind = 2;
+}
+
+message KeyBind {
+ key.Key key = 1;
+ repeated action.Action action = 2;
+}
diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs
new file mode 100644
index 00000000..315fa54b
--- /dev/null
+++ b/zellij-utils/src/plugin_api/event.rs
@@ -0,0 +1,1059 @@
+pub use super::generated_api::api::{
+ action::{Action as ProtobufAction, Position as ProtobufPosition},
+ event::{
+ event::Payload as ProtobufEventPayload, CopyDestination as ProtobufCopyDestination,
+ Event as ProtobufEvent, EventNameList as ProtobufEventNameList,
+ EventType as ProtobufEventType, InputModeKeybinds as ProtobufInputModeKeybinds,
+ KeyBind as ProtobufKeyBind, ModeUpdatePayload as ProtobufModeUpdatePayload,
+ PaneInfo as ProtobufPaneInfo, PaneManifest as ProtobufPaneManifest,
+ TabInfo as ProtobufTabInfo, *,
+ },
+ input_mode::InputMode as ProtobufInputMode,
+ key::Key as ProtobufKey,
+ style::Style as ProtobufStyle,
+};
+use crate::data::{
+ CopyDestination, Direction, Event, EventType, InputMode, Key, ModeInfo, Mouse, Palette,
+ PaletteColor, PaneInfo, PaneManifest, PluginCapabilities, Style, TabInfo, ThemeHue,
+};
+use crate::errors::prelude::*;
+use crate::input::actions::Action;
+
+use std::collections::{HashMap, HashSet};
+use std::convert::TryFrom;
+use std::path::PathBuf;
+
+impl TryFrom<ProtobufEvent> for Event {
+ type Error = &'static str;
+ fn try_from(protobuf_event: ProtobufEvent) -> Result<Self, &'static str> {
+ match ProtobufEventType::from_i32(protobuf_event.name) {
+ Some(ProtobufEventType::ModeUpdate) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::ModeUpdatePayload(protobuf_mode_update_payload)) => {
+ let mode_info: ModeInfo = protobuf_mode_update_payload.try_into()?;
+ Ok(Event::ModeUpdate(mode_info))
+ },
+ _ => Err("Malformed payload for the ModeUpdate Event"),
+ },
+ Some(ProtobufEventType::TabUpdate) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::TabUpdatePayload(protobuf_tab_info_payload)) => {
+ let mut tab_infos: Vec<TabInfo> = vec![];
+ for protobuf_tab_info in protobuf_tab_info_payload.tab_info {
+ tab_infos.push(TabInfo::try_from(protobuf_tab_info)?);
+ }
+ Ok(Event::TabUpdate(tab_infos))
+ },
+ _ => Err("Malformed payload for the TabUpdate Event"),
+ },
+ Some(ProtobufEventType::PaneUpdate) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::PaneUpdatePayload(protobuf_pane_update_payload)) => {
+ let mut pane_manifest: HashMap<usize, Vec<PaneInfo>> = HashMap::new();
+ for protobuf_pane_manifest in protobuf_pane_update_payload.pane_manifest {
+ let tab_index = protobuf_pane_manifest.tab_index as usize;
+ let mut panes = vec![];
+ for protobuf_pane_info in protobuf_pane_manifest.panes {
+ panes.push(protobuf_pane_info.try_into()?);
+ }
+ if pane_manifest.contains_key(&tab_index) {
+ return Err("Duplicate tab definition in pane manifest");
+ }
+ pane_manifest.insert(tab_index, panes);
+ }
+ Ok(Event::PaneUpdate(PaneManifest {
+ panes: pane_manifest,
+ }))
+ },
+ _ => Err("Malformed payload for the PaneUpdate Event"),
+ },
+ Some(ProtobufEventType::Key) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::KeyPayload(protobuf_key)) => {
+ Ok(Event::Key(protobuf_key.try_into()?))
+ },
+ _ => Err("Malformed payload for the Key Event"),
+ },
+ Some(ProtobufEventType::Mouse) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::MouseEventPayload(protobuf_mouse)) => {
+ Ok(Event::Mouse(protobuf_mouse.try_into()?))
+ },
+ _ => Err("Malformed payload for the Mouse Event"),
+ },
+ Some(ProtobufEventType::Timer) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::TimerPayload(seconds)) => {
+ Ok(Event::Timer(seconds as f64))
+ },
+ _ => Err("Malformed payload for the Timer Event"),
+ },
+ Some(ProtobufEventType::CopyToClipboard) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::CopyToClipboardPayload(copy_to_clipboard)) => {
+ let protobuf_copy_to_clipboard =
+ ProtobufCopyDestination::from_i32(copy_to_clipboard)
+ .ok_or("Malformed copy to clipboard payload")?;
+ Ok(Event::CopyToClipboard(
+ protobuf_copy_to_clipboard.try_into()?,
+ ))
+ },
+ _ => Err("Malformed payload for the Copy To Clipboard Event"),
+ },
+ Some(ProtobufEventType::SystemClipboardFailure) => match protobuf_event.payload {
+ None => Ok(Event::SystemClipboardFailure),
+ _ => Err("Malformed payload for the system clipboard failure Event"),
+ },
+ Some(ProtobufEventType::InputReceived) => match protobuf_event.payload {
+ None => Ok(Event::InputReceived),
+ _ => Err("Malformed payload for the input received Event"),
+ },
+ Some(ProtobufEventType::Visible) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::VisiblePayload(is_visible)) => {
+ Ok(Event::Visible(is_visible))
+ },
+ _ => Err("Malformed payload for the visible Event"),
+ },
+ Some(ProtobufEventType::CustomMessage) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::CustomMessagePayload(custom_message_payload)) => {
+ Ok(Event::CustomMessage(
+ custom_message_payload.message_name,
+ custom_message_payload.payload,
+ ))
+ },
+ _ => Err("Malformed payload for the custom message Event"),
+ },
+ Some(ProtobufEventType::FileSystemCreate) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
+ let file_paths = file_list_payload
+ .paths
+ .iter()
+ .map(|p| PathBuf::from(p))
+ .collect();
+ Ok(Event::FileSystemCreate(file_paths))
+ },
+ _ => Err("Malformed payload for the file system create Event"),
+ },
+ Some(ProtobufEventType::FileSystemRead) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
+ let file_paths = file_list_payload
+ .paths
+ .iter()
+ .map(|p| PathBuf::from(p))
+ .collect();
+ Ok(Event::FileSystemRead(file_paths))
+ },
+ _ => Err("Malformed payload for the file system read Event"),
+ },
+ Some(ProtobufEventType::FileSystemUpdate) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
+ let file_paths = file_list_payload
+ .paths
+ .iter()
+ .map(|p| PathBuf::from(p))
+ .collect();
+ Ok(Event::FileSystemUpdate(file_paths))
+ },
+ _ => Err("Malformed payload for the file system update Event"),
+ },
+ Some(ProtobufEventType::FileSystemDelete) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::FileListPayload(file_list_payload)) => {
+ let file_paths = file_list_payload
+ .paths
+ .iter()
+ .map(|p| PathBuf::from(p))
+ .collect();
+ Ok(Event::FileSystemDelete(file_paths))
+ },
+ _ => Err("Malformed payload for the file system delete Event"),
+ },
+ None => Err("Unknown Protobuf Event"),
+ }
+ }
+}
+
+impl TryFrom<Event> for ProtobufEvent {
+ type Error = &'static str;
+ fn try_from(event: Event) -> Result<Self, &'static str> {
+ match event {
+ Event::ModeUpdate(mode_info) => {
+ let protobuf_mode_update_payload = mode_info.try_into()?;
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::ModeUpdate as i32,
+ payload: Some(event::Payload::ModeUpdatePayload(
+ protobuf_mode_update_payload,
+ )),
+ })
+ },
+ Event::TabUpdate(tab_infos) => {
+ let mut protobuf_tab_infos = vec![];
+ for tab_info in tab_infos {
+ protobuf_tab_infos.push(tab_info.try_into()?);
+ }
+ let tab_update_payload = TabUpdatePayload {
+ tab_info: protobuf_tab_infos,
+ };
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::TabUpdate as i32,
+ payload: Some(event::Payload::TabUpdatePayload(tab_update_payload)),
+ })
+ },
+ Event::PaneUpdate(pane_manifest) => {
+ let mut protobuf_pane_manifests = vec![];
+ for (tab_index, pane_infos) in pane_manifest.panes {
+ let mut protobuf_pane_infos = vec![];
+ for pane_info in pane_infos {
+ protobuf_pane_infos.push(pane_info.try_into()?);
+ }
+ protobuf_pane_manifests.push(ProtobufPaneManifest {
+ tab_index: tab_index as u32,
+ panes: protobuf_pane_infos,
+ });
+ }
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::PaneUpdate as i32,
+ payload: Some(event::Payload::PaneUpdatePayload(PaneUpdatePayload {
+ pane_manifest: protobuf_pane_manifests,
+ })),
+ })
+ },
+ Event::Key(key) => Ok(ProtobufEvent {
+ name: ProtobufEventType::Key as i32,
+ payload: Some(event::Payload::KeyPayload(key.try_into()?)),
+ }),
+ Event::Mouse(mouse_event) => {
+ let protobuf_mouse_payload = mouse_event.try_into()?;
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::Mouse as i32,
+ payload: Some(event::Payload::MouseEventPayload(protobuf_mouse_payload)),
+ })
+ },
+ Event::Timer(seconds) => Ok(ProtobufEvent {
+ name: ProtobufEventType::Timer as i32,
+ payload: Some(event::Payload::TimerPayload(seconds as f32)),
+ }),
+ Event::CopyToClipboard(clipboard_destination) => {
+ let protobuf_copy_destination: ProtobufCopyDestination =
+ clipboard_destination.try_into()?;
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::CopyToClipboard as i32,
+ payload: Some(event::Payload::CopyToClipboardPayload(
+ protobuf_copy_destination as i32,
+ )),
+ })
+ },
+ Event::SystemClipboardFailure => Ok(ProtobufEvent {
+ name: ProtobufEventType::SystemClipboardFailure as i32,
+ payload: None,
+ }),
+ Event::InputReceived => Ok(ProtobufEvent {
+ name: ProtobufEventType::InputReceived as i32,
+ payload: None,
+ }),
+ Event::Visible(is_visible) => Ok(ProtobufEvent {
+ name: ProtobufEventType::Visible as i32,
+ payload: Some(event::Payload::VisiblePayload(is_visible)),
+ }),
+ Event::CustomMessage(message, payload) => Ok(ProtobufEvent {
+ name: ProtobufEventType::CustomMessage as i32,
+ payload: Some(event::Payload::CustomMessagePayload(CustomMessagePayload {
+ message_name: message,
+ payload,
+ })),
+ }),
+ Event::FileSystemCreate(paths) => {
+ let file_list_payload = FileListPayload {
+ paths: paths.iter().map(|p| p.display().to_string()).collect(),
+ };
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::FileSystemCreate as i32,
+ payload: Some(event::Payload::FileListPayload(file_list_payload)),
+ })
+ },
+ Event::FileSystemRead(paths) => {
+ let file_list_payload = FileListPayload {
+ paths: paths.iter().map(|p| p.display().to_string()).collect(),
+ };
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::FileSystemRead as i32,
+ payload: Some(event::Payload::FileListPayload(file_list_payload)),
+ })
+ },
+ Event::FileSystemUpdate(paths) => {
+ let file_list_payload = FileListPayload {
+ paths: paths.iter().map(|p| p.display().to_string()).collect(),
+ };
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::FileSystemUpdate as i32,
+ payload: Some(event::Payload::FileListPayload(file_list_payload)),
+ })
+ },
+ Event::FileSystemDelete(paths) => {
+ let file_list_payload = FileListPayload {
+ paths: paths.iter().map(|p| p.display().to_string()).collect(),
+ };
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::FileSystemDelete as i32,
+ payload: Some(event::Payload::FileListPayload(file_list_payload)),
+ })
+ },
+ }
+ }
+}
+
+impl TryFrom<CopyDestination> for ProtobufCopyDestination {
+ type Error = &'static str;
+ fn try_from(copy_destination: CopyDestination) -> Result<Self, &'static str> {
+ match copy_destination {
+ CopyDestination::Command => Ok(ProtobufCopyDestination::Command),
+ CopyDestination::Primary => Ok(ProtobufCopyDestination::Primary),
+ CopyDestination::System => Ok(ProtobufCopyDestination::System),
+ }
+ }
+}
+
+impl TryFrom<ProtobufCopyDestination> for CopyDestination {
+ type Error = &'static str;
+ fn try_from(protobuf_copy_destination: ProtobufCopyDestination) -> Result<Self, &'static str> {
+ match protobuf_copy_destination {
+ ProtobufCopyDestination::Command => Ok(CopyDestination::Command),
+ ProtobufCopyDestination::Primary => Ok(CopyDestination::Primary),
+ ProtobufCopyDestination::System => Ok(CopyDestination::System),
+ }
+ }
+}
+
+impl TryFrom<MouseEventPayload> for Mouse {
+ type Error = &'static str;
+ fn try_from(mouse_event_payload: MouseEventPayload) -> Result<Self, &'static str> {
+ match MouseEventName::from_i32(mouse_event_payload.mouse_event_name) {
+ Some(MouseEventName::MouseScrollUp) => match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
+ Ok(Mouse::ScrollUp(line_count as usize))
+ },
+ _ => Err("Malformed payload for mouse scroll up"),
+ },
+ Some(MouseEventName::MouseScrollDown) => {
+ match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::LineCount(line_count)) => {
+ Ok(Mouse::ScrollDown(line_count as usize))
+ },
+ _ => Err("Malformed payload for mouse scroll down"),
+ }
+ },
+ Some(MouseEventName::MouseLeftClick) => match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
+ Mouse::LeftClick(position.line as isize, position.column as usize),
+ ),
+ _ => Err("Malformed payload for mouse left click"),
+ },
+ Some(MouseEventName::MouseRightClick) => {
+ match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
+ Mouse::RightClick(position.line as isize, position.column as usize),
+ ),
+ _ => Err("Malformed payload for mouse right click"),
+ }
+ },
+ Some(MouseEventName::MouseHold) => match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
+ Mouse::Hold(position.line as isize, position.column as usize),
+ ),
+ _ => Err("Malformed payload for mouse hold"),
+ },
+ Some(MouseEventName::MouseRelease) => match mouse_event_payload.mouse_event_payload {
+ Some(mouse_event_payload::MouseEventPayload::Position(position)) => Ok(
+ Mouse::Release(position.line as isize, position.column as usize),
+ ),
+ _ => Err("Malformed payload for mouse release"),
+ },
+ None => Err("Malformed payload for MouseEventName"),
+ }
+ }
+}
+
+impl TryFrom<Mouse> for MouseEventPayload {
+ type Error = &'static str;
+ fn try_from(mouse: Mouse) -> Result<Self, &'static str> {
+ match mouse {
+ Mouse::ScrollUp(number_of_lines) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseScrollUp as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
+ number_of_lines as u32,
+ )),
+ }),
+ Mouse::ScrollDown(number_of_lines) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseScrollDown as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::LineCount(
+ number_of_lines as u32,
+ )),
+ }),
+ Mouse::LeftClick(line, column) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseLeftClick as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
+ ProtobufPosition {
+ line: line as i64,
+ column: column as i64,
+ },
+ )),
+ }),
+ Mouse::RightClick(line, column) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseRightClick as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
+ ProtobufPosition {
+ line: line as i64,
+ column: column as i64,
+ },
+ )),
+ }),
+ Mouse::Hold(line, column) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseHold as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
+ ProtobufPosition {
+ line: line as i64,
+ column: column as i64,
+ },
+ )),
+ }),
+ Mouse::Release(line, column) => Ok(MouseEventPayload {
+ mouse_event_name: MouseEventName::MouseRelease as i32,
+ mouse_event_payload: Some(mouse_event_payload::MouseEventPayload::Position(
+ ProtobufPosition {
+ line: line as i64,
+ column: column as i64,
+ },
+ )),
+ }),
+ }
+ }
+}
+
+impl TryFrom<ProtobufPaneInfo> for PaneInfo {
+ type Error = &'static str;
+ fn try_from(protobuf_pane_info: ProtobufPaneInfo) -> Result<Self, &'static str> {
+ Ok(PaneInfo {
+ id: protobuf_pane_info.id,
+ is_plugin: protobuf_pane_info.is_plugin,
+ is_focused: protobuf_pane_info.is_focused,
+ is_fullscreen: protobuf_pane_info.is_fullscreen,
+ is_floating: protobuf_pane_info.is_floating,
+ is_suppressed: protobuf_pane_info.is_suppressed,
+ title: protobuf_pane_info.title,
+ exited: protobuf_pane_info.exited,
+ exit_status: protobuf_pane_info.exit_status,
+ is_held: protobuf_pane_info.is_held,
+ pane_x: protobuf_pane_info.pane_x as usize,
+ pane_content_x: protobuf_pane_info.pane_content_x as usize,
+ pane_y: protobuf_pane_info.pane_y as usize,
+ pane_content_y: protobuf_pane_info.pane_content_y as usize,
+ pane_rows: protobuf_pane_info.pane_rows as usize,
+ pane_content_rows: protobuf_pane_info.pane_content_rows as usize,
+ pane_columns: protobuf_pane_info.pane_columns as usize,
+ pane_content_columns: protobuf_pane_info.pane_content_columns as usize,
+ cursor_coordinates_in_pane: protobuf_pane_info
+ .cursor_coordinates_in_pane
+ .map(|position| (position.column as usize, position.line as usize)),
+ terminal_command: protobuf_pane_info.terminal_command,
+ plugin_url: protobuf_pane_info.plugin_url,
+ is_selectable: protobuf_pane_info.is_selectable,
+ })
+ }
+}
+
+impl TryFrom<PaneInfo> for ProtobufPaneInfo {
+ type Error = &'static str;
+ fn try_from(pane_info: PaneInfo) -> Result<Self, &'static str> {
+ Ok(ProtobufPaneInfo {
+ id: pane_info.id,
+ is_plugin: pane_info.is_plugin,
+ is_focused: pane_info.is_focused,
+ is_fullscreen: pane_info.is_fullscreen,
+ is_floating: pane_info.is_floating,
+ is_suppressed: pane_info.is_suppressed,
+ title: pane_info.title,
+ exited: pane_info.exited,
+ exit_status: pane_info.exit_status,
+ is_held: pane_info.is_held,
+ pane_x: pane_info.pane_x as u32,
+ pane_content_x: pane_info.pane_content_x as u32,
+ pane_y: pane_info.pane_y as u32,
+ pane_content_y: pane_info.pane_content_y as u32,
+ pane_rows: pane_info.pane_rows as u32,
+ pane_content_rows: pane_info.pane_content_rows as u32,
+ pane_columns: pane_info.pane_columns as u32,
+ pane_content_columns: pane_info.pane_content_columns as u32,
+ cursor_coordinates_in_pane: pane_info.cursor_coordinates_in_pane.map(|(x, y)| {
+ ProtobufPosition {
+ column: x as i64,
+ line: y as i64,
+ }
+ }),
+ terminal_command: pane_info.terminal_command,
+ plugin_url: pane_info.plugin_url,
+ is_selectable: pane_info.is_selectable,
+ })
+ }
+}
+
+impl TryFrom<ProtobufTabInfo> for TabInfo {
+ type Error = &'static str;
+ fn try_from(protobuf_tab_info: ProtobufTabInfo) -> Result<Self, &'static str> {
+ Ok(TabInfo {
+ position: protobuf_tab_info.position as usize,
+ name: protobuf_tab_info.name,
+ active: protobuf_tab_info.active,
+ panes_to_hide: protobuf_tab_info.panes_to_hide as usize,
+ is_fullscreen_active: protobuf_tab_info.is_fullscreen_active,
+ is_sync_panes_active: protobuf_tab_info.is_sync_panes_active,
+ are_floating_panes_visible: protobuf_tab_info.are_floating_panes_visible,
+ other_focused_clients: protobuf_tab_info
+ .other_focused_clients
+ .iter()
+ .map(|c| *c as u16)
+ .collect(),
+ active_swap_layout_name: protobuf_tab_info.active_swap_layout_name,
+ is_swap_layout_dirty: protobuf_tab_info.is_swap_layout_dirty,
+ })
+ }
+}
+
+impl TryFrom<TabInfo> for ProtobufTabInfo {
+ type Error = &'static str;
+ fn try_from(tab_info: TabInfo) -> Result<Self, &'static str> {
+ Ok(ProtobufTabInfo {
+ position: tab_info.position as u32,
+ name: tab_info.name,
+ active: tab_info.active,
+ panes_to_hide: tab_info.panes_to_hide as u32,
+ is_fullscreen_active: tab_info.is_fullscreen_active,
+ is_sync_panes_active: tab_info.is_sync_panes_active,
+ are_floating_panes_visible: tab_info.are_floating_panes_visible,
+ other_focused_clients: tab_info
+ .other_focused_clients
+ .iter()
+ .map(|c| *c as u32)
+ .collect(),
+ active_swap_layout_name: tab_info.active_swap_layout_name,
+ is_swap_layout_dirty: tab_info.is_swap_layout_dirty,
+ })
+ }
+}
+
+impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
+ type Error = &'static str;
+ fn try_from(
+ mut protobuf_mode_update_payload: ProtobufModeUpdatePayload,
+ ) -> Result<Self, &'static str> {
+ let current_mode: InputMode =
+ ProtobufInputMode::from_i32(protobuf_mode_update_payload.current_mode)
+ .ok_or("Malformed InputMode in the ModeUpdate Event")?
+ .try_into()?;
+ let keybinds: Vec<(InputMode, Vec<(Key, Vec<Action>)>)> = protobuf_mode_update_payload
+ .keybinds
+ .iter_mut()
+ .filter_map(|k| {
+ let input_mode: InputMode = ProtobufInputMode::from_i32(k.mode)
+ .ok_or("Malformed InputMode in the ModeUpdate Event")
+ .ok()?
+ .try_into()
+ .ok()?;
+ let mut keybinds: Vec<(Key, Vec<Action>)> = vec![];
+ for mut protobuf_keybind in k.key_bind.drain(..) {
+ let key: Key = protobuf_keybind.key.unwrap().try_into().ok()?;
+ let mut actions: Vec<Action> = vec![];
+ for action in protobuf_keybind.action.drain(..) {
+ if let Ok(action) = action.try_into() {
+ actions.push(action);
+ }
+ }
+ keybinds.push((key, actions));
+ }
+ Some((input_mode, keybinds))
+ })
+ .collect();
+ let style: Style = protobuf_mode_update_payload
+ .style
+ .and_then(|m| m.try_into().ok())
+ .ok_or("malformed payload for mode_info")?;
+ let session_name = protobuf_mode_update_payload.session_name;
+ let capabilities = PluginCapabilities {
+ arrow_fonts: protobuf_mode_update_payload.arrow_fonts_support,
+ };
+ let mode_info = ModeInfo {
+ mode: current_mode,
+ keybinds,
+ style,
+ capabilities,
+ session_name,
+ };
+ Ok(mode_info)
+ }
+}
+
+impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
+ type Error = &'static str;
+ fn try_from(mode_info: ModeInfo) -> Result<Self, &'static str> {
+ let current_mode: ProtobufInputMode = mode_info.mode.try_into()?;
+ let style: ProtobufStyle = mode_info.style.try_into()?;
+ let arrow_fonts_support: bool = mode_info.capabilities.arrow_fonts;
+ let session_name = mode_info.session_name;
+ let mut protobuf_input_mode_keybinds: Vec<ProtobufInputModeKeybinds> = vec![];
+ for (input_mode, input_mode_keybinds) in mode_info.keybinds {
+ let mode: ProtobufInputMode = input_mode.try_into()?;
+ let mut keybinds: Vec<ProtobufKeyBind> = vec![];
+ for (key, actions) in input_mode_keybinds {
+ let protobuf_key: ProtobufKey = key.try_into()?;
+ let mut protobuf_actions: Vec<ProtobufAction> = vec![];
+ for action in actions {
+ if let Ok(protobuf_action) = action.try_into() {
+ protobuf_actions.push(protobuf_action);
+ }
+ }
+ let key_bind = ProtobufKeyBind {
+ key: Some(protobuf_key),
+ action: protobuf_actions,
+ };
+ keybinds.push(key_bind);
+ }
+ let input_mode_keybind = ProtobufInputModeKeybinds {
+ mode: mode as i32,
+ key_bind: keybinds,
+ };
+ protobuf_input_mode_keybinds.push(input_mode_keybind);
+ }
+ Ok(ProtobufModeUpdatePayload {
+ current_mode: current_mode as i32,
+ style: Some(style),
+ keybinds: protobuf_input_mode_keybinds,
+ arrow_fonts_support,
+ session_name,
+ })
+ }
+}
+
+impl TryFrom<ProtobufEventNameList> for HashSet<EventType> {
+ type Error = &'static str;
+ fn try_from(protobuf_event_name_list: ProtobufEventNameList) -> Result<Self, &'static str> {
+ let event_types: Vec<ProtobufEventType> = protobuf_event_name_list
+ .event_types
+ .iter()
+ .filter_map(|i| ProtobufEventType::from_i32(*i))
+ .collect();
+ let event_types: Vec<EventType> = event_types
+ .iter()
+ .filter_map(|e| EventType::try_from(*e).ok())
+ .collect();
+ Ok(event_types.into_iter().collect())
+ }
+}
+
+impl TryFrom<HashSet<EventType>> for ProtobufEventNameList {
+ type Error = &'static str;
+ fn try_from(event_types: HashSet<EventType>) -> Result<Self, &'static str> {
+ let protobuf_event_name_list = ProtobufEventNameList {
+ event_types: event_types
+ .iter()
+ .filter_map(|e| ProtobufEventType::try_from(*e).ok())
+ .map(|e| e as i32)
+ .collect(),
+ };
+ Ok(protobuf_event_name_list)
+ }
+}
+
+impl TryFrom<ProtobufEventType> for EventType {
+ type Error = &'static str;
+ fn try_from(protobuf_event_type: ProtobufEventType) -> Result<Self, &'static str> {
+ Ok(match protobuf_event_type {
+ ProtobufEventType::ModeUpdate => EventType::ModeUpdate,
+ ProtobufEventType::TabUpdate => EventType::TabUpdate,
+ ProtobufEventType::PaneUpdate => EventType::PaneUpdate,
+ ProtobufEventType::Key => EventType::Key,
+ ProtobufEventType::Mouse => EventType::Mouse,
+ ProtobufEventType::Timer => EventType::Timer,
+ ProtobufEventType::CopyToClipboard => EventType::CopyToClipboard,
+ ProtobufEventType::SystemClipboardFailure => EventType::SystemClipboardFailure,
+ ProtobufEventType::InputReceived => EventType::InputReceived,
+ ProtobufEventType::Visible => EventType::Visible,
+ ProtobufEventType::CustomMessage => EventType::CustomMessage,
+ ProtobufEventType::FileSystemCreate => EventType::FileSystemCreate,
+ ProtobufEventType::FileSystemRead => EventType::FileSystemRead,
+ ProtobufEventType::FileSystemUpdate => EventType::FileSystemUpdate,
+ ProtobufEventType::FileSystemDelete => EventType::FileSystemDelete,
+ })
+ }
+}
+
+impl TryFrom<EventType> for ProtobufEventType {
+ type Error = &'static str;
+ fn try_from(event_type: EventType) -> Result<Self, &'static str> {
+ Ok(match event_type {
+ EventType::ModeUpdate => ProtobufEventType::ModeUpdate,
+ EventType::TabUpdate => ProtobufEventType::TabUpdate,
+ EventType::PaneUpdate => ProtobufEventType::PaneUpdate,
+ EventType::Key => ProtobufEventType::Key,
+ EventType::Mouse => ProtobufEventType::Mouse,
+ EventType::Timer => ProtobufEventType::Timer,
+ EventType::CopyToClipboard => ProtobufEventType::CopyToClipboard,
+ EventType::SystemClipboardFailure => ProtobufEventType::SystemClipboardFailure,
+ EventType::InputReceived => ProtobufEventType::InputReceived,
+ EventType::Visible => ProtobufEventType::Visible,
+ EventType::CustomMessage => ProtobufEventType::CustomMessage,
+ EventType::FileSystemCreate => ProtobufEventType::FileSystemCreate,
+ EventType::FileSystemRead => ProtobufEventType::FileSystemRead,
+ EventType::FileSystemUpdate => ProtobufEventType::FileSystemUpdate,
+ EventType::FileSystemDelete => ProtobufEventType::FileSystemDelete,
+ })
+ }
+}
+
+#[test]
+fn serialize_mode_update_event() {
+ use prost::Message;
+ let mode_update_event = Event::ModeUpdate(Default::default());
+ let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ mode_update_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_mode_update_event_with_non_default_values() {
+ use prost::Message;
+ let mode_update_event = Event::ModeUpdate(ModeInfo {
+ mode: InputMode::Locked,
+ keybinds: vec![
+ (
+ InputMode::Locked,
+ vec![(
+ Key::Alt(crate::data::CharOrArrow::Char('b')),
+ vec![Action::SwitchToMode(InputMode::Normal)],
+ )],
+ ),
+ (
+ InputMode::Tab,
+ vec![(
+ Key::Alt(crate::data::CharOrArrow::Direction(Direction::Up)),
+ vec![Action::SwitchToMode(InputMode::Pane)],
+ )],
+ ),
+ (
+ InputMode::Pane,
+ vec![
+ (
+ Key::Ctrl('b'),
+ vec![
+ Action::SwitchToMode(InputMode::Tmux),
+ Action::Write(vec![10]),
+ ],
+ ),
+ (Key::Char('a'), vec![Action::WriteChars("foo".to_owned())]),
+ ],
+ ),
+ ],
+ style: Style {
+ colors: Palette {
+ source: crate::data::PaletteSource::Default,
+ theme_hue: ThemeHue::Light,
+ fg: PaletteColor::Rgb((1, 1, 1)),
+ bg: PaletteColor::Rgb((200, 200, 200)),
+ black: PaletteColor::EightBit(1),
+ red: PaletteColor::EightBit(2),
+ green: PaletteColor::EightBit(2),
+ yellow: PaletteColor::EightBit(2),
+ blue: PaletteColor::EightBit(2),
+ magenta: PaletteColor::EightBit(2),
+ cyan: PaletteColor::EightBit(2),
+ white: PaletteColor::EightBit(2),
+ orange: PaletteColor::EightBit(2),
+ gray: PaletteColor::EightBit(2),
+ purple: PaletteColor::EightBit(2),
+ gold: PaletteColor::EightBit(2),
+ silver: PaletteColor::EightBit(2),
+ pink: PaletteColor::EightBit(2),
+ brown: PaletteColor::Rgb((222, 221, 220)),
+ },
+ rounded_corners: true,
+ hide_session_name: false,
+ },
+ capabilities: PluginCapabilities { arrow_fonts: false },
+ session_name: Some("my awesome test session".to_owned()),
+ });
+ let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ mode_update_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_tab_update_event() {
+ use prost::Message;
+ let tab_update_event = Event::TabUpdate(Default::default());
+ let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ tab_update_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_tab_update_event_with_non_default_values() {
+ use prost::Message;
+ let tab_update_event = Event::TabUpdate(vec![
+ TabInfo {
+ position: 0,
+ name: "First tab".to_owned(),
+ active: true,
+ panes_to_hide: 2,
+ is_fullscreen_active: true,
+ is_sync_panes_active: false,
+ are_floating_panes_visible: true,
+ other_focused_clients: vec![2, 3, 4],
+ active_swap_layout_name: Some("my cool swap layout".to_owned()),
+ is_swap_layout_dirty: false,
+ },
+ TabInfo {
+ position: 1,
+ name: "Secondtab".to_owned(),
+ active: false,
+ panes_to_hide: 5,
+ is_fullscreen_active: false,
+ is_sync_panes_active: true,
+ are_floating_panes_visible: true,
+ other_focused_clients: vec![1, 5, 111],
+ active_swap_layout_name: None,
+ is_swap_layout_dirty: true,
+ },
+ TabInfo::default(),
+ ]);
+ let protobuf_event: ProtobufEvent = tab_update_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ tab_update_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_pane_update_event() {
+ use prost::Message;
+ let pane_update_event = Event::PaneUpdate(Default::default());
+ let protobuf_event: ProtobufEvent = pane_update_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ pane_update_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_key_event() {
+ use prost::Message;
+ let key_event = Event::Key(Key::Ctrl('a'));
+ let protobuf_event: ProtobufEvent = key_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ key_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_mouse_event() {
+ use prost::Message;
+ let mouse_event = Event::Mouse(Mouse::LeftClick(1, 1));
+ let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ mouse_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_mouse_event_without_position() {
+ use prost::Message;
+ let mouse_event = Event::Mouse(Mouse::ScrollUp(17));
+ let protobuf_event: ProtobufEvent = mouse_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ mouse_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_timer_event() {
+ use prost::Message;
+ let timer_event = Event::Timer(1.5);
+ let protobuf_event: ProtobufEvent = timer_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ timer_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_copy_to_clipboard_event() {
+ use prost::Message;
+ let copy_event = Event::CopyToClipboard(CopyDestination::Primary);
+ let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ copy_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_clipboard_failure_event() {
+ use prost::Message;
+ let copy_event = Event::SystemClipboardFailure;
+ let protobuf_event: ProtobufEvent = copy_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ copy_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_input_received_event() {
+ use prost::Message;
+ let input_received_event = Event::InputReceived;
+ let protobuf_event: ProtobufEvent = input_received_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ input_received_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_visible_event() {
+ use prost::Message;
+ let visible_event = Event::Visible(true);
+ let protobuf_event: ProtobufEvent = visible_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ visible_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_custom_message_event() {
+ use prost::Message;
+ let custom_message_event = Event::CustomMessage("foo".to_owned(), "bar".to_owned());
+ let protobuf_event: ProtobufEvent = custom_message_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ custom_message_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_file_system_create_event() {
+ use prost::Message;
+ let file_system_event =
+ Event::FileSystemCreate(vec!["/absolute/path".into(), "./relative_path".into()]);
+ let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ file_system_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_file_system_read_event() {
+ use prost::Message;
+ let file_system_event =
+ Event::FileSystemRead(vec!["/absolute/path".into(), "./relative_path".into()]);
+ let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ file_system_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_file_system_update_event() {
+ use prost::Message;
+ let file_system_event =
+ Event::FileSystemUpdate(vec!["/absolute/path".into(), "./relative_path".into()]);
+ let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ file_system_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
+
+#[test]
+fn serialize_file_system_delete_event() {
+ use prost::Message;
+ let file_system_event =
+ Event::FileSystemDelete(vec!["/absolute/path".into(), "./relative_path".into()]);
+ let protobuf_event: ProtobufEvent = file_system_event.clone().try_into().unwrap();
+ let serialized_protobuf_event = protobuf_event.encode_to_vec();
+ let deserialized_protobuf_event: ProtobufEvent =
+ Message::decode(serialized_protobuf_event.as_slice()).unwrap();
+ let deserialized_event: Event = deserialized_protobuf_event.try_into().unwrap();
+ assert_eq!(
+ file_system_event, deserialized_event,
+ "Event properly serialized/deserialized without change"
+ );
+}
diff --git a/zellij-utils/src/plugin_api/file.proto b/zellij-utils/src/plugin_api/file.proto
new file mode 100644
index 00000000..b2c5372b
--- /dev/null
+++ b/zellij-utils/src/plugin_api/file.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package api.file;
+
+message File {
+ string path = 1;
+ optional int32 line_number = 2;
+ optional string cwd = 3;
+}
diff --git a/zellij-utils/src/plugin_api/file.rs b/zellij-utils/src/plugin_api/file.rs
new file mode 100644
index 00000000..7c06aa8e
--- /dev/null
+++ b/zellij-utils/src/plugin_api/file.rs
@@ -0,0 +1,30 @@
+pub use super::generated_api::api::file::File as ProtobufFile;
+use crate::data::FileToOpen;
+
+use std::convert::TryFrom;
+use std::path::PathBuf;
+
+impl TryFrom<ProtobufFile> for FileToOpen {
+ type Error = &'static str;
+ fn try_from(protobuf_file: ProtobufFile) -> Result<Self, &'static str> {
+ let path = PathBuf::from(protobuf_file.path);
+ let line_number = protobuf_file.line_number.map(|l| l as usize);
+ let cwd = protobuf_file.cwd.map(|c| PathBuf::from(c));
+ Ok(FileToOpen {
+ path,
+ line_number,
+ cwd,
+ })
+ }
+}
+
+impl TryFrom<FileToOpen> for ProtobufFile {
+ type Error = &'static str;
+ fn try_from(file_to_open: FileToOpen) -> Result<Self, &'static str> {
+ Ok(ProtobufFile {
+ path: file_to_open.path.display().to_string(),
+ line_number: file_to_open.line_number.map(|l| l as i32),
+ cwd: file_to_open.cwd.map(|c| c.display().to_string()),
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/input_mode.proto b/zellij-utils/src/plugin_api/input_mode.proto
new file mode 100644
index 00000000..31122495
--- /dev/null
+++ b/zellij-utils/src/plugin_api/input_mode.proto
@@ -0,0 +1,40 @@
+syntax = "proto3";
+
+package api.input_mode;
+
+message InputModeMessage {
+ InputMode input_mode = 1;
+}
+
+enum InputMode {
+ /// In `Normal` mode, input is always written to the terminal, except for the shortcuts leading
+ /// to other modes
+ Normal = 0;
+ /// In `Locked` mode, input is always written to the terminal and all shortcuts are disabled
+ /// except the one leading back to normal mode
+ Locked = 1;
+ /// `Resize` mode allows resizing the different existing panes.
+ Resize = 2;
+ /// `Pane` mode allows creating and closing panes, as well as moving between them.
+ Pane = 3;
+ /// `Tab` mode allows creating and closing tabs, as well as moving between them.
+ Tab = 4;
+ /// `Scroll` mode allows scrolling up and down within a pane.
+ Scroll = 5;
+ /// `EnterSearch` mode allows for typing in the needle for a search in the scroll buffer of a pane.
+ EnterSearch = 6;
+ /// `Search` mode allows for searching a term in a pane (superset of `Scroll`).
+ Search = 7;
+ /// `RenameTab` mode allows assigning a new name to a tab.
+ RenameTab = 8;
+ /// `RenamePane` mode allows assigning a new name to a pane.
+ RenamePane = 9;
+ /// `Session` mode allows detaching sessions
+ Session = 10;
+ /// `Move` mode allows moving the different existing panes within a tab
+ Move = 11;
+ /// `Prompt` mode allows interacting with active prompts.
+ Prompt = 12;
+ /// `Tmux` mode allows for basic tmux keybindings functionality
+ Tmux = 13;
+}
diff --git a/zellij-utils/src/plugin_api/input_mode.rs b/zellij-utils/src/plugin_api/input_mode.rs
new file mode 100644
index 00000000..83a6a009
--- /dev/null
+++ b/zellij-utils/src/plugin_api/input_mode.rs
@@ -0,0 +1,69 @@
+pub use super::generated_api::api::input_mode::{
+ InputMode as ProtobufInputMode, InputModeMessage as ProtobufInputModeMessage,
+};
+use crate::data::InputMode;
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufInputMode> for InputMode {
+ type Error = &'static str;
+ fn try_from(protobuf_input_mode: ProtobufInputMode) -> Result<Self, &'static str> {
+ match protobuf_input_mode {
+ ProtobufInputMode::Normal => Ok(InputMode::Normal),
+ ProtobufInputMode::Locked => Ok(InputMode::Locked),
+ ProtobufInputMode::Resize => Ok(InputMode::Resize),
+ ProtobufInputMode::Pane => Ok(InputMode::Pane),
+ ProtobufInputMode::Tab => Ok(InputMode::Tab),
+ ProtobufInputMode::Scroll => Ok(InputMode::Scroll),
+ ProtobufInputMode::EnterSearch => Ok(InputMode::EnterSearch),
+ ProtobufInputMode::Search => Ok(InputMode::Search),
+ ProtobufInputMode::RenameTab => Ok(InputMode::RenameTab),
+ ProtobufInputMode::RenamePane => Ok(InputMode::RenamePane),
+ ProtobufInputMode::Session => Ok(InputMode::Session),
+ ProtobufInputMode::Move => Ok(InputMode::Move),
+ ProtobufInputMode::Prompt => Ok(InputMode::Prompt),
+ ProtobufInputMode::Tmux => Ok(InputMode::Tmux),
+ }
+ }
+}
+
+impl TryFrom<InputMode> for ProtobufInputMode {
+ type Error = &'static str;
+ fn try_from(input_mode: InputMode) -> Result<Self, &'static str> {
+ Ok(match input_mode {
+ InputMode::Normal => ProtobufInputMode::Normal,
+ InputMode::Locked => ProtobufInputMode::Locked,
+ InputMode::Resize => ProtobufInputMode::Resize,
+ InputMode::Pane => ProtobufInputMode::Pane,
+ InputMode::Tab => ProtobufInputMode::Tab,
+ InputMode::Scroll => ProtobufInputMode::Scroll,
+ InputMode::EnterSearch => ProtobufInputMode::EnterSearch,
+ InputMode::Search => ProtobufInputMode::Search,
+ InputMode::RenameTab => ProtobufInputMode::RenameTab,
+ InputMode::RenamePane => ProtobufInputMode::RenamePane,
+ InputMode::Session => ProtobufInputMode::Session,
+ InputMode::Move => ProtobufInputMode::Move,
+ InputMode::Prompt => ProtobufInputMode::Prompt,
+ InputMode::Tmux => ProtobufInputMode::Tmux,
+ })
+ }
+}
+
+impl TryFrom<ProtobufInputModeMessage> for InputMode {
+ type Error = &'static str;
+ fn try_from(protobuf_input_mode: ProtobufInputModeMessage) -> Result<Self, &'static str> {
+ ProtobufInputMode::from_i32(protobuf_input_mode.input_mode)
+ .and_then(|p| p.try_into().ok())
+ .ok_or("Invalid input mode")
+ }
+}
+
+impl TryFrom<InputMode> for ProtobufInputModeMessage {
+ type Error = &'static str;
+ fn try_from(input_mode: InputMode) -> Result<Self, &'static str> {
+ let protobuf_input_mode: ProtobufInputMode = input_mode.try_into()?;
+ Ok(ProtobufInputModeMessage {
+ input_mode: protobuf_input_mode as i32,
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/key.proto b/zellij-utils/src/plugin_api/key.proto
new file mode 100644
index 00000000..9a573483
--- /dev/null
+++ b/zellij-utils/src/plugin_api/key.proto
@@ -0,0 +1,83 @@
+syntax = "proto3";
+
+package api.key;
+
+message Key {
+ enum KeyModifier {
+ CTRL = 0;
+ ALT = 1;
+ }
+
+ enum NamedKey {
+ PageDown = 0;
+ PageUp = 1;
+ LeftArrow = 2;
+ DownArrow = 3;
+ UpArrow = 4;
+ RightArrow = 5;
+ Home = 6;
+ End = 7;
+ Backspace = 8;
+ Delete = 9;
+ Insert = 10;
+ F1 = 11;
+ F2 = 12;
+ F3 = 13;
+ F4 = 14;
+ F5 = 15;
+ F6 = 16;
+ F7 = 17;
+ F8 = 18;
+ F9 = 19;
+ F10 = 20;
+ F11 = 21;
+ F12 = 22;
+ Tab = 23;
+ Esc = 24;
+ }
+
+ enum Char {
+ a = 0;
+ b = 1;
+ c = 2;
+ d = 3;
+ e = 4;
+ f = 5;
+ g = 6;
+ h = 7;
+ i = 8;
+ j = 9;
+ k = 10;
+ l = 11;
+ m = 12;
+ n = 13;
+ o = 14;
+ p = 15;
+ q = 16;
+ r = 17;
+ s = 18;
+ t = 19;
+ u = 20;
+ v = 21;
+ w = 22;
+ x = 23;
+ y = 24;
+ z = 25;
+ zero = 26;
+ one = 27;
+ two = 28;
+ three = 29;
+ four = 30;
+ five = 31;
+ six = 32;
+ seven = 33;
+ eight = 34;
+ nine = 35;
+ }
+
+ optional KeyModifier modifier = 1;
+ oneof main_key {
+ NamedKey key = 2;
+ Char char = 3;
+ }
+}
diff --git a/zellij-utils/src/plugin_api/key.rs b/zellij-utils/src/plugin_api/key.rs
new file mode 100644
index 00000000..7cef4ba7
--- /dev/null
+++ b/zellij-utils/src/plugin_api/key.rs
@@ -0,0 +1,222 @@
+pub use super::generated_api::api::key::{
+ key::{KeyModifier, MainKey, NamedKey},
+ Key as ProtobufKey,
+};
+use crate::data::{CharOrArrow, Direction, Key};
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufKey> for Key {
+ type Error = &'static str;
+ fn try_from(protobuf_key: ProtobufKey) -> Result<Self, &'static str> {
+ let key_modifier = parse_optional_modifier(&protobuf_key);
+ match key_modifier {
+ Some(KeyModifier::Ctrl) => {
+ let character = char_from_main_key(protobuf_key.main_key)?;
+ Ok(Key::Ctrl(character))
+ },
+ Some(KeyModifier::Alt) => {
+ let char_or_arrow = CharOrArrow::from_main_key(protobuf_key.main_key)?;
+ Ok(Key::Alt(char_or_arrow))
+ },
+ None => match protobuf_key.main_key.as_ref().ok_or("invalid key")? {
+ MainKey::Char(_key_index) => {
+ let character = char_from_main_key(protobuf_key.main_key)?;
+ Ok(Key::Char(character))
+ },
+ MainKey::Key(key_index) => {
+ let key = NamedKey::from_i32(*key_index).ok_or("invalid_key")?;
+ Ok(named_key_to_key(key))
+ },
+ },
+ }
+ }
+}
+
+impl TryFrom<Key> for ProtobufKey {
+ type Error = &'static str;
+ fn try_from(key: Key) -> Result<Self, &'static str> {
+ match key {
+ Key::PageDown => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::PageDown as i32)),
+ }),
+ Key::PageUp => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::PageUp as i32)),
+ }),
+ Key::Left => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::LeftArrow as i32)),
+ }),
+ Key::Down => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::DownArrow as i32)),
+ }),
+ Key::Up => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::UpArrow as i32)),
+ }),
+ Key::Right => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::RightArrow as i32)),
+ }),
+ Key::Home => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Home as i32)),
+ }),
+ Key::End => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::End as i32)),
+ }),
+ Key::Backspace => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Backspace as i32)),
+ }),
+ Key::Delete => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Delete as i32)),
+ }),
+ Key::Insert => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Insert as i32)),
+ }),
+ Key::F(index) => {
+ let main_key = match index {
+ 1 => Some(MainKey::Key(NamedKey::F1 as i32)),
+ 2 => Some(MainKey::Key(NamedKey::F2 as i32)),
+ 3 => Some(MainKey::Key(NamedKey::F3 as i32)),
+ 4 => Some(MainKey::Key(NamedKey::F4 as i32)),
+ 5 => Some(MainKey::Key(NamedKey::F5 as i32)),
+ 6 => Some(MainKey::Key(NamedKey::F6 as i32)),
+ 7 => Some(MainKey::Key(NamedKey::F7 as i32)),
+ 8 => Some(MainKey::Key(NamedKey::F8 as i32)),
+ 9 => Some(MainKey::Key(NamedKey::F9 as i32)),
+ 10 => Some(MainKey::Key(NamedKey::F10 as i32)),
+ 11 => Some(MainKey::Key(NamedKey::F11 as i32)),
+ 12 => Some(MainKey::Key(NamedKey::F12 as i32)),
+ _ => return Err("Invalid key"),
+ };
+ Ok(ProtobufKey {
+ modifier: None,
+ main_key,
+ })
+ },
+ Key::Char(character) => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Char((character as u8) as i32)),
+ }),
+ Key::Alt(char_or_arrow) => {
+ let main_key = match char_or_arrow {
+ CharOrArrow::Char(character) => MainKey::Char((character as u8) as i32),
+ CharOrArrow::Direction(Direction::Left) => {
+ MainKey::Key(NamedKey::LeftArrow as i32)
+ },
+ CharOrArrow::Direction(Direction::Right) => {
+ MainKey::Key(NamedKey::RightArrow as i32)
+ },
+ CharOrArrow::Direction(Direction::Up) => MainKey::Key(NamedKey::UpArrow as i32),
+ CharOrArrow::Direction(Direction::Down) => {
+ MainKey::Key(NamedKey::DownArrow as i32)
+ },
+ };
+ Ok(ProtobufKey {
+ modifier: Some(KeyModifier::Alt as i32),
+ main_key: Some(main_key),
+ })
+ },
+ Key::Ctrl(character) => Ok(ProtobufKey {
+ modifier: Some(KeyModifier::Ctrl as i32),
+ main_key: Some(MainKey::Char((character as u8) as i32)),
+ }),
+ Key::BackTab => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Tab as i32)),
+ }),
+ Key::Null => {
+ Ok(ProtobufKey {
+ modifier: None,
+ main_key: None, // TODO: does this break deserialization?
+ })
+ },
+ Key::Esc => Ok(ProtobufKey {
+ modifier: None,
+ main_key: Some(MainKey::Key(NamedKey::Esc as i32)),
+ }),
+ }
+ }
+}
+
+impl CharOrArrow {
+ pub fn from_main_key(
+ main_key: std::option::Option<MainKey>,
+ ) -> Result<CharOrArrow, &'static str> {
+ match main_key {
+ Some(MainKey::Char(encoded_key)) => {
+ Ok(CharOrArrow::Char(char_index_to_char(encoded_key)))
+ },
+ Some(MainKey::Key(key_index)) => match NamedKey::from_i32(key_index) {
+ Some(NamedKey::LeftArrow) => Ok(CharOrArrow::Direction(Direction::Left)),
+ Some(NamedKey::RightArrow) => Ok(CharOrArrow::Direction(Direction::Right)),
+ Some(NamedKey::UpArrow) => Ok(CharOrArrow::Direction(Direction::Up)),
+ Some(NamedKey::DownArrow) => Ok(CharOrArrow::Direction(Direction::Down)),
+ _ => Err("Unsupported key"),
+ },
+ _ => {
+ return Err("Unsupported key");
+ },
+ }
+ }
+}
+
+fn parse_optional_modifier(m: &ProtobufKey) -> Option<KeyModifier> {
+ match m.modifier {
+ Some(modifier) => KeyModifier::from_i32(modifier),
+ _ => None,
+ }
+}
+
+fn char_index_to_char(char_index: i32) -> char {
+ char_index as u8 as char
+}
+
+fn char_from_main_key(main_key: Option<MainKey>) -> Result<char, &'static str> {
+ match main_key {
+ Some(MainKey::Char(encoded_key)) => {
+ return Ok(char_index_to_char(encoded_key));
+ },
+ _ => {
+ return Err("Unsupported key");
+ },
+ }
+}
+
+fn named_key_to_key(named_key: NamedKey) -> Key {
+ match named_key {
+ NamedKey::PageDown => Key::PageDown,
+ NamedKey::PageUp => Key::PageUp,
+ NamedKey::LeftArrow => Key::Left,
+ NamedKey::DownArrow => Key::Down,
+ NamedKey::UpArrow => Key::Up,
+ NamedKey::RightArrow => Key::Right,
+ NamedKey::Home => Key::Home,
+ NamedKey::End => Key::End,
+ NamedKey::Backspace => Key::Backspace,
+ NamedKey::Delete => Key::Delete,
+ NamedKey::Insert => Key::Insert,
+ NamedKey::F1 => Key::F(1),
+ NamedKey::F2 => Key::F(2),
+ NamedKey::F3 => Key::F(3),
+ NamedKey::F4 => Key::F(4),
+ NamedKey::F5 => Key::F(5),
+ NamedKey::F6 => Key::F(6),
+ NamedKey::F7 => Key::F(7),
+ NamedKey::F8 => Key::F(8),
+ NamedKey::F9 => Key::F(9),
+ NamedKey::F10 => Key::F(10),
+ NamedKey::F11 => Key::F(11),
+ NamedKey::F12 => Key::F(12),
+ NamedKey::Tab => Key::BackTab,
+ NamedKey::Esc => Key::Esc,
+ }
+}
diff --git a/zellij-utils/src/plugin_api/message.proto b/zellij-utils/src/plugin_api/message.proto
new file mode 100644
index 00000000..35d11150
--- /dev/null
+++ b/zellij-utils/src/plugin_api/message.proto
@@ -0,0 +1,9 @@
+syntax = "proto3";
+
+package api.message;
+
+message Message {
+ string name = 1;
+ string payload = 2;
+ optional string worker_name = 3;
+}
diff --git a/zellij-utils/src/plugin_api/message.rs b/zellij-utils/src/plugin_api/message.rs
new file mode 100644
index 00000000..365a427a
--- /dev/null
+++ b/zellij-utils/src/plugin_api/message.rs
@@ -0,0 +1,29 @@
+pub use super::generated_api::api::message::Message as ProtobufMessage;
+use crate::data::PluginMessage;
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufMessage> for PluginMessage {
+ type Error = &'static str;
+ fn try_from(protobuf_message: ProtobufMessage) -> Result<Self, &'static str> {
+ let name = protobuf_message.name;
+ let payload = protobuf_message.payload;
+ let worker_name = protobuf_message.worker_name;
+ Ok(PluginMessage {
+ name,
+ payload,
+ worker_name,
+ })
+ }
+}
+
+impl TryFrom<PluginMessage> for ProtobufMessage {
+ type Error = &'static str;
+ fn try_from(plugin_message: PluginMessage) -> Result<Self, &'static str> {
+ Ok(ProtobufMessage {
+ name: plugin_message.name,
+ payload: plugin_message.payload,
+ worker_name: plugin_message.worker_name,
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/mod.rs b/zellij-utils/src/plugin_api/mod.rs
new file mode 100644
index 00000000..55ace500
--- /dev/null
+++ b/zellij-utils/src/plugin_api/mod.rs
@@ -0,0 +1,14 @@
+pub mod action;
+pub mod command;
+pub mod event;
+pub mod file;
+pub mod input_mode;
+pub mod key;
+pub mod message;
+pub mod plugin_command;
+pub mod plugin_ids;
+pub mod resize;
+pub mod style;
+pub mod generated_api {
+ include!(concat!(env!("OUT_DIR"), "/generated_plugin_api.rs"));
+}
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
new file mode 100644
index 00000000..f09ccf4b
--- /dev/null
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -0,0 +1,175 @@
+syntax = "proto3";
+
+import "event.proto";
+import "file.proto";
+import "command.proto";
+import "message.proto";
+import "input_mode.proto";
+import "resize.proto";
+
+package api.plugin_command;
+
+enum CommandName {
+ Subscribe = 0;
+ Unsubscribe = 1;
+ SetSelectable = 2;
+ GetPluginIds = 3;
+ GetZellijVersion = 4;
+ OpenFile = 5;
+ OpenFileFloating = 6;
+ OpenTerminal = 7;
+ OpenTerminalFloating = 8;
+ OpenCommandPane = 9;
+ OpenCommandPaneFloating = 10;
+ SwitchTabTo = 11;
+ SetTimeout = 12;
+ ExecCmd = 13;
+ PostMessageTo = 14;
+ PostMessageToPlugin = 15;
+ HideSelf = 16;
+ ShowSelf = 17;
+ SwitchToMode = 18;
+ NewTabsWithLayout = 19;
+ NewTab = 20;
+ GoToNextTab = 21;
+ GoToPreviousTab = 22;
+ Resize = 23;
+ ResizeWithDirection = 24;
+ FocusNextPane = 25;
+ FocusPreviousPane = 26;
+ MoveFocus = 27;
+ MoveFocusOrTab = 28;
+ Detach = 29;
+ EditScrollback = 30;
+ Write = 31;
+ WriteChars = 32;
+ ToggleTab = 33;
+ MovePane = 34;
+ MovePaneWithDirection = 35;
+ ClearScreen = 36;
+ ScrollUp = 37;
+ ScrollDown = 38;
+ ScrollToTop = 39;
+ ScrollToBottom = 40;
+ PageScrollUp = 41;
+ PageScrollDown = 42;
+ ToggleFocusFullscreen = 43;
+ TogglePaneFrames = 44;
+ TogglePaneEmbedOrEject = 45;
+ UndoRenamePane = 46;
+ CloseFocus = 47;
+ ToggleActiveTabSync = 48;
+ CloseFocusedTab = 49;
+ UndoRenameTab = 50;
+ QuitZellij = 51;
+ PreviousSwapLayout = 52;
+ NextSwapLayout = 53;
+ GoToTabName = 54;
+ FocusOrCreateTab = 55;
+ GoToTab = 56;
+ StartOrReloadPlugin = 57;
+ CloseTerminalPane = 58;
+ ClosePluginPane = 59;
+ FocusTerminalPane = 60;
+ FocusPluginPane = 61;
+ RenameTerminalPane = 62;
+ RenamePluginPane = 63;
+ RenameTab = 64;
+ ReportCrash = 65;
+}
+
+message PluginCommand {
+ CommandName name = 1;
+ oneof payload {
+ SubscribePayload subscribe_payload = 2;
+ UnsubscribePayload unsubscribe_payload = 3;
+ bool set_selectable_payload = 4;
+ OpenFilePayload open_file_payload = 5;
+ OpenFilePayload open_file_floating_payload = 6;
+ OpenFilePayload open_terminal_payload = 7;
+ OpenFilePayload open_terminal_floating_payload = 8;
+ OpenCommandPanePayload open_command_pane_payload = 9;
+ OpenCommandPanePayload open_command_pane_floating_payload = 10;
+ SwitchTabToPayload switch_tab_to_payload = 11;
+ SetTimeoutPayload set_timeout_payload = 12;
+ ExecCmdPayload exec_cmd_payload = 13;
+ PluginMessagePayload post_message_to_payload = 14;
+ PluginMessagePayload post_message_to_plugin_payload = 15;
+ bool show_self_payload = 16;
+ SwitchToModePayload switch_to_mode_payload = 17;
+ string new_tabs_with_layout_payload = 18;
+ ResizePayload resize_payload = 19;
+ ResizePayload resize_with_direction_payload = 20;
+ MovePayload move_focus_payload = 21;
+ MovePayload move_focus_or_tab_payload = 22;
+ bytes write_payload = 23;
+ string write_chars_payload = 24;
+ MovePayload move_pane_with_direction_payload = 25;
+ string go_to_tab_name_payload = 26;
+ string focus_or_create_tab_payload = 27;
+ int32 go_to_tab_payload = 28;
+ string start_or_reload_plugin_payload = 29;
+ int32 close_terminal_pane_payload = 30;
+ int32 close_plugin_pane_payload = 31;
+ PaneIdAndShouldFloat focus_terminal_pane_payload = 32;
+ PaneIdAndShouldFloat focus_plugin_pane_payload = 33;
+ IdAndNewName rename_terminal_pane_payload = 34;
+ IdAndNewName rename_plugin_pane_payload = 35;
+ IdAndNewName rename_tab_payload = 36;
+ string report_crash_payload = 37;
+ }
+}
+
+message SubscribePayload {
+ event.EventNameList subscriptions = 1;
+}
+
+message UnsubscribePayload {
+ event.EventNameList subscriptions = 1;
+}
+
+message OpenFilePayload {
+ file.File file_to_open = 1;
+}
+
+message OpenCommandPanePayload {
+ command.Command command_to_run = 1;
+}
+
+message SwitchTabToPayload {
+ int32 tab_index = 1;
+}
+
+message SetTimeoutPayload {
+ float seconds = 1;
+}
+
+message ExecCmdPayload {
+ repeated string command_line = 1;
+}
+
+message PluginMessagePayload {
+ api.message.Message message = 1;
+}
+
+message SwitchToModePayload {
+ input_mode.InputModeMessage input_mode = 1;
+}
+
+message ResizePayload {
+ resize.Resize resize = 1;
+}
+
+message MovePayload {
+ resize.MoveDirection direction = 1;
+}
+
+message PaneIdAndShouldFloat {
+ int32 pane_id = 1;
+ bool should_float = 2;
+}
+
+message IdAndNewName {
+ int32 id = 1; // pane id or tab index
+ string new_name = 2;
+}
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
new file mode 100644
index 00000000..bf359dd2
--- /dev/null
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -0,0 +1,825 @@
+pub use super::generated_api::api::{
+ event::EventNameList as ProtobufEventNameList,
+ plugin_command::{
+ plugin_command::Payload, CommandName, ExecCmdPayload, IdAndNewName, MovePayload,
+ OpenCommandPanePayload, OpenFilePayload, PaneIdAndShouldFloat,
+ PluginCommand as ProtobufPluginCommand, PluginMessagePayload, ResizePayload,
+ SetTimeoutPayload, SubscribePayload, SwitchTabToPayload, SwitchToModePayload,
+ UnsubscribePayload,
+ },
+ resize::ResizeAction as ProtobufResizeAction,
+};
+
+use crate::data::PluginCommand;
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufPluginCommand> for PluginCommand {
+ type Error = &'static str;
+ fn try_from(protobuf_plugin_command: ProtobufPluginCommand) -> Result<Self, &'static str> {
+ match CommandName::from_i32(protobuf_plugin_command.name) {
+ Some(CommandName::Subscribe) => match protobuf_plugin_command.payload {
+ Some(Payload::SubscribePayload(subscribe_payload)) => {
+ let protobuf_event_list = subscribe_payload.subscriptions;
+ match protobuf_event_list {
+ Some(protobuf_event_list) => {
+ Ok(PluginCommand::Subscribe(protobuf_event_list.try_into()?))
+ },
+ None => Err("malformed subscription event"),
+ }
+ },
+ _ => Err("Mismatched payload for Subscribe"),
+ },
+ Some(CommandName::Unsubscribe) => match protobuf_plugin_command.payload {
+ Some(Payload::UnsubscribePayload(unsubscribe_payload)) => {
+ let protobuf_event_list = unsubscribe_payload.subscriptions;
+ match protobuf_event_list {
+ Some(protobuf_event_list) => {
+ Ok(PluginCommand::Unsubscribe(protobuf_event_list.try_into()?))
+ },
+ None => Err("malformed unsubscription event"),
+ }
+ },
+ _ => Err("Mismatched payload for Unsubscribe"),
+ },
+ Some(CommandName::SetSelectable) => match protobuf_plugin_command.payload {
+ Some(Payload::SetSelectablePayload(should_be_selectable)) => {
+ Ok(PluginCommand::SetSelectable(should_be_selectable))
+ },
+ _ => Err("Mismatched payload for SetSelectable"),
+ },
+ Some(CommandName::GetPluginIds) => {
+ if protobuf_plugin_command.payload.is_some() {
+ Err("GetPluginIds should not have a payload")
+ } else {
+ Ok(PluginCommand::GetPluginIds)
+ }
+ },
+ Some(CommandName::GetZellijVersion) => {
+ if protobuf_plugin_command.payload.is_some() {
+ Err("GetZellijVersion should not have a payload")
+ } else {
+ Ok(PluginCommand::GetZellijVersion)
+ }
+ },
+ Some(CommandName::OpenFile) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenFilePayload(file_to_open_payload)) => {
+ match file_to_open_payload.file_to_open {
+ Some(file_to_open) => Ok(PluginCommand::OpenFile(file_to_open.try_into()?)),
+ None => Err("Malformed open file payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenFile"),
+ },
+ Some(CommandName::OpenFileFloating) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenFileFloatingPayload(file_to_open_payload)) => {
+ match file_to_open_payload.file_to_open {
+ Some(file_to_open) => {
+ Ok(PluginCommand::OpenFileFloating(file_to_open.try_into()?))
+ },
+ None => Err("Malformed open file payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenFile"),
+ },
+ Some(CommandName::OpenTerminal) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenTerminalPayload(file_to_open_payload)) => {
+ match file_to_open_payload.file_to_open {
+ Some(file_to_open) => {
+ Ok(PluginCommand::OpenTerminal(file_to_open.try_into()?))
+ },
+ None => Err("Malformed open terminal payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenTerminal"),
+ },
+ Some(CommandName::OpenTerminalFloating) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenTerminalFloatingPayload(file_to_open_payload)) => {
+ match file_to_open_payload.file_to_open {
+ Some(file_to_open) => Ok(PluginCommand::OpenTerminalFloating(
+ file_to_open.try_into()?,
+ )),
+ None => Err("Malformed open terminal floating payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenTerminalFloating"),
+ },
+ Some(CommandName::OpenCommandPane) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenCommandPanePayload(command_to_run_payload)) => {
+ match command_to_run_payload.command_to_run {
+ Some(command_to_run) => {
+ Ok(PluginCommand::OpenCommandPane(command_to_run.try_into()?))
+ },
+ None => Err("Malformed open open command pane payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenCommandPane"),
+ },
+ Some(CommandName::OpenCommandPaneFloating) => match protobuf_plugin_command.payload {
+ Some(Payload::OpenCommandPaneFloatingPayload(command_to_run_payload)) => {
+ match command_to_run_payload.command_to_run {
+ Some(command_to_run) => Ok(PluginCommand::OpenCommandPaneFloating(
+ command_to_run.try_into()?,
+ )),
+ None => Err("Malformed open command pane floating payload"),
+ }
+ },
+ _ => Err("Mismatched payload for OpenCommandPaneFloating"),
+ },
+ Some(CommandName::SwitchTabTo) => match protobuf_plugin_command.payload {
+ Some(Payload::SwitchTabToPayload(switch_to_tab_payload)) => Ok(
+ PluginCommand::SwitchTabTo(switch_to_tab_payload.tab_index as u32),
+ ),
+ _ => Err("Mismatched payload for SwitchToTab"),
+ },
+ Some(CommandName::SetTimeout) => match protobuf_plugin_command.payload {
+ Some(Payload::SetTimeoutPayload(set_timeout_payload)) => {
+ Ok(PluginCommand::SetTimeout(set_timeout_payload.seconds))
+ },
+ _ => Err("Mismatched payload for SetTimeout"),
+ },
+ Some(CommandName::ExecCmd) => match protobuf_plugin_command.payload {
+ Some(Payload::ExecCmdPayload(exec_cmd_payload)) => {
+ Ok(PluginCommand::ExecCmd(exec_cmd_payload.command_line))
+ },
+ _ => Err("Mismatched payload for ExecCmd"),
+ },
+ Some(CommandName::PostMessageTo) => match protobuf_plugin_command.payload {
+ Some(Payload::PostMessageToPayload(post_message_to_payload)) => {
+ match post_message_to_payload.message {
+ Some(message) => Ok(PluginCommand::PostMessageTo(message.try_into()?)),
+ None => Err("Malformed post message to payload"),
+ }
+ },
+ _ => Err("Mismatched payload for PostMessageTo"),
+ },
+ Some(CommandName::PostMessageToPlugin) => match protobuf_plugin_command.payload {
+ Some(Payload::PostMessageToPluginPayload(post_message_to_payload)) => {
+ match post_message_to_payload.message {
+ Some(message) => {
+ Ok(PluginCommand::PostMessageToPlugin(message.try_into()?))
+ },
+ None => Err("Malformed post message to plugin payload"),
+ }
+ },
+ _ => Err("Mismatched payload for PostMessageToPlugin"),
+ },
+ Some(CommandName::HideSelf) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("HideSelf should not have a payload");
+ }
+ Ok(PluginCommand::HideSelf)
+ },
+ Some(CommandName::ShowSelf) => match protobuf_plugin_command.payload {
+ Some(Payload::ShowSelfPayload(should_float_if_hidden)) => {
+ Ok(PluginCommand::ShowSelf(should_float_if_hidden))
+ },
+ _ => Err("Mismatched payload for ShowSelf"),
+ },
+ Some(CommandName::SwitchToMode) => match protobuf_plugin_command.payload {
+ Some(Payload::SwitchToModePayload(switch_to_mode_payload)) => {
+ match switch_to_mode_payload.input_mode {
+ Some(input_mode) => Ok(PluginCommand::SwitchToMode(input_mode.try_into()?)),
+ None => Err("Malformed switch to mode payload"),
+ }
+ },
+ _ => Err("Mismatched payload for SwitchToMode"),
+ },
+ Some(CommandName::NewTabsWithLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::NewTabsWithLayoutPayload(raw_layout)) => {
+ Ok(PluginCommand::NewTabsWithLayout(raw_layout))
+ },
+ _ => Err("Mismatched payload for NewTabsWithLayout"),
+ },
+ Some(CommandName::NewTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("NewTab should not have a payload");
+ }
+ Ok(PluginCommand::NewTab)
+ },
+ Some(CommandName::GoToNextTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("GoToNextTab should not have a payload");
+ }
+ Ok(PluginCommand::GoToNextTab)
+ },
+ Some(CommandName::GoToPreviousTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("GoToPreviousTab should not have a payload");
+ }
+ Ok(PluginCommand::GoToPreviousTab)
+ },
+ Some(CommandName::Resize) => match protobuf_plugin_command.payload {
+ Some(Payload::ResizePayload(resize_payload)) => match resize_payload.resize {
+ Some(resize) => Ok(PluginCommand::Resize(resize.try_into()?)),
+ None => Err("Malformed switch resize payload"),
+ },
+ _ => Err("Mismatched payload for Resize"),
+ },
+ Some(CommandName::ResizeWithDirection) => match protobuf_plugin_command.payload {
+ Some(Payload::ResizeWithDirectionPayload(resize_with_direction_payload)) => {
+ match resize_with_direction_payload.resize {
+ Some(resize) => Ok(PluginCommand::ResizeWithDirection(resize.try_into()?)),
+ None => Err("Malformed switch resize payload"),
+ }
+ },
+ _ => Err("Mismatched payload for Resize"),
+ },
+ Some(CommandName::FocusNextPane) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("FocusNextPane should not have a payload");
+ }
+ Ok(PluginCommand::FocusNextPane)
+ },
+ Some(CommandName::FocusPreviousPane) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("FocusPreviousPane should not have a payload");
+ }
+ Ok(PluginCommand::FocusPreviousPane)
+ },
+ Some(CommandName::MoveFocus) => match protobuf_plugin_command.payload {
+ Some(Payload::MoveFocusPayload(move_payload)) => match move_payload.direction {
+ Some(direction) => Ok(PluginCommand::MoveFocus(direction.try_into()?)),
+ None => Err("Malformed move focus payload"),
+ },
+ _ => Err("Mismatched payload for MoveFocus"),
+ },
+ Some(CommandName::MoveFocusOrTab) => match protobuf_plugin_command.payload {
+ Some(Payload::MoveFocusOrTabPayload(move_payload)) => {
+ match move_payload.direction {
+ Some(direction) => Ok(PluginCommand::MoveFocusOrTab(direction.try_into()?)),
+ None => Err("Malformed move focus or tab payload"),
+ }
+ },
+ _ => Err("Mismatched payload for MoveFocusOrTab"),
+ },
+ Some(CommandName::Detach) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("Detach should not have a payload");
+ }
+ Ok(PluginCommand::Detach)
+ },
+ Some(CommandName::EditScrollback) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("EditScrollback should not have a payload");
+ }
+ Ok(PluginCommand::EditScrollback)
+ },
+ Some(CommandName::Write) => match protobuf_plugin_command.payload {
+ Some(Payload::WritePayload(bytes)) => Ok(PluginCommand::Write(bytes)),
+ _ => Err("Mismatched payload for Write"),
+ },
+ Some(CommandName::WriteChars) => match protobuf_plugin_command.payload {
+ Some(Payload::WriteCharsPayload(chars)) => Ok(PluginCommand::WriteChars(chars)),
+ _ => Err("Mismatched payload for WriteChars"),
+ },
+ Some(CommandName::ToggleTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ToggleTab should not have a payload");
+ }
+ Ok(PluginCommand::ToggleTab)
+ },
+ Some(CommandName::MovePane) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("MovePane should not have a payload");
+ }
+ Ok(PluginCommand::MovePane)
+ },
+ Some(CommandName::MovePaneWithDirection) => match protobuf_plugin_command.payload {
+ Some(Payload::MovePaneWithDirectionPayload(move_payload)) => {
+ match move_payload.direction {
+ Some(direction) => {
+ Ok(PluginCommand::MovePaneWithDirection(direction.try_into()?))
+ },
+ None => Err("Malformed MovePaneWithDirection payload"),
+ }
+ },
+ _ => Err("Mismatched payload for MovePaneWithDirection"),
+ },
+ Some(CommandName::ClearScreen) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ClearScreen should not have a payload");
+ }
+ Ok(PluginCommand::ClearScreen)
+ },
+ Some(CommandName::ScrollUp) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ScrollUp should not have a payload");
+ }
+ Ok(PluginCommand::ScrollUp)
+ },
+ Some(CommandName::ScrollDown) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ScrollDown should not have a payload");
+ }
+ Ok(PluginCommand::ScrollDown)
+ },
+ Some(CommandName::ScrollToTop) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ScrollToTop should not have a payload");
+ }
+ Ok(PluginCommand::ScrollToTop)
+ },
+ Some(CommandName::ScrollToBottom) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ScrollToBottom should not have a payload");
+ }
+ Ok(PluginCommand::ScrollToBottom)
+ },
+ Some(CommandName::PageScrollUp) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("PageScrollUp should not have a payload");
+ }
+ Ok(PluginCommand::PageScrollUp)
+ },
+ Some(CommandName::PageScrollDown) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("PageScrollDown should not have a payload");
+ }
+ Ok(PluginCommand::PageScrollDown)
+ },
+ Some(CommandName::ToggleFocusFullscreen) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ToggleFocusFullscreen should not have a payload");
+ }
+ Ok(PluginCommand::ToggleFocusFullscreen)
+ },
+ Some(CommandName::TogglePaneFrames) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("TogglePaneFrames should not have a payload");
+ }
+ Ok(PluginCommand::TogglePaneFrames)
+ },
+ Some(CommandName::TogglePaneEmbedOrEject) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("TogglePaneEmbedOrEject should not have a payload");
+ }
+ Ok(PluginCommand::TogglePaneEmbedOrEject)
+ },
+ Some(CommandName::UndoRenamePane) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("UndoRenamePane should not have a payload");
+ }
+ Ok(PluginCommand::UndoRenamePane)
+ },
+ Some(CommandName::CloseFocus) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("CloseFocus should not have a payload");
+ }
+ Ok(PluginCommand::CloseFocus)
+ },
+ Some(CommandName::ToggleActiveTabSync) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ToggleActiveTabSync should not have a payload");
+ }
+ Ok(PluginCommand::ToggleActiveTabSync)
+ },
+ Some(CommandName::CloseFocusedTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("CloseFocusedTab should not have a payload");
+ }
+ Ok(PluginCommand::CloseFocusedTab)
+ },
+ Some(CommandName::UndoRenameTab) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("UndoRenameTab should not have a payload");
+ }
+ Ok(PluginCommand::UndoRenameTab)
+ },
+ Some(CommandName::QuitZellij) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("QuitZellij should not have a payload");
+ }
+ Ok(PluginCommand::QuitZellij)
+ },
+ Some(CommandName::PreviousSwapLayout) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("PreviousSwapLayout should not have a payload");
+ }
+ Ok(PluginCommand::PreviousSwapLayout)
+ },
+ Some(CommandName::NextSwapLayout) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("NextSwapLayout should not have a payload");
+ }
+ Ok(PluginCommand::NextSwapLayout)
+ },
+ Some(CommandName::GoToTabName) => match protobuf_plugin_command.payload {
+ Some(Payload::GoToTabNamePayload(tab_name)) => {
+ Ok(PluginCommand::GoToTabName(tab_name))
+ },
+ _ => Err("Mismatched payload for GoToTabName"),
+ },
+ Some(CommandName::FocusOrCreateTab) => match protobuf_plugin_command.payload {
+ Some(Payload::FocusOrCreateTabPayload(tab_name)) => {
+ Ok(PluginCommand::FocusOrCreateTab(tab_name))
+ },
+ _ => Err("Mismatched payload for FocusOrCreateTab"),
+ },
+ Some(CommandName::GoToTab) => match protobuf_plugin_command.payload {
+ Some(Payload::GoToTabPayload(tab_index)) => {
+ Ok(PluginCommand::GoToTab(tab_index as u32))
+ },
+ _ => Err("Mismatched payload for GoToTab"),
+ },
+ Some(CommandName::StartOrReloadPlugin) => match protobuf_plugin_command.payload {
+ Some(Payload::StartOrReloadPluginPayload(url)) => {
+ Ok(PluginCommand::StartOrReloadPlugin(url))
+ },
+ _ => Err("Mismatched payload for StartOrReloadPlugin"),
+ },
+ Some(CommandName::CloseTerminalPane) => match protobuf_plugin_command.payload {
+ Some(Payload::CloseTerminalPanePayload(pane_id)) => {
+ Ok(PluginCommand::CloseTerminalPane(pane_id as u32))
+ },
+ _ => Err("Mismatched payload for CloseTerminalPane"),
+ },
+ Some(CommandName::ClosePluginPane) => match protobuf_plugin_command.payload {
+ Some(Payload::ClosePluginPanePayload(pane_id)) => {
+ Ok(PluginCommand::ClosePluginPane(pane_id as u32))
+ },
+ _ => Err("Mismatched payload for ClosePluginPane"),
+ },
+ Some(CommandName::FocusTerminalPane) => match protobuf_plugin_command.payload {
+ Some(Payload::FocusTerminalPanePayload(payload)) => {
+ let pane_id = payload.pane_id as u32;
+ let should_float = payload.should_float;
+ Ok(PluginCommand::FocusTerminalPane(pane_id, should_float))
+ },
+ _ => Err("Mismatched payload for ClosePluginPane"),
+ },
+ Some(CommandName::FocusPluginPane) => match protobuf_plugin_command.payload {
+ Some(Payload::FocusPluginPanePayload(payload)) => {
+ let pane_id = payload.pane_id as u32;
+ let should_float = payload.should_float;
+ Ok(PluginCommand::FocusPluginPane(pane_id, should_float))
+ },
+ _ => Err("Mismatched payload for ClosePluginPane"),
+ },
+ Some(CommandName::RenameTerminalPane) => match protobuf_plugin_command.payload {
+ Some(Payload::RenameTerminalPanePayload(payload)) => {
+ let pane_id = payload.id as u32;
+ let new_name = payload.new_name;
+ Ok(PluginCommand::RenameTerminalPane(pane_id, new_name))
+ },
+ _ => Err("Mismatched payload for RenameTerminalPane"),
+ },
+ Some(CommandName::RenamePluginPane) => match protobuf_plugin_command.payload {
+ Some(Payload::RenamePluginPanePayload(payload)) => {
+ let pane_id = payload.id as u32;
+ let new_name = payload.new_name;
+ Ok(PluginCommand::RenamePluginPane(pane_id, new_name))
+ },
+ _ => Err("Mismatched payload for RenamePluginPane"),
+ },
+ Some(CommandName::RenameTab) => match protobuf_plugin_command.payload {
+ Some(Payload::RenameTabPayload(payload)) => {
+ let tab_index = payload.id as u32;
+ let name = payload.new_name;
+ Ok(PluginCommand::RenameTab(tab_index, name))
+ },
+ _ => Err("Mismatched payload for RenameTab"),
+ },
+ Some(CommandName::ReportCrash) => match protobuf_plugin_command.payload {
+ Some(Payload::ReportCrashPayload(payload)) => {
+ Ok(PluginCommand::ReportPanic(payload))
+ },
+ _ => Err("Mismatched payload for ReportCrash"),
+ },
+ None => Err("Unrecognized plugin command"),
+ }
+ }
+}
+
+impl TryFrom<PluginCommand> for ProtobufPluginCommand {
+ type Error = &'static str;
+ fn try_from(plugin_command: PluginCommand) -> Result<Self, &'static str> {
+ match plugin_command {
+ PluginCommand::Subscribe(subscriptions) => {
+ let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
+ Ok(ProtobufPluginCommand {
+ name: CommandName::Subscribe as i32,
+ payload: Some(Payload::SubscribePayload(SubscribePayload {
+ subscriptions: Some(subscriptions),
+ })),
+ })
+ },
+ PluginCommand::Unsubscribe(subscriptions) => {
+ let subscriptions: ProtobufEventNameList = subscriptions.try_into()?;
+ Ok(ProtobufPluginCommand {
+ name: CommandName::Unsubscribe as i32,
+ payload: Some(Payload::UnsubscribePayload(UnsubscribePayload {
+ subscriptions: Some(subscriptions),
+ })),
+ })
+ },
+ PluginCommand::SetSelectable(should_be_selectable) => Ok(ProtobufPluginCommand {
+ name: CommandName::SetSelectable as i32,
+ payload: Some(Payload::SetSelectablePayload(should_be_selectable)),
+ }),
+ PluginCommand::GetPluginIds => Ok(ProtobufPluginCommand {
+ name: CommandName::GetPluginIds as i32,
+ payload: None,
+ }),
+ PluginCommand::GetZellijVersion => Ok(ProtobufPluginCommand {
+ name: CommandName::GetZellijVersion as i32,
+ payload: None,
+ }),
+ PluginCommand::OpenFile(file_to_open) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenFile as i32,
+ payload: Some(Payload::OpenFilePayload(OpenFilePayload {
+ file_to_open: Some(file_to_open.try_into()?),
+ })),
+ }),
+ PluginCommand::OpenFileFloating(file_to_open) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenFileFloating as i32,
+ payload: Some(Payload::OpenFileFloatingPayload(OpenFilePayload {
+ file_to_open: Some(file_to_open.try_into()?),
+ })),
+ }),
+ PluginCommand::OpenTerminal(cwd) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenTerminal as i32,
+ payload: Some(Payload::OpenTerminalPayload(OpenFilePayload {
+ file_to_open: Some(cwd.try_into()?),
+ })),
+ }),
+ PluginCommand::OpenTerminalFloating(cwd) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenTerminalFloating as i32,
+ payload: Some(Payload::OpenTerminalFloatingPayload(OpenFilePayload {
+ file_to_open: Some(cwd.try_into()?),
+ })),
+ }),
+ PluginCommand::OpenCommandPane(command_to_run) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenCommandPane as i32,
+ payload: Some(Payload::OpenCommandPanePayload(OpenCommandPanePayload {
+ command_to_run: Some(command_to_run.try_into()?),
+ })),
+ }),
+ PluginCommand::OpenCommandPaneFloating(command_to_run) => Ok(ProtobufPluginCommand {
+ name: CommandName::OpenCommandPaneFloating as i32,
+ payload: Some(Payload::OpenCommandPaneFloatingPayload(
+ OpenCommandPanePayload {
+ command_to_run: Some(command_to_run.try_into()?),
+ },
+ )),
+ }),
+ PluginCommand::SwitchTabTo(tab_index) => Ok(ProtobufPluginCommand {
+ name: CommandName::SwitchTabTo as i32,
+ payload: Some(Payload::SwitchTabToPayload(SwitchTabToPayload {
+ tab_index: tab_index as i32,
+ })),
+ }),
+ PluginCommand::SetTimeout(seconds) => Ok(ProtobufPluginCommand {
+ name: CommandName::SetTimeout as i32,
+ payload: Some(Payload::SetTimeoutPayload(SetTimeoutPayload { seconds })),
+ }),
+ PluginCommand::ExecCmd(command_line) => Ok(ProtobufPluginCommand {
+ name: CommandName::ExecCmd as i32,
+ payload: Some(Payload::ExecCmdPayload(ExecCmdPayload { command_line })),
+ }),
+ PluginCommand::PostMessageTo(plugin_message) => Ok(ProtobufPluginCommand {
+ name: CommandName::PostMessageTo as i32,
+ payload: Some(Payload::PostMessageToPayload(PluginMessagePayload {
+ message: Some(plugin_message.try_into()?),
+ })),
+ }),
+ PluginCommand::PostMessageToPlugin(plugin_message) => Ok(ProtobufPluginCommand {
+ name: CommandName::PostMessageToPlugin as i32,
+ payload: Some(Payload::PostMessageToPluginPayload(PluginMessagePayload {
+ message: Some(plugin_message.try_into()?),
+ })),
+ }),
+ PluginCommand::HideSelf => Ok(ProtobufPluginCommand {
+ name: CommandName::HideSelf as i32,
+ payload: None,
+ }),
+ PluginCommand::ShowSelf(should_float_if_hidden) => Ok(ProtobufPluginCommand {
+ name: CommandName::ShowSelf as i32,
+ payload: Some(Payload::ShowSelfPayload(should_float_if_hidden)),
+ }),
+ PluginCommand::SwitchToMode(input_mode) => Ok(ProtobufPluginCommand {
+ name: CommandName::SwitchToMode as i32,
+ payload: Some(Payload::SwitchToModePayload(SwitchToModePayload {
+ input_mode: Some(input_mode.try_into()?),
+ })),
+ }),
+ PluginCommand::NewTabsWithLayout(raw_layout) => Ok(ProtobufPluginCommand {
+ name: CommandName::NewTabsWithLayout as i32,
+ payload: Some(Payload::NewTabsWithLayoutPayload(raw_layout)),
+ }),
+ PluginCommand::NewTab => Ok(ProtobufPluginCommand {
+ name: CommandName::NewTab as i32,
+ payload: None,
+ }),
+ PluginCommand::GoToNextTab => Ok(ProtobufPluginCommand {
+ name: CommandName::GoToNextTab as i32,
+ payload: None,
+ }),
+ PluginCommand::GoToPreviousTab => Ok(ProtobufPluginCommand {
+ name: CommandName::GoToPreviousTab as i32,
+ payload: None,
+ }),
+ PluginCommand::Resize(resize) => Ok(ProtobufPluginCommand {
+ name: CommandName::Resize as i32,
+ payload: Some(Payload::ResizePayload(ResizePayload {
+ resize: Some(resize.try_into()?),
+ })),
+ }),
+ PluginCommand::ResizeWithDirection(resize) => Ok(ProtobufPluginCommand {
+ name: CommandName::ResizeWithDirection as i32,
+ payload: Some(Payload::ResizeWithDirectionPayload(ResizePayload {
+ resize: Some(resize.try_into()?),
+ })),
+ }),
+ PluginCommand::FocusNextPane => Ok(ProtobufPluginCommand {
+ name: CommandName::FocusNextPane as i32,
+ payload: None,
+ }),
+ PluginCommand::FocusPreviousPane => Ok(ProtobufPluginCommand {
+ name: CommandName::FocusPreviousPane as i32,
+ payload: None,
+ }),
+ PluginCommand::MoveFocus(direction) => Ok(ProtobufPluginCommand {
+ name: CommandName::MoveFocus as i32,
+ payload: Some(Payload::MoveFocusPayload(MovePayload {
+ direction: Some(direction.try_into()?),
+ })),
+ }),
+ PluginCommand::MoveFocusOrTab(direction) => Ok(ProtobufPluginCommand {
+ name: CommandName::MoveFocusOrTab as i32,
+ payload: Some(Payload::MoveFocusOrTabPayload(MovePayload {
+ direction: Some(direction.try_into()?),
+ })),
+ }),
+ PluginCommand::Detach => Ok(ProtobufPluginCommand {
+ name: CommandName::Detach as i32,
+ payload: None,
+ }),
+ PluginCommand::EditScrollback => Ok(ProtobufPluginCommand {
+ name: CommandName::EditScrollback as i32,
+ payload: None,
+ }),
+ PluginCommand::Write(bytes) => Ok(ProtobufPluginCommand {
+ name: CommandName::Write as i32,
+ payload: Some(Payload::WritePayload(bytes)),
+ }),
+ PluginCommand::WriteChars(chars) => Ok(ProtobufPluginCommand {
+ name: CommandName::WriteChars as i32,
+ payload: Some(Payload::WriteCharsPayload(chars)),
+ }),
+ PluginCommand::ToggleTab => Ok(ProtobufPluginCommand {
+ name: CommandName::ToggleTab as i32,
+ payload: None,
+ }),
+ PluginCommand::MovePane => Ok(ProtobufPluginCommand {
+ name: CommandName::MovePane as i32,
+ payload: None,
+ }),
+ PluginCommand::MovePaneWithDirection(direction) => Ok(ProtobufPluginCommand {
+ name: CommandName::MovePaneWithDirection as i32,
+ payload: Some(Payload::MovePaneWithDirectionPayload(MovePayload {
+ direction: Some(direction.try_into()?),
+ })),
+ }),
+ PluginCommand::ClearScreen => Ok(ProtobufPluginCommand {
+ name: CommandName::ClearScreen as i32,
+ payload: None,
+ }),
+ PluginCommand::ScrollUp => Ok(ProtobufPluginCommand {
+ name: CommandName::ScrollUp as i32,
+ payload: None,
+ }),
+ PluginCommand::ScrollDown => Ok(ProtobufPluginCommand {
+ name: CommandName::ScrollDown as i32,
+ payload: None,
+ }),
+ PluginCommand::ScrollToTop => Ok(ProtobufPluginCommand {
+ name: CommandName::ScrollToTop as i32,
+ payload: None,
+ }),
+ PluginCommand::ScrollToBottom => Ok(ProtobufPluginCommand {
+ name: CommandName::ScrollToBottom as i32,
+ payload: None,
+ }),
+ PluginCommand::PageScrollUp => Ok(ProtobufPluginCommand {
+ name: CommandName::PageScrollUp as i32,
+ payload: None,
+ }),
+ PluginCommand::PageScrollDown => Ok(ProtobufPluginCommand {
+ name: CommandName::PageScrollDown as i32,
+ payload: None,
+ }),
+ PluginCommand::ToggleFocusFullscreen => Ok(ProtobufPluginCommand {
+ name: CommandName::ToggleFocusFullscreen as i32,
+ payload: None,
+ }),
+ PluginCommand::TogglePaneFrames => Ok(ProtobufPluginCommand {
+ name: CommandName::TogglePaneFrames as i32,
+ payload: None,
+ }),
+ PluginCommand::TogglePaneEmbedOrEject => Ok(ProtobufPluginCommand {
+ name: CommandName::TogglePaneEmbedOrEject as i32,
+ payload: None,
+ }),
+ PluginCommand::UndoRenamePane => Ok(ProtobufPluginCommand {
+ name: CommandName::UndoRenamePane as i32,
+ payload: None,
+ }),
+ PluginCommand::CloseFocus => Ok(ProtobufPluginCommand {
+ name: CommandName::CloseFocus as i32,
+ payload: None,
+ }),
+ PluginCommand::ToggleActiveTabSync => Ok(ProtobufPluginCommand {
+ name: CommandName::ToggleActiveTabSync as i32,
+ payload: None,
+ }),
+ PluginCommand::CloseFocusedTab => Ok(ProtobufPluginCommand {
+ name: CommandName::CloseFocusedTab as i32,
+ payload: None,
+ }),
+ PluginCommand::UndoRenameTab => Ok(ProtobufPluginCommand {
+ name: CommandName::UndoRenameTab as i32,
+ payload: None,
+ }),
+ PluginCommand::QuitZellij => Ok(ProtobufPluginCommand {
+ name: CommandName::QuitZellij as i32,
+ payload: None,
+ }),
+ PluginCommand::PreviousSwapLayout => Ok(ProtobufPluginCommand {
+ name: CommandName::PreviousSwapLayout as i32,
+ payload: None,
+ }),
+ PluginCommand::NextSwapLayout => Ok(ProtobufPluginCommand {
+ name: CommandName::NextSwapLayout as i32,
+ payload: None,
+ }),
+ PluginCommand::GoToTabName(tab_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::GoToTabName as i32,
+ payload: Some(Payload::GoToTabNamePayload(tab_name)),
+ }),
+ PluginCommand::FocusOrCreateTab(tab_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::FocusOrCreateTab as i32,
+ payload: Some(Payload::FocusOrCreateTabPayload(tab_name)),
+ }),
+ PluginCommand::GoToTab(tab_index) => Ok(ProtobufPluginCommand {
+ name: CommandName::GoToTab as i32,
+ payload: Some(Payload::GoToTabPayload(tab_index as i32)),
+ }),
+ PluginCommand::StartOrReloadPlugin(url) => Ok(ProtobufPluginCommand {
+ name: CommandName::StartOrReloadPlugin as i32,
+ payload: Some(Payload::StartOrReloadPluginPayload(url)),
+ }),
+ PluginCommand::CloseTerminalPane(pane_id) => Ok(ProtobufPluginCommand {
+ name: CommandName::CloseTerminalPane as i32,
+ payload: Some(Payload::CloseTerminalPanePayload(pane_id as i32)),
+ }),
+ PluginCommand::ClosePluginPane(pane_id) => Ok(ProtobufPluginCommand {
+ name: CommandName::ClosePluginPane as i32,
+ payload: Some(Payload::ClosePluginPanePayload(pane_id as i32)),
+ }),
+ PluginCommand::FocusTerminalPane(pane_id, should_float_if_hidden) => {
+ Ok(ProtobufPluginCommand {
+ name: CommandName::FocusTerminalPane as i32,
+ payload: Some(Payload::FocusTerminalPanePayload(PaneIdAndShouldFloat {
+ pane_id: pane_id as i32,
+ should_float: should_float_if_hidden,
+ })),
+ })
+ },
+ PluginCommand::FocusPluginPane(pane_id, should_float_if_hidden) => {
+ Ok(ProtobufPluginCommand {
+ name: CommandName::FocusPluginPane as i32,
+ payload: Some(Payload::FocusPluginPanePayload(PaneIdAndShouldFloat {
+ pane_id: pane_id as i32,
+ should_float: should_float_if_hidden,
+ })),
+ })
+ },
+ PluginCommand::RenameTerminalPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::RenameTerminalPane as i32,
+ payload: Some(Payload::RenameTerminalPanePayload(IdAndNewName {
+ id: pane_id as i32,
+ new_name,
+ })),
+ }),
+ PluginCommand::RenamePluginPane(pane_id, new_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::RenamePluginPane as i32,
+ payload: Some(Payload::RenamePluginPanePayload(IdAndNewName {
+ id: pane_id as i32,
+ new_name,
+ })),
+ }),
+ PluginCommand::RenameTab(tab_index, new_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::RenameTab as i32,
+ payload: Some(Payload::RenameTabPayload(IdAndNewName {
+ id: tab_index as i32,
+ new_name,
+ })),
+ }),
+ PluginCommand::ReportPanic(payload) => Ok(ProtobufPluginCommand {
+ name: CommandName::ReportCrash as i32,
+ payload: Some(Payload::ReportCrashPayload(payload)),
+ }),
+ }
+ }
+}
diff --git a/zellij-utils/src/plugin_api/plugin_ids.proto b/zellij-utils/src/plugin_api/plugin_ids.proto
new file mode 100644
index 00000000..2977dbe4
--- /dev/null
+++ b/zellij-utils/src/plugin_api/plugin_ids.proto
@@ -0,0 +1,12 @@
+syntax = "proto3";
+
+package api.plugin_ids;
+
+message PluginIds {
+ int32 plugin_id = 1;
+ int32 zellij_pid = 2;
+}
+
+message ZellijVersion {
+ string version = 1;
+}
diff --git a/zellij-utils/src/plugin_api/plugin_ids.rs b/zellij-utils/src/plugin_api/plugin_ids.rs
new file mode 100644
index 00000000..51f526c6
--- /dev/null
+++ b/zellij-utils/src/plugin_api/plugin_ids.rs
@@ -0,0 +1,35 @@
+pub use super::generated_api::api::plugin_ids::{
+ PluginIds as ProtobufPluginIds, ZellijVersion as ProtobufZellijVersion,
+};
+use crate::data::PluginIds;
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufPluginIds> for PluginIds {
+ type Error = &'static str;
+ fn try_from(protobuf_plugin_ids: ProtobufPluginIds) -> Result<Self, &'static str> {
+ Ok(PluginIds {
+ plugin_id: protobuf_plugin_ids.plugin_id as u32,
+ zellij_pid: protobuf_plugin_ids.zellij_pid as u32,
+ })
+ }
+}
+
+impl TryFrom<PluginIds> for ProtobufPluginIds {
+ type Error = &'static str;
+ fn try_from(plugin_ids: PluginIds) -> Result<Self, &'static str> {
+ Ok(ProtobufPluginIds {
+ plugin_id: plugin_ids.plugin_id as i32,
+ zellij_pid: plugin_ids.zellij_pid as i32,
+ })
+ }
+}
+
+impl TryFrom<&str> for ProtobufZellijVersion {
+ type Error = &'static str;
+ fn try_from(zellij_version: &str) -> Result<Self, &'static str> {
+ Ok(ProtobufZellijVersion {
+ version: zellij_version.to_owned(),
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/resize.proto b/zellij-utils/src/plugin_api/resize.proto
new file mode 100644
index 00000000..eebac79d
--- /dev/null
+++ b/zellij-utils/src/plugin_api/resize.proto
@@ -0,0 +1,24 @@
+syntax = "proto3";
+
+package api.resize;
+
+enum ResizeAction {
+ Increase = 0;
+ Decrease = 1;
+}
+
+enum ResizeDirection {
+ Left = 0;
+ Right = 1;
+ Up = 2;
+ Down = 3;
+}
+
+message Resize {
+ ResizeAction resize_action = 1;
+ optional ResizeDirection direction = 2;
+}
+
+message MoveDirection {
+ ResizeDirection direction = 1;
+}
diff --git a/zellij-utils/src/plugin_api/resize.rs b/zellij-utils/src/plugin_api/resize.rs
new file mode 100644
index 00000000..61031c09
--- /dev/null
+++ b/zellij-utils/src/plugin_api/resize.rs
@@ -0,0 +1,130 @@
+pub use super::generated_api::api::resize::{
+ MoveDirection as ProtobufMoveDirection, Resize as ProtobufResize, ResizeAction,
+ ResizeDirection, ResizeDirection as ProtobufResizeDirection,
+};
+use crate::data::{Direction, Resize, ResizeStrategy};
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufResize> for Resize {
+ type Error = &'static str;
+ fn try_from(protobuf_resize: ProtobufResize) -> Result<Self, &'static str> {
+ if protobuf_resize.direction.is_some() {
+ return Err("Resize cannot have a direction");
+ }
+ match ResizeAction::from_i32(protobuf_resize.resize_action) {
+ Some(ResizeAction::Increase) => Ok(Resize::Increase),
+ Some(ResizeAction::Decrease) => Ok(Resize::Decrease),
+ None => Err("No resize action for the given index"),
+ }
+ }
+}
+
+impl TryFrom<Resize> for ProtobufResize {
+ type Error = &'static str;
+ fn try_from(resize: Resize) -> Result<Self, &'static str> {
+ Ok(ProtobufResize {
+ resize_action: match resize {
+ Resize::Increase => ResizeAction::Increase as i32,
+ Resize::Decrease => ResizeAction::Decrease as i32,
+ },
+ direction: None,
+ })
+ }
+}
+
+impl TryFrom<ProtobufResize> for ResizeStrategy {
+ type Error = &'static str;
+ fn try_from(protobuf_resize: ProtobufResize) -> Result<Self, &'static str> {
+ let direction = match protobuf_resize
+ .direction
+ .and_then(|r| ResizeDirection::from_i32(r))
+ {
+ Some(ResizeDirection::Left) => Some(Direction::Left),
+ Some(ResizeDirection::Right) => Some(Direction::Right),
+ Some(ResizeDirection::Up) => Some(Direction::Up),
+ Some(ResizeDirection::Down) => Some(Direction::Down),
+ None => None,
+ };
+ let resize = match ResizeAction::from_i32(protobuf_resize.resize_action) {
+ Some(ResizeAction::Increase) => Resize::Increase,
+ Some(ResizeAction::Decrease) => Resize::Decrease,
+ None => return Err("No resize action for the given index"),
+ };
+ Ok(ResizeStrategy {
+ direction,
+ resize,
+ invert_on_boundaries: false,
+ })
+ }
+}
+
+impl TryFrom<ResizeStrategy> for ProtobufResize {
+ type Error = &'static str;
+ fn try_from(resize_strategy: ResizeStrategy) -> Result<Self, &'static str> {
+ Ok(ProtobufResize {
+ resize_action: match resize_strategy.resize {
+ Resize::Increase => ResizeAction::Increase as i32,
+ Resize::Decrease => ResizeAction::Decrease as i32,
+ },
+ direction: match resize_strategy.direction {
+ Some(Direction::Left) => Some(ResizeDirection::Left as i32),
+ Some(Direction::Right) => Some(ResizeDirection::Right as i32),
+ Some(Direction::Up) => Some(ResizeDirection::Up as i32),
+ Some(Direction::Down) => Some(ResizeDirection::Down as i32),
+ None => None,
+ },
+ })
+ }
+}
+
+impl TryFrom<ProtobufMoveDirection> for Direction {
+ type Error = &'static str;
+ fn try_from(protobuf_move_direction: ProtobufMoveDirection) -> Result<Self, &'static str> {
+ match ResizeDirection::from_i32(protobuf_move_direction.direction) {
+ Some(ResizeDirection::Left) => Ok(Direction::Left),
+ Some(ResizeDirection::Right) => Ok(Direction::Right),
+ Some(ResizeDirection::Up) => Ok(Direction::Up),
+ Some(ResizeDirection::Down) => Ok(Direction::Down),
+ None => Err("No direction for the given index"),
+ }
+ }
+}
+
+impl TryFrom<Direction> for ProtobufMoveDirection {
+ type Error = &'static str;
+ fn try_from(direction: Direction) -> Result<Self, &'static str> {
+ Ok(ProtobufMoveDirection {
+ direction: match direction {
+ Direction::Left => ResizeDirection::Left as i32,
+ Direction::Right => ResizeDirection::Right as i32,
+ Direction::Up => ResizeDirection::Up as i32,
+ Direction::Down => ResizeDirection::Down as i32,
+ },
+ })
+ }
+}
+
+impl TryFrom<ProtobufResizeDirection> for Direction {
+ type Error = &'static str;
+ fn try_from(protobuf_resize_direction: ProtobufResizeDirection) -> Result<Self, &'static str> {
+ match protobuf_resize_direction {
+ ProtobufResizeDirection::Left => Ok(Direction::Left),
+ ProtobufResizeDirection::Right => Ok(Direction::Right),
+ ProtobufResizeDirection::Up => Ok(Direction::Up),
+ ProtobufResizeDirection::Down => Ok(Direction::Down),
+ }
+ }
+}
+
+impl TryFrom<Direction> for ProtobufResizeDirection {
+ type Error = &'static str;
+ fn try_from(direction: Direction) -> Result<Self, &'static str> {
+ Ok(match direction {
+ Direction::Left => ProtobufResizeDirection::Left,
+ Direction::Right => ProtobufResizeDirection::Right,
+ Direction::Up => ProtobufResizeDirection::Up,
+ Direction::Down => ProtobufResizeDirection::Down,
+ })
+ }
+}
diff --git a/zellij-utils/src/plugin_api/style.proto b/zellij-utils/src/plugin_api/style.proto
new file mode 100644
index 00000000..f4f3b758
--- /dev/null
+++ b/zellij-utils/src/plugin_api/style.proto
@@ -0,0 +1,54 @@
+syntax = "proto3";
+
+package api.style;
+
+message Style {
+ Palette palette = 1;
+ bool rounded_corners = 2;
+ bool hide_session_name = 3;
+}
+
+message Palette {
+ ThemeHue theme_hue = 1;
+ Color fg = 2;
+ Color bg = 3;
+ Color black = 4;
+ Color red = 5;
+ Color green = 6;
+ Color yellow = 7;
+ Color blue = 8;
+ Color magenta = 9;
+ Color cyan = 10;
+ Color white = 11;
+ Color orange = 12;
+ Color gray = 13;
+ Color purple = 14;
+ Color gold = 15;
+ Color silver = 16;
+ Color pink = 17;
+ Color brown = 18;
+}
+
+message Color {
+ ColorType color_type = 1;
+ oneof payload {
+ RgbColorPayload rgb_color_payload = 2;
+ uint32 eight_bit_color_payload = 3;
+ }
+}
+
+message RgbColorPayload {
+ uint32 red = 1;
+ uint32 green = 2;
+ uint32 blue = 3;
+}
+
+enum ColorType {
+ Rgb = 0;
+ EightBit = 1;
+}
+
+enum ThemeHue {
+ Dark = 0;
+ Light = 1;
+}
diff --git a/zellij-utils/src/plugin_api/style.rs b/zellij-utils/src/plugin_api/style.rs
new file mode 100644
index 00000000..1e3ba677
--- /dev/null
+++ b/zellij-utils/src/plugin_api/style.rs
@@ -0,0 +1,213 @@
+use super::generated_api::api::style::{
+ color::Payload as ProtobufColorPayload, Color as ProtobufColor, ColorType as ProtobufColorType,
+ Palette as ProtobufPalette, RgbColorPayload as ProtobufRgbColorPayload, Style as ProtobufStyle,
+ ThemeHue as ProtobufThemeHue,
+};
+use crate::data::{Palette, PaletteColor, Style, ThemeHue};
+use crate::errors::prelude::*;
+
+use std::convert::TryFrom;
+
+impl TryFrom<ProtobufStyle> for Style {
+ type Error = &'static str;
+ fn try_from(protobuf_style: ProtobufStyle) -> Result<Self, &'static str> {
+ Ok(Style {
+ colors: protobuf_style
+ .palette
+ .ok_or("malformed style payload")?
+ .try_into()?,
+ rounded_corners: protobuf_style.rounded_corners,
+ hide_session_name: protobuf_style.hide_session_name,
+ })
+ }
+}
+
+impl TryFrom<Style> for ProtobufStyle {
+ type Error = &'static str;
+ fn try_from(style: Style) -> Result<Self, &'static str> {
+ Ok(ProtobufStyle {
+ palette: Some(style.colors.try_into()?),
+ rounded_corners: style.rounded_corners,
+ hide_session_name: style.hide_session_name,
+ })
+ }
+}
+
+impl TryFrom<ProtobufPalette> for Palette {
+ type Error = &'static str;
+ fn try_from(protobuf_palette: ProtobufPalette) -> Result<Self, &'static str> {
+ Ok(Palette {
+ theme_hue: ProtobufThemeHue::from_i32(protobuf_palette.theme_hue)
+ .ok_or("malformed theme_hue payload for Palette")?
+ .try_into()?,
+ fg: protobuf_palette
+ .fg
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ bg: protobuf_palette
+ .bg
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ black: protobuf_palette
+ .black
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ red: protobuf_palette
+ .red
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ green: protobuf_palette
+ .green
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ yellow: protobuf_palette
+ .yellow
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ blue: protobuf_palette
+ .blue
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ magenta: protobuf_palette
+ .magenta
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ cyan: protobuf_palette
+ .cyan
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ white: protobuf_palette
+ .white
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ orange: protobuf_palette
+ .orange
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ gray: protobuf_palette
+ .gray
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ purple: protobuf_palette
+ .purple
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ gold: protobuf_palette
+ .gold
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ silver: protobuf_palette
+ .silver
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ pink: protobuf_palette
+ .pink
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ brown: protobuf_palette
+ .brown
+ .ok_or("malformed palette payload")?
+ .try_into()?,
+ ..Default::default()
+ })
+ }
+}
+
+impl TryFrom<Palette> for ProtobufPalette {
+ type Error = &'static str;
+ fn try_from(palette: Palette) -> Result<Self, &'static str> {
+ let theme_hue: ProtobufThemeHue = palette
+ .theme_hue
+ .try_into()
+ .map_err(|_| "malformed payload for palette")?;
+ Ok(ProtobufPalette {
+ theme_hue: theme_hue as i32,
+ fg: Some(palette.fg.try_into()?),
+ bg: Some(palette.bg.try_into()?),
+ black: Some(palette.black.try_into()?),
+ red: Some(palette.red.try_into()?),
+ green: Some(palette.green.try_into()?),
+ yellow: Some(palette.yellow.try_into()?),
+ blue: Some(palette.blue.try_into()?),
+ magenta: Some(palette.magenta.try_into()?),
+ cyan: Some(palette.cyan.try_into()?),
+ white: Some(palette.white.try_into()?),
+ orange: Some(palette.orange.try_into()?),
+ gray: Some(palette.gray.try_into()?),
+ purple: Some(palette.purple.try_into()?),
+ gold: Some(palette.gold.try_into()?),
+ silver: Some(palette.silver.try_into()?),
+ pink: Some(palette.pink.try_into()?),
+ brown: Some(palette.brown.try_into()?),
+ ..Default::default()
+ })
+ }
+}
+
+impl TryFrom<ProtobufColor> for PaletteColor {
+ type Error = &'static str;
+ fn try_from(protobuf_color: ProtobufColor) -> Result<Self, &'static str> {
+ match ProtobufColorType::from_i32(protobuf_color.color_type) {
+ Some(ProtobufColorType::Rgb) => match protobuf_color.payload {
+ Some(ProtobufColorPayload::RgbColorPayload(rgb_color_payload)) => {
+ Ok(PaletteColor::Rgb((
+ rgb_color_payload.red as u8,
+ rgb_color_payload.green as u8,
+ rgb_color_payload.blue as u8,
+ )))
+ },
+ _ => Err("malformed payload for Rgb color"),
+ },
+ Some(ProtobufColorType::EightBit) => match protobuf_color.payload {
+ Some(ProtobufColorPayload::EightBitColorPayload(eight_bit_payload)) => {
+ Ok(PaletteColor::EightBit(eight_bit_payload as u8))
+ },
+ _ => Err("malformed payload for 8bit color"),
+ },
+ None => Err("malformed payload for Color"),
+ }
+ }
+}
+
+impl TryFrom<PaletteColor> for ProtobufColor {
+ type Error = &'static str;
+ fn try_from(color: PaletteColor) -> Result<Self, &'static str> {
+ match color {
+ PaletteColor::Rgb((red, green, blue)) => {
+ let red = red as u32;
+ let green = green as u32;
+ let blue = blue as u32;
+ Ok(ProtobufColor {
+ color_type: ProtobufColorType::Rgb as i32,
+ payload: Some(ProtobufColorPayload::RgbColorPayload(
+ ProtobufRgbColorPayload { red, green, blue },
+ )),
+ })
+ },
+ PaletteColor::EightBit(color) => Ok(ProtobufColor {
+ color_type: ProtobufColorType::EightBit as i32,
+ payload: Some(ProtobufColorPayload::EightBitColorPayload(color as u32)),
+ }),
+ }
+ }
+}
+
+impl TryFrom<ThemeHue> for ProtobufThemeHue {
+ type Error = &'static str;
+ fn try_from(theme_hue: ThemeHue) -> Result<Self, &'static str> {
+ match theme_hue {
+ ThemeHue::Light => Ok(ProtobufThemeHue::Light),
+ ThemeHue::Dark => Ok(ProtobufThemeHue::Dark),
+ }
+ }
+}
+
+impl TryFrom<ProtobufThemeHue> for ThemeHue {
+ type Error = &'static str;
+ fn try_from(protobuf_theme_hue: ProtobufThemeHue) -> Result<Self, &'static str> {
+ match protobuf_theme_hue {
+ ProtobufThemeHue::Light => Ok(ThemeHue::Light),
+ ProtobufThemeHue::Dark => Ok(ThemeHue::Dark),
+ }
+ }
+}