@@ -1123,6 +1123,8 @@
"g g": "menu::SelectFirst",
"shift-g": "menu::SelectLast",
"/": "agents_sidebar::FocusSidebarFilter",
+ "d d": "agents_sidebar::RemoveSelected",
+ "o": "agents_sidebar::NewThreadInGroup",
"z a": "editor::ToggleFold",
"z c": "menu::SelectParent",
"z o": "menu::SelectChild",
@@ -54,6 +54,10 @@ gpui::actions!(
NewThreadInGroup,
/// Toggles between the thread list and the archive view.
ToggleArchive,
+ /// Closes the currently selected workspace.
+ RemoveSelectedWorkspace,
+ /// Removes the selected entry: archives a thread or closes a workspace.
+ RemoveSelected,
]
);
@@ -2453,6 +2457,43 @@ impl Sidebar {
self.archive_thread(&session_id, window, cx);
}
+ fn remove_selected_workspace(
+ &mut self,
+ _: &RemoveSelectedWorkspace,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ let Some(ix) = self.selection else {
+ return;
+ };
+ let Some(ListEntry::ProjectHeader { workspace, .. }) = self.contents.entries.get(ix)
+ else {
+ return;
+ };
+ let workspace = workspace.clone();
+ self.remove_workspace(&workspace, window, cx);
+ }
+
+ fn remove_selected(
+ &mut self,
+ _: &RemoveSelected,
+ window: &mut Window,
+ cx: &mut Context<Self>,
+ ) {
+ let Some(ix) = self.selection else {
+ return;
+ };
+ match self.contents.entries.get(ix) {
+ Some(ListEntry::Thread(_)) => {
+ self.remove_selected_thread(&RemoveSelectedThread, window, cx);
+ }
+ Some(ListEntry::ProjectHeader { .. }) => {
+ self.remove_selected_workspace(&RemoveSelectedWorkspace, window, cx);
+ }
+ _ => {}
+ }
+ }
+
fn render_thread(
&self,
ix: usize,
@@ -3160,6 +3201,8 @@ impl Render for Sidebar {
.on_action(cx.listener(Self::unfold_all))
.on_action(cx.listener(Self::cancel))
.on_action(cx.listener(Self::remove_selected_thread))
+ .on_action(cx.listener(Self::remove_selected_workspace))
+ .on_action(cx.listener(Self::remove_selected))
.on_action(cx.listener(Self::new_thread_in_group))
.on_action(cx.listener(Self::toggle_archive))
.on_action(cx.listener(Self::focus_sidebar_filter))
@@ -4730,12 +4730,36 @@ impl Workspace {
.as_ref()
.map(|h| Target::Sidebar(h.clone()));
+ let sidebar_on_left = self
+ .multi_workspace
+ .as_ref()
+ .and_then(|mw| mw.upgrade())
+ .map_or(true, |mw| mw.read(cx).sidebar_side(cx) == SidebarSide::Left);
+
+ let sidebar_on_side = |side: SplitDirection| -> Option<ActivateInDirectionTarget> {
+ if (side == SplitDirection::Left) == sidebar_on_left {
+ sidebar_target.clone()
+ } else {
+ None
+ }
+ };
+
let target = match (origin, direction) {
- // From the sidebar, only Right navigates into the workspace.
- (Origin::Sidebar, SplitDirection::Right) => try_dock(&self.left_dock)
- .or_else(|| get_last_active_pane().map(Target::Pane))
- .or_else(|| try_dock(&self.bottom_dock))
- .or_else(|| try_dock(&self.right_dock)),
+ // From the sidebar, only the inward direction navigates into
+ // the workspace. Which direction is "inward" depends on which
+ // side the sidebar is on.
+ (Origin::Sidebar, SplitDirection::Right) if sidebar_on_left => {
+ try_dock(&self.left_dock)
+ .or_else(|| get_last_active_pane().map(Target::Pane))
+ .or_else(|| try_dock(&self.bottom_dock))
+ .or_else(|| try_dock(&self.right_dock))
+ }
+ (Origin::Sidebar, SplitDirection::Left) if !sidebar_on_left => {
+ try_dock(&self.right_dock)
+ .or_else(|| get_last_active_pane().map(Target::Pane))
+ .or_else(|| try_dock(&self.bottom_dock))
+ .or_else(|| try_dock(&self.left_dock))
+ }
(Origin::Sidebar, _) => None,
@@ -4748,8 +4772,12 @@ impl Workspace {
match direction {
SplitDirection::Up => None,
SplitDirection::Down => try_dock(&self.bottom_dock),
- SplitDirection::Left => try_dock(&self.left_dock).or(sidebar_target),
- SplitDirection::Right => try_dock(&self.right_dock),
+ SplitDirection::Left => {
+ try_dock(&self.left_dock).or_else(|| sidebar_on_side(direction))
+ }
+ SplitDirection::Right => {
+ try_dock(&self.right_dock).or_else(|| sidebar_on_side(direction))
+ }
}
}
}
@@ -4762,27 +4790,29 @@ impl Workspace {
}
}
- (Origin::LeftDock, SplitDirection::Left) => sidebar_target,
+ (Origin::LeftDock, SplitDirection::Left) => sidebar_on_side(SplitDirection::Left),
(Origin::LeftDock, SplitDirection::Down)
| (Origin::RightDock, SplitDirection::Down) => try_dock(&self.bottom_dock),
(Origin::BottomDock, SplitDirection::Up) => get_last_active_pane().map(Target::Pane),
(Origin::BottomDock, SplitDirection::Left) => {
- try_dock(&self.left_dock).or(sidebar_target)
+ try_dock(&self.left_dock).or_else(|| sidebar_on_side(SplitDirection::Left))
+ }
+ (Origin::BottomDock, SplitDirection::Right) => {
+ try_dock(&self.right_dock).or_else(|| sidebar_on_side(SplitDirection::Right))
}
- (Origin::BottomDock, SplitDirection::Right) => try_dock(&self.right_dock),
(Origin::RightDock, SplitDirection::Left) => {
if let Some(last_active_pane) = get_last_active_pane() {
Some(Target::Pane(last_active_pane))
} else {
- try_dock(&self.bottom_dock)
- .or_else(|| try_dock(&self.left_dock))
- .or(sidebar_target)
+ try_dock(&self.bottom_dock).or_else(|| try_dock(&self.left_dock))
}
}
+ (Origin::RightDock, SplitDirection::Right) => sidebar_on_side(SplitDirection::Right),
+
_ => None,
};