pane: Improve close active item to better handle pinned tabs (#23488)

Closes #22247

- [x] Do not close pinned tab on keyboard shortcuts like `ctrl+w` or
`alt+f4`
- [x] Close pinned tab on context menu action, menu bar action, or vim
bang
- [x] While closing pinned tab via shortcut (where it won't close),
instead activate any other non-pinned tab in same pane
- [x] Else, if any other pane contains non-pinned tab, activate that
- [x] Tests

Co-authored-by: uncenter <47499684+uncenter@users.noreply.github.com>

Release Notes:

- Pinned tab now stay open when using close shortcuts, auto focuses to
any other non-pinned tab instead.
This commit is contained in:
smit 2025-02-07 22:54:57 +05:30 committed by GitHub
parent f0565b4e2e
commit 44c6a54f95
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 298 additions and 36 deletions

View file

@ -274,8 +274,8 @@
"ctrl-pagedown": "pane::ActivateNextItem", "ctrl-pagedown": "pane::ActivateNextItem",
"ctrl-shift-pageup": "pane::SwapItemLeft", "ctrl-shift-pageup": "pane::SwapItemLeft",
"ctrl-shift-pagedown": "pane::SwapItemRight", "ctrl-shift-pagedown": "pane::SwapItemRight",
"ctrl-f4": "pane::CloseActiveItem", "ctrl-f4": ["pane::CloseActiveItem", { "close_pinned": false }],
"ctrl-w": "pane::CloseActiveItem", "ctrl-w": ["pane::CloseActiveItem", { "close_pinned": false }],
"alt-ctrl-t": ["pane::CloseInactiveItems", { "close_pinned": false }], "alt-ctrl-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
"alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes", "alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes",
"ctrl-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }], "ctrl-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }],

View file

@ -349,7 +349,7 @@
"cmd-}": "pane::ActivateNextItem", "cmd-}": "pane::ActivateNextItem",
"ctrl-shift-pageup": "pane::SwapItemLeft", "ctrl-shift-pageup": "pane::SwapItemLeft",
"ctrl-shift-pagedown": "pane::SwapItemRight", "ctrl-shift-pagedown": "pane::SwapItemRight",
"cmd-w": "pane::CloseActiveItem", "cmd-w": ["pane::CloseActiveItem", { "close_pinned": false }],
"alt-cmd-t": ["pane::CloseInactiveItems", { "close_pinned": false }], "alt-cmd-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
"ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes", "ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes",
"cmd-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }], "cmd-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }],

View file

@ -817,7 +817,10 @@ async fn test_external_files_history(cx: &mut gpui::TestAppContext) {
.as_u64() as usize, .as_u64() as usize,
) )
}); });
cx.dispatch_action(workspace::CloseActiveItem { save_intent: None }); cx.dispatch_action(workspace::CloseActiveItem {
save_intent: None,
close_pinned: false,
});
let initial_history_items = let initial_history_items =
open_close_queried_buffer("sec", 1, "second.rs", &workspace, cx).await; open_close_queried_buffer("sec", 1, "second.rs", &workspace, cx).await;
@ -2000,7 +2003,10 @@ async fn open_close_queried_buffer(
) )
.await; .await;
cx.dispatch_action(workspace::CloseActiveItem { save_intent: None }); cx.dispatch_action(workspace::CloseActiveItem {
save_intent: None,
close_pinned: false,
});
history_items history_items
} }

View file

@ -257,7 +257,13 @@ impl TerminalView {
.action("Inline Assist", Box::new(InlineAssist::default())) .action("Inline Assist", Box::new(InlineAssist::default()))
}) })
.separator() .separator()
.action("Close", Box::new(CloseActiveItem { save_intent: None })) .action(
"Close",
Box::new(CloseActiveItem {
save_intent: None,
close_pinned: true,
}),
)
}); });
window.focus(&context_menu.focus_handle(cx)); window.focus(&context_menu.focus_handle(cx));

View file

