aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/plugin_api
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-07-27 18:24:37 +0200
committerGitHub <noreply@github.com>2026-07-27 18:24:37 +0200
commitea07e2d5b6bbc9ea6f9c765b0838b3e91156a58d (patch)
tree4a8fac8a9b27f2a8b32b3af61a3b5419b9937c81 /zellij-utils/src/plugin_api
parentSwitch from the unmaintained daemonize crate to a maintained fork (#4512) (diff)
downloadsl0ppij-ea07e2d5b6bbc9ea6f9c765b0838b3e91156a58d.tar.gz
sl0ppij-ea07e2d5b6bbc9ea6f9c765b0838b3e91156a58d.tar.xz
sl0ppij-ea07e2d5b6bbc9ea6f9c765b0838b3e91156a58d.zip
Nested session handling (#5417)
* fix: theme query and updated pixel dimensions * add no-ui-fullscreen key/action/capability * protocol core * integration test harness * fix integration tests * fix flaky tests * nested ui (dimming) and directional focus initial implementation * integration tests for nested ui dimming and directional focus * initial full screen nesteed implementation * fix: keep hidden floating panes hidden across nested no-ui fullscreen * fix integration tests * no ui fullscreen integration tests * hardening behavior/tests * fix(nested): re-derive descend/dim on host tab switch and new-tab so clicking dimmed chrome ascends * initial modal implementation * initial ui improvements * fix integration tests * improve nested selection ui * nested session modal refactoring and tests * improve integration test speed somewhat * some ui adjustments * simplify full/auto nested session handling * hints in compact-bar * guest stdin leak fix * allow floating panes to be fullscreen * make nested session handling configurable * protocol reannounce * refactor: naming confusion * improve ux somewhat * rustfmt * merge fixes * improve integration test rate limiting (fix ci) * add pr
Diffstat (limited to 'zellij-utils/src/plugin_api')
-rw-r--r--zellij-utils/src/plugin_api/action.proto4
-rw-r--r--zellij-utils/src/plugin_api/action.rs37
-rw-r--r--zellij-utils/src/plugin_api/event.proto6
-rw-r--r--zellij-utils/src/plugin_api/event.rs58
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto2
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs20
6 files changed, 127 insertions, 0 deletions
diff --git a/zellij-utils/src/plugin_api/action.proto b/zellij-utils/src/plugin_api/action.proto
index f9370961..1d896cef 100644
--- a/zellij-utils/src/plugin_api/action.proto
+++ b/zellij-utils/src/plugin_api/action.proto
@@ -501,6 +501,10 @@ enum ActionName {
ToggleTheme = 103;
FocusLastPane = 104;
SetPaneFrameStyle = 105;
+ ToggleFocusNoUiFullscreen = 106;
+ FocusHostSession = 107;
+ ToggleHostFullscreen = 108;
+ FocusGuestSession = 109;
}
message Position {
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
index f1d71222..c11b56f1 100644
--- a/zellij-utils/src/plugin_api/action.rs
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -298,6 +298,12 @@ impl TryFrom<ProtobufAction> for Action {
None => Ok(Action::ToggleFocusFullscreen),
}
},
+ Some(ProtobufActionName::ToggleFocusNoUiFullscreen) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleFocusNoUiFullscreen should not have a payload"),
+ None => Ok(Action::ToggleFocusNoUiFullscreen),
+ }
+ },
Some(ProtobufActionName::TogglePaneFrames) => match protobuf_action.optional_payload {
Some(_) => Err("TogglePaneFrames should not have a payload"),
None => Ok(Action::TogglePaneFrames),
@@ -1092,6 +1098,20 @@ impl TryFrom<ProtobufAction> for Action {
},
_ => Err("Wrong payload for Action::NewInPlacePane"),
},
+ Some(ProtobufActionName::FocusHostSession) => match protobuf_action.optional_payload {
+ Some(_) => Err("FocusHostSession should not have a payload"),
+ None => Ok(Action::FocusHostSession),
+ },
+ Some(ProtobufActionName::FocusGuestSession) => match protobuf_action.optional_payload {
+ Some(_) => Err("FocusGuestSession should not have a payload"),
+ None => Ok(Action::FocusGuestSession),
+ },
+ Some(ProtobufActionName::ToggleHostFullscreen) => {
+ match protobuf_action.optional_payload {
+ Some(_) => Err("ToggleHostFullscreen should not have a payload"),
+ None => Ok(Action::ToggleHostFullscreen),
+ }
+ },
_ => Err("Unknown Action"),
}
}
@@ -1148,6 +1168,7 @@ impl TryFrom<Action> for ProtobufAction {
| Action::ClearScreenByPaneId { .. }
| Action::EditScrollbackByPaneId { .. }
| Action::ToggleFocusFullscreenByPaneId { .. }
+ | Action::ToggleFocusNoUiFullscreenByPaneId { .. }
| Action::TogglePaneEmbedOrFloatingByPaneId { .. }
| Action::CloseFocusByPaneId { .. }
| Action::RenamePaneByPaneId { .. }
@@ -1323,6 +1344,10 @@ impl TryFrom<Action> for ProtobufAction {
name: ProtobufActionName::ToggleFocusFullscreen as i32,
optional_payload: None,
}),
+ Action::ToggleFocusNoUiFullscreen => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleFocusNoUiFullscreen as i32,
+ optional_payload: None,
+ }),
Action::TogglePaneFrames => Ok(ProtobufAction {
name: ProtobufActionName::TogglePaneFrames as i32,
optional_payload: None,
@@ -1960,6 +1985,18 @@ impl TryFrom<Action> for ProtobufAction {
)),
})
},
+ Action::FocusHostSession => Ok(ProtobufAction {
+ name: ProtobufActionName::FocusHostSession as i32,
+ optional_payload: None,
+ }),
+ Action::FocusGuestSession => Ok(ProtobufAction {
+ name: ProtobufActionName::FocusGuestSession as i32,
+ optional_payload: None,
+ }),
+ Action::ToggleHostFullscreen => Ok(ProtobufAction {
+ name: ProtobufActionName::ToggleHostFullscreen as i32,
+ optional_payload: None,
+ }),
Action::NoOp
| Action::Confirm
| Action::NewInPlacePluginPane {
diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto
index d3148edf..6814e8d8 100644
--- a/zellij-utils/src/plugin_api/event.proto
+++ b/zellij-utils/src/plugin_api/event.proto
@@ -511,6 +511,12 @@ message ModeUpdatePayload {
optional uint32 web_server_port = 14;
optional bool web_server_capability = 15;
optional PaneFrameStyle pane_frame_style = 16;
+ optional bool session_dimmed = 17;
+ repeated string ancestry = 18;
+ optional bool host_fullscreen = 19;
+ repeated string nested_ascend_keys = 20;
+ optional bool session_ascended = 21;
+ repeated string nested_descend_keys = 22;
}
enum WebSharing {
diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs
index 190552d4..970f5e2c 100644
--- a/zellij-utils/src/plugin_api/event.rs
+++ b/zellij-utils/src/plugin_api/event.rs
@@ -2020,6 +2020,26 @@ impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
.and_then(|p| ProtobufPaneFrameStyle::from_i32(p))
.map(|p| p.into());
+ let session_dimmed = protobuf_mode_update_payload.session_dimmed;
+
+ let session_ancestry = protobuf_mode_update_payload.ancestry;
+
+ let host_fullscreen = protobuf_mode_update_payload.host_fullscreen;
+
+ let nested_ascend_keys = protobuf_mode_update_payload
+ .nested_ascend_keys
+ .iter()
+ .filter_map(|key| KeyWithModifier::from_str(key).ok())
+ .collect();
+
+ let session_ascended = protobuf_mode_update_payload.session_ascended;
+
+ let nested_descend_keys = protobuf_mode_update_payload
+ .nested_descend_keys
+ .iter()
+ .filter_map(|key| KeyWithModifier::from_str(key).ok())
+ .collect();
+
let mode_info = ModeInfo {
mode: current_mode,
keybinds,
@@ -2037,6 +2057,12 @@ impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
web_server_port,
web_server_capability,
pane_frame_style,
+ session_dimmed,
+ session_ancestry,
+ host_fullscreen,
+ nested_ascend_keys,
+ session_ascended,
+ nested_descend_keys,
};
Ok(mode_info)
}
@@ -2065,6 +2091,20 @@ impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
let protobuf_pane_frame_style: ProtobufPaneFrameStyle = p.into();
protobuf_pane_frame_style as i32
});
+ let session_dimmed = mode_info.session_dimmed;
+ let session_ancestry = mode_info.session_ancestry;
+ let host_fullscreen = mode_info.host_fullscreen;
+ let nested_ascend_keys = mode_info
+ .nested_ascend_keys
+ .iter()
+ .map(|key| key.to_kdl())
+ .collect();
+ let session_ascended = mode_info.session_ascended;
+ let nested_descend_keys = mode_info
+ .nested_descend_keys
+ .iter()
+ .map(|key| key.to_kdl())
+ .collect();
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()?;
@@ -2106,6 +2146,12 @@ impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
web_server_port,
web_server_capability,
pane_frame_style,
+ session_dimmed,
+ ancestry: session_ancestry,
+ host_fullscreen,
+ nested_ascend_keys,
+ session_ascended,
+ nested_descend_keys,
})
}
}
@@ -2460,6 +2506,18 @@ fn serialize_mode_update_event_with_non_default_values() {
web_server_port: Some(8082),
web_server_capability: Some(true),
pane_frame_style: Some(crate::input::options::PaneFrameStyle::Titles),
+ session_dimmed: Some(true),
+ session_ancestry: vec!["work".to_owned(), "prod".to_owned()],
+ host_fullscreen: Some(true),
+ nested_ascend_keys: vec![
+ KeyWithModifier::new(BareKey::Char('o')).with_ctrl_modifier(),
+ KeyWithModifier::new(BareKey::Up),
+ ],
+ session_ascended: Some(true),
+ nested_descend_keys: vec![
+ KeyWithModifier::new(BareKey::Char('o')).with_ctrl_modifier(),
+ KeyWithModifier::new(BareKey::Down),
+ ],
});
let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
let serialized_protobuf_event = protobuf_event.encode_to_vec();
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
index 8d31727d..e9dff3c6 100644
--- a/zellij-utils/src/plugin_api/plugin_command.proto
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -218,6 +218,8 @@ enum CommandName {
SetPaneFrameStyle = 224;
ToggleFloatingPanes = 225;
NewPane = 226;
+ ToggleFocusNoUiFullscreen = 227;
+ FocusHostSession = 228;
}
message PluginCommand {
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
index 38c42565..3d86bc20 100644
--- a/zellij-utils/src/plugin_api/plugin_command.rs
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -1110,6 +1110,18 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
}
Ok(PluginCommand::ToggleFocusFullscreen)
},
+ Some(CommandName::ToggleFocusNoUiFullscreen) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("ToggleFocusNoUiFullscreen should not have a payload");
+ }
+ Ok(PluginCommand::ToggleFocusNoUiFullscreen)
+ },
+ Some(CommandName::FocusHostSession) => {
+ if protobuf_plugin_command.payload.is_some() {
+ return Err("FocusHostSession should not have a payload");
+ }
+ Ok(PluginCommand::FocusHostSession)
+ },
Some(CommandName::TogglePaneFrames) => {
if protobuf_plugin_command.payload.is_some() {
return Err("TogglePaneFrames should not have a payload");
@@ -3127,6 +3139,14 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
name: CommandName::ToggleFocusFullscreen as i32,
payload: None,
}),
+ PluginCommand::ToggleFocusNoUiFullscreen => Ok(ProtobufPluginCommand {
+ name: CommandName::ToggleFocusNoUiFullscreen as i32,
+ payload: None,
+ }),
+ PluginCommand::FocusHostSession => Ok(ProtobufPluginCommand {
+ name: CommandName::FocusHostSession as i32,
+ payload: None,
+ }),
PluginCommand::TogglePaneFrames => Ok(ProtobufPluginCommand {
name: CommandName::TogglePaneFrames as i32,
payload: None,