diff options
| author | Karl Bunch <karlbunch@users.noreply.github.com> | 2026-03-04 08:26:26 -0500 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-04 14:26:26 +0100 |
| commit | f77cdec298576164f34baf0456e4b986bde269e6 (patch) | |
| tree | af9fb93cfc6edf465378952c0aff38d48820e142 /zellij-utils/src/plugin_api | |
| parent | docs(changelog): native Windows support (!!) (diff) | |
| download | sl0ppij-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.rs | 7 | ||||
| -rw-r--r-- | zellij-utils/src/plugin_api/event.proto | 2 | ||||
| -rw-r--r-- | zellij-utils/src/plugin_api/event.rs | 8 | ||||
| -rw-r--r-- | zellij-utils/src/plugin_api/plugin_command.proto | 8 | ||||
| -rw-r--r-- | zellij-utils/src/plugin_api/plugin_command.rs | 21 |
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, + })), + }), } } } |
