aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/plugin_api
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-01-13 11:27:07 +0100
committerGitHub <noreply@github.com>2026-01-13 11:27:07 +0100
commit4a27ceea0d99b036ca607e05714cef15689d7c26 (patch)
tree22c0148718a82082bdb196c5e867697f514cc541 /zellij-utils/src/plugin_api
parentdocs(CONTRIBUTING): Describe rust toolchain versioning policy (#4585) (diff)
downloadsl0ppij-4a27ceea0d99b036ca607e05714cef15689d7c26.tar.gz
sl0ppij-4a27ceea0d99b036ca607e05714cef15689d7c26.tar.xz
sl0ppij-4a27ceea0d99b036ca607e05714cef15689d7c26.zip
Layout manager (#4601)
* ad plugin override_layout command * watch available layouts and report to plugin thread * Event::AvailableLayoutInfo * save layout command * refactor save_layout * fix api and permissions * delete_layout API command * edit layout in place API * edit layout response through api * propagate layout parsing errors * generate random name plugin api * dump stringified layout API * synchronicity dump_session_layout and include LayoutMetadata in sync response * parse_layout plugin api * fix: default to default layout dir in plugin api * rename_layout plugin command API * initial implementation of multi-tab override * apply to multiple tabs * allow applying to only the active tab * add tab/pane names to layout parsing metadata * indicate is_builtin_plugin in PaneMetadata * get_layout_dir plugin API command * consolidate (and fix) is_builtin_plugin logic * fix bad ret * allow dumping the layout for just a specific tab in the session * get focused pane and tab sync api * color last substring variants * add plugin * update assets * fix tests * add e2e tests for new plugin apis * update ui with new shortcut * rustfmt * docs(changelog): add PR
Diffstat (limited to 'zellij-utils/src/plugin_api')
-rw-r--r--zellij-utils/src/plugin_api/action.proto20
-rw-r--r--zellij-utils/src/plugin_api/action.rs181
-rw-r--r--zellij-utils/src/plugin_api/event.proto55
-rw-r--r--zellij-utils/src/plugin_api/event.rs304
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto137
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs385
6 files changed, 941 insertions, 141 deletions
diff --git a/zellij-utils/src/plugin_api/action.proto b/zellij-utils/src/plugin_api/action.proto
index de8ef44f..6b899b48 100644
--- a/zellij-utils/src/plugin_api/action.proto
+++ b/zellij-utils/src/plugin_api/action.proto
@@ -162,14 +162,20 @@ message NewTabPayload {
optional UnblockCondition first_pane_unblock_condition = 9;
}
+message TabLayoutInfo {
+ uint32 tab_index = 1;
+ optional string tab_name = 2;
+ TiledPaneLayout tiled_layout = 3;
+ repeated FloatingPaneLayout floating_layouts = 4;
+ repeated SwapTiledLayout swap_tiled_layouts = 5;
+ repeated SwapFloatingLayout swap_floating_layouts = 6;
+}
+
message OverrideLayoutPayload {
- optional TiledPaneLayout tiled_layout = 1;
- repeated FloatingPaneLayout floating_layouts = 2;
- repeated SwapTiledLayout swap_tiled_layouts = 3;
- repeated SwapFloatingLayout swap_floating_layouts = 4;
- optional string tab_name = 5;
- bool retain_existing_terminal_panes = 10;
- bool retain_existing_plugin_panes = 11;
+ repeated TabLayoutInfo tabs = 1;
+ bool retain_existing_terminal_panes = 2;
+ bool retain_existing_plugin_panes = 3;
+ bool apply_only_to_active_tab = 4;
}
message Action {
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
index 860b090b..aa4c8b09 100644
--- a/zellij-utils/src/plugin_api/action.rs
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -62,6 +62,7 @@ pub use super::generated_api::api::{
SwapFloatingLayout as ProtobufSwapFloatingLayout,
SwapTiledLayout as ProtobufSwapTiledLayout,
SwitchToModePayload,
+ TabLayoutInfo as ProtobufTabLayoutInfo,
TiledPaneLayout as ProtobufTiledPaneLayout,
TiledPlacement as ProtobufTiledPlacement,
UnblockCondition as ProtobufUnblockCondition,
@@ -83,7 +84,7 @@ use crate::input::layout::SplitSize;
use crate::input::layout::{
FloatingPaneLayout, LayoutConstraint, PercentOrFixed, PluginAlias, PluginUserConfiguration,
Run, RunPlugin, RunPluginLocation, RunPluginOrAlias, SplitDirection, SwapFloatingLayout,
- SwapTiledLayout, TiledPaneLayout,
+ SwapTiledLayout, TabLayoutInfo, TiledPaneLayout,
};
use crate::input::mouse::{MouseEvent, MouseEventType};
use crate::position::Position;
@@ -723,48 +724,15 @@ impl TryFrom<ProtobufAction> for Action {
},
Some(ProtobufActionName::OverrideLayout) => match protobuf_action.optional_payload {
Some(OptionalPayload::OverrideLayoutPayload(payload)) => {
- let tiled_layout = payload.tiled_layout.map(|l| l.try_into()).transpose()?;
-
- let floating_layouts = payload
- .floating_layouts
- .into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()?;
-
- let swap_tiled_layouts = if payload.swap_tiled_layouts.is_empty() {
- None
- } else {
- Some(
- payload
- .swap_tiled_layouts
- .into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()?,
- )
- };
-
- let swap_floating_layouts = if payload.swap_floating_layouts.is_empty() {
- None
- } else {
- Some(
- payload
- .swap_floating_layouts
- .into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()?,
- )
- };
-
- let tab_name = payload.tab_name.filter(|s| !s.is_empty());
-
Ok(Action::OverrideLayout {
- tiled_layout,
- floating_layouts,
- swap_tiled_layouts,
- swap_floating_layouts,
- tab_name,
+ tabs: payload
+ .tabs
+ .into_iter()
+ .map(|t| t.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
retain_existing_terminal_panes: payload.retain_existing_terminal_panes,
retain_existing_plugin_panes: payload.retain_existing_plugin_panes,
+ apply_only_to_active_tab: payload.apply_only_to_active_tab,
})
},
Some(_) => Err("Mismatched payload for OverrideLayout"),
@@ -1556,56 +1524,24 @@ impl TryFrom<Action> for ProtobufAction {
optional_payload: None,
}),
Action::OverrideLayout {
- tiled_layout,
- floating_layouts,
- swap_tiled_layouts,
- swap_floating_layouts,
- tab_name,
+ tabs,
retain_existing_terminal_panes,
retain_existing_plugin_panes,
- } => {
- let protobuf_tiled_layout = tiled_layout.map(|l| l.try_into()).transpose()?;
-
- let protobuf_floating_layouts = floating_layouts
- .into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()?;
-
- let protobuf_swap_tiled_layouts = swap_tiled_layouts
- .map(|layouts| {
- layouts
- .into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()
- })
- .transpose()?
- .unwrap_or_default();
-
- let protobuf_swap_floating_layouts = swap_floating_layouts
- .map(|layouts| {
- layouts
+ apply_only_to_active_tab,
+ } => Ok(ProtobufAction {
+ name: ProtobufActionName::OverrideLayout as i32,
+ optional_payload: Some(OptionalPayload::OverrideLayoutPayload(
+ OverrideLayoutPayload {
+ tabs: tabs
.into_iter()
- .map(|l| l.try_into())
- .collect::<Result<Vec<_>, _>>()
- })
- .transpose()?
- .unwrap_or_default();
-
- Ok(ProtobufAction {
- name: ProtobufActionName::OverrideLayout as i32,
- optional_payload: Some(OptionalPayload::OverrideLayoutPayload(
- OverrideLayoutPayload {
- tiled_layout: protobuf_tiled_layout,
- floating_layouts: protobuf_floating_layouts,
- swap_tiled_layouts: protobuf_swap_tiled_layouts,
- swap_floating_layouts: protobuf_swap_floating_layouts,
- tab_name: tab_name.clone(),
- retain_existing_terminal_panes,
- retain_existing_plugin_panes,
- },
- )),
- })
- },
+ .map(|t| t.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ retain_existing_terminal_panes,
+ retain_existing_plugin_panes,
+ apply_only_to_active_tab,
+ },
+ )),
+ }),
Action::QueryTabNames => Ok(ProtobufAction {
name: ProtobufActionName::QueryTabNames as i32,
optional_payload: None,
@@ -2739,6 +2675,77 @@ impl TryFrom<CommandOrPlugin> for ProtobufCommandOrPlugin {
}
}
+impl TryFrom<ProtobufTabLayoutInfo> for TabLayoutInfo {
+ type Error = &'static str;
+
+ fn try_from(protobuf_tab: ProtobufTabLayoutInfo) -> Result<Self, Self::Error> {
+ Ok(TabLayoutInfo {
+ tab_index: protobuf_tab.tab_index as usize,
+ tab_name: protobuf_tab.tab_name.filter(|s| !s.is_empty()),
+ tiled_layout: protobuf_tab
+ .tiled_layout
+ .ok_or("missing tiled_layout")?
+ .try_into()?,
+ floating_layouts: protobuf_tab
+ .floating_layouts
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ swap_tiled_layouts: if protobuf_tab.swap_tiled_layouts.is_empty() {
+ None
+ } else {
+ Some(
+ protobuf_tab
+ .swap_tiled_layouts
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ )
+ },
+ swap_floating_layouts: if protobuf_tab.swap_floating_layouts.is_empty() {
+ None
+ } else {
+ Some(
+ protobuf_tab
+ .swap_floating_layouts
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ )
+ },
+ })
+ }
+}
+
+impl TryFrom<TabLayoutInfo> for ProtobufTabLayoutInfo {
+ type Error = &'static str;
+
+ fn try_from(tab_info: TabLayoutInfo) -> Result<Self, Self::Error> {
+ Ok(ProtobufTabLayoutInfo {
+ tab_index: tab_info.tab_index as u32,
+ tab_name: tab_info.tab_name,
+ tiled_layout: Some(tab_info.tiled_layout.try_into()?),
+ floating_layouts: tab_info
+ .floating_layouts
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ swap_tiled_layouts: tab_info
+ .swap_tiled_layouts
+ .unwrap_or_default()
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ swap_floating_layouts: tab_info
+ .swap_floating_layouts
+ .unwrap_or_default()
+ .into_iter()
+ .map(|l| l.try_into())
+ .collect::<Result<Vec<_>, _>>()?,
+ })
+ }
+}
+
impl TryFrom<ProtobufTiledPaneLayout> for TiledPaneLayout {
type Error = &'static str;
fn try_from(protobuf: ProtobufTiledPaneLayout) -> Result<Self, Self::Error> {
diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto
index 3bdeea19..10125387 100644
--- a/zellij-utils/src/plugin_api/event.proto
+++ b/zellij-utils/src/plugin_api/event.proto
@@ -62,6 +62,7 @@ enum EventType {
UserAction = 37;
ActionComplete = 38;
CwdChanged = 39;
+ AvailableLayoutInfo = 40;
}
message EventNameList {
@@ -103,6 +104,7 @@ message Event {
UserActionPayload user_action_payload = 31;
ActionCompletePayload action_complete_payload = 32;
CwdChangedPayload cwd_changed_payload = 33;
+ AvailableLayoutInfoPayload available_layout_info_payload = 34;
}
}
@@ -202,6 +204,11 @@ message SessionUpdatePayload {
repeated ResurrectableSession resurrectable_sessions = 2;
}
+message AvailableLayoutInfoPayload {
+ repeated LayoutInfo available_layouts = 1;
+ repeated LayoutWithError layouts_with_errors = 2;
+}
+
message RunCommandResultPayload {
optional int32 exit_code = 1;
bytes stdout = 2;
@@ -318,6 +325,54 @@ message PluginInfo {
message LayoutInfo {
string name = 1;
string source = 2;
+ optional LayoutMetadata layout_metadata = 5;
+}
+
+message LayoutWithError {
+ string layout_name = 1;
+ LayoutParsingError error = 2;
+}
+
+message LayoutParsingError {
+ oneof error_type {
+ KdlErrorVariant kdl_error = 1;
+ SyntaxError syntax_error = 2;
+ }
+}
+
+message KdlErrorVariant {
+ KdlError kdl_error = 1;
+ string file_name = 2;
+ string source_code = 3;
+}
+
+message SyntaxError {
+ // Empty message, just a marker
+}
+
+message KdlError {
+ string error_message = 1;
+ optional uint64 offset = 2;
+ optional uint64 len = 3;
+ optional string help_message = 4;
+}
+
+message LayoutMetadata {
+ repeated TabMetadata tabs = 1;
+ string creation_time = 2;
+ string update_time = 3;
+
+}
+
+message TabMetadata {
+ repeated PaneMetadata pane_metadata = 1;
+ optional string name = 2;
+}
+
+message PaneMetadata {
+ optional string name = 1;
+ bool is_plugin = 2;
+ bool is_builtin_plugin = 3;
}
message ResurrectableSession {
diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs
index 4e430b0b..80d77e56 100644
--- a/zellij-utils/src/plugin_api/event.rs
+++ b/zellij-utils/src/plugin_api/event.rs
@@ -1,23 +1,29 @@
pub use super::generated_api::api::{
action::{Action as ProtobufAction, Position as ProtobufPosition},
event::{
- event::Payload as ProtobufEventPayload, pane_scrollback_response,
- ActionCompletePayload as ProtobufActionCompletePayload, ClientInfo as ProtobufClientInfo,
- ClientPaneHistory as ProtobufClientPaneHistory,
+ event::Payload as ProtobufEventPayload,
+ layout_parsing_error::ErrorType as ProtobufLayoutParsingErrorType,
+ pane_scrollback_response, ActionCompletePayload as ProtobufActionCompletePayload,
+ AvailableLayoutInfoPayload as ProtobufAvailableLayoutInfoPayload,
+ ClientInfo as ProtobufClientInfo, ClientPaneHistory as ProtobufClientPaneHistory,
ClientTabHistory as ProtobufClientTabHistory, ContextItem as ProtobufContextItem,
CopyDestination as ProtobufCopyDestination, CwdChangedPayload as ProtobufCwdChangedPayload,
Event as ProtobufEvent, EventNameList as ProtobufEventNameList,
EventType as ProtobufEventType, FileMetadata as ProtobufFileMetadata,
- InputModeKeybinds as ProtobufInputModeKeybinds, KeyBind as ProtobufKeyBind,
- LayoutInfo as ProtobufLayoutInfo, ModeUpdatePayload as ProtobufModeUpdatePayload,
+ InputModeKeybinds as ProtobufInputModeKeybinds, KdlError as ProtobufKdlError,
+ KdlErrorVariant as ProtobufKdlErrorVariant, KeyBind as ProtobufKeyBind,
+ LayoutInfo as ProtobufLayoutInfo, LayoutMetadata as ProtobufLayoutMetadata,
+ LayoutParsingError as ProtobufLayoutParsingError,
+ LayoutWithError as ProtobufLayoutWithError, ModeUpdatePayload as ProtobufModeUpdatePayload,
PaneContents as ProtobufPaneContents, PaneContentsEntry as ProtobufPaneContentsEntry,
PaneId as ProtobufPaneId, PaneInfo as ProtobufPaneInfo,
- PaneManifest as ProtobufPaneManifest,
+ PaneManifest as ProtobufPaneManifest, PaneMetadata as ProtobufPaneMetadata,
PaneRenderReportPayload as ProtobufPaneRenderReportPayload,
PaneScrollbackResponse as ProtobufPaneScrollbackResponse, PaneType as ProtobufPaneType,
PluginInfo as ProtobufPluginInfo, ResurrectableSession as ProtobufResurrectableSession,
SelectedText as ProtobufSelectedText, SessionManifest as ProtobufSessionManifest,
- TabInfo as ProtobufTabInfo, UserActionPayload as ProtobufUserActionPayload,
+ SyntaxError as ProtobufSyntaxError, TabInfo as ProtobufTabInfo,
+ TabMetadata as ProtobufTabMetadata, UserActionPayload as ProtobufUserActionPayload,
WebServerStatusPayload as ProtobufWebServerStatusPayload, WebSharing as ProtobufWebSharing,
*,
},
@@ -28,9 +34,10 @@ pub use super::generated_api::api::{
#[allow(hidden_glob_reexports)]
use crate::data::{
ClientId, ClientInfo, CopyDestination, Event, EventType, FileMetadata, InputMode,
- KeyWithModifier, LayoutInfo, ModeInfo, Mouse, PaneContents, PaneId, PaneInfo, PaneManifest,
- PaneScrollbackResponse, PermissionStatus, PluginCapabilities, PluginInfo, SelectedText,
- SessionInfo, Style, TabInfo, WebServerStatus, WebSharing,
+ KeyWithModifier, LayoutInfo, LayoutMetadata, ModeInfo, Mouse, PaneContents, PaneId, PaneInfo,
+ PaneManifest, PaneMetadata, PaneScrollbackResponse, PermissionStatus, PluginCapabilities,
+ PluginInfo, SelectedText, SessionInfo, Style, TabInfo, TabMetadata, WebServerStatus,
+ WebSharing,
};
use crate::errors::prelude::*;
@@ -458,6 +465,29 @@ impl TryFrom<ProtobufEvent> for Event {
},
_ => Err("Malformed payload for the CwdChanged Event"),
},
+ Some(ProtobufEventType::AvailableLayoutInfo) => match protobuf_event.payload {
+ Some(ProtobufEventPayload::AvailableLayoutInfoPayload(
+ available_layout_info_payload,
+ )) => {
+ let mut available_layouts: Vec<LayoutInfo> = vec![];
+ let mut layouts_with_errors: Vec<crate::data::LayoutWithError> = vec![];
+
+ for protobuf_layout_info in available_layout_info_payload.available_layouts {
+ available_layouts.push(LayoutInfo::try_from(protobuf_layout_info)?);
+ }
+
+ for protobuf_error in available_layout_info_payload.layouts_with_errors {
+ layouts_with_errors
+ .push(crate::data::LayoutWithError::try_from(protobuf_error)?);
+ }
+
+ Ok(Event::AvailableLayoutInfo(
+ available_layouts,
+ layouts_with_errors,
+ ))
+ },
+ _ => Err("Malformed payload for the AvailableLayoutInfo Event"),
+ },
None => Err("Unknown Protobuf Event"),
}
}
@@ -910,6 +940,30 @@ impl TryFrom<Event> for ProtobufEvent {
payload: Some(event::Payload::CwdChangedPayload(cwd_changed_payload)),
})
},
+ Event::AvailableLayoutInfo(available_layouts, layouts_with_errors) => {
+ let mut protobuf_available_layouts = vec![];
+ let mut protobuf_layouts_with_errors = vec![];
+
+ for layout_info in available_layouts {
+ protobuf_available_layouts.push(layout_info.try_into()?);
+ }
+
+ for layout_error in layouts_with_errors {
+ protobuf_layouts_with_errors.push(layout_error.try_into()?);
+ }
+
+ let available_layout_info_payload = ProtobufAvailableLayoutInfoPayload {
+ available_layouts: protobuf_available_layouts,
+ layouts_with_errors: protobuf_layouts_with_errors,
+ };
+
+ Ok(ProtobufEvent {
+ name: ProtobufEventType::AvailableLayoutInfo as i32,
+ payload: Some(event::Payload::AvailableLayoutInfoPayload(
+ available_layout_info_payload,
+ )),
+ })
+ },
}
}
}
@@ -1078,21 +1132,25 @@ impl TryFrom<LayoutInfo> for ProtobufLayoutInfo {
type Error = &'static str;
fn try_from(layout_info: LayoutInfo) -> Result<Self, &'static str> {
match layout_info {
- LayoutInfo::File(name) => Ok(ProtobufLayoutInfo {
+ LayoutInfo::File(name, layout_metadata) => Ok(ProtobufLayoutInfo {
source: "file".to_owned(),
name,
+ layout_metadata: Some(layout_metadata.try_into()?),
}),
LayoutInfo::BuiltIn(name) => Ok(ProtobufLayoutInfo {
source: "built-in".to_owned(),
name,
+ layout_metadata: None,
}),
LayoutInfo::Url(name) => Ok(ProtobufLayoutInfo {
source: "url".to_owned(),
name,
+ layout_metadata: None,
}),
LayoutInfo::Stringified(stringified_layout) => Ok(ProtobufLayoutInfo {
source: "stringified".to_owned(),
name: stringified_layout.clone(),
+ layout_metadata: None,
}),
}
}
@@ -1102,7 +1160,14 @@ impl TryFrom<ProtobufLayoutInfo> for LayoutInfo {
type Error = &'static str;
fn try_from(protobuf_layout_info: ProtobufLayoutInfo) -> Result<Self, &'static str> {
match protobuf_layout_info.source.as_str() {
- "file" => Ok(LayoutInfo::File(protobuf_layout_info.name)),
+ "file" => {
+ let layout_metadata = protobuf_layout_info
+ .layout_metadata
+ .map(|m| m.try_into())
+ .transpose()?
+ .unwrap_or_default();
+ Ok(LayoutInfo::File(protobuf_layout_info.name, layout_metadata))
+ },
"built-in" => Ok(LayoutInfo::BuiltIn(protobuf_layout_info.name)),
"url" => Ok(LayoutInfo::Url(protobuf_layout_info.name)),
"stringified" => Ok(LayoutInfo::Stringified(protobuf_layout_info.name)),
@@ -1111,6 +1176,183 @@ impl TryFrom<ProtobufLayoutInfo> for LayoutInfo {
}
}
+impl TryFrom<ProtobufLayoutMetadata> for LayoutMetadata {
+ type Error = &'static str;
+ fn try_from(protobuf_metadata: ProtobufLayoutMetadata) -> Result<Self, &'static str> {
+ let tabs = protobuf_metadata
+ .tabs
+ .into_iter()
+ .map(|t| t.try_into())
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(LayoutMetadata {
+ tabs,
+ creation_time: protobuf_metadata.creation_time,
+ update_time: protobuf_metadata.update_time,
+ })
+ }
+}
+
+impl TryFrom<LayoutMetadata> for ProtobufLayoutMetadata {
+ type Error = &'static str;
+ fn try_from(metadata: LayoutMetadata) -> Result<Self, &'static str> {
+ let tabs = metadata
+ .tabs
+ .into_iter()
+ .map(|t| t.try_into())
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(ProtobufLayoutMetadata {
+ tabs,
+ creation_time: metadata.creation_time,
+ update_time: metadata.update_time,
+ })
+ }
+}
+
+impl TryFrom<ProtobufTabMetadata> for TabMetadata {
+ type Error = &'static str;
+ fn try_from(protobuf_metadata: ProtobufTabMetadata) -> Result<Self, &'static str> {
+ let panes = protobuf_metadata
+ .pane_metadata
+ .into_iter()
+ .map(|p| p.try_into())
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(TabMetadata {
+ panes,
+ name: protobuf_metadata.name,
+ })
+ }
+}
+
+impl TryFrom<TabMetadata> for ProtobufTabMetadata {
+ type Error = &'static str;
+ fn try_from(metadata: TabMetadata) -> Result<Self, &'static str> {
+ let pane_metadata = metadata
+ .panes
+ .into_iter()
+ .map(|p| p.try_into())
+ .collect::<Result<Vec<_>, _>>()?;
+ Ok(ProtobufTabMetadata {
+ pane_metadata,
+ name: metadata.name,
+ })
+ }
+}
+
+impl TryFrom<ProtobufPaneMetadata> for PaneMetadata {
+ type Error = &'static str;
+ fn try_from(protobuf_metadata: ProtobufPaneMetadata) -> Result<Self, &'static str> {
+ Ok(PaneMetadata {
+ name: protobuf_metadata.name,
+ is_plugin: protobuf_metadata.is_plugin,
+ is_builtin_plugin: protobuf_metadata.is_builtin_plugin,
+ })
+ }
+}
+
+impl TryFrom<PaneMetadata> for ProtobufPaneMetadata {
+ type Error = &'static str;
+ fn try_from(metadata: PaneMetadata) -> Result<Self, &'static str> {
+ Ok(ProtobufPaneMetadata {
+ name: metadata.name,
+ is_plugin: metadata.is_plugin,
+ is_builtin_plugin: metadata.is_builtin_plugin,
+ })
+ }
+}
+
+// LayoutWithError conversions
+impl TryFrom<ProtobufLayoutWithError> for crate::data::LayoutWithError {
+ type Error = &'static str;
+ fn try_from(protobuf: ProtobufLayoutWithError) -> Result<Self, Self::Error> {
+ Ok(crate::data::LayoutWithError {
+ layout_name: protobuf.layout_name,
+ error: protobuf.error.ok_or("Missing error field")?.try_into()?,
+ })
+ }
+}
+
+impl TryFrom<crate::data::LayoutWithError> for ProtobufLayoutWithError {
+ type Error = &'static str;
+ fn try_from(layout_error: crate::data::LayoutWithError) -> Result<Self, Self::Error> {
+ Ok(ProtobufLayoutWithError {
+ layout_name: layout_error.layout_name,
+ error: Some(layout_error.error.try_into()?),
+ })
+ }
+}
+
+// LayoutParsingError conversions
+impl TryFrom<ProtobufLayoutParsingError> for crate::data::LayoutParsingError {
+ type Error = &'static str;
+ fn try_from(protobuf: ProtobufLayoutParsingError) -> Result<Self, Self::Error> {
+ match protobuf.error_type.ok_or("Missing error_type")? {
+ ProtobufLayoutParsingErrorType::KdlError(kdl_variant) => {
+ Ok(crate::data::LayoutParsingError::KdlError {
+ kdl_error: kdl_variant
+ .kdl_error
+ .ok_or("Missing kdl_error")?
+ .try_into()?,
+ file_name: kdl_variant.file_name,
+ source_code: kdl_variant.source_code,
+ })
+ },
+ ProtobufLayoutParsingErrorType::SyntaxError(_) => {
+ Ok(crate::data::LayoutParsingError::SyntaxError)
+ },
+ }
+ }
+}
+
+impl TryFrom<crate::data::LayoutParsingError> for ProtobufLayoutParsingError {
+ type Error = &'static str;
+ fn try_from(error: crate::data::LayoutParsingError) -> Result<Self, Self::Error> {
+ let error_type = match error {
+ crate::data::LayoutParsingError::KdlError {
+ kdl_error,
+ file_name,
+ source_code,
+ } => ProtobufLayoutParsingErrorType::KdlError(ProtobufKdlErrorVariant {
+ kdl_error: Some(kdl_error.try_into()?),
+ file_name,
+ source_code,
+ }),
+ crate::data::LayoutParsingError::SyntaxError => {
+ ProtobufLayoutParsingErrorType::SyntaxError(ProtobufSyntaxError {})
+ },
+ };
+ Ok(ProtobufLayoutParsingError {
+ error_type: Some(error_type),
+ })
+ }
+}
+
+// KdlError conversions
+impl TryFrom<ProtobufKdlError> for crate::input::config::KdlError {
+ type Error = &'static str;
+ fn try_from(protobuf: ProtobufKdlError) -> Result<Self, Self::Error> {
+ Ok(crate::input::config::KdlError {
+ error_message: protobuf.error_message,
+ src: None, // We don't serialize NamedSource
+ offset: protobuf.offset.map(|o| o as usize),
+ len: protobuf.len.map(|l| l as usize),
+ help_message: protobuf.help_message,
+ })
+ }
+}
+
+impl TryFrom<crate::input::config::KdlError> for ProtobufKdlError {
+ type Error = &'static str;
+ fn try_from(kdl: crate::input::config::KdlError) -> Result<Self, Self::Error> {
+ Ok(ProtobufKdlError {
+ error_message: kdl.error_message,
+ // src is not serialized
+ offset: kdl.offset.map(|o| o as u64),
+ len: kdl.len.map(|l| l as u64),
+ help_message: kdl.help_message,
+ })
+ }
+}
+
impl TryFrom<CopyDestination> for ProtobufCopyDestination {
type Error = &'static str;
fn try_from(copy_destination: CopyDestination) -> Result<Self, &'static str> {
@@ -1620,6 +1862,7 @@ impl TryFrom<ProtobufEventType> for EventType {
ProtobufEventType::UserAction => EventType::UserAction,
ProtobufEventType::ActionComplete => EventType::ActionComplete,
ProtobufEventType::CwdChanged => EventType::CwdChanged,
+ ProtobufEventType::AvailableLayoutInfo => EventType::AvailableLayoutInfo,
})
}
}
@@ -1667,6 +1910,7 @@ impl TryFrom<EventType> for ProtobufEventType {
EventType::UserAction => ProtobufEventType::UserAction,
EventType::ActionComplete => ProtobufEventType::ActionComplete,
EventType::CwdChanged => ProtobufEventType::CwdChanged,
+ EventType::AvailableLayoutInfo => ProtobufEventType::AvailableLayoutInfo,
})
}
}
@@ -2268,9 +2512,23 @@ fn serialize_session_update_event_with_non_default_values() {
connected_clients: 2,
is_current_session: true,
available_layouts: vec![
- LayoutInfo::File("layout 1".to_owned()),
+ LayoutInfo::File(
+ "layout 1".to_owned(),
+ LayoutMetadata {
+ tabs: vec![],
+ creation_time: "0".to_owned(),
+ update_time: "0".to_owned(),
+ },
+ ),
LayoutInfo::BuiltIn("layout2".to_owned()),
- LayoutInfo::File("layout3".to_owned()),
+ LayoutInfo::File(
+ "layout3".to_owned(),
+ LayoutMetadata {
+ tabs: vec![],
+ creation_time: "0".to_owned(),
+ update_time: "0".to_owned(),
+ },
+ ),
],
plugins,
web_clients_allowed: false,
@@ -2287,9 +2545,23 @@ fn serialize_session_update_event_with_non_default_values() {
connected_clients: 0,
is_current_session: false,
available_layouts: vec![
- LayoutInfo::File("layout 1".to_owned()),
+ LayoutInfo::File(
+ "layout 1".to_owned(),
+ LayoutMetadata {
+ tabs: vec![],
+ creation_time: "0".to_owned(),
+ update_time: "0".to_owned(),
+ },
+ ),
LayoutInfo::BuiltIn("layout2".to_owned()),
- LayoutInfo::File("layout3".to_owned()),
+ LayoutInfo::File(
+ "layout3".to_owned(),
+ LayoutMetadata {
+ tabs: vec![],
+ creation_time: "0".to_owned(),
+ update_time: "0".to_owned(),
+ },
+ ),
],
plugins: Default::default(),
web_clients_allowed: false,
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
index fb456ccd..0a0ad2b0 100644
--- a/zellij-utils/src/plugin_api/plugin_command.proto
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -166,6 +166,16 @@ enum CommandName {
SendSigintToPaneId = 171;
SendSigkillToPaneId = 172;
GetPanePid = 173;
+ OverrideLayout = 174;
+ SaveLayout = 175;
+ DeleteLayout = 176;
+ EditLayout = 177;
+ GenerateRandomName = 178;
+ DumpLayout = 179;
+ ParseLayout = 180;
+ RenameLayout = 181;
+ GetLayoutDir = 182;
+ GetFocusedPaneInfo = 183;
}
message PluginCommand {
@@ -280,6 +290,17 @@ message PluginCommand {
PaneId send_sigint_to_pane_id_payload = 121;
PaneId send_sigkill_to_pane_id_payload = 122;
GetPanePidPayload get_pane_pid_payload = 123;
+ OverrideLayoutPayload override_layout_payload = 124;
+ SaveLayoutPayload save_layout_payload = 125;
+ DeleteLayoutPayload delete_layout_payload = 126;
+ EditLayoutPayload edit_layout_payload = 127;
+ GenerateRandomNamePayload generate_random_name_payload = 128;
+ DumpLayoutPayload dump_layout_payload = 129;
+ ParseLayoutPayload parse_layout_payload = 130;
+ RenameLayoutPayload rename_layout_payload = 131;
+ GetLayoutDirPayload get_layout_dir_payload = 132;
+ DumpSessionLayoutPayload dump_session_layout_payload = 133;
+ GetFocusedPaneInfoPayload get_focused_pane_info_payload = 134;
}
}
@@ -288,6 +309,10 @@ message NewTabPayload {
optional string cwd = 2;
}
+message DumpSessionLayoutPayload {
+ optional uint32 tab_index = 1;
+}
+
message RunActionPayload {
action.Action action = 1;
repeated ContextItem context = 2;
@@ -755,3 +780,115 @@ message GetPanePidResponse {
string error = 2;
}
}
+
+message SaveLayoutResponse {
+ oneof result {
+ bool success = 1;
+ string error = 2;
+ }
+}
+
+message DeleteLayoutResponse {
+ oneof result {
+ bool success = 1;
+ string error = 2;
+ }
+}
+
+message EditLayoutResponse {
+ oneof result {
+ bool success = 1;
+ string error = 2;
+ }
+}
+
+message GenerateRandomNameResponse {
+ string name = 1;
+}
+
+message OverrideLayoutPayload {
+ event.LayoutInfo layout_info = 1;
+ repeated ContextItem context = 2;
+ bool retain_existing_terminal_panes = 3;
+ bool retain_existing_plugin_panes = 4;
+ bool apply_only_to_active_tab = 5;
+}
+
+message SaveLayoutPayload {
+ string layout_name = 1;
+ string layout_kdl = 2;
+ bool overwrite = 3;
+}
+
+message DeleteLayoutPayload {
+ string layout_name = 1;
+}
+
+message EditLayoutPayload {
+ string layout_name = 1;
+ repeated ContextItem context = 2;
+}
+
+message GenerateRandomNamePayload {}
+
+message DumpLayoutPayload {
+ string layout_name = 1;
+}
+
+message DumpLayoutResponse {
+ oneof result {
+ string layout_content = 1;
+ string error = 2;
+ }
+}
+
+message DumpSessionLayoutResponse {
+ oneof result {
+ string layout_content = 1;
+ string error = 2;
+ }
+ optional api.event.LayoutMetadata metadata = 3;
+}
+
+message ParseLayoutPayload {
+ string layout_string = 1;
+}
+
+message ParseLayoutResponse {
+ oneof result {
+ api.event.LayoutMetadata metadata = 1;
+ api.event.LayoutParsingError error = 2;
+ }
+}
+
+message RenameLayoutPayload {
+ string old_layout_name = 1;
+ string new_layout_name = 2;
+}
+
+message RenameLayoutResponse {
+ oneof result {
+ bool success = 1;
+ string error = 2;
+ }
+}
+
+message GetLayoutDirPayload {}
+
+message GetLayoutDirResponse {
+ string layout_dir = 1;
+}
+
+message GetFocusedPaneInfoPayload {}
+
+message GetFocusedPaneInfoResponse {
+ oneof result {
+ FocusedPaneInfo focused_pane_info = 1;
+ string error = 2;
+ }
+}
+
+message FocusedPaneInfo {
+ uint32 focused_tab_index = 1;
+ PaneId focused_pane_id = 2;
+}
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
index 542e1ea2..8c4bf451 100644
--- a/zellij-utils/src/plugin_api/plugin_command.rs
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -3,35 +3,48 @@ pub use super::generated_api::api::{
event::{EventNameList as ProtobufEventNameList, Header},
input_mode::InputMode as ProtobufInputMode,
plugin_command::{
- get_pane_pid_response, plugin_command::Payload, BreakPanesToNewTabPayload,
- BreakPanesToTabWithIndexPayload, ChangeFloatingPanesCoordinatesPayload,
- ChangeHostFolderPayload, ClearScreenForPaneIdPayload, CliPipeOutputPayload,
- CloseMultiplePanesPayload, CloseTabWithIndexPayload, CommandName, ContextItem,
- CopyToClipboardPayload, CreateTokenResponse as ProtobufCreateTokenResponse,
- CreateTokenResponse, CursorPosition, EditScrollbackForPaneWithIdPayload,
- EmbedMultiplePanesPayload, EnvVariable, ExecCmdPayload,
+ delete_layout_response, dump_layout_response, dump_session_layout_response,
+ edit_layout_response, get_focused_pane_info_response, get_pane_pid_response,
+ parse_layout_response, plugin_command::Payload, rename_layout_response,
+ save_layout_response, BreakPanesToNewTabPayload, BreakPanesToTabWithIndexPayload,
+ ChangeFloatingPanesCoordinatesPayload, ChangeHostFolderPayload,
+ ClearScreenForPaneIdPayload, CliPipeOutputPayload, CloseMultiplePanesPayload,
+ CloseTabWithIndexPayload, CommandName, ContextItem, CopyToClipboardPayload,
+ CreateTokenResponse as ProtobufCreateTokenResponse, CreateTokenResponse, CursorPosition,
+ DeleteLayoutPayload, DeleteLayoutResponse as ProtobufDeleteLayoutResponse,
+ DumpLayoutPayload, DumpLayoutResponse as ProtobufDumpLayoutResponse,
+ DumpSessionLayoutPayload, DumpSessionLayoutResponse as ProtobufDumpSessionLayoutResponse,
+ EditLayoutPayload, EditLayoutResponse as ProtobufEditLayoutResponse,
+ EditScrollbackForPaneWithIdPayload, EmbedMultiplePanesPayload, EnvVariable, ExecCmdPayload,
FixedOrPercent as ProtobufFixedOrPercent,
FixedOrPercentValue as ProtobufFixedOrPercentValue, FloatMultiplePanesPayload,
- FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, GenerateWebLoginTokenPayload,
- GetPanePidPayload, GetPanePidResponse as ProtobufGetPanePidResponse,
- GetPaneScrollbackPayload, GroupAndUngroupPanesPayload, HidePaneWithIdPayload,
- HighlightAndUnhighlightPanesPayload, HttpVerb as ProtobufHttpVerb, IdAndNewName,
- KeyToRebind, KeyToUnbind, KillSessionsPayload, ListTokensResponse, LoadNewPluginPayload,
- MessageToPluginPayload, MovePaneWithPaneIdInDirectionPayload, MovePaneWithPaneIdPayload,
- MovePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabPayload,
- NewTabsWithLayoutInfoPayload, OpenCommandPaneFloatingNearPluginPayload,
- OpenCommandPaneInPlaceOfPluginPayload, OpenCommandPaneNearPluginPayload,
- OpenCommandPanePayload, OpenFileFloatingNearPluginPayload, OpenFileInPlaceOfPluginPayload,
+ FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, FocusedPaneInfo,
+ GenerateRandomNamePayload,
+ GenerateRandomNameResponse as ProtobufGenerateRandomNameResponse,
+ GenerateWebLoginTokenPayload, GetFocusedPaneInfoPayload,
+ GetFocusedPaneInfoResponse as ProtobufGetFocusedPaneInfoResponse, GetLayoutDirPayload,
+ GetLayoutDirResponse as ProtobufGetLayoutDirResponse, GetPanePidPayload,
+ GetPanePidResponse as ProtobufGetPanePidResponse, GetPaneScrollbackPayload,
+ GroupAndUngroupPanesPayload, HidePaneWithIdPayload, HighlightAndUnhighlightPanesPayload,
+ HttpVerb as ProtobufHttpVerb, IdAndNewName, KeyToRebind, KeyToUnbind, KillSessionsPayload,
+ ListTokensResponse, LoadNewPluginPayload, MessageToPluginPayload,
+ MovePaneWithPaneIdInDirectionPayload, MovePaneWithPaneIdPayload, MovePayload,
+ NewPluginArgs as ProtobufNewPluginArgs, NewTabPayload, NewTabsWithLayoutInfoPayload,
+ OpenCommandPaneFloatingNearPluginPayload, OpenCommandPaneInPlaceOfPluginPayload,
+ OpenCommandPaneNearPluginPayload, OpenCommandPanePayload,
+ OpenFileFloatingNearPluginPayload, OpenFileInPlaceOfPluginPayload,
OpenFileNearPluginPayload, OpenFilePayload, OpenTerminalFloatingNearPluginPayload,
- OpenTerminalInPlaceOfPluginPayload, OpenTerminalNearPluginPayload,
+ OpenTerminalInPlaceOfPluginPayload, OpenTerminalNearPluginPayload, OverrideLayoutPayload,
PageScrollDownInPaneIdPayload, PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId,
- PaneIdAndFloatingPaneCoordinates, PaneType as ProtobufPaneType,
- PluginCommand as ProtobufPluginCommand, PluginMessagePayload, RebindKeysPayload,
- ReconfigurePayload, ReloadPluginPayload, RenameWebLoginTokenPayload,
- RenameWebTokenResponse, ReplacePaneWithExistingPanePayload, RequestPluginPermissionPayload,
- RerunCommandPanePayload, ResizePaneIdWithDirectionPayload, ResizePayload,
- RevokeAllWebTokensResponse, RevokeTokenResponse, RevokeWebLoginTokenPayload,
- RunActionPayload, RunCommandPayload, ScrollDownInPaneIdPayload,
+ PaneIdAndFloatingPaneCoordinates, PaneType as ProtobufPaneType, ParseLayoutPayload,
+ ParseLayoutResponse as ProtobufParseLayoutResponse, PluginCommand as ProtobufPluginCommand,
+ PluginMessagePayload, RebindKeysPayload, ReconfigurePayload, ReloadPluginPayload,
+ RenameLayoutPayload, RenameLayoutResponse as ProtobufRenameLayoutResponse,
+ RenameWebLoginTokenPayload, RenameWebTokenResponse, ReplacePaneWithExistingPanePayload,
+ RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePaneIdWithDirectionPayload,
+ ResizePayload, RevokeAllWebTokensResponse, RevokeTokenResponse, RevokeWebLoginTokenPayload,
+ RunActionPayload, RunCommandPayload, SaveLayoutPayload,
+ SaveLayoutResponse as ProtobufSaveLayoutResponse, ScrollDownInPaneIdPayload,
ScrollToBottomInPaneIdPayload, ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload,
SetFloatingPanePinnedPayload, SetSelfMouseSelectionSupportPayload, SetTimeoutPayload,
ShowCursorPayload, ShowPaneWithIdPayload, StackPanesPayload, SubscribePayload,
@@ -44,8 +57,10 @@ pub use super::generated_api::api::{
};
use crate::data::{
- ConnectToSession, FloatingPaneCoordinates, GetPanePidResponse, HttpVerb, InputMode,
- KeyWithModifier, MessageToPlugin, NewPluginArgs, PaneId, PermissionType, PluginCommand,
+ ConnectToSession, DeleteLayoutResponse, EditLayoutResponse, FloatingPaneCoordinates,
+ GetFocusedPaneInfoResponse, GetPanePidResponse, HttpVerb, InputMode, KeyWithModifier,
+ MessageToPlugin, NewPluginArgs, PaneId, PermissionType, PluginCommand, RenameLayoutResponse,
+ SaveLayoutResponse,
};
use crate::input::actions::Action;
use crate::input::layout::SplitSize;
@@ -227,6 +242,135 @@ impl From<GetPanePidResponse> for ProtobufGetPanePidResponse {
}
}
+impl From<GetFocusedPaneInfoResponse> for ProtobufGetFocusedPaneInfoResponse {
+ fn from(response: GetFocusedPaneInfoResponse) -> Self {
+ match response {
+ GetFocusedPaneInfoResponse::Ok { tab_index, pane_id } => {
+ let protobuf_pane_id = ProtobufPaneId {
+ pane_type: match pane_id {
+ PaneId::Terminal(_) => ProtobufPaneType::Terminal as i32,
+ PaneId::Plugin(_) => ProtobufPaneType::Plugin as i32,
+ },
+ id: match pane_id {
+ PaneId::Terminal(id) | PaneId::Plugin(id) => id,
+ },
+ };
+ ProtobufGetFocusedPaneInfoResponse {
+ result: Some(get_focused_pane_info_response::Result::FocusedPaneInfo(
+ FocusedPaneInfo {
+ focused_tab_index: tab_index as u32,
+ focused_pane_id: Some(protobuf_pane_id),
+ },
+ )),
+ }
+ },
+ GetFocusedPaneInfoResponse::Err(err) => ProtobufGetFocusedPaneInfoResponse {
+ result: Some(get_focused_pane_info_response::Result::Error(err)),
+ },
+ }
+ }
+}
+
+impl TryFrom<ProtobufSaveLayoutResponse> for SaveLayoutResponse {
+ type Error = &'static str;
+ fn try_from(protobuf_response: ProtobufSaveLayoutResponse) -> Result<Self, &'static str> {
+ match protobuf_response.result {
+ Some(save_layout_response::Result::Success(_)) => Ok(SaveLayoutResponse::Ok(())),
+ Some(save_layout_response::Result::Error(error)) => Ok(SaveLayoutResponse::Err(error)),
+ None => Err("Empty SaveLayoutResponse"),
+ }
+ }
+}
+
+impl From<SaveLayoutResponse> for ProtobufSaveLayoutResponse {
+ fn from(response: SaveLayoutResponse) -> Self {
+ match response {
+ SaveLayoutResponse::Ok(_) => ProtobufSaveLayoutResponse {
+ result: Some(save_layout_response::Result::Success(true)),
+ },
+ SaveLayoutResponse::Err(error) => ProtobufSaveLayoutResponse {
+ result: Some(save_layout_response::Result::Error(error)),
+ },
+ }
+ }
+}
+
+impl TryFrom<ProtobufDeleteLayoutResponse> for DeleteLayoutResponse {
+ type Error = &'static str;
+ fn try_from(protobuf_response: ProtobufDeleteLayoutResponse) -> Result<Self, &'static str> {
+ match protobuf_response.result {
+ Some(delete_layout_response::Result::Success(_)) => Ok(DeleteLayoutResponse::Ok(())),
+ Some(delete_layout_response::Result::Error(error)) => {
+ Ok(DeleteLayoutResponse::Err(error))
+ },
+ None => Err("Empty DeleteLayoutResponse"),
+ }
+ }
+}
+
+impl From<DeleteLayoutResponse> for ProtobufDeleteLayoutResponse {
+ fn from(response: DeleteLayoutResponse) -> Self {
+ match response {
+ DeleteLayoutResponse::Ok(_) => ProtobufDeleteLayoutResponse {
+ result: Some(delete_layout_response::Result::Success(true)),
+ },
+ DeleteLayoutResponse::Err(error) => ProtobufDeleteLayoutResponse {
+ result: Some(delete_layout_response::Result::Error(error)),
+ },
+ }
+ }
+}
+
+impl TryFrom<ProtobufRenameLayoutResponse> for RenameLayoutResponse {
+ type Error = &'static str;
+ fn try_from(protobuf_response: ProtobufRenameLayoutResponse) -> Result<Self, &'static str> {
+ match protobuf_response.result {
+ Some(rename_layout_response::Result::Success(_)) => Ok(RenameLayoutResponse::Ok(())),
+ Some(rename_layout_response::Result::Error(error)) => {
+ Ok(RenameLayoutResponse::Err(error))
+ },
+ None => Err("Empty RenameLayoutResponse"),
+ }
+ }
+}
+
+impl From<RenameLayoutResponse> for ProtobufRenameLayoutResponse {
+ fn from(response: RenameLayoutResponse) -> Self {
+ match response {
+ RenameLayoutResponse::Ok(_) => ProtobufRenameLayoutResponse {
+ result: Some(rename_layout_response::Result::Success(true)),
+ },
+ RenameLayoutResponse::Err(error) => ProtobufRenameLayoutResponse {
+ result: Some(rename_layout_response::Result::Error(error)),
+ },
+ }
+ }
+}
+
+impl TryFrom<ProtobufEditLayoutResponse> for EditLayoutResponse {
+ type Error = &'static str;
+ fn try_from(protobuf_response: ProtobufEditLayoutResponse) -> Result<Self, &'static str> {
+ match protobuf_response.result {
+ Some(edit_layout_response::Result::Success(_)) => Ok(EditLayoutResponse::Ok(())),
+ Some(edit_layout_response::Result::Error(error)) => Ok(EditLayoutResponse::Err(error)),
+ None => Err("Empty EditLayoutResponse"),
+ }
+ }
+}
+
+impl From<EditLayoutResponse> for ProtobufEditLayoutResponse {
+ fn from(response: EditLayoutResponse) -> Self {
+ match response {
+ EditLayoutResponse::Ok(_) => ProtobufEditLayoutResponse {
+ result: Some(edit_layout_response::Result::Success(true)),
+ },
+ EditLayoutResponse::Err(error) => ProtobufEditLayoutResponse {
+ result: Some(edit_layout_response::Result::Error(error)),
+ },
+ }
+ }
+}
+
impl TryFrom<(InputMode, KeyWithModifier, Vec<Action>)> for KeyToRebind {
type Error = &'static str;
fn try_from(
@@ -1047,8 +1191,13 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
None => Ok(PluginCommand::WatchFilesystem),
},
Some(CommandName::DumpSessionLayout) => match protobuf_plugin_command.payload {
- Some(_) => Err("DumpSessionLayout should have no payload, found a payload"),
- None => Ok(PluginCommand::DumpSessionLayout),
+ Some(Payload::DumpSessionLayoutPayload(payload)) => {
+ Ok(PluginCommand::DumpSessionLayout {
+ tab_index: payload.tab_index.map(|i| i as usize),
+ })
+ },
+ None => Ok(PluginCommand::DumpSessionLayout { tab_index: None }),
+ _ => Err("Mismatched payload for DumpSessionLayout"),
},
Some(CommandName::CloseSelf) => match protobuf_plugin_command.payload {
Some(_) => Err("CloseSelf should have no payload, found a payload"),
@@ -1215,6 +1364,70 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
},
_ => Err("Mismatched payload for GetPanePid"),
},
+ Some(CommandName::OverrideLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::OverrideLayoutPayload(override_layout_payload)) => {
+ let layout_info = override_layout_payload
+ .layout_info
+ .ok_or("OverrideLayout missing layout_info")?
+ .try_into()
+ .map_err(|_| "Failed to parse LayoutInfo")?;
+ let context = override_layout_payload
+ .context
+ .into_iter()
+ .map(|c| (c.name, c.value))
+ .collect();
+ Ok(PluginCommand::OverrideLayout(
+ layout_info,
+ override_layout_payload.retain_existing_terminal_panes,
+ override_layout_payload.retain_existing_plugin_panes,
+ override_layout_payload.apply_only_to_active_tab,
+ context,
+ ))
+ },
+ _ => Err("Mismatched payload for OverrideLayout"),
+ },
+ Some(CommandName::SaveLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::SaveLayoutPayload(save_layout_payload)) => {
+ Ok(PluginCommand::SaveLayout {
+ layout_name: save_layout_payload.layout_name,
+ layout_kdl: save_layout_payload.layout_kdl,
+ overwrite: save_layout_payload.overwrite,
+ })
+ },
+ _ => Err("Mismatched payload for SaveLayout"),
+ },
+ Some(CommandName::DeleteLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::DeleteLayoutPayload(delete_layout_payload)) => {
+ Ok(PluginCommand::DeleteLayout {
+ layout_name: delete_layout_payload.layout_name,
+ })
+ },
+ _ => Err("Mismatched payload for DeleteLayout"),
+ },
+ Some(CommandName::RenameLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::RenameLayoutPayload(rename_layout_payload)) => {
+ Ok(PluginCommand::RenameLayout {
+ old_layout_name: rename_layout_payload.old_layout_name,
+ new_layout_name: rename_layout_payload.new_layout_name,
+ })
+ },
+ _ => Err("Mismatched payload for RenameLayout"),
+ },
+ Some(CommandName::EditLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::EditLayoutPayload(edit_layout_payload)) => {
+ let layout_name = edit_layout_payload.layout_name;
+ let context: BTreeMap<String, String> = edit_layout_payload
+ .context
+ .into_iter()
+ .map(|e| (e.name, e.value))
+ .collect();
+ Ok(PluginCommand::EditLayout {
+ layout_name,
+ context,
+ })
+ },
+ _ => Err("Mismatched payload for EditLayout"),
+ },
Some(CommandName::MovePaneWithPaneId) => match protobuf_plugin_command.payload {
Some(Payload::MovePaneWithPaneIdPayload(move_pane_with_pane_id_payload)) => {
match move_pane_with_pane_id_payload.pane_id {
@@ -1845,6 +2058,21 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
},
_ => Err("Mismatched payload for CopyToClipboard"),
},
+ Some(CommandName::GenerateRandomName) => Ok(PluginCommand::GenerateRandomName),
+ Some(CommandName::DumpLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::DumpLayoutPayload(payload)) => {
+ Ok(PluginCommand::DumpLayout(payload.layout_name))
+ },
+ _ => Err("Mismatched payload for DumpLayout"),
+ },
+ Some(CommandName::ParseLayout) => match protobuf_plugin_command.payload {
+ Some(Payload::ParseLayoutPayload(payload)) => {
+ Ok(PluginCommand::ParseLayout(payload.layout_string))
+ },
+ _ => Err("Mismatched payload for ParseLayout"),
+ },
+ Some(CommandName::GetLayoutDir) => Ok(PluginCommand::GetLayoutDir),
+ Some(CommandName::GetFocusedPaneInfo) => Ok(PluginCommand::GetFocusedPaneInfo),
None => Err("Unrecognized plugin command"),
}
}
@@ -2417,9 +2645,13 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
name: CommandName::WatchFilesystem as i32,
payload: None,
}),
- PluginCommand::DumpSessionLayout => Ok(ProtobufPluginCommand {
+ PluginCommand::DumpSessionLayout { tab_index } => Ok(ProtobufPluginCommand {
name: CommandName::DumpSessionLayout as i32,
- payload: None,
+ payload: tab_index.map(|idx| {
+ Payload::DumpSessionLayoutPayload(DumpSessionLayoutPayload {
+ tab_index: Some(idx as u32),
+ })
+ }),
}),
PluginCommand::CloseSelf => Ok(ProtobufPluginCommand {
name: CommandName::CloseSelf as i32,
@@ -2545,6 +2777,69 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
pane_id: Some(pane_id.try_into()?),
})),
}),
+ PluginCommand::OverrideLayout(
+ layout_info,
+ retain_existing_terminal_panes,
+ retain_existing_plugin_panes,
+ apply_only_to_active_tab,
+ context,
+ ) => Ok(ProtobufPluginCommand {
+ name: CommandName::OverrideLayout as i32,
+ payload: Some(Payload::OverrideLayoutPayload(OverrideLayoutPayload {
+ layout_info: layout_info.try_into().ok(),
+ context: context
+ .into_iter()
+ .map(|(name, value)| ContextItem { name, value })
+ .collect(),
+ retain_existing_terminal_panes,
+ retain_existing_plugin_panes,
+ apply_only_to_active_tab,
+ })),
+ }),
+ PluginCommand::SaveLayout {
+ layout_name,
+ layout_kdl,
+ overwrite,
+ } => Ok(ProtobufPluginCommand {
+ name: CommandName::SaveLayout as i32,
+ payload: Some(Payload::SaveLayoutPayload(SaveLayoutPayload {
+ layout_name,
+ layout_kdl,
+ overwrite,
+ })),
+ }),
+ PluginCommand::DeleteLayout { layout_name } => Ok(ProtobufPluginCommand {
+ name: CommandName::DeleteLayout as i32,
+ payload: Some(Payload::DeleteLayoutPayload(DeleteLayoutPayload {
+ layout_name,
+ })),
+ }),
+ PluginCommand::RenameLayout {
+ old_layout_name,
+ new_layout_name,
+ } => Ok(ProtobufPluginCommand {
+ name: CommandName::RenameLayout as i32,
+ payload: Some(Payload::RenameLayoutPayload(RenameLayoutPayload {
+ old_layout_name,
+ new_layout_name,
+ })),
+ }),
+ PluginCommand::EditLayout {
+ layout_name,
+ context,
+ } => {
+ let context: Vec<_> = context
+ .into_iter()
+ .map(|(name, value)| ContextItem { name, value })
+ .collect();
+ Ok(ProtobufPluginCommand {
+ name: CommandName::EditLayout as i32,
+ payload: Some(Payload::EditLayoutPayload(EditLayoutPayload {
+ layout_name,
+ context,
+ })),
+ })
+ },
PluginCommand::MovePaneWithPaneId(pane_id) => Ok(ProtobufPluginCommand {
name: CommandName::MovePaneWithPaneId as i32,
payload: Some(Payload::MovePaneWithPaneIdPayload(
@@ -3073,6 +3368,34 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
text,
})),
}),
+ PluginCommand::GenerateRandomName => Ok(ProtobufPluginCommand {
+ name: CommandName::GenerateRandomName as i32,
+ payload: Some(Payload::GenerateRandomNamePayload(
+ GenerateRandomNamePayload {},
+ )),
+ }),
+ PluginCommand::DumpLayout(layout_name) => Ok(ProtobufPluginCommand {
+ name: CommandName::DumpLayout as i32,
+ payload: Some(Payload::DumpLayoutPayload(DumpLayoutPayload {
+ layout_name,
+ })),
+ }),
+ PluginCommand::ParseLayout(layout_string) => Ok(ProtobufPluginCommand {
+ name: CommandName::ParseLayout as i32,
+ payload: Some(Payload::ParseLayoutPayload(ParseLayoutPayload {
+ layout_string,
+ })),
+ }),
+ PluginCommand::GetLayoutDir => Ok(ProtobufPluginCommand {
+ name: CommandName::GetLayoutDir as i32,
+ payload: Some(Payload::GetLayoutDirPayload(GetLayoutDirPayload {})),
+ }),
+ PluginCommand::GetFocusedPaneInfo => Ok(ProtobufPluginCommand {
+ name: CommandName::GetFocusedPaneInfo as i32,
+ payload: Some(Payload::GetFocusedPaneInfoPayload(
+ GetFocusedPaneInfoPayload {},
+ )),
+ }),
}
}
}