From f445f22fe6cba11579804c3bf4913d6212f2be36 Mon Sep 17 00:00:00 2001 From: Josh Piasecki <138541977+FloppyDisco@users.noreply.github.com> Date: Mon, 1 Dec 2025 23:01:11 -0600 Subject: [PATCH] Add an action listener to workspace for ActivatePreviousItem and ActivateNextItem (#42588) Release Notes: - pane::ActivatePreviousItem and pane::ActivateNextItem now toggle the most recent pane when called from a dock panel a couple months ago i posted a work around that used `SendKeystrokes` to cycle through pane items when focused on a dock. #35253 this pr would add this functionality to the these actions by default. i implemented this by adding an action listener to the workspace level. ------ if the current context is a dock that does not hold a pane it retrieves the most recent pane from `activation_history` and activates the next item on that pane instead. - `"Pane > Editor"` cycles through the current pane like normal - `"Dock > Pane > Terminal"` also cycles through the pane items like normal - `"Dock > (Any Child that is not a child of Pane)"` cycles through the items of the most recent pane. this is the standard behavior in VS Code i believe. in the video below you can see the actions cycling through the editor like normal when focus is on the editor. then you can see the editor continue to cycle when the focus is on the project panel. and that the focus stays on the project panel. and you can see the action cycle the terminal items when the focus is moved to the terminal https://github.com/user-attachments/assets/999ab740-d2fa-4d00-9e53-f7605217e6ac the only thing i noticed is that for this to work the keybindings must be set above `Pane` so they have to be set globally or on workspace. otherwise they do not match in the context --- crates/workspace/src/workspace.rs | 82 +++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/crates/workspace/src/workspace.rs b/crates/workspace/src/workspace.rs index cf102fc16109555971defbdc279e89738582ab74..aa100550749142b94df034195385c31dd54dbba3 100644 --- a/crates/workspace/src/workspace.rs +++ b/crates/workspace/src/workspace.rs @@ -5967,6 +5967,88 @@ impl Workspace { }, )) .on_action(cx.listener(Workspace::toggle_centered_layout)) + .on_action(cx.listener( + |workspace: &mut Workspace, _action: &pane::ActivateNextItem, window, cx| { + if let Some(active_dock) = workspace.active_dock(window, cx) { + let dock = active_dock.read(cx); + if let Some(active_panel) = dock.active_panel() { + if active_panel.pane(cx).is_none() { + let mut recent_pane: Option> = None; + let mut recent_timestamp = 0; + for pane_handle in workspace.panes() { + let pane = pane_handle.read(cx); + for entry in pane.activation_history() { + if entry.timestamp > recent_timestamp { + recent_timestamp = entry.timestamp; + recent_pane = Some(pane_handle.clone()); + } + } + } + + if let Some(pane) = recent_pane { + pane.update(cx, |pane, cx| { + let current_index = pane.active_item_index(); + let items_len = pane.items_len(); + if items_len > 0 { + let next_index = if current_index + 1 < items_len { + current_index + 1 + } else { + 0 + }; + pane.activate_item( + next_index, false, false, window, cx, + ); + } + }); + return; + } + } + } + } + cx.propagate(); + }, + )) + .on_action(cx.listener( + |workspace: &mut Workspace, _action: &pane::ActivatePreviousItem, window, cx| { + if let Some(active_dock) = workspace.active_dock(window, cx) { + let dock = active_dock.read(cx); + if let Some(active_panel) = dock.active_panel() { + if active_panel.pane(cx).is_none() { + let mut recent_pane: Option> = None; + let mut recent_timestamp = 0; + for pane_handle in workspace.panes() { + let pane = pane_handle.read(cx); + for entry in pane.activation_history() { + if entry.timestamp > recent_timestamp { + recent_timestamp = entry.timestamp; + recent_pane = Some(pane_handle.clone()); + } + } + } + + if let Some(pane) = recent_pane { + pane.update(cx, |pane, cx| { + let current_index = pane.active_item_index(); + let items_len = pane.items_len(); + if items_len > 0 { + let prev_index = if current_index > 0 { + current_index - 1 + } else { + items_len.saturating_sub(1) + }; + pane.activate_item( + prev_index, false, false, window, cx, + ); + } + }); + return; + } + } + } + } + cx.propagate(); + }, + )) .on_action(cx.listener(Workspace::cancel)) }