debugger: Add support for setting multiple breakpoints via actions (#28437)
Allow setting multiple breakpoints with multi cursors Release Notes: - N/A --------- Co-authored-by: Anthony Eid <hello@anthonyeid.me> Co-authored-by: Remco Smits <djsmits12@gmail.com> Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
parent
5757e352b0
commit
c35238bd72
2 changed files with 93 additions and 64 deletions
|
@ -8854,15 +8854,6 @@ impl Editor {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn breakpoint_at_cursor_head(
|
|
||||||
&self,
|
|
||||||
window: &mut Window,
|
|
||||||
cx: &mut Context<Self>,
|
|
||||||
) -> Option<(Anchor, Breakpoint)> {
|
|
||||||
let cursor_position: Point = self.selections.newest(cx).head();
|
|
||||||
self.breakpoint_at_row(cursor_position.row, window, cx)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn breakpoint_at_row(
|
pub(crate) fn breakpoint_at_row(
|
||||||
&self,
|
&self,
|
||||||
row: u32,
|
row: u32,
|
||||||
|
@ -8872,6 +8863,15 @@ impl Editor {
|
||||||
let snapshot = self.snapshot(window, cx);
|
let snapshot = self.snapshot(window, cx);
|
||||||
let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
|
let breakpoint_position = snapshot.buffer_snapshot.anchor_before(Point::new(row, 0));
|
||||||
|
|
||||||
|
self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn breakpoint_at_anchor(
|
||||||
|
&self,
|
||||||
|
breakpoint_position: Anchor,
|
||||||
|
snapshot: &EditorSnapshot,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Option<(Anchor, Breakpoint)> {
|
||||||
let project = self.project.clone()?;
|
let project = self.project.clone()?;
|
||||||
|
|
||||||
let buffer_id = breakpoint_position.buffer_id.or_else(|| {
|
let buffer_id = breakpoint_position.buffer_id.or_else(|| {
|
||||||
|
@ -8929,29 +8929,51 @@ impl Editor {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
let (anchor, bp) = self
|
for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
|
||||||
.breakpoint_at_cursor_head(window, cx)
|
let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
|
||||||
.unwrap_or_else(|| {
|
message: None,
|
||||||
let cursor_position: Point = self.selections.newest(cx).head();
|
state: BreakpointState::Enabled,
|
||||||
|
condition: None,
|
||||||
|
hit_condition: None,
|
||||||
|
});
|
||||||
|
|
||||||
let breakpoint_position = self
|
self.add_edit_breakpoint_block(
|
||||||
.snapshot(window, cx)
|
anchor,
|
||||||
|
&breakpoint,
|
||||||
|
BreakpointPromptEditAction::Log,
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn breakpoints_at_cursors(
|
||||||
|
&self,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Vec<(Anchor, Option<Breakpoint>)> {
|
||||||
|
let snapshot = self.snapshot(window, cx);
|
||||||
|
let cursors = self
|
||||||
|
.selections
|
||||||
|
.disjoint_anchors()
|
||||||
|
.into_iter()
|
||||||
|
.map(|selection| {
|
||||||
|
let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot);
|
||||||
|
|
||||||
|
let breakpoint_position = snapshot
|
||||||
.display_snapshot
|
.display_snapshot
|
||||||
.buffer_snapshot
|
.buffer_snapshot
|
||||||
.anchor_after(Point::new(cursor_position.row, 0));
|
.anchor_after(Point::new(cursor_position.row, 0));
|
||||||
|
let breakpoint = self
|
||||||
|
.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
|
||||||
|
.map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
|
||||||
|
|
||||||
(
|
breakpoint.unwrap_or_else(|| (breakpoint_position, None))
|
||||||
breakpoint_position,
|
})
|
||||||
Breakpoint {
|
// There might be multiple cursors on the same line; all of them should have the same anchors though as their breakpoints positions, which makes it possible to sort and dedup the list.
|
||||||
message: None,
|
.collect::<HashMap<Anchor, _>>();
|
||||||
state: BreakpointState::Enabled,
|
|
||||||
condition: None,
|
|
||||||
hit_condition: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
});
|
|
||||||
|
|
||||||
self.add_edit_breakpoint_block(anchor, &bp, BreakpointPromptEditAction::Log, window, cx);
|
cursors.into_iter().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn enable_breakpoint(
|
pub fn enable_breakpoint(
|
||||||
|
@ -8960,15 +8982,16 @@ impl Editor {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
if let Some((anchor, breakpoint)) = self.breakpoint_at_cursor_head(window, cx) {
|
for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
|
||||||
if breakpoint.is_disabled() {
|
let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
|
||||||
self.edit_breakpoint_at_anchor(
|
continue;
|
||||||
anchor,
|
};
|
||||||
breakpoint,
|
self.edit_breakpoint_at_anchor(
|
||||||
BreakpointEditAction::InvertState,
|
anchor,
|
||||||
cx,
|
breakpoint,
|
||||||
);
|
BreakpointEditAction::InvertState,
|
||||||
}
|
cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8978,15 +9001,16 @@ impl Editor {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
if let Some((anchor, breakpoint)) = self.breakpoint_at_cursor_head(window, cx) {
|
for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
|
||||||
if breakpoint.is_enabled() {
|
let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
|
||||||
self.edit_breakpoint_at_anchor(
|
continue;
|
||||||
anchor,
|
};
|
||||||
breakpoint,
|
self.edit_breakpoint_at_anchor(
|
||||||
BreakpointEditAction::InvertState,
|
anchor,
|
||||||
cx,
|
breakpoint,
|
||||||
);
|
BreakpointEditAction::InvertState,
|
||||||
}
|
cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8996,25 +9020,22 @@ impl Editor {
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
let edit_action = BreakpointEditAction::Toggle;
|
for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
|
||||||
|
if let Some(breakpoint) = breakpoint {
|
||||||
if let Some((anchor, breakpoint)) = self.breakpoint_at_cursor_head(window, cx) {
|
self.edit_breakpoint_at_anchor(
|
||||||
self.edit_breakpoint_at_anchor(anchor, breakpoint, edit_action, cx);
|
anchor,
|
||||||
} else {
|
breakpoint,
|
||||||
let cursor_position: Point = self.selections.newest(cx).head();
|
BreakpointEditAction::Toggle,
|
||||||
|
cx,
|
||||||
let breakpoint_position = self
|
);
|
||||||
.snapshot(window, cx)
|
} else {
|
||||||
.display_snapshot
|
self.edit_breakpoint_at_anchor(
|
||||||
.buffer_snapshot
|
anchor,
|
||||||
.anchor_after(Point::new(cursor_position.row, 0));
|
Breakpoint::new_standard(),
|
||||||
|
BreakpointEditAction::Toggle,
|
||||||
self.edit_breakpoint_at_anchor(
|
cx,
|
||||||
breakpoint_position,
|
);
|
||||||
Breakpoint::new_standard(),
|
}
|
||||||
edit_action,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17999,7 +17999,15 @@ fn add_log_breakpoint_at_cursor(
|
||||||
cx: &mut Context<Editor>,
|
cx: &mut Context<Editor>,
|
||||||
) {
|
) {
|
||||||
let (anchor, bp) = editor
|
let (anchor, bp) = editor
|
||||||
.breakpoint_at_cursor_head(window, cx)
|
.breakpoints_at_cursors(window, cx)
|
||||||
|
.first()
|
||||||
|
.and_then(|(anchor, bp)| {
|
||||||
|
if let Some(bp) = bp {
|
||||||
|
Some((*anchor, bp.clone()))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
let cursor_position: Point = editor.selections.newest(cx).head();
|
let cursor_position: Point = editor.selections.newest(cx).head();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue