pane: Disable the "Close..." controls depending on certain scenarios (#25037)

Danilo Leal created

Closes https://github.com/zed-industries/zed/issues/12471

- Disables "Close Others" if there's just one tab
- Disables "Close Left"/"Close Right" if the above is true or if there's
no tabs to the left/right side of the active tab

Release Notes:

- N/A

Change summary

crates/workspace/src/pane.rs | 108 ++++++++++++++++++++-----------------
1 file changed, 58 insertions(+), 50 deletions(-)

Detailed changes

crates/workspace/src/pane.rs 🔗

@@ -40,11 +40,11 @@ use std::{
 };
 use theme::ThemeSettings;
 use ui::{
-    prelude::*, right_click_menu, ButtonSize, Color, DecoratedIcon, IconButton, IconButtonShape,
-    IconDecoration, IconDecorationKind, IconName, IconSize, Indicator, Label, PopoverMenu,
-    PopoverMenuHandle, Tab, TabBar, TabPosition, Tooltip,
+    prelude::*, right_click_menu, ButtonSize, Color, ContextMenu, ContextMenuEntry,
+    ContextMenuItem, DecoratedIcon, IconButton, IconButtonShape, IconDecoration,
+    IconDecorationKind, IconName, IconSize, Indicator, Label, PopoverMenu, PopoverMenuHandle, Tab,
+    TabBar, TabPosition, Tooltip,
 };
-use ui::{v_flex, ContextMenu};
 use util::{debug_panic, maybe, truncate_and_remove_front, ResultExt};
 
 /// A selected entry in e.g. project panel.
@@ -2395,6 +2395,9 @@ impl Pane {
             }
         };
 
+        let total_items = self.items.len();
+        let has_items_to_left = ix > 0;
+        let has_items_to_right = ix < total_items - 1;
         let is_pinned = self.is_tab_pinned(ix);
         let pane = cx.entity().downgrade();
         let menu_context = item.item_focus_handle(cx);
@@ -2415,54 +2418,59 @@ impl Pane {
                                     .detach_and_log_err(cx);
                             }),
                         )
-                        .entry(
-                            "Close Others",
-                            Some(Box::new(CloseInactiveItems {
-                                save_intent: None,
-                                close_pinned: false,
-                            })),
-                            window.handler_for(&pane, move |pane, window, cx| {
-                                pane.close_items(window, cx, SaveIntent::Close, |id| id != item_id)
+                        .item(ContextMenuItem::Entry(
+                            ContextMenuEntry::new("Close Others")
+                                .action(Some(Box::new(CloseInactiveItems {
+                                    save_intent: None,
+                                    close_pinned: false,
+                                })))
+                                .disabled(total_items == 1)
+                                .handler(window.handler_for(&pane, move |pane, window, cx| {
+                                    pane.close_items(window, cx, SaveIntent::Close, |id| {
+                                        id != item_id
+                                    })
                                     .detach_and_log_err(cx);
-                            }),
-                        )
+                                })),
+                        ))
                         .separator()
-                        .entry(
-                            "Close Left",
-                            Some(Box::new(CloseItemsToTheLeft {
-                                close_pinned: false,
-                            })),
-                            window.handler_for(&pane, move |pane, window, cx| {
-                                pane.close_items_to_the_left_by_id(
-                                    item_id,
-                                    &CloseItemsToTheLeft {
-                                        close_pinned: false,
-                                    },
-                                    pane.get_non_closeable_item_ids(false),
-                                    window,
-                                    cx,
-                                )
-                                .detach_and_log_err(cx);
-                            }),
-                        )
-                        .entry(
-                            "Close Right",
-                            Some(Box::new(CloseItemsToTheRight {
-                                close_pinned: false,
-                            })),
-                            window.handler_for(&pane, move |pane, window, cx| {
-                                pane.close_items_to_the_right_by_id(
-                                    item_id,
-                                    &CloseItemsToTheRight {
-                                        close_pinned: false,
-                                    },
-                                    pane.get_non_closeable_item_ids(false),
-                                    window,
-                                    cx,
-                                )
-                                .detach_and_log_err(cx);
-                            }),
-                        )
+                        .item(ContextMenuItem::Entry(
+                            ContextMenuEntry::new("Close Left")
+                                .action(Some(Box::new(CloseItemsToTheLeft {
+                                    close_pinned: false,
+                                })))
+                                .disabled(!has_items_to_left)
+                                .handler(window.handler_for(&pane, move |pane, window, cx| {
+                                    pane.close_items_to_the_left_by_id(
+                                        item_id,
+                                        &CloseItemsToTheLeft {
+                                            close_pinned: false,
+                                        },
+                                        pane.get_non_closeable_item_ids(false),
+                                        window,
+                                        cx,
+                                    )
+                                    .detach_and_log_err(cx);
+                                })),
+                        ))
+                        .item(ContextMenuItem::Entry(
+                            ContextMenuEntry::new("Close Right")
+                                .action(Some(Box::new(CloseItemsToTheRight {
+                                    close_pinned: false,
+                                })))
+                                .disabled(!has_items_to_right)
+                                .handler(window.handler_for(&pane, move |pane, window, cx| {
+                                    pane.close_items_to_the_right_by_id(
+                                        item_id,
+                                        &CloseItemsToTheRight {
+                                            close_pinned: false,
+                                        },
+                                        pane.get_non_closeable_item_ids(false),
+                                        window,
+                                        cx,
+                                    )
+                                    .detach_and_log_err(cx);
+                                })),
+                        ))
                         .separator()
                         .entry(
                             "Close Clean",