aboutsummaryrefslogtreecommitdiffstats
path: root/zellij-utils/src/plugin_api
diff options
context:
space:
mode:
authorKarl Bunch <karlbunch@users.noreply.github.com>2026-03-04 08:26:26 -0500
committerGitHub <noreply@github.com>2026-03-04 14:26:26 +0100
commitf77cdec298576164f34baf0456e4b986bde269e6 (patch)
treeaf9fb93cfc6edf465378952c0aff38d48820e142 /zellij-utils/src/plugin_api
parentdocs(changelog): native Windows support (!!) (diff)
downloadsl0ppij-f77cdec298576164f34baf0456e4b986bde269e6.tar.gz
sl0ppij-f77cdec298576164f34baf0456e4b986bde269e6.tar.xz
sl0ppij-f77cdec298576164f34baf0456e4b986bde269e6.zip
feat: add per-pane default foreground/background color support (#4737)
* feat: add per-pane default foreground/background color support Add per-pane default foreground and background colors, configurable through four surfaces: - OSC 10/11 escape sequences (set/query) and OSC 110/111 (reset) - CLI action: zellij action set-pane-color --pane-id <id> --fg/--bg - Layout config: default_fg/default_bg properties on pane nodes - Plugin API: set_pane_color() SDK function and PaneInfo read-side Colors are applied at render time as a fallback when cells have no explicit foreground/background, without mutating stored grid data. Closes #4712 * refactor: address review feedback for pane color support - Extract adjust_styles_for_custom_bg_fg in output/mod.rs - Move color parsing (xparse_color) from tab into Grid - Move color serialization (ansi_code_to_color_string) into Grid - Pane trait now uses Option<String> for color getters/setters - Add colors to session serialization (dump-layout) - Add default_fg/default_bg to protobuf IPC schema to fix layout-in-session color loss - Update example layout with tab-bar and status-bar * fix stack overflow and ordering * rustfmt * update e2e snapshots --------- Co-authored-by: Karl Bunch <karl@karlbunch.com> Co-authored-by: Aram Drevekenin <aram@poor.dev>
Diffstat (limited to 'zellij-utils/src/plugin_api')
-rw-r--r--zellij-utils/src/plugin_api/action.rs7
-rw-r--r--zellij-utils/src/plugin_api/event.proto2
-rw-r--r--zellij-utils/src/plugin_api/event.rs8
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.proto8
-rw-r--r--zellij-utils/src/plugin_api/plugin_command.rs21
5 files changed, 44 insertions, 2 deletions
diff --git a/zellij-utils/src/plugin_api/action.rs b/zellij-utils/src/plugin_api/action.rs
index 5bb58db3..81db2c67 100644
--- a/zellij-utils/src/plugin_api/action.rs
+++ b/zellij-utils/src/plugin_api/action.rs
@@ -1836,7 +1836,8 @@ impl TryFrom<Action> for ProtobufAction {
| Action::SwitchSession { .. }
| Action::SaveSession
| Action::ListTabs { .. }
- | Action::CurrentTabInfo { .. } => Err("Unsupported action"),
+ | Action::CurrentTabInfo { .. }
+ | Action::SetPaneColor { .. } => Err("Unsupported action"),
}
}
}
@@ -2916,6 +2917,8 @@ impl TryFrom<ProtobufTiledPaneLayout> for TiledPaneLayout {
run_instructions_to_ignore,
hide_floating_panes: protobuf.hide_floating_panes,
pane_initial_contents: protobuf.pane_initial_contents,
+ default_fg: None,
+ default_bg: None,
})
}
}
@@ -2972,6 +2975,8 @@ impl TryFrom<ProtobufFloatingPaneLayout> for FloatingPaneLayout {
pane_initial_contents: protobuf.pane_initial_contents,
logical_position: protobuf.logical_position.map(|p| p as usize),
borderless: protobuf.borderless,
+ default_fg: None,
+ default_bg: None,
})
}
}
diff --git a/zellij-utils/src/plugin_api/event.proto b/zellij-utils/src/plugin_api/event.proto
index 5aa119a9..bbee50a3 100644
--- a/zellij-utils/src/plugin_api/event.proto
+++ b/zellij-utils/src/plugin_api/event.proto
@@ -406,6 +406,8 @@ message PaneInfo {
optional string plugin_url = 21;
bool is_selectable = 22;
repeated IndexInPaneGroup index_in_pane_group = 23;
+ optional string default_fg = 24;
+ optional string default_bg = 25;
}
message IndexInPaneGroup {
diff --git a/zellij-utils/src/plugin_api/event.rs b/zellij-utils/src/plugin_api/event.rs
index 3b135b6d..631d5069 100644
--- a/zellij-utils/src/plugin_api/event.rs
+++ b/zellij-utils/src/plugin_api/event.rs
@@ -1560,6 +1560,8 @@ impl TryFrom<ProtobufPaneInfo> for PaneInfo {
)
})
.collect(),
+ default_fg: protobuf_pane_info.default_fg,
+ default_bg: protobuf_pane_info.default_bg,
})
}
}
@@ -1603,6 +1605,8 @@ impl TryFrom<PaneInfo> for ProtobufPaneInfo {
index: index as u32,
})
.collect(),
+ default_fg: pane_info.default_fg,
+ default_bg: pane_info.default_bg,
})
}
}
@@ -2511,6 +2515,8 @@ fn serialize_session_update_event_with_non_default_values() {
plugin_url: None,
is_selectable: true,
index_in_pane_group: index_in_pane_group_1,
+ default_fg: None,
+ default_bg: None,
},
PaneInfo {
id: 1,
@@ -2536,6 +2542,8 @@ fn serialize_session_update_event_with_non_default_values() {
plugin_url: Some("i_am_a_fake_plugin".to_owned()),
is_selectable: true,
index_in_pane_group: index_in_pane_group_2,
+ default_fg: None,
+ default_bg: None,
},
];
panes.insert(0, panes_list);
diff --git a/zellij-utils/src/plugin_api/plugin_command.proto b/zellij-utils/src/plugin_api/plugin_command.proto
index 7ba3aabe..53e9d729 100644
--- a/zellij-utils/src/plugin_api/plugin_command.proto
+++ b/zellij-utils/src/plugin_api/plugin_command.proto
@@ -198,6 +198,7 @@ enum CommandName {
OpenEditPaneInPlaceOfPaneId = 203;
HideFloatingPanes = 204;
ShowFloatingPanes = 205;
+ SetPaneColor = 206;
}
message PluginCommand {
@@ -345,6 +346,7 @@ message PluginCommand {
OpenEditPaneInPlaceOfPaneIdPayload open_edit_pane_in_place_of_pane_id_payload = 154;
HideFloatingPanesPayload hide_floating_panes_payload = 155;
ShowFloatingPanesPayload show_floating_panes_payload = 156;
+ SetPaneColorPayload set_pane_color_payload = 157;
}
}
@@ -1212,3 +1214,9 @@ message HideFloatingPanesResponse {
string error = 2;
}
}
+
+message SetPaneColorPayload {
+ PaneId pane_id = 1;
+ optional string fg = 2;
+ optional string bg = 3;
+}
diff --git a/zellij-utils/src/plugin_api/plugin_command.rs b/zellij-utils/src/plugin_api/plugin_command.rs
index c3741591..abd9a994 100644
--- a/zellij-utils/src/plugin_api/plugin_command.rs
+++ b/zellij-utils/src/plugin_api/plugin_command.rs
@@ -102,7 +102,7 @@ pub use super::generated_api::api::{
SaveLayoutPayload, SaveLayoutResponse as ProtobufSaveLayoutResponse, SaveSessionPayload,
SaveSessionResponse as ProtobufSaveSessionResponse, ScrollDownInPaneIdPayload,
ScrollToBottomInPaneIdPayload, ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload,
- SetFloatingPanePinnedPayload, SetPaneBorderlessPayload,
+ SetFloatingPanePinnedPayload, SetPaneBorderlessPayload, SetPaneColorPayload,
SetSelfMouseSelectionSupportPayload, SetTimeoutPayload, ShowCursorPayload,
ShowFloatingPanesPayload as ProtobufShowFloatingPanesPayload,
ShowFloatingPanesResponse as ProtobufShowFloatingPanesResponse, ShowPaneWithIdPayload,
@@ -2423,6 +2423,17 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
None => Ok(PluginCommand::ShowFloatingPanes { tab_id: None }),
_ => Err("Mismatched payload for ShowFloatingPanes"),
},
+ Some(CommandName::SetPaneColor) => match protobuf_plugin_command.payload {
+ Some(Payload::SetPaneColorPayload(payload)) => match payload.pane_id {
+ Some(pane_id) => Ok(PluginCommand::SetPaneColor(
+ pane_id.try_into()?,
+ payload.fg,
+ payload.bg,
+ )),
+ None => Err("Malformed SetPaneColor payload"),
+ },
+ _ => Err("Mismatched payload for SetPaneColor"),
+ },
None => Err("Unrecognized plugin command"),
}
}
@@ -3975,6 +3986,14 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
},
)),
}),
+ PluginCommand::SetPaneColor(pane_id, fg, bg) => Ok(ProtobufPluginCommand {
+ name: CommandName::SetPaneColor as i32,
+ payload: Some(Payload::SetPaneColorPayload(SetPaneColorPayload {
+ pane_id: Some(pane_id.try_into()?),
+ fg,
+ bg,
+ })),
+ }),
}
}
}