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/kdl | |
| 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/kdl')
| -rw-r--r-- | zellij-utils/src/kdl/kdl_layout_parser.rs | 16 | ||||
| -rw-r--r-- | zellij-utils/src/kdl/mod.rs | 6 |
2 files changed, 22 insertions, 0 deletions
diff --git a/zellij-utils/src/kdl/kdl_layout_parser.rs b/zellij-utils/src/kdl/kdl_layout_parser.rs index 6e1e2c76..ff7fcfe3 100644 --- a/zellij-utils/src/kdl/kdl_layout_parser.rs +++ b/zellij-utils/src/kdl/kdl_layout_parser.rs @@ -106,6 +106,8 @@ impl<'a> KdlLayoutParser<'a> { || property_name == "expanded" || property_name == "exclude_from_sync" || property_name == "contents_file" + || property_name == "default_fg" + || property_name == "default_bg" } fn is_a_valid_floating_pane_property(&self, property_name: &str) -> bool { property_name == "borderless" @@ -124,6 +126,8 @@ impl<'a> KdlLayoutParser<'a> { || property_name == "height" || property_name == "pinned" || property_name == "contents_file" + || property_name == "default_fg" + || property_name == "default_bg" } fn is_a_valid_tab_property(&self, property_name: &str) -> bool { property_name == "focus" @@ -563,6 +567,10 @@ impl<'a> KdlLayoutParser<'a> { kdl_node.span().len(), )); } + let default_fg = kdl_get_string_property_or_child_value_with_error!(kdl_node, "default_fg") + .map(|s| s.to_string()); + let default_bg = kdl_get_string_property_or_child_value_with_error!(kdl_node, "default_bg") + .map(|s| s.to_string()); self.assert_no_mixed_children_and_properties(kdl_node)?; let pane_initial_contents = contents_file.and_then(|contents_file| { self.file_name @@ -585,6 +593,8 @@ impl<'a> KdlLayoutParser<'a> { children_are_stacked, is_expanded_in_stack, pane_initial_contents, + default_fg, + default_bg, ..Default::default() }) } @@ -605,6 +615,10 @@ impl<'a> KdlLayoutParser<'a> { .map(|name| name.to_string()); let contents_file = kdl_get_string_property_or_child_value_with_error!(kdl_node, "contents_file"); + let default_fg = kdl_get_string_property_or_child_value_with_error!(kdl_node, "default_fg") + .map(|s| s.to_string()); + let default_bg = kdl_get_string_property_or_child_value_with_error!(kdl_node, "default_bg") + .map(|s| s.to_string()); self.assert_no_mixed_children_and_properties(kdl_node)?; let pane_initial_contents = contents_file.and_then(|contents_file| { self.file_name @@ -625,6 +639,8 @@ impl<'a> KdlLayoutParser<'a> { pinned, borderless, pane_initial_contents, + default_fg, + default_bg, ..Default::default() }) } diff --git a/zellij-utils/src/kdl/mod.rs b/zellij-utils/src/kdl/mod.rs index 12eadff6..9fcb3113 100644 --- a/zellij-utils/src/kdl/mod.rs +++ b/zellij-utils/src/kdl/mod.rs @@ -5927,6 +5927,8 @@ impl PaneInfo { plugin_url, is_selectable, index_in_pane_group: Default::default(), // we don't serialize this + default_fg: None, + default_bg: None, }; Ok((tab_position, pane_info)) } @@ -6075,6 +6077,8 @@ fn serialize_and_deserialize_session_info_with_data() { plugin_url: None, is_selectable: true, index_in_pane_group: Default::default(), // we don't serialize this + default_fg: None, + default_bg: None, }, PaneInfo { id: 1, @@ -6100,6 +6104,8 @@ fn serialize_and_deserialize_session_info_with_data() { plugin_url: Some("i_am_a_fake_plugin".to_owned()), is_selectable: true, index_in_pane_group: Default::default(), // we don't serialize this + default_fg: None, + default_bg: None, }, ]; let mut panes = HashMap::new(); |
