debugger: Surface validity of breakpoints (#30380)

We now show on the breakpoint itself whether it can ever be hit.

![image](https://github.com/user-attachments/assets/148d7712-53c9-4a0a-9fc0-4ff80dec5fb1)

Release Notes:

- N/A

---------

Signed-off-by: Umesh Yadav <git@umesh.dev>
Co-authored-by: Anthony <anthony@zed.dev>
Co-authored-by: Cole Miller <cole@zed.dev>
Co-authored-by: Michael Sloan <michael@zed.dev>
Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Ben Kunkle <ben@zed.dev>
Co-authored-by: Danilo Leal <67129314+danilo-leal@users.noreply.github.com>
Co-authored-by: Agus Zubiaga <hi@aguz.me>
Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com>
Co-authored-by: Agus Zubiaga <agus@zed.dev>
Co-authored-by: Danilo Leal <daniloleal09@gmail.com>
Co-authored-by: Richard Feldman <oss@rtfeldman.com>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
Co-authored-by: peppidesu <bakker.pepijn@gmail.com>
Co-authored-by: Kirill Bulatov <kirill@zed.dev>
Co-authored-by: Ben Kunkle <ben.kunkle@gmail.com>
Co-authored-by: Jens Krause <47693+sectore@users.noreply.github.com>
Co-authored-by: Bennet Bo Fenner <bennet@zed.dev>
Co-authored-by: Max Nordlund <max.nordlund@gmail.com>
Co-authored-by: Finn Evers <dev@bahn.sh>
Co-authored-by: tidely <43219534+tidely@users.noreply.github.com>
Co-authored-by: Sergei Kartsev <kartsevsb@gmail.com>
Co-authored-by: Shardul Vaidya <31039336+5herlocked@users.noreply.github.com>
Co-authored-by: Chris Kelly <amateurhuman@gmail.com>
Co-authored-by: Peter Tripp <peter@zed.dev>
Co-authored-by: Umesh Yadav <23421535+imumesh18@users.noreply.github.com>
Co-authored-by: Julia Ryan <juliaryan3.14@gmail.com>
Co-authored-by: Cole Miller <m@cole-miller.net>
Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com>
Co-authored-by: william341 <wwokwilliam@gmail.com>
Co-authored-by: Liam <33645555+lj3954@users.noreply.github.com>
Co-authored-by: AidanV <aidanvanduyne@gmail.com>
Co-authored-by: imumesh18 <umesh4257@gmail.com>
Co-authored-by: d1y <chenhonzhou@gmail.com>
Co-authored-by: AidanV <84053180+AidanV@users.noreply.github.com>
Co-authored-by: Anthony Eid <56899983+Anthony-Eid@users.noreply.github.com>
Co-authored-by: 张小白 <364772080@qq.com>
Co-authored-by: THELOSTSOUL <1095533751@qq.com>
Co-authored-by: Ron Harel <55725807+ronharel02@users.noreply.github.com>
Co-authored-by: Tristan Hume <tristan@anthropic.com>
Co-authored-by: Stanislav Alekseev <43210583+WeetHet@users.noreply.github.com>
Co-authored-by: Joseph T. Lyons <JosephTLyons@gmail.com>
Co-authored-by: Remco Smits <djsmits12@gmail.com>
Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Oleksiy Syvokon <oleksiy@zed.dev>
Co-authored-by: Thomas David Baker <bakert@gmail.com>
Co-authored-by: Nate Butler <iamnbutler@gmail.com>
Co-authored-by: Mikayla Maki <mikayla@zed.dev>
Co-authored-by: Rob McBroom <github@skurfer.com>
Co-authored-by: CharlesChen0823 <yongchen0823@gmail.com>
This commit is contained in:
Piotr Osiewicz 2025-05-20 17:56:15 +02:00 committed by GitHub
parent 36ae564b61
commit 17cf04558b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 439 additions and 237 deletions

View file

@ -1,3 +1,5 @@
use crate::debugger::breakpoint_store::BreakpointSessionState;
use super::breakpoint_store::{
BreakpointStore, BreakpointStoreEvent, BreakpointUpdatedReason, SourceBreakpoint,
};
@ -218,25 +220,55 @@ impl LocalMode {
breakpoint_store: &Entity<BreakpointStore>,
cx: &mut App,
) -> Task<()> {
let breakpoints = breakpoint_store
.read_with(cx, |store, cx| store.breakpoints_from_path(&abs_path, cx))
let breakpoints =
breakpoint_store
.read_with(cx, |store, cx| {
store.source_breakpoints_from_path(&abs_path, cx)
})
.into_iter()
.filter(|bp| bp.state.is_enabled())
.chain(self.tmp_breakpoint.iter().filter_map(|breakpoint| {
breakpoint.path.eq(&abs_path).then(|| breakpoint.clone())
}))
.map(Into::into)
.collect();
let raw_breakpoints = breakpoint_store
.read(cx)
.breakpoints_from_path(&abs_path)
.into_iter()
.filter(|bp| bp.state.is_enabled())
.chain(self.tmp_breakpoint.clone())
.map(Into::into)
.collect();
.filter(|bp| bp.bp.state.is_enabled())
.collect::<Vec<_>>();
let task = self.request(dap_command::SetBreakpoints {
source: client_source(&abs_path),
source_modified: Some(matches!(reason, BreakpointUpdatedReason::FileSaved)),
breakpoints,
});
cx.background_spawn(async move {
match task.await {
Ok(_) => {}
Err(err) => log::warn!("Set breakpoints request failed for path: {}", err),
let session_id = self.client.id();
let breakpoint_store = breakpoint_store.downgrade();
cx.spawn(async move |cx| match cx.background_spawn(task).await {
Ok(breakpoints) => {
let breakpoints =
breakpoints
.into_iter()
.zip(raw_breakpoints)
.filter_map(|(dap_bp, zed_bp)| {
Some((
zed_bp,
BreakpointSessionState {
id: dap_bp.id?,
verified: dap_bp.verified,
},
))
});
breakpoint_store
.update(cx, |this, _| {
this.mark_breakpoints_verified(session_id, &abs_path, breakpoints);
})
.ok();
}
Err(err) => log::warn!("Set breakpoints request failed for path: {}", err),
})
}
@ -271,8 +303,11 @@ impl LocalMode {
cx: &App,
) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
let mut breakpoint_tasks = Vec::new();
let breakpoints = breakpoint_store.read_with(cx, |store, cx| store.all_breakpoints(cx));
let breakpoints =
breakpoint_store.read_with(cx, |store, cx| store.all_source_breakpoints(cx));
let mut raw_breakpoints = breakpoint_store.read_with(cx, |this, _| this.all_breakpoints());
debug_assert_eq!(raw_breakpoints.len(), breakpoints.len());
let session_id = self.client.id();
for (path, breakpoints) in breakpoints {
let breakpoints = if ignore_breakpoints {
vec![]
@ -284,14 +319,46 @@ impl LocalMode {
.collect()
};
breakpoint_tasks.push(
self.request(dap_command::SetBreakpoints {
let raw_breakpoints = raw_breakpoints
.remove(&path)
.unwrap_or_default()
.into_iter()
.filter(|bp| bp.bp.state.is_enabled());
let error_path = path.clone();
let send_request = self
.request(dap_command::SetBreakpoints {
source: client_source(&path),
source_modified: Some(false),
breakpoints,
})
.map(|result| result.map_err(|e| (path, e))),
);
.map(|result| result.map_err(move |e| (error_path, e)));
let task = cx.spawn({
let breakpoint_store = breakpoint_store.downgrade();
async move |cx| {
let breakpoints = cx.background_spawn(send_request).await?;
let breakpoints = breakpoints.into_iter().zip(raw_breakpoints).filter_map(
|(dap_bp, zed_bp)| {
Some((
zed_bp,
BreakpointSessionState {
id: dap_bp.id?,
verified: dap_bp.verified,
},
))
},
);
breakpoint_store
.update(cx, |this, _| {
this.mark_breakpoints_verified(session_id, &path, breakpoints);
})
.ok();
Ok(())
}
});
breakpoint_tasks.push(task);
}
cx.background_spawn(async move {
@ -1204,7 +1271,9 @@ impl Session {
self.output_token.0 += 1;
cx.notify();
}
Events::Breakpoint(_) => {}
Events::Breakpoint(event) => self.breakpoint_store.update(cx, |store, _| {
store.update_session_breakpoint(self.session_id(), event.reason, event.breakpoint);
}),
Events::Module(event) => {
match event.reason {
dap::ModuleEventReason::New => {