@ -567,37 +567,45 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
("q", "uit"), ("q", "uit"),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Close), save_intent: Some(SaveIntent::Close),
close_pinned: false,
}, },
) )
.bang(workspace::CloseActiveItem { .bang(workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Skip), save_intent: Some(SaveIntent::Skip),
close_pinned: true,
}), }),
VimCommand::new( VimCommand::new(
("wq", ""), ("wq", ""),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Save), save_intent: Some(SaveIntent::Save),
close_pinned: false,
}, },
) )
.bang(workspace::CloseActiveItem { .bang(workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Overwrite), save_intent: Some(SaveIntent::Overwrite),
close_pinned: true,
}), }),
VimCommand::new( VimCommand::new(
("x", "it"), ("x", "it"),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::SaveAll), save_intent: Some(SaveIntent::SaveAll),
close_pinned: false,
}, },
) )
.bang(workspace::CloseActiveItem { .bang(workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Overwrite), save_intent: Some(SaveIntent::Overwrite),
close_pinned: true,
}), }),
VimCommand::new( VimCommand::new(
("ex", "it"), ("ex", "it"),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::SaveAll), save_intent: Some(SaveIntent::SaveAll),
close_pinned: false,
}, },
) )
.bang(workspace::CloseActiveItem { .bang(workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Overwrite), save_intent: Some(SaveIntent::Overwrite),
close_pinned: true,
}), }),
VimCommand::new( VimCommand::new(
("up", "date"), ("up", "date"),
@ -657,10 +665,12 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
("bd", "elete"), ("bd", "elete"),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Close), save_intent: Some(SaveIntent::Close),
close_pinned: false,
}, },
) )
.bang(workspace::CloseActiveItem { .bang(workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Skip), save_intent: Some(SaveIntent::Skip),
close_pinned: true,
}), }),
VimCommand::new(("bn", "ext"), workspace::ActivateNextItem).count(), VimCommand::new(("bn", "ext"), workspace::ActivateNextItem).count(),
VimCommand::new(("bN", "ext"), workspace::ActivatePrevItem).count(), VimCommand::new(("bN", "ext"), workspace::ActivatePrevItem).count(),
@ -679,6 +689,7 @@ fn generate_commands(_: &App) -> Vec<VimCommand> {
("tabc", "lose"), ("tabc", "lose"),
workspace::CloseActiveItem { workspace::CloseActiveItem {
save_intent: Some(SaveIntent::Close), save_intent: Some(SaveIntent::Close),
close_pinned: false,
}, },
), ),
VimCommand::new( VimCommand::new(

View file

@ -99,6 +99,8 @@ pub struct ActivateItem(pub usize);
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct CloseActiveItem { pub struct CloseActiveItem {
pub save_intent: Option<SaveIntent>, pub save_intent: Option<SaveIntent>,
#[serde(default)]
pub close_pinned: bool,
} }
#[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema, Default)] #[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema, Default)]
@ -1224,6 +1226,37 @@ impl Pane {
return None; return None;
} }
if self.is_tab_pinned(self.active_item_index) && !action.close_pinned {
// Activate any non-pinned tab in same pane
let non_pinned_tab_index = self
.items()
.enumerate()
.find(|(index, _item)| !self.is_tab_pinned(*index))
.map(|(index, _item)| index);
if let Some(index) = non_pinned_tab_index {
self.activate_item(index, false, false, window, cx);
return None;
}
// Activate any non-pinned tab in different pane
let current_pane = cx.entity();
self.workspace
.update(cx, |workspace, cx| {
let panes = workspace.center.panes();
let pane_with_unpinned_tab = panes.iter().find(|pane| {
if **pane == &current_pane {
return false;
}
pane.read(cx).has_unpinned_tabs()
});
if let Some(pane) = pane_with_unpinned_tab {
pane.update(cx, |pane, cx| pane.activate_unpinned_tab(window, cx));
}
})
.ok();
return None;
};
let active_item_id = self.items[self.active_item_index].item_id(); let active_item_id = self.items[self.active_item_index].item_id();
Some(self.close_item_by_id( Some(self.close_item_by_id(
active_item_id, active_item_id,
@ -2105,6 +2138,24 @@ impl Pane {
self.pinned_tab_count != 0 self.pinned_tab_count != 0
} }
fn has_unpinned_tabs(&self) -> bool {
self.pinned_tab_count < self.items.len()
}
fn activate_unpinned_tab(&mut self, window: &mut Window, cx: &mut Context<Self>) {
if self.items.is_empty() {
return;
}
let Some(index) = self
.items()
.enumerate()
.find_map(|(index, _item)| (!self.is_tab_pinned(index)).then_some(index))
else {
return;
};
self.activate_item(index, true, true, window, cx);
}
fn render_tab( fn render_tab(
&self, &self,
ix: usize, ix: usize,
@ -2280,7 +2331,10 @@ impl Pane {
pane.unpin_tab_at(ix, window, cx); pane.unpin_tab_at(ix, window, cx);
})) }))
} else { } else {
end_slot_action = &CloseActiveItem { save_intent: None }; end_slot_action = &CloseActiveItem {
save_intent: None,
close_pinned: false,
};
end_slot_tooltip_text = "Close Tab"; end_slot_tooltip_text = "Close Tab";
IconButton::new("close tab", IconName::Close) IconButton::new("close tab", IconName::Close)
.when(!always_show_close_button, |button| { .when(!always_show_close_button, |button| {
@ -2350,7 +2404,10 @@ impl Pane {
menu = menu menu = menu
.entry( .entry(
"Close", "Close",
Some(Box::new(CloseActiveItem { save_intent: None })), Some(Box::new(CloseActiveItem {
save_intent: None,
close_pinned: true,
})),
window.handler_for(&pane, move |pane, window, cx| { window.handler_for(&pane, move |pane, window, cx| {
pane.close_item_by_id(item_id, SaveIntent::Close, window, cx) pane.close_item_by_id(item_id, SaveIntent::Close, window, cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
@ -2991,14 +3048,9 @@ impl Pane {
self.items self.items
.iter() .iter()
.map(|item| item.item_id()) .enumerate()
.filter(|item_id| { .filter(|(index, _item)| self.is_tab_pinned(*index))
if let Some(ix) = self.index_for_item_id(*item_id) { .map(|(_, item)| item.item_id())
self.is_tab_pinned(ix)
} else {
true
}
})
.collect() .collect()
} }
@ -3561,7 +3613,14 @@ mod tests {
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
assert!(pane assert!(pane
.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) .close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false
},
window,
cx
)
.is_none()) .is_none())
}); });
} }
@ -3902,7 +3961,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx); assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3915,7 +3981,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "C", "D*"], cx); assert_item_labels(&pane, ["A", "B", "C", "D*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3923,7 +3996,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B*", "C"], cx); assert_item_labels(&pane, ["A", "B*", "C"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3931,7 +4011,14 @@ mod tests {
assert_item_labels(&pane, ["A", "C*"], cx); assert_item_labels(&pane, ["A", "C*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3967,7 +4054,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx); assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3980,7 +4074,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "C", "D*"], cx); assert_item_labels(&pane, ["A", "B", "C", "D*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3988,7 +4089,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "C*"], cx); assert_item_labels(&pane, ["A", "B", "C*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -3996,7 +4104,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B*"], cx); assert_item_labels(&pane, ["A", "B*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -4032,7 +4147,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx); assert_item_labels(&pane, ["A", "B", "1*", "C", "D"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -4045,7 +4167,14 @@ mod tests {
assert_item_labels(&pane, ["A", "B", "C", "D*"], cx); assert_item_labels(&pane, ["A", "B", "C", "D*"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -4058,7 +4187,14 @@ mod tests {
assert_item_labels(&pane, ["A*", "B", "C"], cx); assert_item_labels(&pane, ["A*", "B", "C"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -4066,7 +4202,14 @@ mod tests {
assert_item_labels(&pane, ["B*", "C"], cx); assert_item_labels(&pane, ["B*", "C"], cx);
pane.update_in(cx, |pane, window, cx| { pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.unwrap() .unwrap()
.await .await
@ -4300,7 +4443,7 @@ mod tests {
let project = Project::test(fs, None, cx).await; let project = Project::test(fs, None, cx).await;
let (workspace, cx) = let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); cx.add_window_view(|window, cx| Workspace::test_new(project, window, cx));
let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone()); let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
let item_a = add_labeled_item(&pane, "A", false, cx); let item_a = add_labeled_item(&pane, "A", false, cx);
@ -4326,6 +4469,71 @@ mod tests {
assert_item_labels(&pane, [], cx); assert_item_labels(&pane, [], cx);
} }
#[gpui::test]
async fn test_close_pinned_tab_with_non_pinned_in_same_pane(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
let project = Project::test(fs, None, cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project, window, cx));
// Non-pinned tabs in same pane
let pane = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
add_labeled_item(&pane, "A", false, cx);
add_labeled_item(&pane, "B", false, cx);
add_labeled_item(&pane, "C", false, cx);
pane.update_in(cx, |pane, window, cx| {
pane.pin_tab_at(0, window, cx);
});
set_labeled_items(&pane, ["A*", "B", "C"], cx);
pane.update_in(cx, |pane, window, cx| {
pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
);
});
// Non-pinned tab should be active
assert_item_labels(&pane, ["A", "B*", "C"], cx);
}
#[gpui::test]
async fn test_close_pinned_tab_with_non_pinned_in_different_pane(cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(cx.executor());
let project = Project::test(fs, None, cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project, window, cx));
// No non-pinned tabs in same pane, non-pinned tabs in another pane
let pane1 = workspace.update(cx, |workspace, _| workspace.active_pane().clone());
let pane2 = workspace.update_in(cx, |workspace, window, cx| {
workspace.split_pane(pane1.clone(), SplitDirection::Right, window, cx)
});
add_labeled_item(&pane1, "A", false, cx);
pane1.update_in(cx, |pane, window, cx| {
pane.pin_tab_at(0, window, cx);
});
set_labeled_items(&pane1, ["A*"], cx);
add_labeled_item(&pane2, "B", false, cx);
set_labeled_items(&pane2, ["B"], cx);
pane1.update_in(cx, |pane, window, cx| {
pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
);
});
// Non-pinned tab of other pane should be active
assert_item_labels(&pane2, ["B*"], cx);
}
fn init_test(cx: &mut TestAppContext) { fn init_test(cx: &mut TestAppContext) {
cx.update(|cx| { cx.update(|cx| {
let settings_store = SettingsStore::test(cx); let settings_store = SettingsStore::test(cx);

View file

@ -8175,6 +8175,7 @@ mod tests {
pane.close_active_item( pane.close_active_item(
&CloseActiveItem { &CloseActiveItem {
save_intent: Some(SaveIntent::Close), save_intent: Some(SaveIntent::Close),
close_pinned: false,
}, },
window, window,
cx, cx,
@ -8279,7 +8280,14 @@ mod tests {
}); });
let close_singleton_buffer_task = pane let close_singleton_buffer_task = pane
.update_in(cx, |pane, window, cx| { .update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.expect("should have active singleton buffer to close"); .expect("should have active singleton buffer to close");
cx.background_executor.run_until_parked(); cx.background_executor.run_until_parked();
@ -8385,7 +8393,14 @@ mod tests {
}); });
let _close_multi_buffer_task = pane let _close_multi_buffer_task = pane
.update_in(cx, |pane, window, cx| { .update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.expect("should have active multi buffer to close"); .expect("should have active multi buffer to close");
cx.background_executor.run_until_parked(); cx.background_executor.run_until_parked();
@ -8476,7 +8491,14 @@ mod tests {
}); });
let close_multi_buffer_task = pane let close_multi_buffer_task = pane
.update_in(cx, |pane, window, cx| { .update_in(cx, |pane, window, cx| {
pane.close_active_item(&CloseActiveItem { save_intent: None }, window, cx) pane.close_active_item(
&CloseActiveItem {
save_intent: None,
close_pinned: false,
},
window,
cx,
)
}) })
.expect("should have active multi buffer to close"); .expect("should have active multi buffer to close");
cx.background_executor.run_until_parked(); cx.background_executor.run_until_parked();

View file

@ -3103,7 +3103,10 @@ mod tests {
}); });
cx.dispatch_action( cx.dispatch_action(
window.into(), window.into(),
workspace::CloseActiveItem { save_intent: None }, workspace::CloseActiveItem {
save_intent: None,
close_pinned: false,
},
); );
cx.background_executor.run_until_parked(); cx.background_executor.run_until_parked();
@ -3116,7 +3119,10 @@ mod tests {
cx.dispatch_action( cx.dispatch_action(
window.into(), window.into(),
workspace::CloseActiveItem { save_intent: None }, workspace::CloseActiveItem {
save_intent: None,
close_pinned: false,
},
); );
cx.background_executor.run_until_parked(); cx.background_executor.run_until_parked();
cx.simulate_prompt_answer(1); cx.simulate_prompt_answer(1);

View file

@ -76,7 +76,10 @@ pub fn app_menus() -> Vec<Menu> {
MenuItem::action("Save All", workspace::SaveAll { save_intent: None }), MenuItem::action("Save All", workspace::SaveAll { save_intent: None }),
MenuItem::action( MenuItem::action(
"Close Editor", "Close Editor",
workspace::CloseActiveItem { save_intent: None }, workspace::CloseActiveItem {
save_intent: None,
close_pinned: true,
},
), ),
MenuItem::action("Close Window", workspace::CloseWindow), MenuItem::action("Close Window", workspace::CloseWindow),
], ],