Disable close clean menu item when all are dirty (#31859)
This PR disables the "Close Clean" tab context menu action if all items are dirty. <img width="595" alt="SCR-20250601-kaev" src="https://github.com/user-attachments/assets/add30762-b483-4701-9053-141d2dfe9b05" /> <img width="573" alt="SCR-20250601-kahl" src="https://github.com/user-attachments/assets/24f260e4-01d6-48d6-a6f4-a13ae59c246e" /> Also did a bit more general refactoring. Release Notes: - N/A
This commit is contained in:
parent
f13f2dfb70
commit
d3bc561f26
1 changed files with 63 additions and 85 deletions
|
@ -392,6 +392,11 @@ pub struct DraggedTab {
|
||||||
|
|
||||||
impl EventEmitter<Event> for Pane {}
|
impl EventEmitter<Event> for Pane {}
|
||||||
|
|
||||||
|
pub enum Side {
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
impl Pane {
|
impl Pane {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
workspace: WeakEntity<Workspace>,
|
workspace: WeakEntity<Workspace>,
|
||||||
|
@ -1314,63 +1319,31 @@ impl Pane {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_items_to_the_left(
|
|
||||||
&mut self,
|
|
||||||
action: &CloseItemsToTheLeft,
|
|
||||||
window: &mut Window,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
if self.items.is_empty() {
|
|
||||||
return Task::ready(Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let active_item_id = self.active_item_id();
|
|
||||||
let pinned_item_ids = self.pinned_item_ids();
|
|
||||||
|
|
||||||
self.close_items_to_the_left_by_id(active_item_id, action, pinned_item_ids, window, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close_items_to_the_left_by_id(
|
pub fn close_items_to_the_left_by_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_id: EntityId,
|
item_id: Option<EntityId>,
|
||||||
action: &CloseItemsToTheLeft,
|
action: &CloseItemsToTheLeft,
|
||||||
pinned_item_ids: HashSet<EntityId>,
|
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
if self.items.is_empty() {
|
self.close_items_to_the_side_by_id(item_id, Side::Left, action.close_pinned, window, cx)
|
||||||
return Task::ready(Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let to_the_left_item_ids = self.to_the_left_item_ids(item_id);
|
|
||||||
|
|
||||||
self.close_items(window, cx, SaveIntent::Close, move |item_id| {
|
|
||||||
to_the_left_item_ids.contains(&item_id)
|
|
||||||
&& (action.close_pinned || !pinned_item_ids.contains(&item_id))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close_items_to_the_right(
|
|
||||||
&mut self,
|
|
||||||
action: &CloseItemsToTheRight,
|
|
||||||
window: &mut Window,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Task<Result<()>> {
|
|
||||||
if self.items.is_empty() {
|
|
||||||
return Task::ready(Ok(()));
|
|
||||||
}
|
|
||||||
|
|
||||||
let active_item_id = self.active_item_id();
|
|
||||||
let pinned_item_ids = self.pinned_item_ids();
|
|
||||||
|
|
||||||
self.close_items_to_the_right_by_id(active_item_id, action, pinned_item_ids, window, cx)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_items_to_the_right_by_id(
|
pub fn close_items_to_the_right_by_id(
|
||||||
&mut self,
|
&mut self,
|
||||||
item_id: EntityId,
|
item_id: Option<EntityId>,
|
||||||
action: &CloseItemsToTheRight,
|
action: &CloseItemsToTheRight,
|
||||||
pinned_item_ids: HashSet<EntityId>,
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Task<Result<()>> {
|
||||||
|
self.close_items_to_the_side_by_id(item_id, Side::Right, action.close_pinned, window, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close_items_to_the_side_by_id(
|
||||||
|
&mut self,
|
||||||
|
item_id: Option<EntityId>,
|
||||||
|
side: Side,
|
||||||
|
close_pinned: bool,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
|
@ -1378,11 +1351,13 @@ impl Pane {
|
||||||
return Task::ready(Ok(()));
|
return Task::ready(Ok(()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let to_the_right_item_ids = self.to_the_right_item_ids(item_id);
|
let item_id = item_id.unwrap_or_else(|| self.active_item_id());
|
||||||
|
let to_the_side_item_ids = self.to_the_side_item_ids(item_id, side);
|
||||||
|
let pinned_item_ids = self.pinned_item_ids();
|
||||||
|
|
||||||
self.close_items(window, cx, SaveIntent::Close, move |item_id| {
|
self.close_items(window, cx, SaveIntent::Close, move |item_id| {
|
||||||
to_the_right_item_ids.contains(&item_id)
|
to_the_side_item_ids.contains(&item_id)
|
||||||
&& (action.close_pinned || !pinned_item_ids.contains(&item_id))
|
&& (close_pinned || !pinned_item_ids.contains(&item_id))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2376,6 +2351,7 @@ impl Pane {
|
||||||
let total_items = self.items.len();
|
let total_items = self.items.len();
|
||||||
let has_items_to_left = ix > 0;
|
let has_items_to_left = ix > 0;
|
||||||
let has_items_to_right = ix < total_items - 1;
|
let has_items_to_right = ix < total_items - 1;
|
||||||
|
let has_clean_items = self.items.iter().any(|item| !item.is_dirty(cx));
|
||||||
let is_pinned = self.is_tab_pinned(ix);
|
let is_pinned = self.is_tab_pinned(ix);
|
||||||
let pane = cx.entity().downgrade();
|
let pane = cx.entity().downgrade();
|
||||||
let menu_context = item.item_focus_handle(cx);
|
let menu_context = item.item_focus_handle(cx);
|
||||||
|
@ -2436,9 +2412,8 @@ impl Pane {
|
||||||
.disabled(!has_items_to_left)
|
.disabled(!has_items_to_left)
|
||||||
.handler(window.handler_for(&pane, move |pane, window, cx| {
|
.handler(window.handler_for(&pane, move |pane, window, cx| {
|
||||||
pane.close_items_to_the_left_by_id(
|
pane.close_items_to_the_left_by_id(
|
||||||
item_id,
|
Some(item_id),
|
||||||
&close_items_to_the_left_action,
|
&close_items_to_the_left_action,
|
||||||
pane.pinned_item_ids(),
|
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2451,9 +2426,8 @@ impl Pane {
|
||||||
.disabled(!has_items_to_right)
|
.disabled(!has_items_to_right)
|
||||||
.handler(window.handler_for(&pane, move |pane, window, cx| {
|
.handler(window.handler_for(&pane, move |pane, window, cx| {
|
||||||
pane.close_items_to_the_right_by_id(
|
pane.close_items_to_the_right_by_id(
|
||||||
item_id,
|
Some(item_id),
|
||||||
&close_items_to_the_right_action,
|
&close_items_to_the_right_action,
|
||||||
pane.pinned_item_ids(),
|
|
||||||
window,
|
window,
|
||||||
cx,
|
cx,
|
||||||
)
|
)
|
||||||
|
@ -2461,14 +2435,19 @@ impl Pane {
|
||||||
})),
|
})),
|
||||||
))
|
))
|
||||||
.separator()
|
.separator()
|
||||||
.entry(
|
.item(ContextMenuItem::Entry(
|
||||||
"Close Clean",
|
ContextMenuEntry::new("Close Clean")
|
||||||
Some(Box::new(close_clean_items_action.clone())),
|
.action(Box::new(close_clean_items_action.clone()))
|
||||||
window.handler_for(&pane, move |pane, window, cx| {
|
.disabled(!has_clean_items)
|
||||||
pane.close_clean_items(&close_clean_items_action, window, cx)
|
.handler(window.handler_for(&pane, move |pane, window, cx| {
|
||||||
.detach_and_log_err(cx)
|
pane.close_clean_items(
|
||||||
}),
|
&close_clean_items_action,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
)
|
)
|
||||||
|
.detach_and_log_err(cx)
|
||||||
|
})),
|
||||||
|
))
|
||||||
.entry(
|
.entry(
|
||||||
"Close All",
|
"Close All",
|
||||||
Some(Box::new(close_all_items_action.clone())),
|
Some(Box::new(close_all_items_action.clone())),
|
||||||
|
@ -3102,19 +3081,20 @@ impl Pane {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_the_left_item_ids(&self, item_id: EntityId) -> HashSet<EntityId> {
|
fn to_the_side_item_ids(&self, item_id: EntityId, side: Side) -> HashSet<EntityId> {
|
||||||
self.items()
|
match side {
|
||||||
|
Side::Left => self
|
||||||
|
.items()
|
||||||
.take_while(|item| item.item_id() != item_id)
|
.take_while(|item| item.item_id() != item_id)
|
||||||
.map(|item| item.item_id())
|
.map(|item| item.item_id())
|
||||||
.collect()
|
.collect(),
|
||||||
}
|
Side::Right => self
|
||||||
|
.items()
|
||||||
fn to_the_right_item_ids(&self, item_id: EntityId) -> HashSet<EntityId> {
|
|
||||||
self.items()
|
|
||||||
.rev()
|
.rev()
|
||||||
.take_while(|item| item.item_id() != item_id)
|
.take_while(|item| item.item_id() != item_id)
|
||||||
.map(|item| item.item_id())
|
.map(|item| item.item_id())
|
||||||
.collect()
|
.collect(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn drag_split_direction(&self) -> Option<SplitDirection> {
|
pub fn drag_split_direction(&self) -> Option<SplitDirection> {
|
||||||
|
@ -3333,13 +3313,13 @@ impl Render for Pane {
|
||||||
)
|
)
|
||||||
.on_action(cx.listener(
|
.on_action(cx.listener(
|
||||||
|pane: &mut Self, action: &CloseItemsToTheLeft, window, cx| {
|
|pane: &mut Self, action: &CloseItemsToTheLeft, window, cx| {
|
||||||
pane.close_items_to_the_left(action, window, cx)
|
pane.close_items_to_the_left_by_id(None, action, window, cx)
|
||||||
.detach_and_log_err(cx)
|
.detach_and_log_err(cx)
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
.on_action(cx.listener(
|
.on_action(cx.listener(
|
||||||
|pane: &mut Self, action: &CloseItemsToTheRight, window, cx| {
|
|pane: &mut Self, action: &CloseItemsToTheRight, window, cx| {
|
||||||
pane.close_items_to_the_right(action, window, cx)
|
pane.close_items_to_the_right_by_id(None, action, window, cx)
|
||||||
.detach_and_log_err(cx)
|
.detach_and_log_err(cx)
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
@ -3349,12 +3329,6 @@ impl Render for Pane {
|
||||||
.detach_and_log_err(cx)
|
.detach_and_log_err(cx)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.on_action(
|
|
||||||
cx.listener(|pane: &mut Self, action: &CloseActiveItem, window, cx| {
|
|
||||||
pane.close_active_item(action, window, cx)
|
|
||||||
.detach_and_log_err(cx)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
.on_action(
|
.on_action(
|
||||||
cx.listener(|pane: &mut Self, action: &RevealInProjectPanel, _, cx| {
|
cx.listener(|pane: &mut Self, action: &RevealInProjectPanel, _, cx| {
|
||||||
let entry_id = action
|
let entry_id = action
|
||||||
|
@ -4436,7 +4410,8 @@ mod tests {
|
||||||
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
||||||
|
|
||||||
pane.update_in(cx, |pane, window, cx| {
|
pane.update_in(cx, |pane, window, cx| {
|
||||||
pane.close_items_to_the_left(
|
pane.close_items_to_the_left_by_id(
|
||||||
|
None,
|
||||||
&CloseItemsToTheLeft {
|
&CloseItemsToTheLeft {
|
||||||
close_pinned: false,
|
close_pinned: false,
|
||||||
},
|
},
|
||||||
|
@ -4462,7 +4437,8 @@ mod tests {
|
||||||
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
|
||||||
|
|
||||||
pane.update_in(cx, |pane, window, cx| {
|
pane.update_in(cx, |pane, window, cx| {
|
||||||
pane.close_items_to_the_right(
|
pane.close_items_to_the_right_by_id(
|
||||||
|
None,
|
||||||
&CloseItemsToTheRight {
|
&CloseItemsToTheRight {
|
||||||
close_pinned: false,
|
close_pinned: false,
|
||||||
},
|
},
|
||||||
|
@ -4779,7 +4755,8 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
pane.update_in(cx, |pane, window, cx| {
|
pane.update_in(cx, |pane, window, cx| {
|
||||||
pane.close_items_to_the_right(
|
pane.close_items_to_the_right_by_id(
|
||||||
|
None,
|
||||||
&CloseItemsToTheRight {
|
&CloseItemsToTheRight {
|
||||||
close_pinned: false,
|
close_pinned: false,
|
||||||
},
|
},
|
||||||
|
@ -4791,7 +4768,8 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
pane.update_in(cx, |pane, window, cx| {
|
pane.update_in(cx, |pane, window, cx| {
|
||||||
pane.close_items_to_the_left(
|
pane.close_items_to_the_left_by_id(
|
||||||
|
None,
|
||||||
&CloseItemsToTheLeft {
|
&CloseItemsToTheLeft {
|
||||||
close_pinned: false,
|
close_pinned: false,
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue