From 2213a45188d4a25624b4550043da355f4df1e411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?A=CC=82nderson=20Q?= Date: Wed, 10 Jun 2026 13:50:31 -0300 Subject: [PATCH] workspace: Add command to reset pane sizes Expose the existing recursive pane-size reset as a command-palette action, so it can be invoked outside of vim mode. The center pane grid's sizes can already be evened out by double-clicking a divider, or via vim::ResetPaneSizes (ctrl-w =) when vim mode is on, but there was no general action for it. The new workspace::ResetPaneSizes resets every axis in the center pane group to equal sizes, preserving the split layout. It reuses the same Workspace::reset_pane_sizes path the vim binding does. Docks and the terminal panel are left untouched (they have their own reset actions). --- crates/workspace/src/workspace.rs | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index 5edc156371161b..06bfa4ac8121a7 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -303,6 +303,8 @@ actions!( ResetActiveDockSize, /// Resets all open docks to their default sizes. ResetOpenDocksSize, + /// Resets all panes in the center group to equal sizes, preserving the split layout. + ResetPaneSizes, /// Reloads the application Reload, /// Formats and saves the current file, regardless of the format_on_save setting. @@ -7651,6 +7653,11 @@ impl Workspace { } }, )) + .on_action(cx.listener( + |workspace: &mut Workspace, _: &ResetPaneSizes, _window, cx| { + workspace.reset_pane_sizes(cx); + }, + )) .on_action(cx.listener( |workspace: &mut Workspace, act: &IncreaseActiveDockSize, window, cx| { adjust_active_dock_size_by_px( @@ -12771,6 +12778,74 @@ mod tests { }); } + #[gpui::test] + async fn test_reset_pane_sizes(cx: &mut gpui::TestAppContext) { + init_test(cx); + let fs = FakeFs::new(cx.executor()); + let project = Project::test(fs, [], cx).await; + let (multi_workspace, cx) = + cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx)); + let workspace = multi_workspace.read_with(cx, |mw, _| mw.workspace().clone()); + + // A horizontal split of three panes whose last child is itself a vertical + // split, so equalizing has to recurse into the nested axis. + workspace.update_in(cx, |workspace, window, cx| { + let item = cx.new(|cx| { + TestItem::new(cx).with_project_items(&[TestProjectItem::new(1, "1.txt", cx)]) + }); + workspace.add_item_to_active_pane(Box::new(item), None, true, window, cx); + workspace.split_pane( + workspace.active_pane().clone(), + SplitDirection::Right, + window, + cx, + ); + workspace.split_pane( + workspace.active_pane().clone(), + SplitDirection::Right, + window, + cx, + ); + workspace.split_pane( + workspace.active_pane().clone(), + SplitDirection::Down, + window, + cx, + ); + }); + + let nested_axis = |workspace: &Workspace| { + let Member::Axis(top) = &workspace.center.root else { + panic!("expected the center to be a split axis"); + }; + let nested = top + .members + .iter() + .find_map(|member| match member { + Member::Axis(axis) => Some(axis.clone()), + Member::Pane(_) => None, + }) + .expect("expected a nested split axis"); + (top.clone(), nested) + }; + + // Skew every axis away from uniform sizes. + workspace.update(cx, |workspace, _| { + let (top, nested) = nested_axis(workspace); + *top.flexes.lock() = vec![1.6, 0.7, 0.7]; + *nested.flexes.lock() = vec![1.3, 0.7]; + }); + + cx.run_until_parked(); + cx.dispatch_action(ResetPaneSizes); + + workspace.update(cx, |workspace, _| { + let (top, nested) = nested_axis(workspace); + assert_eq!(*top.flexes.lock(), vec![1.0; top.members.len()]); + assert_eq!(*nested.flexes.lock(), vec![1.0; nested.members.len()]); + }); + } + #[gpui::test] async fn test_toggle_docks_and_panels(cx: &mut gpui::TestAppContext) { init_test(cx);