debugger: Add a couple more keybindings (#31103)

Cole Miller created

- Add missing handler for `debugger::Continue` so `f5` works
- Add bindings based on VS Code for `debugger::Restart` and
`debug_panel::ToggleFocus`
- Remove breakpoint-related buttons from the debug panel's top strip,
and surface the bindings for `editor::ToggleBreakpoint` in gutter
tooltip instead

Release Notes:

- Debugger Beta: Added keybindings for `debugger::Continue`,
`debugger::Restart`, and `debug_panel::ToggleFocus`.
- Debugger Beta: Removed breakpoint-related buttons from the top of the
debug panel.
- Compatibility note: on Linux, `ctrl-shift-d` is now bound to
`debug_panel::ToggleFocus` by default, instead of
`editor::DuplicateLineDown`.

Change summary

assets/keymaps/default-linux.json        |  3 +
assets/keymaps/default-macos.json        |  2 +
crates/debugger_ui/src/debugger_panel.rs | 49 --------------------------
crates/debugger_ui/src/debugger_ui.rs    | 11 +++++
crates/editor/src/editor.rs              | 29 +++++++++------
5 files changed, 32 insertions(+), 62 deletions(-)

Detailed changes

assets/keymaps/default-linux.json 🔗

@@ -33,6 +33,7 @@
       "f4": "debugger::Start",
       "f5": "debugger::Continue",
       "shift-f5": "debugger::Stop",
+      "ctrl-shift-f5": "debugger::Restart",
       "f6": "debugger::Pause",
       "f7": "debugger::StepOver",
       "cmd-f11": "debugger::StepInto",
@@ -558,6 +559,7 @@
       "ctrl-shift-e": "project_panel::ToggleFocus",
       "ctrl-shift-b": "outline_panel::ToggleFocus",
       "ctrl-shift-g": "git_panel::ToggleFocus",
+      "ctrl-shift-d": "debug_panel::ToggleFocus",
       "ctrl-?": "agent::ToggleFocus",
       "alt-save": "workspace::SaveAll",
       "ctrl-alt-s": "workspace::SaveAll",
@@ -595,7 +597,6 @@
   {
     "context": "Editor",
     "bindings": {
-      "ctrl-shift-d": "editor::DuplicateLineDown",
       "ctrl-shift-j": "editor::JoinLines",
       "ctrl-alt-backspace": "editor::DeleteToPreviousSubwordStart",
       "ctrl-alt-h": "editor::DeleteToPreviousSubwordStart",

assets/keymaps/default-macos.json 🔗

@@ -17,6 +17,7 @@
       "f4": "debugger::Start",
       "f5": "debugger::Continue",
       "shift-f5": "debugger::Stop",
+      "shift-cmd-f5": "debugger::Restart",
       "f6": "debugger::Pause",
       "f7": "debugger::StepOver",
       "f11": "debugger::StepInto",
@@ -624,6 +625,7 @@
       "cmd-shift-e": "project_panel::ToggleFocus",
       "cmd-shift-b": "outline_panel::ToggleFocus",
       "ctrl-shift-g": "git_panel::ToggleFocus",
+      "cmd-shift-d": "debug_panel::ToggleFocus",
       "cmd-?": "agent::ToggleFocus",
       "cmd-alt-s": "workspace::SaveAll",
       "cmd-k m": "language_selector::Toggle",

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -752,55 +752,6 @@ impl DebugPanel {
                                         }),
                                     )
                                     .child(Divider::vertical())
-                                    .child(
-                                        IconButton::new(
-                                            "debug-enable-breakpoint",
-                                            IconName::DebugDisabledBreakpoint,
-                                        )
-                                        .icon_size(IconSize::XSmall)
-                                        .shape(ui::IconButtonShape::Square)
-                                        .disabled(thread_status != ThreadStatus::Stopped),
-                                    )
-                                    .child(
-                                        IconButton::new(
-                                            "debug-disable-breakpoint",
-                                            IconName::CircleOff,
-                                        )
-                                        .icon_size(IconSize::XSmall)
-                                        .shape(ui::IconButtonShape::Square)
-                                        .disabled(thread_status != ThreadStatus::Stopped),
-                                    )
-                                    .child(
-                                        IconButton::new(
-                                            "debug-disable-all-breakpoints",
-                                            IconName::BugOff,
-                                        )
-                                        .icon_size(IconSize::XSmall)
-                                        .shape(ui::IconButtonShape::Square)
-                                        .disabled(
-                                            thread_status == ThreadStatus::Exited
-                                                || thread_status == ThreadStatus::Ended,
-                                        )
-                                        .on_click(window.listener_for(
-                                            &running_state,
-                                            |this, _, _window, cx| {
-                                                this.toggle_ignore_breakpoints(cx);
-                                            },
-                                        ))
-                                        .tooltip({
-                                            let focus_handle = focus_handle.clone();
-                                            move |window, cx| {
-                                                Tooltip::for_action_in(
-                                                    "Disable all breakpoints",
-                                                    &ToggleIgnoreBreakpoints,
-                                                    &focus_handle,
-                                                    window,
-                                                    cx,
-                                                )
-                                            }
-                                        }),
-                                    )
-                                    .child(Divider::vertical())
                                     .child(
                                         IconButton::new("debug-restart", IconName::DebugRestart)
                                             .icon_size(IconSize::XSmall)

crates/debugger_ui/src/debugger_ui.rs 🔗

@@ -95,6 +95,17 @@ pub fn init(cx: &mut App) {
                         }
                     }
                 })
