diff options
| author | user <user@clank> | 2026-08-08 21:06:40 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-08-12 19:34:19 +0200 |
| commit | 0ba57cf6e9bfec08c198fc8eb5fa219b0c8c96ba (patch) | |
| tree | 28bcfea151d04f0fa7a8294f802df686c6f845e7 | |
| parent | sl0p: uniform pane gap + aspect-corrected horizontal gap (diff) | |
| download | sl0ppi-0ba57cf6e9bfec08c198fc8eb5fa219b0c8c96ba.tar.gz sl0ppi-0ba57cf6e9bfec08c198fc8eb5fa219b0c8c96ba.tar.xz sl0ppi-0ba57cf6e9bfec08c198fc8eb5fa219b0c8c96ba.zip | |
sl0p: CSS-style 1/2/4-value shorthand for inner padding
`padding` now accepts:
padding 1 -> all four sides
padding 1 2 -> up/down = 1, left/right = 2
padding 1 2 3 4 -> up=1 down=2 left=3 right=4
NOTE the 4-value order is UP DOWN LEFT RIGHT as requested, deliberately NOT
CSS's clockwise top-right-bottom-left. Documented on PanePadding and at the
parser, since the similarity to CSS invites the wrong assumption.
3 or 5 values are rejected with a message naming the accepted forms, rather
than being silently reinterpreted. Negative values clamp to 0.
ASPECT: only the 1-value form is aspect-corrected (left/right multiplied by
gap_aspect) so `padding 1` looks square on a non-square cell grid. The 2- and
4-value forms are literal: specifying axes separately means the caller is
already controlling horizontal size, and silently doubling it would surprise.
Style now carries a PanePadding {top,bottom,left,right} instead of an x/y
pair, which also collapses the reconfigure plumbing back to a single field
rather than growing another parameter per side.
to_kdl always emits the explicit 4-value form: emitting the 1-value form
would re-apply gap_aspect on the next read and silently double the padding
on every config round-trip.
Baselines held: zellij-utils 435/5, zellij-server 1421/30.
| -rw-r--r-- | sl0ppij/zellij-client/src/web_client/server_listener.rs | 3 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/lib.rs | 9 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/panes/floating_panes/mod.rs | 8 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/panes/plugin_pane.rs | 14 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/panes/terminal_pane.rs | 14 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/panes/tiled_panes/mod.rs | 8 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/screen.rs | 16 | ||||
| -rw-r--r-- | sl0ppij/zellij-server/src/tab/mod.rs | 15 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/data.rs | 34 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/input/config.rs | 45 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/input/theme.rs | 12 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/kdl/mod.rs | 64 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/plugin_api/event.rs | 3 | ||||
| -rw-r--r-- | sl0ppij/zellij-utils/src/plugin_api/style.rs | 3 |
14 files changed, 171 insertions, 77 deletions
diff --git a/sl0ppij/zellij-client/src/web_client/server_listener.rs b/sl0ppij/zellij-client/src/web_client/server_listener.rs index 8f80f4a..398c973 100644 --- a/sl0ppij/zellij-client/src/web_client/server_listener.rs +++ b/sl0ppij/zellij-client/src/web_client/server_listener.rs @@ -86,8 +86,7 @@ pub fn zellij_server_listener( pane_title_alignment: config.ui.pane_frames.title_alignment, pane_gap_x: config.ui.pane_frames.resolved_gap().0, pane_gap_y: config.ui.pane_frames.resolved_gap().1, - pane_padding_x: config.ui.pane_frames.resolved_padding().0, - pane_padding_y: config.ui.pane_frames.resolved_padding().1, + pane_padding: config.ui.pane_frames.resolved_padding(), }, }; diff --git a/sl0ppij/zellij-server/src/lib.rs b/sl0ppij/zellij-server/src/lib.rs index a80bda2..fe5b3b1 100644 --- a/sl0ppij/zellij-server/src/lib.rs +++ b/sl0ppij/zellij-server/src/lib.rs @@ -462,8 +462,7 @@ impl SessionMetaData { pane_title_alignment: new_config.ui.pane_frames.title_alignment, pane_gap_x: new_config.ui.pane_frames.resolved_gap().0, pane_gap_y: new_config.ui.pane_frames.resolved_gap().1, - pane_padding_x: new_config.ui.pane_frames.resolved_padding().0, - pane_padding_y: new_config.ui.pane_frames.resolved_padding().1, + pane_padding: new_config.ui.pane_frames.resolved_padding(), stacked_resize: new_config.options.stacked_resize.unwrap_or(true), stacked_pane_list: new_config.options.stacked_pane_list.unwrap_or(true), default_editor: new_config.options.scrollback_editor.clone(), @@ -1008,8 +1007,7 @@ pub fn start_server_impl( pane_title_alignment: config.ui.pane_frames.title_alignment, pane_gap_x: config.ui.pane_frames.resolved_gap().0, pane_gap_y: config.ui.pane_frames.resolved_gap().1, - pane_padding_x: config.ui.pane_frames.resolved_padding().0, - pane_padding_y: config.ui.pane_frames.resolved_padding().1, + pane_padding: config.ui.pane_frames.resolved_padding(), }, }; @@ -1196,8 +1194,7 @@ pub fn start_server_impl( pane_title_alignment: config.ui.pane_frames.title_alignment, pane_gap_x: config.ui.pane_frames.resolved_gap().0, pane_gap_y: config.ui.pane_frames.resolved_gap().1, - pane_padding_x: config.ui.pane_frames.resolved_padding().0, - pane_padding_y: config.ui.pane_frames.resolved_padding().1, + pane_padding: config.ui.pane_frames.resolved_padding(), }, }; diff --git a/sl0ppij/zellij-server/src/panes/floating_panes/mod.rs b/sl0ppij/zellij-server/src/panes/floating_panes/mod.rs index 8252612..3e5e80f 100644 --- a/sl0ppij/zellij-server/src/panes/floating_panes/mod.rs +++ b/sl0ppij/zellij-server/src/panes/floating_panes/mod.rs @@ -1725,16 +1725,14 @@ impl FloatingPanes { title_alignment: zellij_utils::data::PaneTitleAlignment, gap_x: usize, gap_y: usize, - padding_x: usize, - padding_y: usize, + padding: zellij_utils::data::PanePadding, ) { self.style.pane_title_alignment = title_alignment; self.style.pane_gap_x = gap_x; self.style.pane_gap_y = gap_y; - self.style.pane_padding_x = padding_x; - self.style.pane_padding_y = padding_y; + self.style.pane_padding = padding; for pane in self.panes.values_mut() { - pane.update_frame_layout(title_alignment, gap_x, gap_y, padding_x, padding_y); + pane.update_frame_layout(title_alignment, gap_x, gap_y, padding); } // Unlike the tiled panes, `set_pane_frame_style` only re-runs the // content-offset sweep for a fullscreen floating pane, so gap/padding diff --git a/sl0ppij/zellij-server/src/panes/plugin_pane.rs b/sl0ppij/zellij-server/src/panes/plugin_pane.rs index 4f4e138..6c1e870 100644 --- a/sl0ppij/zellij-server/src/panes/plugin_pane.rs +++ b/sl0ppij/zellij-server/src/panes/plugin_pane.rs @@ -773,10 +773,10 @@ impl Pane for PluginPane { Offset::default() } else { Offset { - top: self.gap_offset.top.saturating_add(self.style.pane_padding_y), - bottom: self.gap_offset.bottom.saturating_add(self.style.pane_padding_y), - left: self.gap_offset.left.saturating_add(self.style.pane_padding_x), - right: self.gap_offset.right.saturating_add(self.style.pane_padding_x), + top: self.gap_offset.top.saturating_add(self.style.pane_padding.top), + bottom: self.gap_offset.bottom.saturating_add(self.style.pane_padding.bottom), + left: self.gap_offset.left.saturating_add(self.style.pane_padding.left), + right: self.gap_offset.right.saturating_add(self.style.pane_padding.right), } }; self.content_offset = @@ -915,14 +915,12 @@ impl Pane for PluginPane { title_alignment: zellij_utils::data::PaneTitleAlignment, gap_x: usize, gap_y: usize, - padding_x: usize, - padding_y: usize, + padding: zellij_utils::data::PanePadding, ) { self.style.pane_title_alignment = title_alignment; self.style.pane_gap_x = gap_x; self.style.pane_gap_y = gap_y; - self.style.pane_padding_x = padding_x; - self.style.pane_padding_y = padding_y; + self.style.pane_padding = padding; self.frame.clear(); } fn set_should_be_suppressed(&mut self, should_be_suppressed: bool) { diff --git a/sl0ppij/zellij-server/src/panes/terminal_pane.rs b/sl0ppij/zellij-server/src/panes/terminal_pane.rs index 8c44d7b..7fb7817 100644 --- a/sl0ppij/zellij-server/src/panes/terminal_pane.rs +++ b/sl0ppij/zellij-server/src/panes/terminal_pane.rs @@ -991,10 +991,10 @@ impl Pane for TerminalPane { Offset::default() } else { Offset { - top: self.gap_offset.top.saturating_add(self.style.pane_padding_y), - bottom: self.gap_offset.bottom.saturating_add(self.style.pane_padding_y), - left: self.gap_offset.left.saturating_add(self.style.pane_padding_x), - right: self.gap_offset.right.saturating_add(self.style.pane_padding_x), + top: self.gap_offset.top.saturating_add(self.style.pane_padding.top), + bottom: self.gap_offset.bottom.saturating_add(self.style.pane_padding.bottom), + left: self.gap_offset.left.saturating_add(self.style.pane_padding.left), + right: self.gap_offset.right.saturating_add(self.style.pane_padding.right), } }; self.content_offset = @@ -1269,14 +1269,12 @@ impl Pane for TerminalPane { title_alignment: zellij_utils::data::PaneTitleAlignment, gap_x: usize, gap_y: usize, - padding_x: usize, - padding_y: usize, + padding: zellij_utils::data::PanePadding, ) { self.style.pane_title_alignment = title_alignment; self.style.pane_gap_x = gap_x; self.style.pane_gap_y = gap_y; - self.style.pane_padding_x = padding_x; - self.style.pane_padding_y = padding_y; + self.style.pane_padding = padding; self.frame.clear(); } fn drain_fake_cursors(&mut self) -> Option<HashSet<(usize, usize)>> { diff --git a/sl0ppij/zellij-server/src/panes/tiled_panes/mod.rs b/sl0ppij/zellij-server/src/panes/tiled_panes/mod.rs index 835c8e7..4d8f0a4 100644 --- a/sl0ppij/zellij-server/src/panes/tiled_panes/mod.rs +++ b/sl0ppij/zellij-server/src/panes/tiled_panes/mod.rs @@ -3156,16 +3156,14 @@ impl TiledPanes { title_alignment: zellij_utils::data::PaneTitleAlignment, gap_x: usize, gap_y: usize, - padding_x: usize, - padding_y: usize, + padding: zellij_utils::data::PanePadding, ) { self.style.pane_title_alignment = title_alignment; self.style.pane_gap_x = gap_x; self.style.pane_gap_y = gap_y; - self.style.pane_padding_x = padding_x; - self.style.pane_padding_y = padding_y; + self.style.pane_padding = padding; for pane in self.panes.values_mut() { - pane.update_frame_layout(title_alignment, gap_x, gap_y, padding_x, padding_y); + pane.update_frame_layout(title_alignment, gap_x, gap_y, padding); } } pub fn stack_panes( diff --git a/sl0ppij/zellij-server/src/screen.rs b/sl0ppij/zellij-server/src/screen.rs index c3c06ca..438fee2 100644 --- a/sl0ppij/zellij-server/src/screen.rs +++ b/sl0ppij/zellij-server/src/screen.rs @@ -43,7 +43,7 @@ use zellij_utils::data::{ CommandOrPlugin, Direction, EventType, FloatingPaneCoordinates, GetFocusedPaneInfoResponse, HostTerminalThemeMode, KeyWithModifier, LayoutInfo, LayoutWithError, ListPanesResponse, ListTabsResponse, NewPanePlacement, PaneContents, PaneInfo, PaneListEntry, PaneManifest, - PaneRenderReport, PaneScrollbackResponse, PaneTitleAlignment, PluginPermission, + PaneRenderReport, PanePadding, PaneScrollbackResponse, PaneTitleAlignment, PluginPermission, RegexHighlight, Resize, ResizeStrategy, SessionInfo, Styling, TabInfo, ThemeHue, WebSharing, }; @@ -779,8 +779,7 @@ pub enum ScreenInstruction { pane_title_alignment: PaneTitleAlignment, pane_gap_x: usize, pane_gap_y: usize, - pane_padding_x: usize, - pane_padding_y: usize, + pane_padding: PanePadding, stacked_resize: bool, stacked_pane_list: bool, default_editor: Option<PathBuf>, @@ -6270,8 +6269,7 @@ impl Screen { pane_title_alignment: PaneTitleAlignment, pane_gap_x: usize, pane_gap_y: usize, - pane_padding_x: usize, - pane_padding_y: usize, + pane_padding: PanePadding, stacked_resize: bool, stacked_pane_list: bool, default_editor: Option<PathBuf>, @@ -6331,7 +6329,7 @@ impl Screen { tab.update_copy_options(&self.copy_options); // must precede set_pane_frames: gap/padding are baked into // content_offset by the sweep that set_pane_frames triggers - tab.update_frame_layout(pane_title_alignment, pane_gap_x, pane_gap_y, pane_padding_x, pane_padding_y); + tab.update_frame_layout(pane_title_alignment, pane_gap_x, pane_gap_y, pane_padding); tab.set_pane_frames(pane_frame_style); tab.update_arrow_fonts(should_support_arrow_fonts); tab.update_advanced_mouse_actions(advanced_mouse_actions); @@ -10850,8 +10848,7 @@ pub(crate) fn screen_thread_main( pane_title_alignment, pane_gap_x, pane_gap_y, - pane_padding_x, - pane_padding_y, + pane_padding, stacked_resize, stacked_pane_list, default_editor, @@ -10882,8 +10879,7 @@ pub(crate) fn screen_thread_main( pane_title_alignment, pane_gap_x, pane_gap_y, - pane_padding_x, - pane_padding_y, + pane_padding, stacked_resize, stacked_pane_list, default_editor, diff --git a/sl0ppij/zellij-server/src/tab/mod.rs b/sl0ppij/zellij-server/src/tab/mod.rs index c9047d6..ec08842 100644 --- a/sl0ppij/zellij-server/src/tab/mod.rs +++ b/sl0ppij/zellij-server/src/tab/mod.rs @@ -751,8 +751,7 @@ pub trait Pane { _title_alignment: zellij_utils::data::PaneTitleAlignment, _gap_x: usize, _gap_y: usize, - _padding_x: usize, - _padding_y: usize, + _padding: zellij_utils::data::PanePadding, ) { } fn set_should_be_suppressed(&mut self, _should_be_suppressed: bool) {} @@ -7420,20 +7419,18 @@ impl Tab { title_alignment: zellij_utils::data::PaneTitleAlignment, gap_x: usize, gap_y: usize, - padding_x: usize, - padding_y: usize, + padding: zellij_utils::data::PanePadding, ) { self.style.pane_title_alignment = title_alignment; self.style.pane_gap_x = gap_x; self.style.pane_gap_y = gap_y; - self.style.pane_padding_x = padding_x; - self.style.pane_padding_y = padding_y; + self.style.pane_padding = padding; self.floating_panes - .update_pane_frame_layout(title_alignment, gap_x, gap_y, padding_x, padding_y); + .update_pane_frame_layout(title_alignment, gap_x, gap_y, padding); self.tiled_panes - .update_pane_frame_layout(title_alignment, gap_x, gap_y, padding_x, padding_y); + .update_pane_frame_layout(title_alignment, gap_x, gap_y, padding); for (_, pane) in self.suppressed_panes.values_mut() { - pane.update_frame_layout(title_alignment, gap_x, gap_y, padding_x, padding_y); + pane.update_frame_layout(title_alignment, gap_x, gap_y, padding); } } pub fn update_arrow_fonts(&mut self, should_support_arrow_fonts: bool) { diff --git a/sl0ppij/zellij-utils/src/data.rs b/sl0ppij/zellij-utils/src/data.rs index aa455b3..218db21 100644 --- a/sl0ppij/zellij-utils/src/data.rs +++ b/sl0ppij/zellij-utils/src/data.rs @@ -1413,6 +1413,32 @@ impl std::str::FromStr for PaneTitleAlignment { } } +/// Inner padding between a pane's frame and its content, per side. +/// +/// Configured CSS-shorthand style, but note the 4-value order is +/// **up down left right** (as requested), NOT the CSS clockwise +/// top-right-bottom-left. See the KDL parser for the accepted forms. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] +pub struct PanePadding { + pub top: usize, + pub bottom: usize, + pub left: usize, + pub right: usize, +} + +impl PanePadding { + pub fn uniform(n: usize) -> Self { + Self { top: n, bottom: n, left: n, right: n } + } + /// vertical (up/down) and horizontal (left/right) + pub fn axes(v: usize, h: usize) -> Self { + Self { top: v, bottom: v, left: h, right: h } + } + pub fn is_zero(&self) -> bool { + self.top == 0 && self.bottom == 0 && self.left == 0 && self.right == 0 + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize)] pub struct Style { pub colors: Styling, @@ -1436,11 +1462,9 @@ pub struct Style { /// an equal distance. See FrameConfig::gap_aspect. pub pane_gap_x: usize, pub pane_gap_y: usize, - /// INNER padding: cells between a pane's frame and its content. Purely - /// cosmetic breathing room inside the pane; does not move the frame. - /// Also aspect-corrected. - pub pane_padding_x: usize, - pub pane_padding_y: usize, + /// INNER padding: cells between a pane's frame and its content, per side. + /// Purely cosmetic breathing room inside the pane; does not move the frame. + pub pane_padding: PanePadding, } #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Deserialize, Serialize)] diff --git a/sl0ppij/zellij-utils/src/input/config.rs b/sl0ppij/zellij-utils/src/input/config.rs index be08adb..db86de5 100644 --- a/sl0ppij/zellij-utils/src/input/config.rs +++ b/sl0ppij/zellij-utils/src/input/config.rs @@ -1393,6 +1393,51 @@ mod config_test { } #[test] + fn pane_padding_accepts_1_2_and_4_value_shorthand() { + let parse = |padding: &str| { + let contents = format!( + "ui {{\n pane_frames {{\n padding {}\n }}\n}}", + padding + ); + Config::from_kdl(&contents, None).map(|c| c.ui.pane_frames.padding) + }; + + // 1 value: all sides, and left/right are aspect-corrected (x2 default) + // so that `padding 1` reads as square on a non-square cell grid + let p = parse("1").unwrap(); + assert_eq!((p.top, p.bottom), (1, 1), "1-value: vertical"); + assert_eq!((p.left, p.right), (2, 2), "1-value: horizontal is aspect-corrected"); + + // 2 values: up/down then left/right, taken LITERALLY (no aspect scaling - + // the caller is already controlling the horizontal size) + let p = parse("1 2").unwrap(); + assert_eq!((p.top, p.bottom, p.left, p.right), (1, 1, 2, 2), "2-value"); + + // 4 values: up down left right (NOT css clockwise order) + let p = parse("1 2 3 4").unwrap(); + assert_eq!((p.top, p.bottom, p.left, p.right), (1, 2, 3, 4), "4-value"); + + // 3 and 5 are rejected rather than silently reinterpreted + assert!(parse("1 2 3").is_err(), "3 values must be rejected"); + assert!(parse("1 2 3 4 5").is_err(), "5 values must be rejected"); + + // negatives clamp to 0 instead of wrapping to a huge usize + let p = parse("-4").unwrap(); + assert!(p.is_zero(), "negative padding must clamp to zero, got {:?}", p); + } + + #[test] + fn pane_padding_aspect_is_configurable() { + let contents = "ui {\n pane_frames {\n gap_aspect 1\n padding 1\n }\n}"; + let p = Config::from_kdl(contents, None).unwrap().ui.pane_frames.padding; + assert_eq!( + (p.top, p.left), + (1, 1), + "gap_aspect 1 disables horizontal correction" + ); + } + + #[test] fn can_define_ui_configuration_in_configfile() { let config_contents = r#" ui { diff --git a/sl0ppij/zellij-utils/src/input/theme.rs b/sl0ppij/zellij-utils/src/input/theme.rs index f4f2ec8..f1e0adf 100644 --- a/sl0ppij/zellij-utils/src/input/theme.rs +++ b/sl0ppij/zellij-utils/src/input/theme.rs @@ -30,8 +30,9 @@ pub struct FrameConfig { /// outer gap between panes, expressed in ROWS (see Style::pane_gap_y). /// Columns are scaled by `gap_aspect` so the gap looks square. pub gap: usize, - /// inner padding between a pane's frame and its content, in ROWS - pub padding: usize, + /// inner padding between a pane's frame and its content, per side. + /// Already resolved at parse time (including any aspect correction). + pub padding: crate::data::PanePadding, /// Columns per row. Terminal cells are roughly twice as tall as they are /// wide, so 1 row of gap needs ~2 columns to look like the same distance. /// 0 is treated as 1 (no correction). @@ -49,7 +50,7 @@ impl Default for FrameConfig { hide_session_name: false, title_alignment: Default::default(), gap: 0, - padding: 0, + padding: Default::default(), gap_aspect: 2, } } @@ -63,9 +64,8 @@ impl FrameConfig { pub fn resolved_gap(&self) -> (usize, usize) { (self.gap * self.aspect(), self.gap) } - /// (columns, rows) of inner padding - pub fn resolved_padding(&self) -> (usize, usize) { - (self.padding * self.aspect(), self.padding) + pub fn resolved_padding(&self) -> crate::data::PanePadding { + self.padding } } diff --git a/sl0ppij/zellij-utils/src/kdl/mod.rs b/sl0ppij/zellij-utils/src/kdl/mod.rs index c2500eb..b567019 100644 --- a/sl0ppij/zellij-utils/src/kdl/mod.rs +++ b/sl0ppij/zellij-utils/src/kdl/mod.rs @@ -3,7 +3,7 @@ use crate::data::{ BareKey, Direction, FloatingPaneCoordinates, InputMode, KeyWithModifier, LayoutInfo, LayoutMetadata, MultiplayerColors, Palette, PaletteColor, PaneId, PaneInfo, PaneManifest, PermissionType, Resize, SessionInfo, StyleDeclaration, Styling, TabInfo, WebSharing, - DEFAULT_STYLES, + DEFAULT_STYLES, PanePadding, }; use crate::envs::EnvironmentVariables; use crate::home::{find_default_config_dir, get_layout_dir}; @@ -5548,16 +5548,53 @@ impl UiConfig { }; // negative values are meaningless here and would wrap on `as usize`, // so clamp at 0 rather than silently producing a gigantic inset - let gap = kdl_children_property_first_arg_as_i64!(pane_frames, "gap") - .unwrap_or(0) - .max(0) as usize; - let padding = kdl_children_property_first_arg_as_i64!(pane_frames, "padding") - .unwrap_or(0) - .max(0) as usize; // default 2: terminal cells are ~2x taller than wide let gap_aspect = kdl_children_property_first_arg_as_i64!(pane_frames, "gap_aspect") .unwrap_or(2) .max(1) as usize; + let gap = kdl_children_property_first_arg_as_i64!(pane_frames, "gap") + .unwrap_or(0) + .max(0) as usize; + // `padding` accepts CSS-style shorthand, but note the 4-value order + // is UP DOWN LEFT RIGHT (not CSS's clockwise top-right-bottom-left): + // padding 1 -> all four sides + // padding 1 2 -> up/down = 1, left/right = 2 + // padding 1 2 3 4 -> up=1 down=2 left=3 right=4 + // + // ASPECT: the single-value form is aspect-corrected (left/right are + // multiplied by gap_aspect) so `padding 1` looks square. The 2- and + // 4-value forms are taken literally, because specifying axes + // separately means you are already controlling the horizontal size + // and silently doubling it would be surprising. + let padding = match pane_frames.children().and_then(|c| c.get("padding")) { + Some(node) => { + let values: Vec<i64> = kdl_entries_as_i64!(node).flatten().collect(); + let clamp = |v: i64| v.max(0) as usize; + match values.len() { + 0 => Default::default(), + 1 => PanePadding::axes(clamp(values[0]), clamp(values[0]) * gap_aspect), + 2 => PanePadding::axes(clamp(values[0]), clamp(values[1])), + 4 => PanePadding { + top: clamp(values[0]), + bottom: clamp(values[1]), + left: clamp(values[2]), + right: clamp(values[3]), + }, + n => { + return Err(ConfigError::new_kdl_error( + format!( + "padding takes 1, 2 or 4 values (got {}): \ +`padding <all>`, `padding <up/down> <left/right>`, or `padding <up> <down> <left> <right>`", + n + ), + node.span().offset(), + node.span().len(), + )) + }, + } + }, + None => Default::default(), + }; let frame_config = FrameConfig { rounded_corners, hide_session_name, @@ -5607,10 +5644,19 @@ impl UiConfig { gap.push(KdlValue::Base10(self.pane_frames.gap as i64)); frame_config_children.nodes_mut().push(gap); } - if self.pane_frames.padding > 0 { + if !self.pane_frames.padding.is_zero() { has_ui_config = true; + // always the explicit 4-value form: the 1-value form would be + // re-multiplied by gap_aspect when read back let mut padding = KdlNode::new("padding"); - padding.push(KdlValue::Base10(self.pane_frames.padding as i64)); + for v in [ + self.pane_frames.padding.top, + self.pane_frames.padding.bottom, + self.pane_frames.padding.left, + self.pane_frames.padding.right, + ] { + padding.push(KdlValue::Base10(v as i64)); + } frame_config_children.nodes_mut().push(padding); } if self.pane_frames.gap_aspect != 2 { diff --git a/sl0ppij/zellij-utils/src/plugin_api/event.rs b/sl0ppij/zellij-utils/src/plugin_api/event.rs index 87af043..7bb1c7a 100644 --- a/sl0ppij/zellij-utils/src/plugin_api/event.rs +++ b/sl0ppij/zellij-utils/src/plugin_api/event.rs @@ -2495,8 +2495,7 @@ fn serialize_mode_update_event_with_non_default_values() { pane_title_alignment: Default::default(), pane_gap_x: Default::default(), pane_gap_y: Default::default(), - pane_padding_x: Default::default(), - pane_padding_y: Default::default(), + pane_padding: Default::default(), }, capabilities: PluginCapabilities { arrow_fonts: false }, session_name: Some("my awesome test session".to_owned()), diff --git a/sl0ppij/zellij-utils/src/plugin_api/style.rs b/sl0ppij/zellij-utils/src/plugin_api/style.rs index 266ab7f..527f984 100644 --- a/sl0ppij/zellij-utils/src/plugin_api/style.rs +++ b/sl0ppij/zellij-utils/src/plugin_api/style.rs @@ -28,8 +28,7 @@ impl TryFrom<ProtobufStyle> for Style { pane_title_alignment: Default::default(), pane_gap_x: Default::default(), pane_gap_y: Default::default(), - pane_padding_x: Default::default(), - pane_padding_y: Default::default(), + pane_padding: Default::default(), }) } } |
