Add ability to clone item when using workspace::MoveItemToPane
(#32895)
This PR adds an optional `clone: bool` argument to `workspace::MoveItemToPane` and `workspace::MoveItemToPaneInDirection` which causes the item to be cloned into the destination pane rather than moved. It provides similar functionality to `workbench.action.splitEditorToRightGroup` in vscode. This PR supercedes #25030. Closes #24889 Release Notes: - Add optional `clone: bool` (default: `false`) to `workspace::MoveItemToPane` and `workspace::MoveItemToPaneInDirection` which causes the item to be cloned into the destination pane rather than moved.
This commit is contained in:
parent
324cbecb74
commit
95f10fd187
1 changed files with 132 additions and 18 deletions
|
@ -222,6 +222,8 @@ pub struct MoveItemToPane {
|
|||
pub destination: usize,
|
||||
#[serde(default = "default_true")]
|
||||
pub focus: bool,
|
||||
#[serde(default)]
|
||||
pub clone: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize, PartialEq, JsonSchema)]
|
||||
|
@ -230,6 +232,8 @@ pub struct MoveItemToPaneInDirection {
|
|||
pub direction: SplitDirection,
|
||||
#[serde(default = "default_true")]
|
||||
pub focus: bool,
|
||||
#[serde(default)]
|
||||
pub clone: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Deserialize, JsonSchema)]
|
||||
|
@ -3355,7 +3359,7 @@ impl Workspace {
|
|||
let destination = match panes.get(action.destination) {
|
||||
Some(&destination) => destination.clone(),
|
||||
None => {
|
||||
if self.active_pane.read(cx).items_len() < 2 {
|
||||
if !action.clone && self.active_pane.read(cx).items_len() < 2 {
|
||||
return;
|
||||
}
|
||||
let direction = SplitDirection::Right;
|
||||
|
@ -3375,6 +3379,16 @@ impl Workspace {
|
|||
}
|
||||
};
|
||||
|
||||
if action.clone {
|
||||
clone_active_item(
|
||||
self.database_id(),
|
||||
&self.active_pane,
|
||||
&destination,
|
||||
action.focus,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
move_active_item(
|
||||
&self.active_pane,
|
||||
&destination,
|
||||
|
@ -3384,6 +3398,7 @@ impl Workspace {
|
|||
cx,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn activate_next_pane(&mut self, window: &mut Window, cx: &mut App) {
|
||||
let panes = self.center.panes();
|
||||
|
@ -3526,7 +3541,7 @@ impl Workspace {
|
|||
let destination = match self.find_pane_in_direction(action.direction, cx) {
|
||||
Some(destination) => destination,
|
||||
None => {
|
||||
if self.active_pane.read(cx).items_len() < 2 {
|
||||
if !action.clone && self.active_pane.read(cx).items_len() < 2 {
|
||||
return;
|
||||
}
|
||||
let new_pane = self.add_pane(window, cx);
|
||||
|
@ -3542,6 +3557,16 @@ impl Workspace {
|
|||
}
|
||||
};
|
||||
|
||||
if action.clone {
|
||||
clone_active_item(
|
||||
self.database_id(),
|
||||
&self.active_pane,
|
||||
&destination,
|
||||
action.focus,
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
move_active_item(
|
||||
&self.active_pane,
|
||||
&destination,
|
||||
|
@ -3551,6 +3576,7 @@ impl Workspace {
|
|||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bounding_box_for_pane(&self, pane: &Entity<Pane>) -> Option<Bounds<Pixels>> {
|
||||
self.center.bounding_box_for_pane(pane)
|
||||
|
@ -7631,6 +7657,35 @@ pub fn move_active_item(
|
|||
});
|
||||
}
|
||||
|
||||
pub fn clone_active_item(
|
||||
workspace_id: Option<WorkspaceId>,
|
||||
source: &Entity<Pane>,
|
||||
destination: &Entity<Pane>,
|
||||
focus_destination: bool,
|
||||
window: &mut Window,
|
||||
cx: &mut App,
|
||||
) {
|
||||
if source == destination {
|
||||
return;
|
||||
}
|
||||
let Some(active_item) = source.read(cx).active_item() else {
|
||||
return;
|
||||
};
|
||||
destination.update(cx, |target_pane, cx| {
|
||||
let Some(clone) = active_item.clone_on_split(workspace_id, window, cx) else {
|
||||
return;
|
||||
};
|
||||
target_pane.add_item(
|
||||
clone,
|
||||
focus_destination,
|
||||
focus_destination,
|
||||
Some(target_pane.items_len()),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct WorkspacePosition {
|
||||
pub window_bounds: Option<WindowBounds>,
|
||||
|
@ -9814,6 +9869,7 @@ mod tests {
|
|||
&MoveItemToPaneInDirection {
|
||||
direction: SplitDirection::Right,
|
||||
focus: true,
|
||||
clone: false,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
@ -9822,6 +9878,7 @@ mod tests {
|
|||
&MoveItemToPane {
|
||||
destination: 3,
|
||||
focus: true,
|
||||
clone: false,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
@ -9848,6 +9905,7 @@ mod tests {
|
|||
&MoveItemToPaneInDirection {
|
||||
direction: SplitDirection::Right,
|
||||
focus: true,
|
||||
clone: false,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
@ -9884,6 +9942,7 @@ mod tests {
|
|||
&MoveItemToPane {
|
||||
destination: 3,
|
||||
focus: true,
|
||||
clone: false,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
|
@ -9907,6 +9966,61 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_moving_items_can_clone_panes(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
let project = Project::test(fs, [], cx).await;
|
||||
let (workspace, cx) =
|
||||
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
|
||||
let item_1 = cx.new(|cx| {
|
||||
TestItem::new(cx).with_project_items(&[TestProjectItem::new(1, "first.txt", cx)])
|
||||
});
|
||||
workspace.update_in(cx, |workspace, window, cx| {
|
||||
workspace.add_item_to_active_pane(Box::new(item_1), None, true, window, cx);
|
||||
workspace.move_item_to_pane_in_direction(
|
||||
&MoveItemToPaneInDirection {
|
||||
direction: SplitDirection::Right,
|
||||
focus: true,
|
||||
clone: true,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
workspace.move_item_to_pane_at_index(
|
||||
&MoveItemToPane {
|
||||
destination: 3,
|
||||
focus: true,
|
||||
clone: true,
|
||||
},
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
|
||||
assert_eq!(workspace.panes.len(), 3, "Two new panes were created");
|
||||
for pane in workspace.panes() {
|
||||
assert_eq!(
|
||||
pane_items_paths(pane, cx),
|
||||
vec!["first.txt".to_string()],
|
||||
"Single item exists in all panes"
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// verify that the active pane has been updated after waiting for the
|
||||
// pane focus event to fire and resolve
|
||||
workspace.read_with(cx, |workspace, _app| {
|
||||
assert_eq!(
|
||||
workspace.active_pane(),
|
||||
&workspace.panes[2],
|
||||
"The third pane should be the active one: {:?}",
|
||||
workspace.panes
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
mod register_project_item_tests {
|
||||
|
||||
use super::*;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue