From 782ca51c3674cb9f89b96b582007e1bfe31c0f77 Mon Sep 17 00:00:00 2001 From: Danilo Leal <67129314+danilo-leal@users.noreply.github.com> Date: Tue, 13 Jan 2026 14:36:40 -0300 Subject: [PATCH] debugger_ui: Make view in the new session picker keyboard navigable (#46662) This makes the new session picker in the Debugger panel consistent with the new unified Git picker (https://github.com/zed-industries/zed/pull/46621): https://github.com/user-attachments/assets/e94662da-31cc-48d8-b633-a6f0a2812569 Release Notes: - Debugger: Make possible to navigate with the keyboard between the views in the new session picker. --- assets/keymaps/default-linux.json | 9 + assets/keymaps/default-macos.json | 9 + assets/keymaps/default-windows.json | 9 + crates/debugger_ui/src/new_process_modal.rs | 199 +++++++++++++------- crates/zed/src/zed.rs | 1 + 5 files changed, 157 insertions(+), 70 deletions(-) diff --git a/assets/keymaps/default-linux.json b/assets/keymaps/default-linux.json index 1693f3262d1dc900a0b2746c08cd1744e1001404..1cbcdb03b480ffce43e34b382aab918a09c77eee 100644 --- a/assets/keymaps/default-linux.json +++ b/assets/keymaps/default-linux.json @@ -1340,6 +1340,15 @@ "ctrl-shift-i": "branch_picker::FilterRemotes", }, }, + { + "context": "RunModal", + "bindings": { + "alt-1": "new_process_modal::ActivateTaskTab", + "alt-2": "new_process_modal::ActivateDebugTab", + "alt-3": "new_process_modal::ActivateAttachTab", + "alt-4": "new_process_modal::ActivateLaunchTab", + }, + }, { "context": "GitPicker", "bindings": { diff --git a/assets/keymaps/default-macos.json b/assets/keymaps/default-macos.json index cfe13134ab282cb60db9e8bcde43227ff384be6f..9fb2c57c641a9bca9f11403cc67924feecba1b3d 100644 --- a/assets/keymaps/default-macos.json +++ b/assets/keymaps/default-macos.json @@ -1442,6 +1442,15 @@ "cmd-shift-i": "branch_picker::FilterRemotes", }, }, + { + "context": "RunModal", + "bindings": { + "cmd-1": "new_process_modal::ActivateTaskTab", + "cmd-2": "new_process_modal::ActivateDebugTab", + "cmd-3": "new_process_modal::ActivateAttachTab", + "cmd-4": "new_process_modal::ActivateLaunchTab", + }, + }, { "context": "GitPicker", "bindings": { diff --git a/assets/keymaps/default-windows.json b/assets/keymaps/default-windows.json index 2fbf8c51f03048dfa89bb90b282dbd32dfc52366..d13dcfdd6d6c5e75e96424a596e7be5e89dc0c46 100644 --- a/assets/keymaps/default-windows.json +++ b/assets/keymaps/default-windows.json @@ -1361,6 +1361,15 @@ "ctrl-shift-i": "branch_picker::FilterRemotes", }, }, + { + "context": "RunModal", + "bindings": { + "alt-1": "new_process_modal::ActivateTaskTab", + "alt-2": "new_process_modal::ActivateDebugTab", + "alt-3": "new_process_modal::ActivateAttachTab", + "alt-4": "new_process_modal::ActivateLaunchTab", + }, + }, { "context": "GitPicker", "bindings": { diff --git a/crates/debugger_ui/src/new_process_modal.rs b/crates/debugger_ui/src/new_process_modal.rs index 1ea8bcca76eac61702acd9c31b703bf33383d552..862242a3d4fbc16b83f7424c4ccbe2927222424e 100644 --- a/crates/debugger_ui/src/new_process_modal.rs +++ b/crates/debugger_ui/src/new_process_modal.rs @@ -16,16 +16,16 @@ use editor::Editor; use fuzzy::{StringMatch, StringMatchCandidate}; use gpui::{ Action, App, AppContext, DismissEvent, Entity, EventEmitter, FocusHandle, Focusable, - KeyContext, Render, Subscription, Task, WeakEntity, + KeyContext, Render, Subscription, Task, WeakEntity, actions, }; use itertools::Itertools as _; use picker::{Picker, PickerDelegate, highlighted_match_with_paths::HighlightedMatch}; use project::{DebugScenarioContext, Project, TaskContexts, TaskSourceKind, task_store::TaskStore}; use task::{DebugScenario, RevealTarget, VariableName, ZedDebugConfig}; use ui::{ - ContextMenu, DropdownMenu, FluentBuilder, IconWithIndicator, Indicator, KeyBinding, ListItem, - ListItemSpacing, Switch, SwitchLabelPosition, ToggleButtonGroup, ToggleButtonSimple, - ToggleState, Tooltip, prelude::*, + ContextMenu, DropdownMenu, IconWithIndicator, Indicator, KeyBinding, ListItem, ListItemSpacing, + Switch, SwitchLabelPosition, ToggleButtonGroup, ToggleButtonSimple, ToggleState, Tooltip, + prelude::*, }; use ui_input::InputField; use util::{ResultExt, debug_panic, rel_path::RelPath, shell::ShellKind}; @@ -36,6 +36,16 @@ use crate::{ debugger_panel::DebugPanel, }; +actions!( + new_process_modal, + [ + ActivateTaskTab, + ActivateDebugTab, + ActivateAttachTab, + ActivateLaunchTab + ] +); + pub(super) struct NewProcessModal { workspace: WeakEntity, debug_panel: WeakEntity, @@ -547,11 +557,13 @@ impl Focusable for NewProcessMode { } impl Render for NewProcessModal { - fn render( - &mut self, - window: &mut ui::Window, - cx: &mut ui::Context, - ) -> impl ui::IntoElement { + fn render(&mut self, window: &mut Window, cx: &mut Context) -> impl IntoElement { + let focus_handle = self.mode_focus_handle(cx); + let task_focus_handle = focus_handle.clone(); + let debug_focus_handle = focus_handle.clone(); + let attach_focus_handle = focus_handle.clone(); + let launch_focus_handle = focus_handle; + v_flex() .key_context({ let mut key_context = KeyContext::new_with_defaults(); @@ -588,72 +600,119 @@ impl Render for NewProcessModal { this.mode_focus_handle(cx).focus(window, cx); }), ) + .on_action(cx.listener(|this, _: &ActivateTaskTab, window, cx| { + this.mode = NewProcessMode::Task; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + })) + .on_action(cx.listener(|this, _: &ActivateDebugTab, window, cx| { + this.mode = NewProcessMode::Debug; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + })) + .on_action(cx.listener(|this, _: &ActivateAttachTab, window, cx| { + this.mode = NewProcessMode::Attach; + if let Some(debugger) = this.debugger.as_ref() { + Self::update_attach_picker(&this.attach_mode, debugger, window, cx); + } + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + })) + .on_action(cx.listener(|this, _: &ActivateLaunchTab, window, cx| { + this.mode = NewProcessMode::Launch; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + })) .child( - h_flex() - .p_2() - .w_full() - .border_b_1() - .border_color(cx.theme().colors().border_variant) - .child( - ToggleButtonGroup::single_row( - "debugger-mode-buttons", - [ - ToggleButtonSimple::new( - NewProcessMode::Task.to_string(), - cx.listener(|this, _, window, cx| { - this.mode = NewProcessMode::Task; - this.mode_focus_handle(cx).focus(window, cx); - cx.notify(); - }), + h_flex().p_2().pb_0p5().w_full().child( + ToggleButtonGroup::single_row( + "debugger-mode-buttons", + [ + ToggleButtonSimple::new( + NewProcessMode::Task.to_string(), + cx.listener(|this, _, window, cx| { + this.mode = NewProcessMode::Task; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + }), + ) + .tooltip(move |_, cx| { + Tooltip::for_action_in( + "Run predefined task", + &ActivateTaskTab, + &task_focus_handle, + cx, ) - .tooltip(Tooltip::text("Run predefined task")), - ToggleButtonSimple::new( - NewProcessMode::Debug.to_string(), - cx.listener(|this, _, window, cx| { - this.mode = NewProcessMode::Debug; - this.mode_focus_handle(cx).focus(window, cx); - cx.notify(); - }), + }), + ToggleButtonSimple::new( + NewProcessMode::Debug.to_string(), + cx.listener(|this, _, window, cx| { + this.mode = NewProcessMode::Debug; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + }), + ) + .tooltip(move |_, cx| { + Tooltip::for_action_in( + "Start a predefined debug scenario", + &ActivateDebugTab, + &debug_focus_handle, + cx, ) - .tooltip(Tooltip::text("Start a predefined debug scenario")), - ToggleButtonSimple::new( - NewProcessMode::Attach.to_string(), - cx.listener(|this, _, window, cx| { - this.mode = NewProcessMode::Attach; - - if let Some(debugger) = this.debugger.as_ref() { - Self::update_attach_picker( - &this.attach_mode, - debugger, - window, - cx, - ); - } - this.mode_focus_handle(cx).focus(window, cx); - cx.notify(); - }), + }), + ToggleButtonSimple::new( + NewProcessMode::Attach.to_string(), + cx.listener(|this, _, window, cx| { + this.mode = NewProcessMode::Attach; + + if let Some(debugger) = this.debugger.as_ref() { + Self::update_attach_picker( + &this.attach_mode, + debugger, + window, + cx, + ); + } + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + }), + ) + .tooltip(move |_, cx| { + Tooltip::for_action_in( + "Attach the debugger to a running process", + &ActivateAttachTab, + &attach_focus_handle, + cx, ) - .tooltip(Tooltip::text("Attach the debugger to a running process")), - ToggleButtonSimple::new( - NewProcessMode::Launch.to_string(), - cx.listener(|this, _, window, cx| { - this.mode = NewProcessMode::Launch; - this.mode_focus_handle(cx).focus(window, cx); - cx.notify(); - }), + }), + ToggleButtonSimple::new( + NewProcessMode::Launch.to_string(), + cx.listener(|this, _, window, cx| { + this.mode = NewProcessMode::Launch; + this.mode_focus_handle(cx).focus(window, cx); + cx.notify(); + }), + ) + .tooltip(move |_, cx| { + Tooltip::for_action_in( + "Launch a new process with a debugger", + &ActivateLaunchTab, + &launch_focus_handle, + cx, ) - .tooltip(Tooltip::text("Launch a new process with a debugger")), - ], - ) - .label_size(LabelSize::Default) - .auto_width() - .selected_index(match self.mode { - NewProcessMode::Task => 0, - NewProcessMode::Debug => 1, - NewProcessMode::Attach => 2, - NewProcessMode::Launch => 3, - }), - ), + }), + ], + ) + .style(ui::ToggleButtonGroupStyle::Outlined) + .label_size(LabelSize::Default) + .auto_width() + .selected_index(match self.mode { + NewProcessMode::Task => 0, + NewProcessMode::Debug => 1, + NewProcessMode::Attach => 2, + NewProcessMode::Launch => 3, + }), + ), ) .child(v_flex().child(self.render_mode(window, cx))) .map(|el| { diff --git a/crates/zed/src/zed.rs b/crates/zed/src/zed.rs index cb68a9616eea27a9654abc18efea17484e88eaa2..7ebb2781ace473a4c3b212cdd3f55bf607f4cf9b 100644 --- a/crates/zed/src/zed.rs +++ b/crates/zed/src/zed.rs @@ -4750,6 +4750,7 @@ mod tests { "lsp_tool", "markdown", "menu", + "new_process_modal", "notebook", "notification_panel", "onboarding",