From 4e482288cb42fc998e6af18b87d643940c5fa3bf Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Tue, 16 Dec 2025 09:15:08 -0300 Subject: [PATCH] agent_ui: Add keybinding to cycle through profiles (#44979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Similar to the mode selector in external agents, it will now be possible to use `shift-tab` to cycle through profiles. Screenshot 2025-12-16 at 9  04@2x Release Notes: - Added the ability to use `shift-tab` to cycle through profiles for the built-in Zed agent. --- crates/agent_ui/src/acp/thread_view.rs | 6 ++- crates/agent_ui/src/profile_selector.rs | 56 +++++++++++++++++++++---- 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/crates/agent_ui/src/acp/thread_view.rs b/crates/agent_ui/src/acp/thread_view.rs index 6cd2ec2fa3442bbf4961dffb0c4538ac9615d982..bc449c3c3a0238a5989c52abec029a708bf9f0ba 100644 --- a/crates/agent_ui/src/acp/thread_view.rs +++ b/crates/agent_ui/src/acp/thread_view.rs @@ -4208,7 +4208,11 @@ impl AcpThreadView { } })) .on_action(cx.listener(|this, _: &CycleModeSelector, window, cx| { - if let Some(mode_selector) = this.mode_selector() { + if let Some(profile_selector) = this.profile_selector.as_ref() { + profile_selector.update(cx, |profile_selector, cx| { + profile_selector.cycle_profile(cx); + }); + } else if let Some(mode_selector) = this.mode_selector() { mode_selector.update(cx, |mode_selector, cx| { mode_selector.cycle_mode(window, cx); }); diff --git a/crates/agent_ui/src/profile_selector.rs b/crates/agent_ui/src/profile_selector.rs index 0182be0912d3b8a8a046371ce725e7d21a0ddb58..ac08070fcefa92854b51bc8a66d4d388d08e087d 100644 --- a/crates/agent_ui/src/profile_selector.rs +++ b/crates/agent_ui/src/profile_selector.rs @@ -1,4 +1,4 @@ -use crate::{ManageProfiles, ToggleProfileSelector}; +use crate::{CycleModeSelector, ManageProfiles, ToggleProfileSelector}; use agent_settings::{ AgentProfile, AgentProfileId, AgentSettings, AvailableProfiles, builtin_profiles, }; @@ -70,6 +70,29 @@ impl ProfileSelector { self.picker_handle.clone() } + pub fn cycle_profile(&mut self, cx: &mut Context) { + if !self.provider.profiles_supported(cx) { + return; + } + + let profiles = AgentProfile::available_profiles(cx); + if profiles.is_empty() { + return; + } + + let current_profile_id = self.provider.profile_id(cx); + let current_index = profiles + .keys() + .position(|id| id == ¤t_profile_id) + .unwrap_or(0); + + let next_index = (current_index + 1) % profiles.len(); + + if let Some((next_profile_id, _)) = profiles.get_index(next_index) { + self.provider.set_profile(next_profile_id.clone(), cx); + } + } + fn ensure_picker( &mut self, window: &mut Window, @@ -163,14 +186,29 @@ impl Render for ProfileSelector { PickerPopoverMenu::new( picker, trigger_button, - move |_window, cx| { - Tooltip::for_action_in( - "Toggle Profile Menu", - &ToggleProfileSelector, - &focus_handle, - cx, - ) - }, + Tooltip::element({ + move |_window, cx| { + let container = || h_flex().gap_1().justify_between(); + v_flex() + .gap_1() + .child( + container() + .pb_1() + .border_b_1() + .border_color(cx.theme().colors().border_variant) + .child(Label::new("Cycle Through Profiles")) + .child(KeyBinding::for_action_in( + &CycleModeSelector, + &focus_handle, + cx, + )), + ) + .child(container().child(Label::new("Toggle Profile Menu")).child( + KeyBinding::for_action_in(&ToggleProfileSelector, &focus_handle, cx), + )) + .into_any() + } + }), gpui::Corner::BottomRight, cx, )