Editor tab bar settings (#7356)

Andrew Lygin and Mikayla created

This PR is another step to tabless editing (#6424, #4963). It adds
support for tab bar settings that allow the user to change its placement
or to hide completely.

Configuraton:

```json
"tab_bar": {
  "show": true
}
```

Placemnet options are "top", "bottom" and "no".

This PR intentionally doesn't affect tab bars of other panes (Terminal
for instance) to keep code changes small. I guess we'll do the rest in
separate PRs.

Release Notes:

- Added support for configuring the editor tab bar (part of #6424,
#4963).

---------

Co-authored-by: Mikayla <mikayla@zed.dev>

Change summary

assets/settings/default.json               |  2 
crates/terminal_view/src/terminal_panel.rs |  1 
crates/workspace/src/item.rs               |  2 
crates/workspace/src/pane.rs               | 14 ++++
crates/workspace/src/workspace_settings.rs |  5 +
docs/src/configuring-zed.md                | 76 ++++++++++++++++++++++++
6 files changed, 98 insertions(+), 2 deletions(-)

Detailed changes

assets/settings/default.json 🔗

@@ -316,6 +316,8 @@
   "autosave": "off",
   // Settings related to the editor's tab bar.
   "tab_bar": {
+    // Whether or not to show the tab bar in the editor
+    "show": true,
     // Whether or not to show the navigation history buttons.
     "show_nav_history_buttons": true
   },

crates/terminal_view/src/terminal_panel.rs 🔗

@@ -74,6 +74,7 @@ impl TerminalPanel {
             pane.set_can_split(false, cx);
             pane.set_can_navigate(false, cx);
             pane.display_nav_history_buttons(None);
+            pane.set_should_display_tab_bar(|_| true);
             pane.set_render_tab_bar_buttons(cx, move |pane, cx| {
                 h_flex()
                     .gap_2()

crates/workspace/src/item.rs 🔗

@@ -69,7 +69,7 @@ impl ClosePosition {
 pub struct ItemSettingsContent {
     /// Whether to show the Git file status on a tab item.
     ///
-    /// Default: true
+    /// Default: false
     git_status: Option<bool>,
     /// Position of the close button in a tab.
     ///

crates/workspace/src/pane.rs 🔗

@@ -203,6 +203,7 @@ pub struct Pane {
     custom_drop_handle:
         Option<Arc<dyn Fn(&mut Pane, &dyn Any, &mut ViewContext<Pane>) -> ControlFlow<(), ()>>>,
     can_split: bool,
+    should_display_tab_bar: Rc<dyn Fn(&ViewContext<Pane>) -> bool>,
     render_tab_bar_buttons: Rc<dyn Fn(&mut Pane, &mut ViewContext<Pane>) -> AnyElement>,
     _subscriptions: Vec<Subscription>,
     tab_bar_scroll_handle: ScrollHandle,
@@ -312,6 +313,7 @@ impl Pane {
             can_drop_predicate,
             custom_drop_handle: None,
             can_split: true,
+            should_display_tab_bar: Rc::new(|cx| TabBarSettings::get_global(cx).show),
             render_tab_bar_buttons: Rc::new(move |pane, cx| {
                 // Ideally we would return a vec of elements here to pass directly to the [TabBar]'s
                 // `end_slot`, but due to needing a view here that isn't possible.
@@ -468,6 +470,13 @@ impl Pane {
         &self.activation_history
     }
 
+    pub fn set_should_display_tab_bar<F>(&mut self, should_display_tab_bar: F)
+    where
+        F: 'static + Fn(&ViewContext<Pane>) -> bool,
+    {
+        self.should_display_tab_bar = Rc::new(should_display_tab_bar);
+    }
+
     pub fn set_can_split(&mut self, can_split: bool, cx: &mut ViewContext<Self>) {
         self.can_split = can_split;
         cx.notify();
@@ -1963,6 +1972,9 @@ impl Render for Pane {
             key_context.add("EmptyPane");
         }
 
+        let should_display_tab_bar = self.should_display_tab_bar.clone();
+        let display_tab_bar = should_display_tab_bar(cx);
+
         v_flex()
             .key_context(key_context)
             .track_focus(&self.focus_handle)
@@ -2061,7 +2073,7 @@ impl Render for Pane {
                     }
                 }),
             )
-            .when(self.active_item().is_some(), |pane| {
+            .when(self.active_item().is_some() && display_tab_bar, |pane| {
                 pane.child(self.render_tab_bar(cx))
             })
             .child({

crates/workspace/src/workspace_settings.rs 🔗

@@ -60,11 +60,16 @@ pub struct WorkspaceSettingsContent {
 
 #[derive(Deserialize)]
 pub struct TabBarSettings {
+    pub show: bool,
     pub show_nav_history_buttons: bool,
 }
 
 #[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
 pub struct TabBarSettingsContent {
+    /// Whether or not to show the tab bar in the editor.
+    ///
+    /// Default: top
+    pub show: Option<bool>,
     /// Whether or not to show the navigation history buttons in the tab bar.
     ///
     /// Default: true

docs/src/configuring-zed.md 🔗

@@ -315,6 +315,82 @@ List of `string` values
 
 `boolean` values
 
+## Editor Tab Bar
+
+- Description: Settings related to the editor's tab bar.
+- Settings: `tab_bar`
+- Default:
+
+```json
+"tab_bar": {
+  "show": true,
+  "show_nav_history_buttons": true
+}
+```
+
+### Show
+
+- Description: Whether or not to show the tab bar in the editor.
+- Setting: `show`
+- Default: `true`
+
+**Options**
+
+`boolean` values
+
+### Navigation History Buttons
+
+- Description: Whether or not to show the navigation history buttons.
+- Setting: `show_nav_history_buttons`
+- Default: `true`
+
+**Options**
+
+`boolean` values
+
+## Editor Tabs
+
+- Description: Configuration for the editor tabs.
+- Setting: `tabs`
+- Default:
+
+```json
+"tabs": {
+  "close_position": "right",
+  "git_status": false
+},
+```
+
+### Close Position
+
+- Description: Where to display close button within a tab.
+- Setting: `close_position`
+- Default: `right`
+
+**Options**
+
+1. Display the close button on the right:
+
+```json
+{
+  "close_position": "right"
+}
+```
+
+2. Display the close button on the left:
+
+```json
+{
+  "close_position": "left"
+}
+```
+
+### Git Status
+
+- Description: Whether or not to show Git file status in tab.
+- Setting: `git_status`
+- Default: `false`
+
 ## Editor Toolbar
 
 - Description: Whether or not to show various elements in the editor toolbar.