Workspace move editor actions (#21760)

Closes #20205

Release Notes:

- Added `MoveItemToPane` and `MoveItemToPaneInDirection` actions

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
This commit is contained in:
Ignat S. 2024-12-17 14:39:36 +03:00 committed by GitHub
parent 9082a006d6
commit e1bc48c554
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 150 additions and 20 deletions

View file

@ -93,7 +93,7 @@ use theme::{ActiveTheme, SystemAppearance, ThemeSettings};
pub use toolbar::{Toolbar, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView};
pub use ui;
use ui::prelude::*;
use util::{paths::SanitizedPath, ResultExt, TryFutureExt};
use util::{paths::SanitizedPath, serde::default_true, ResultExt, TryFutureExt};
use uuid::Uuid;
pub use workspace_settings::{
AutosaveSetting, RestoreOnStartupBehavior, TabBarSettings, WorkspaceSettings,
@ -173,6 +173,20 @@ pub struct ActivatePaneInDirection(pub SplitDirection);
#[derive(Clone, Deserialize, PartialEq)]
pub struct SwapPaneInDirection(pub SplitDirection);
#[derive(Clone, Deserialize, PartialEq)]
pub struct MoveItemToPane {
pub destination: usize,
#[serde(default = "default_true")]
pub focus: bool,
}
#[derive(Clone, Deserialize, PartialEq)]
pub struct MoveItemToPaneInDirection {
pub direction: SplitDirection,
#[serde(default = "default_true")]
pub focus: bool,
}
#[derive(Clone, PartialEq, Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SaveAll {
@ -222,6 +236,8 @@ impl_actions!(
ActivatePaneInDirection,
CloseAllItemsAndPanes,
CloseInactiveTabsAndPanes,
MoveItemToPane,
MoveItemToPaneInDirection,
OpenTerminal,
Reload,
Save,
@ -2829,6 +2845,13 @@ impl Workspace {
}
}
fn move_item_to_pane_at_index(&mut self, action: &MoveItemToPane, cx: &mut ViewContext<Self>) {
let Some(&target_pane) = self.center.panes().get(action.destination) else {
return;
};
move_active_item(&self.active_pane, target_pane, action.focus, true, cx);
}
pub fn activate_next_pane(&mut self, cx: &mut WindowContext) {
let panes = self.center.panes();
if let Some(ix) = panes.iter().position(|pane| **pane == self.active_pane) {
@ -2947,6 +2970,16 @@ impl Workspace {
}
}
pub fn move_item_to_pane_in_direction(
&mut self,
action: &MoveItemToPaneInDirection,
cx: &mut WindowContext,
) {
if let Some(destination) = self.find_pane_in_direction(action.direction, cx) {
move_active_item(&self.active_pane, &destination, action.focus, true, cx);
}
}
pub fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
self.center.bounding_box_for_pane(pane)
}
@ -2967,14 +3000,14 @@ impl Workspace {
cx: &mut ViewContext<Self>,
) {
if let Some(to) = self.find_pane_in_direction(direction, cx) {
self.center.swap(&self.active_pane.clone(), &to);
self.center.swap(&self.active_pane, &to);
cx.notify();
}
}
pub fn resize_pane(&mut self, axis: gpui::Axis, amount: Pixels, cx: &mut ViewContext<Self>) {
self.center
.resize(&self.active_pane.clone(), axis, amount, &self.bounds);
.resize(&self.active_pane, axis, amount, &self.bounds);
cx.notify();
}
@ -4408,6 +4441,7 @@ impl Workspace {
.on_action(cx.listener(Self::follow_next_collaborator))
.on_action(cx.listener(Self::close_window))
.on_action(cx.listener(Self::activate_pane_at_index))
.on_action(cx.listener(Self::move_item_to_pane_at_index))
.on_action(cx.listener(|workspace, _: &Unfollow, cx| {
let pane = workspace.active_pane().clone();
workspace.unfollow_in_pane(&pane, cx);
@ -4438,6 +4472,11 @@ impl Workspace {
workspace.activate_pane_in_direction(action.0, cx)
}),
)
.on_action(
cx.listener(|workspace, action: &MoveItemToPaneInDirection, cx| {
workspace.move_item_to_pane_in_direction(action, cx)
}),
)
.on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| {
workspace.swap_pane_in_direction(action.0, cx)
}))
@ -6181,6 +6220,34 @@ pub fn move_item(
});
}
pub fn move_active_item(
source: &View<Pane>,
destination: &View<Pane>,
focus_destination: bool,
close_if_empty: bool,
cx: &mut WindowContext<'_>,
) {
if source == destination {
return;
}
let Some(active_item) = source.read(cx).active_item() else {
return;
};
source.update(cx, |source_pane, cx| {
let item_id = active_item.item_id();
source_pane.remove_item(item_id, false, close_if_empty, cx);
destination.update(cx, |target_pane, cx| {
target_pane.add_item(
active_item,
focus_destination,
focus_destination,
Some(target_pane.items_len()),
cx,
);
});
});
}
#[cfg(test)]
mod tests {
use std::{cell::RefCell, rc::Rc};