Add option to set split direction (#16345)

Jeroen van Baarsen created

This adds an option to set the split direction for both the horizontal
splits, and the vertical splits.

A couple of things to look for when reviewing:

* The `derive` keywords on the Enums were copy pasted, no clue what they
should be
* Tried adding tests for this, but got stuck.

Co-authored with @Tobbe

Fixes: https://github.com/zed-industries/zed/issues/11342

Change summary

assets/settings/default.json               |  4 ++++
crates/vim/src/command.rs                  |  4 ++--
crates/workspace/src/pane.rs               | 24 +++++++++++++++++++++++-
crates/workspace/src/workspace_settings.rs | 24 ++++++++++++++++++++++++
4 files changed, 53 insertions(+), 3 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -69,6 +69,10 @@
   // The factor to grow the active pane by. Defaults to 1.0
   // which gives the same size as all other panes.
   "active_pane_magnification": 1.0,
+  // The direction that you want to split panes horizontally. Defaults to "up"
+  "pane_split_direction_horizontal": "up",
+  // The direction that you want to split panes horizontally. Defaults to "left"
+  "pane_split_direction_vertical": "left",
   // Centered layout related settings.
   "centered_layout": {
     // The relative width of the left padding of the central pane from the

crates/vim/src/command.rs 🔗

@@ -529,8 +529,8 @@ fn generate_commands(_: &AppContext) -> Vec<VimCommand> {
             save_intent: Some(SaveIntent::Overwrite),
         }),
         VimCommand::new(("cq", "uit"), zed_actions::Quit),
-        VimCommand::new(("sp", "lit"), workspace::SplitUp),
-        VimCommand::new(("vs", "plit"), workspace::SplitLeft),
+        VimCommand::new(("sp", "lit"), workspace::SplitHorizontal),
+        VimCommand::new(("vs", "plit"), workspace::SplitVertical),
         VimCommand::new(
             ("bd", "elete"),
             workspace::CloseActiveItem {

crates/workspace/src/pane.rs 🔗

@@ -5,7 +5,10 @@ use crate::{
     },
     notifications::NotifyResultExt,
     toolbar::Toolbar,
-    workspace_settings::{AutosaveSetting, TabBarSettings, WorkspaceSettings},
+    workspace_settings::{
+        AutosaveSetting, PaneSplitDirectionHorizontal, PaneSplitDirectionVertical, TabBarSettings,
+        WorkspaceSettings,
+    },
     CloseWindow, CopyPath, CopyRelativePath, NewFile, NewTerminal, OpenInTerminal, OpenTerminal,
     OpenVisible, SplitDirection, ToggleFileFinder, ToggleProjectSymbols, ToggleZoom, Workspace,
 };
@@ -152,6 +155,8 @@ actions!(
         SplitUp,
         SplitRight,
         SplitDown,
+        SplitHorizontal,
+        SplitVertical,
         TogglePreviewTab,
     ]
 );
@@ -2254,6 +2259,23 @@ impl Render for Pane {
             }))
             .on_action(cx.listener(|pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx)))
             .on_action(cx.listener(|pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)))
+            .on_action(cx.listener(|pane, _: &SplitHorizontal, cx| {
+                let split_direction =
+                    WorkspaceSettings::get(None, cx).pane_split_direction_horizontal;
+                match split_direction {
+                    PaneSplitDirectionHorizontal::Down => pane.split(SplitDirection::Down, cx),
+                    _ => pane.split(SplitDirection::Up, cx),
+                }
+            }))
+            .on_action(cx.listener(|pane, _: &SplitVertical, cx| {
+                let split_direction =
+                    WorkspaceSettings::get(None, cx).pane_split_direction_vertical;
+
+                match split_direction {
+                    PaneSplitDirectionVertical::Right => pane.split(SplitDirection::Right, cx),
+                    _ => pane.split(SplitDirection::Left, cx),
+                }
+            }))
             .on_action(
                 cx.listener(|pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx)),
             )

crates/workspace/src/workspace_settings.rs 🔗

@@ -8,6 +8,8 @@ use settings::{Settings, SettingsSources};
 #[derive(Deserialize)]
 pub struct WorkspaceSettings {
     pub active_pane_magnification: f32,
+    pub pane_split_direction_horizontal: PaneSplitDirectionHorizontal,
+    pub pane_split_direction_vertical: PaneSplitDirectionVertical,
     pub centered_layout: CenteredLayoutSettings,
     pub confirm_quit: bool,
     pub show_call_status_icon: bool,
@@ -61,6 +63,14 @@ pub struct WorkspaceSettingsContent {
     ///
     /// Default: `1.0`
     pub active_pane_magnification: Option<f32>,
+    // Direction to split horizontally.
+    //
+    // Default: "up"
+    pub pane_split_direction_horizontal: Option<PaneSplitDirectionHorizontal>,
+    // Direction to split vertically.
+    //
+    // Default: "left"
+    pub pane_split_direction_vertical: Option<PaneSplitDirectionVertical>,
     // Centered layout related settings.
     pub centered_layout: Option<CenteredLayoutSettings>,
     /// Whether or not to prompt the user to confirm before closing the application.
@@ -131,6 +141,20 @@ pub enum AutosaveSetting {
     OnWindowChange,
 }
 
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum PaneSplitDirectionHorizontal {
+    Up,
+    Down,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
+#[serde(rename_all = "snake_case")]
+pub enum PaneSplitDirectionVertical {
+    Left,
+    Right,
+}
+
 #[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema)]
 #[serde(rename_all = "snake_case")]
 pub struct CenteredLayoutSettings {