debugger: Fix breakpoint color only updating when mouse moves (#46427)
The other day I was testing the debugging feature and I noticed a **very** small visual bug. When you click on the breakpoint circle to set a breakpoint, the breakpoint color remains in the wrong state until the mouse moves. After debugging for a while, I noticed that the issue was that the PhantomVariableIndicator variable attribute `collides_with_existing_breakpoint` was not being updated until the mouse moved. With the following change, the attribute is updated when the user clicks the breakpoint, toggleling tha attribute. ### Prior behaviour: https://github.com/user-attachments/assets/3dfa8e25-e970-49a3-8e87-0ecadabb3a3c As you can see in the video, prior to this change, the breakpoint would only change to the correct color when the mouse moved. ### New behaviour https://github.com/user-attachments/assets/356e84dc-42e5-4440-afab-0fbc4b3a1f0a With this new change, the breakpoint updates right after the user clicks, no need to move the mouse. ### Disclaimers - I'm new to this codebase, so any feedback is extremely welcomed! If you know of a better place where this could be handled, let me know and I'll explore further. https://github.com/user-attachments/assets/12d4b9df-e5d7-4955-b58d-dd63563c5c1b Release Notes: - N/A --------- Co-authored-by: Anthony Eid <anthony@zed.dev>
This commit is contained in:
1 parent
87dff2a1db
commit
1fe80040b1
2 files changed
+130
No files matched your search
@@ -8984,6 +8984,7 @@ impl Editor {
|
||||
};
|
||||
|
||||
window.focus(&editor.focus_handle(cx), cx);
|
||||
editor.update_breakpoint_collision_on_toggle(row, &edit_action);
|
||||
editor.edit_breakpoint_at_anchor(
|
||||
position,
|
||||
breakpoint.as_ref().clone(),
|
||||
@@ -11847,7 +11848,19 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
|
||||
if self.gutter_breakpoint_indicator.0.is_some() {
|
||||
let display_row = anchor
|
||||
.to_point(snapshot.buffer_snapshot())
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
self.update_breakpoint_collision_on_toggle(
|
||||
display_row,
|
||||
&BreakpointEditAction::Toggle,
|
||||
);
|
||||
}
|
||||
|
||||
if let Some(breakpoint) = breakpoint {
|
||||
self.edit_breakpoint_at_anchor(
|
||||
anchor,
|
||||
@@ -11866,6 +11879,21 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn update_breakpoint_collision_on_toggle(
|
||||
&mut self,
|
||||
display_row: DisplayRow,
|
||||
edit_action: &BreakpointEditAction,
|
||||
) {
|
||||
if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
|
||||
if breakpoint_indicator.display_row == display_row
|
||||
&& matches!(edit_action, BreakpointEditAction::Toggle)
|
||||
{
|
||||
breakpoint_indicator.collides_with_existing_breakpoint =
|
||||
!breakpoint_indicator.collides_with_existing_breakpoint;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn edit_breakpoint_at_anchor(
|
||||
&mut self,
|
||||
breakpoint_position: Anchor,
|
||||
|
||||
@@ -24836,6 +24836,108 @@ async fn test_breakpoint_enabling_and_disabling(cx: &mut TestAppContext) {
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_breakpoint_phantom_indicator_collision_on_toggle(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let sample_text = "First line\nSecond line\nThird line\nFourth line".to_string();
|
||||
let fs = FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/a"),
|
||||
json!({
|
||||
"main.rs": sample_text,
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
let project = Project::test(fs, [path!("/a").as_ref()], cx).await;
|
||||
let workspace = cx.add_window(|window, cx| Workspace::test_new(project.clone(), window, cx));
|
||||
let cx = &mut VisualTestContext::from_window(*workspace.deref(), cx);
|
||||
let worktree_id = workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
workspace.project().update(cx, |project, cx| {
|
||||
project.worktrees(cx).next().unwrap().read(cx).id()
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let buffer = project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_buffer((worktree_id, rel_path("main.rs")), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let (editor, cx) = cx.add_window_view(|window, cx| {
|
||||
Editor::new(
|
||||
EditorMode::full(),
|
||||
MultiBuffer::build_from_buffer(buffer, cx),
|
||||
Some(project.clone()),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
// Simulate hovering over row 0 with no existing breakpoint.
|
||||
editor.update(cx, |editor, _cx| {
|
||||
editor.gutter_breakpoint_indicator.0 = Some(PhantomBreakpointIndicator {
|
||||
display_row: DisplayRow(0),
|
||||
is_active: true,
|
||||
collides_with_existing_breakpoint: false,
|
||||
});
|
||||
});
|
||||
|
||||
// Toggle breakpoint on the same row (row 0) — collision should flip to true.
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
|
||||
});
|
||||
editor.update(cx, |editor, _cx| {
|
||||
let indicator = editor.gutter_breakpoint_indicator.0.unwrap();
|
||||
assert!(
|
||||
indicator.collides_with_existing_breakpoint,
|
||||
"Adding a breakpoint on the hovered row should set collision to true"
|
||||
);
|
||||
});
|
||||
|
||||
// Toggle again on the same row — breakpoint is removed, collision should flip back to false.
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
|
||||
});
|
||||
editor.update(cx, |editor, _cx| {
|
||||
let indicator = editor.gutter_breakpoint_indicator.0.unwrap();
|
||||
assert!(
|
||||
!indicator.collides_with_existing_breakpoint,
|
||||
"Removing a breakpoint on the hovered row should set collision to false"
|
||||
);
|
||||
});
|
||||
|
||||
// Now move cursor to row 2 while phantom indicator stays on row 0.
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.move_down(&MoveDown, window, cx);
|
||||
editor.move_down(&MoveDown, window, cx);
|
||||
});
|
||||
|
||||
// Ensure phantom indicator is still on row 0, not colliding.
|
||||
editor.update(cx, |editor, _cx| {
|
||||
editor.gutter_breakpoint_indicator.0 = Some(PhantomBreakpointIndicator {
|
||||
display_row: DisplayRow(0),
|
||||
is_active: true,
|
||||
collides_with_existing_breakpoint: false,
|
||||
});
|
||||
});
|
||||
|
||||
// Toggle breakpoint on row 2 (cursor row) — phantom on row 0 should NOT be affected.
|
||||
editor.update_in(cx, |editor, window, cx| {
|
||||
editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
|
||||
});
|
||||
editor.update(cx, |editor, _cx| {
|
||||
let indicator = editor.gutter_breakpoint_indicator.0.unwrap();
|
||||
assert!(
|
||||
!indicator.collides_with_existing_breakpoint,
|
||||
"Toggling a breakpoint on a different row should not affect the phantom indicator"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_rename_with_duplicate_edits(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
Reference in new issue
Block a user