Allow SplitAndMove on panes (#38034)

Updates #19350

Release Notes:

- Add `pane::SplitAndMove{Up,Down,Left,Right}` to allow creating a split
without cloning the current buffer.
This commit is contained in:
Conrad Irwin
2025-09-12 03:18:28 +00:00
committed by GitHub
parent ffb85d7e81
commit fcfc54c515
3 changed files with 118 additions and 19 deletions
+35 -10
View File
@@ -385,19 +385,44 @@ impl TerminalPanel {
}
self.serialize(cx);
}
&pane::Event::Split(direction) => {
let fut = self.new_pane_with_cloned_active_terminal(window, cx);
let pane = pane.clone();
cx.spawn_in(window, async move |panel, cx| {
let Some(new_pane) = fut.await else {
&pane::Event::Split {
direction,
clone_active_item,
} => {
if clone_active_item {
let fut = self.new_pane_with_cloned_active_terminal(window, cx);
let pane = pane.clone();
cx.spawn_in(window, async move |panel, cx| {
let Some(new_pane) = fut.await else {
return;
};
panel
.update_in(cx, |panel, window, cx| {
panel.center.split(&pane, &new_pane, direction).log_err();
window.focus(&new_pane.focus_handle(cx));
})
.ok();
})
.detach();
} else {
let Some(item) = pane.update(cx, |pane, cx| pane.take_active_item(window, cx))
else {
return;
};
_ = panel.update_in(cx, |panel, window, cx| {
panel.center.split(&pane, &new_pane, direction).log_err();
window.focus(&new_pane.focus_handle(cx));
let Ok(project) = self
.workspace
.update(cx, |workspace, _| workspace.project().clone())
else {
return;
};
let new_pane =
new_terminal_pane(self.workspace.clone(), project, false, window, cx);
new_pane.update(cx, |pane, cx| {
pane.add_item(item, true, true, None, window, cx);
});
})
.detach();
self.center.split(&pane, &new_pane, direction).log_err();
window.focus(&new_pane.focus_handle(cx));
}
}
pane::Event::Focus => {
self.active_pane = pane.clone();
+56 -7
View File
@@ -206,14 +206,22 @@ actions!(
JoinAll,
/// Reopens the most recently closed item.
ReopenClosedItem,
/// Splits the pane to the left.
/// Splits the pane to the left, cloning the current item.
SplitLeft,
/// Splits the pane upward.
/// Splits the pane upward, cloning the current item.
SplitUp,
/// Splits the pane to the right.
/// Splits the pane to the right, cloning the current item.
SplitRight,
/// Splits the pane downward.
/// Splits the pane downward, cloning the current item.
SplitDown,
/// Splits the pane to the left, moving the current item.
SplitAndMoveLeft,
/// Splits the pane upward, moving the current item.
SplitAndMoveUp,
/// Splits the pane to the right, moving the current item.
SplitAndMoveRight,
/// Splits the pane downward, moving the current item.
SplitAndMoveDown,
/// Splits the pane horizontally.
SplitHorizontal,
/// Splits the pane vertically.
@@ -257,7 +265,10 @@ pub enum Event {
RemovedItem {
item: Box<dyn ItemHandle>,
},
Split(SplitDirection),
Split {
direction: SplitDirection,
clone_active_item: bool,
},
ItemPinned,
ItemUnpinned,
JoinAll,
@@ -288,9 +299,13 @@ impl fmt::Debug for Event {
.debug_struct("RemovedItem")
.field("item", &item.item_id())
.finish(),
Event::Split(direction) => f
Event::Split {
direction,
clone_active_item,
} => f
.debug_struct("Split")
.field("direction", direction)
.field("clone_active_item", clone_active_item)
.finish(),
Event::JoinAll => f.write_str("JoinAll"),
Event::JoinIntoNext => f.write_str("JoinIntoNext"),
@@ -1776,6 +1791,16 @@ impl Pane {
})
}
pub fn take_active_item(
&mut self,
window: &mut Window,
cx: &mut Context<Self>,
) -> Option<Box<dyn ItemHandle>> {
let item = self.active_item()?;
self.remove_item(item.item_id(), false, false, window, cx);
Some(item)
}
pub fn remove_item(
&mut self,
item_id: EntityId,
@@ -2222,7 +2247,19 @@ impl Pane {
}
pub fn split(&mut self, direction: SplitDirection, cx: &mut Context<Self>) {
cx.emit(Event::Split(direction));
cx.emit(Event::Split {
direction,
clone_active_item: true,
});
}
pub fn split_and_move(&mut self, direction: SplitDirection, cx: &mut Context<Self>) {
if self.items.len() > 1 {
cx.emit(Event::Split {
direction,
clone_active_item: false,
});
}
}
pub fn toolbar(&self) -> &Entity<Toolbar> {
@@ -3566,6 +3603,18 @@ impl Render for Pane {
.on_action(
cx.listener(|pane, _: &SplitDown, _, cx| pane.split(SplitDirection::Down, cx)),
)
.on_action(cx.listener(|pane, _: &SplitAndMoveUp, _, cx| {
pane.split_and_move(SplitDirection::Up, cx)
}))
.on_action(cx.listener(|pane, _: &SplitAndMoveDown, _, cx| {
pane.split_and_move(SplitDirection::Down, cx)
}))
.on_action(cx.listener(|pane, _: &SplitAndMoveLeft, _, cx| {
pane.split_and_move(SplitDirection::Left, cx)
}))
.on_action(cx.listener(|pane, _: &SplitAndMoveRight, _, cx| {
pane.split_and_move(SplitDirection::Right, cx)
}))
.on_action(cx.listener(|_, _: &JoinIntoNext, _, cx| {
cx.emit(Event::JoinIntoNext);
}))
+27 -2
View File
@@ -3929,8 +3929,15 @@ impl Workspace {
item: item.boxed_clone(),
});
}
pane::Event::Split(direction) => {
self.split_and_clone(pane.clone(), *direction, window, cx);
pane::Event::Split {
direction,
clone_active_item,
} => {
if *clone_active_item {
self.split_and_clone(pane.clone(), *direction, window, cx);
} else {
self.split_and_move(pane.clone(), *direction, window, cx);
}
}
pane::Event::JoinIntoNext => {
self.join_pane_into_next(pane.clone(), window, cx);
@@ -4044,6 +4051,24 @@ impl Workspace {
new_pane
}
pub fn split_and_move(
&mut self,
pane: Entity<Pane>,
direction: SplitDirection,
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(item) = pane.update(cx, |pane, cx| pane.take_active_item(window, cx)) else {
return;
};
let new_pane = self.add_pane(window, cx);
new_pane.update(cx, |pane, cx| {
pane.add_item(item, true, true, None, window, cx)
});
self.center.split(&pane, &new_pane, direction).unwrap();
cx.notify();
}
pub fn split_and_clone(
&mut self,
pane: Entity<Pane>,