+                .register_action(|workspace, _: &Continue, _, cx| {
+                    if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
+                        if let Some(active_item) = debug_panel.read_with(cx, |panel, cx| {
+                            panel
+                                .active_session()
+                                .map(|session| session.read(cx).running_state().clone())
+                        }) {
+                            active_item.update(cx, |item, cx| item.continue_thread(cx))
+                        }
+                    }
+                })
                 .register_action(|workspace, _: &StepInto, _, cx| {
                     if let Some(debug_panel) = workspace.panel::<DebugPanel>(cx) {
                         if let Some(active_item) = debug_panel.read_with(cx, |panel, cx| {

crates/editor/src/editor.rs 🔗

@@ -7266,24 +7266,22 @@ impl Editor {
             ..Default::default()
         };
         let primary_action_text = if breakpoint.is_disabled() {
-            "enable"
+            "Enable breakpoint"
         } else if is_phantom && !collides_with_existing {
-            "set"
+            "Set breakpoint"
         } else {
-            "unset"
+            "Unset breakpoint"
         };
-        let mut primary_text = format!("Click to {primary_action_text}");
-        if collides_with_existing && !breakpoint.is_disabled() {
-            use std::fmt::Write;
-            write!(primary_text, ", {alt_as_text}-click to disable").ok();
-        }
-        let primary_text = SharedString::from(primary_text);
         let focus_handle = self.focus_handle.clone();
 
         let meta = if is_rejected {
-            "No executable code is associated with this line."
+            SharedString::from("No executable code is associated with this line.")
+        } else if collides_with_existing && !breakpoint.is_disabled() {
+            SharedString::from(format!(
+                "{alt_as_text}-click to disable,\nright-click for more options."
+            ))
         } else {
-            "Right-click for more options."
+            SharedString::from("Right-click for more options.")
         };
         IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
             .icon_size(IconSize::XSmall)
@@ -7322,7 +7320,14 @@ impl Editor {
                 );
             }))
             .tooltip(move |window, cx| {
-                Tooltip::with_meta_in(primary_text.clone(), None, meta, &focus_handle, window, cx)
+                Tooltip::with_meta_in(
+                    primary_action_text,
+                    Some(&ToggleBreakpoint),
+                    meta.clone(),
+                    &focus_handle,
+                    window,
+                    cx,
+                )
             })
     }