Add :tabonly and :only vim commands (#8337)

Release Notes:

- Added
[`:tabo[nly][!]`](https://neovim.io/doc/user/tabpage.html#%3Atabonly),
closes all the tabs except the active one but in the current pane only,
every other split pane remains unaffected.
The version with the `!` force closes the tabs while the one without
asks you to save or discard the changes.
- Added [`:on[ly][!]`](https://neovim.io/doc/user/windows.html#%3Aonly),
closes all the tabs *and* panes except the active one.
The version with the `!` force closes the tabs while the one without
asks you to save or discard the changes.
Since Zed does not have different splits per tab like in Neovim `:only`
works the same as it does in VscodeVim.

---------

Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
This commit is contained in:
riccardofano 2024-02-27 06:15:50 +01:00 committed by GitHub
parent c31626717f
commit a42b987929
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 53 additions and 11 deletions

View file

@ -201,6 +201,34 @@ pub fn command_interceptor(mut query: &str, cx: &AppContext) -> Option<CommandIn
} }
.boxed_clone(), .boxed_clone(),
), ),
"tabo" | "tabon" | "tabonl" | "tabonly" => (
"tabonly",
workspace::CloseInactiveItems {
save_intent: Some(SaveIntent::Close),
}
.boxed_clone(),
),
"tabo!" | "tabon!" | "tabonl!" | "tabonly!" => (
"tabonly!",
workspace::CloseInactiveItems {
save_intent: Some(SaveIntent::Skip),
}
.boxed_clone(),
),
"on" | "onl" | "only" => (
"only",
workspace::CloseInactiveTabsAndPanes {
save_intent: Some(SaveIntent::Close),
}
.boxed_clone(),
),
"on!" | "onl!" | "only!" => (
"only!",
workspace::CloseInactiveTabsAndPanes {
save_intent: Some(SaveIntent::Skip),
}
.boxed_clone(),
),
// quickfix / loclist (merged together for now) // quickfix / loclist (merged together for now)
"cl" | "cli" | "clis" | "clist" => ( "cl" | "cli" | "clis" | "clist" => (

View file

@ -66,6 +66,12 @@ pub struct CloseActiveItem {
pub save_intent: Option<SaveIntent>, pub save_intent: Option<SaveIntent>,
} }
#[derive(Clone, PartialEq, Debug, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CloseInactiveItems {
pub save_intent: Option<SaveIntent>,
}
#[derive(Clone, PartialEq, Debug, Deserialize, Default)] #[derive(Clone, PartialEq, Debug, Deserialize, Default)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CloseAllItems { pub struct CloseAllItems {
@ -83,6 +89,7 @@ impl_actions!(
[ [
CloseAllItems, CloseAllItems,
CloseActiveItem, CloseActiveItem,
CloseInactiveItems,
ActivateItem, ActivateItem,
RevealInProjectPanel RevealInProjectPanel
] ]
@ -94,7 +101,6 @@ actions!(
ActivatePrevItem, ActivatePrevItem,
ActivateNextItem, ActivateNextItem,
ActivateLastItem, ActivateLastItem,
CloseInactiveItems,
CloseCleanItems, CloseCleanItems,
CloseItemsToTheLeft, CloseItemsToTheLeft,
CloseItemsToTheRight, CloseItemsToTheRight,
@ -767,7 +773,7 @@ impl Pane {
pub fn close_inactive_items( pub fn close_inactive_items(
&mut self, &mut self,
_: &CloseInactiveItems, action: &CloseInactiveItems,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<Task<Result<()>>> { ) -> Option<Task<Result<()>>> {
if self.items.is_empty() { if self.items.is_empty() {
@ -775,9 +781,11 @@ impl Pane {
} }
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_items(cx, SaveIntent::Close, move |item_id| { Some(self.close_items(
item_id != active_item_id cx,
})) action.save_intent.unwrap_or(SaveIntent::Close),
move |item_id| item_id != active_item_id,
))
} }
pub fn close_clean_items( pub fn close_clean_items(
@ -1397,7 +1405,7 @@ impl Pane {
) )
.entry( .entry(
"Close Others", "Close Others",
Some(Box::new(CloseInactiveItems)), Some(Box::new(CloseInactiveItems { save_intent: None })),
cx.handler_for(&pane, move |pane, cx| { cx.handler_for(&pane, move |pane, cx| {
pane.close_items(cx, SaveIntent::Close, |id| id != item_id) pane.close_items(cx, SaveIntent::Close, |id| id != item_id)
.detach_and_log_err(cx); .detach_and_log_err(cx);
@ -2432,7 +2440,7 @@ mod tests {
set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx); set_labeled_items(&pane, ["A", "B", "C*", "D", "E"], cx);
pane.update(cx, |pane, cx| { pane.update(cx, |pane, cx| {
pane.close_inactive_items(&CloseInactiveItems, cx) pane.close_inactive_items(&CloseInactiveItems { save_intent: None }, cx)
}) })
.unwrap() .unwrap()
.await .await

View file

@ -103,7 +103,6 @@ actions!(
NewFile, NewFile,
NewWindow, NewWindow,
CloseWindow, CloseWindow,
CloseInactiveTabsAndPanes,
AddFolderToProject, AddFolderToProject,
Unfollow, Unfollow,
SaveAs, SaveAs,
@ -161,6 +160,12 @@ pub struct CloseAllItemsAndPanes {
pub save_intent: Option<SaveIntent>, pub save_intent: Option<SaveIntent>,
} }
#[derive(Clone, PartialEq, Debug, Deserialize, Default)]
#[serde(rename_all = "camelCase")]
pub struct CloseInactiveTabsAndPanes {
pub save_intent: Option<SaveIntent>,
}
#[derive(Clone, Deserialize, PartialEq)] #[derive(Clone, Deserialize, PartialEq)]
pub struct SendKeystrokes(pub String); pub struct SendKeystrokes(pub String);
@ -170,6 +175,7 @@ impl_actions!(
ActivatePane, ActivatePane,
ActivatePaneInDirection, ActivatePaneInDirection,
CloseAllItemsAndPanes, CloseAllItemsAndPanes,
CloseInactiveTabsAndPanes,
NewFileInDirection, NewFileInDirection,
OpenTerminal, OpenTerminal,
Save, Save,
@ -1620,10 +1626,10 @@ impl Workspace {
pub fn close_inactive_items_and_panes( pub fn close_inactive_items_and_panes(
&mut self, &mut self,
_: &CloseInactiveTabsAndPanes, action: &CloseInactiveTabsAndPanes,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) { ) {
self.close_all_internal(true, SaveIntent::Close, cx) self.close_all_internal(true, action.save_intent.unwrap_or(SaveIntent::Close), cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
} }
@ -1648,7 +1654,7 @@ impl Workspace {
if retain_active_pane { if retain_active_pane {
if let Some(current_pane_close) = current_pane.update(cx, |pane, cx| { if let Some(current_pane_close) = current_pane.update(cx, |pane, cx| {
pane.close_inactive_items(&CloseInactiveItems, cx) pane.close_inactive_items(&CloseInactiveItems { save_intent: None }, cx)
}) { }) {
tasks.push(current_pane_close); tasks.push(current_pane_close);
}; };