debugger: Clear active debug line on thread continued (#29811)
I also moved the breakpoint store to session from local mode, because both remote/local modes will need the ability to remove active debug lines. Release Notes: - N/A
This commit is contained in:
parent
e6b0d8e48b
commit
da98e300cc
5 changed files with 65 additions and 40 deletions
|
@ -353,7 +353,6 @@ impl DebugPanel {
|
||||||
};
|
};
|
||||||
|
|
||||||
let dap_store_handle = self.project.read(cx).dap_store().clone();
|
let dap_store_handle = self.project.read(cx).dap_store().clone();
|
||||||
let breakpoint_store = self.project.read(cx).breakpoint_store();
|
|
||||||
let definition = parent_session.read(cx).definition().clone();
|
let definition = parent_session.read(cx).definition().clone();
|
||||||
let mut binary = parent_session.read(cx).binary().clone();
|
let mut binary = parent_session.read(cx).binary().clone();
|
||||||
binary.request_args = request.clone();
|
binary.request_args = request.clone();
|
||||||
|
@ -364,13 +363,7 @@ impl DebugPanel {
|
||||||
dap_store.new_session(definition.clone(), Some(parent_session.clone()), cx);
|
dap_store.new_session(definition.clone(), Some(parent_session.clone()), cx);
|
||||||
|
|
||||||
let task = session.update(cx, |session, cx| {
|
let task = session.update(cx, |session, cx| {
|
||||||
session.boot(
|
session.boot(binary, worktree, dap_store_handle.downgrade(), cx)
|
||||||
binary,
|
|
||||||
worktree,
|
|
||||||
breakpoint_store,
|
|
||||||
dap_store_handle.downgrade(),
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
(session, task)
|
(session, task)
|
||||||
})?;
|
})?;
|
||||||
|
|
|
@ -1663,6 +1663,33 @@ async fn test_active_debug_line_setting(executor: BackgroundExecutor, cx: &mut T
|
||||||
"Second stacktrace request handler was not called"
|
"Second stacktrace request handler was not called"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
client
|
||||||
|
.fake_event(dap::messages::Events::Continued(dap::ContinuedEvent {
|
||||||
|
thread_id: 0,
|
||||||
|
all_threads_continued: Some(true),
|
||||||
|
}))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.run_until_parked();
|
||||||
|
|
||||||
|
second_editor.update(cx, |editor, _| {
|
||||||
|
let active_debug_lines: Vec<_> = editor.highlighted_rows::<ActiveDebugLine>().collect();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
active_debug_lines.is_empty(),
|
||||||
|
"There shouldn't be any active debug lines"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
main_editor.update(cx, |editor, _| {
|
||||||
|
let active_debug_lines: Vec<_> = editor.highlighted_rows::<ActiveDebugLine>().collect();
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
active_debug_lines.is_empty(),
|
||||||
|
"There shouldn't be any active debug lines"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
let shutdown_session = project.update(cx, |project, cx| {
|
let shutdown_session = project.update(cx, |project, cx| {
|
||||||
project.dap_store().update(cx, |dap_store, cx| {
|
project.dap_store().update(cx, |dap_store, cx| {
|
||||||
|
|
|
@ -442,7 +442,6 @@ impl DapStore {
|
||||||
};
|
};
|
||||||
|
|
||||||
let dap_store = cx.weak_entity();
|
let dap_store = cx.weak_entity();
|
||||||
let breakpoint_store = self.breakpoint_store.clone();
|
|
||||||
let definition = session.read(cx).definition();
|
let definition = session.read(cx).definition();
|
||||||
|
|
||||||
cx.spawn({
|
cx.spawn({
|
||||||
|
@ -456,7 +455,7 @@ impl DapStore {
|
||||||
|
|
||||||
session
|
session
|
||||||
.update(cx, |session, cx| {
|
.update(cx, |session, cx| {
|
||||||
session.boot(binary, worktree, breakpoint_store, dap_store, cx)
|
session.boot(binary, worktree, dap_store, cx)
|
||||||
})?
|
})?
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
|
@ -126,7 +126,6 @@ pub enum Mode {
|
||||||
pub struct LocalMode {
|
pub struct LocalMode {
|
||||||
client: Arc<DebugAdapterClient>,
|
client: Arc<DebugAdapterClient>,
|
||||||
binary: DebugAdapterBinary,
|
binary: DebugAdapterBinary,
|
||||||
pub(crate) breakpoint_store: Entity<BreakpointStore>,
|
|
||||||
tmp_breakpoint: Option<SourceBreakpoint>,
|
tmp_breakpoint: Option<SourceBreakpoint>,
|
||||||
worktree: WeakEntity<Worktree>,
|
worktree: WeakEntity<Worktree>,
|
||||||
executor: BackgroundExecutor,
|
executor: BackgroundExecutor,
|
||||||
|
@ -152,7 +151,6 @@ impl LocalMode {
|
||||||
session_id: SessionId,
|
session_id: SessionId,
|
||||||
parent_session: Option<Entity<Session>>,
|
parent_session: Option<Entity<Session>>,
|
||||||
worktree: WeakEntity<Worktree>,
|
worktree: WeakEntity<Worktree>,
|
||||||
breakpoint_store: Entity<BreakpointStore>,
|
|
||||||
binary: DebugAdapterBinary,
|
binary: DebugAdapterBinary,
|
||||||
messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
|
messages_tx: futures::channel::mpsc::UnboundedSender<Message>,
|
||||||
cx: AsyncApp,
|
cx: AsyncApp,
|
||||||
|
@ -178,7 +176,6 @@ impl LocalMode {
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
client,
|
client,
|
||||||
breakpoint_store,
|
|
||||||
worktree,
|
worktree,
|
||||||
tmp_breakpoint: None,
|
tmp_breakpoint: None,
|
||||||
binary,
|
binary,
|
||||||
|
@ -219,10 +216,10 @@ impl LocalMode {
|
||||||
&self,
|
&self,
|
||||||
abs_path: Arc<Path>,
|
abs_path: Arc<Path>,
|
||||||
reason: BreakpointUpdatedReason,
|
reason: BreakpointUpdatedReason,
|
||||||
|
breakpoint_store: &Entity<BreakpointStore>,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Task<()> {
|
) -> Task<()> {
|
||||||
let breakpoints = self
|
let breakpoints = breakpoint_store
|
||||||
.breakpoint_store
|
|
||||||
.read_with(cx, |store, cx| store.breakpoints_from_path(&abs_path, cx))
|
.read_with(cx, |store, cx| store.breakpoints_from_path(&abs_path, cx))
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|bp| bp.state.is_enabled())
|
.filter(|bp| bp.state.is_enabled())
|
||||||
|
@ -271,12 +268,11 @@ impl LocalMode {
|
||||||
fn send_source_breakpoints(
|
fn send_source_breakpoints(
|
||||||
&self,
|
&self,
|
||||||
ignore_breakpoints: bool,
|
ignore_breakpoints: bool,
|
||||||
|
breakpoint_store: &Entity<BreakpointStore>,
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
|
) -> Task<HashMap<Arc<Path>, anyhow::Error>> {
|
||||||
let mut breakpoint_tasks = Vec::new();
|
let mut breakpoint_tasks = Vec::new();
|
||||||
let breakpoints = self
|
let breakpoints = breakpoint_store.read_with(cx, |store, cx| store.all_breakpoints(cx));
|
||||||
.breakpoint_store
|
|
||||||
.read_with(cx, |store, cx| store.all_breakpoints(cx));
|
|
||||||
|
|
||||||
for (path, breakpoints) in breakpoints {
|
for (path, breakpoints) in breakpoints {
|
||||||
let breakpoints = if ignore_breakpoints {
|
let breakpoints = if ignore_breakpoints {
|
||||||
|
@ -314,6 +310,7 @@ impl LocalMode {
|
||||||
definition: &DebugTaskDefinition,
|
definition: &DebugTaskDefinition,
|
||||||
initialized_rx: oneshot::Receiver<()>,
|
initialized_rx: oneshot::Receiver<()>,
|
||||||
dap_store: WeakEntity<DapStore>,
|
dap_store: WeakEntity<DapStore>,
|
||||||
|
breakpoint_store: Entity<BreakpointStore>,
|
||||||
cx: &App,
|
cx: &App,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
let mut raw = self.binary.request_args.clone();
|
let mut raw = self.binary.request_args.clone();
|
||||||
|
@ -354,7 +351,7 @@ impl LocalMode {
|
||||||
async move |cx| {
|
async move |cx| {
|
||||||
initialized_rx.await?;
|
initialized_rx.await?;
|
||||||
let errors_by_path = cx
|
let errors_by_path = cx
|
||||||
.update(|cx| this.send_source_breakpoints(false, cx))?
|
.update(|cx| this.send_source_breakpoints(false, &breakpoint_store, cx))?
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
dap_store.update(cx, |_, cx| {
|
dap_store.update(cx, |_, cx| {
|
||||||
|
@ -513,7 +510,6 @@ pub struct Session {
|
||||||
id: SessionId,
|
id: SessionId,
|
||||||
child_session_ids: HashSet<SessionId>,
|
child_session_ids: HashSet<SessionId>,
|
||||||
parent_session: Option<Entity<Session>>,
|
parent_session: Option<Entity<Session>>,
|
||||||
ignore_breakpoints: bool,
|
|
||||||
modules: Vec<dap::Module>,
|
modules: Vec<dap::Module>,
|
||||||
loaded_sources: Vec<dap::Source>,
|
loaded_sources: Vec<dap::Source>,
|
||||||
output_token: OutputToken,
|
output_token: OutputToken,
|
||||||
|
@ -525,6 +521,8 @@ pub struct Session {
|
||||||
locations: HashMap<u64, dap::LocationsResponse>,
|
locations: HashMap<u64, dap::LocationsResponse>,
|
||||||
is_session_terminated: bool,
|
is_session_terminated: bool,
|
||||||
requests: HashMap<TypeId, HashMap<RequestSlot, Shared<Task<Option<()>>>>>,
|
requests: HashMap<TypeId, HashMap<RequestSlot, Shared<Task<Option<()>>>>>,
|
||||||
|
pub(crate) breakpoint_store: Entity<BreakpointStore>,
|
||||||
|
ignore_breakpoints: bool,
|
||||||
exception_breakpoints: BTreeMap<String, (ExceptionBreakpointsFilter, IsEnabled)>,
|
exception_breakpoints: BTreeMap<String, (ExceptionBreakpointsFilter, IsEnabled)>,
|
||||||
background_tasks: Vec<Task<()>>,
|
background_tasks: Vec<Task<()>>,
|
||||||
}
|
}
|
||||||
|
@ -642,14 +640,14 @@ impl Session {
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Entity<Self> {
|
) -> Entity<Self> {
|
||||||
cx.new::<Self>(|cx| {
|
cx.new::<Self>(|cx| {
|
||||||
cx.subscribe(&breakpoint_store, |this, _, event, cx| match event {
|
cx.subscribe(&breakpoint_store, |this, store, event, cx| match event {
|
||||||
BreakpointStoreEvent::BreakpointsUpdated(path, reason) => {
|
BreakpointStoreEvent::BreakpointsUpdated(path, reason) => {
|
||||||
if let Some(local) = (!this.ignore_breakpoints)
|
if let Some(local) = (!this.ignore_breakpoints)
|
||||||
.then(|| this.as_local_mut())
|
.then(|| this.as_local_mut())
|
||||||
.flatten()
|
.flatten()
|
||||||
{
|
{
|
||||||
local
|
local
|
||||||
.send_breakpoints_from_path(path.clone(), *reason, cx)
|
.send_breakpoints_from_path(path.clone(), *reason, &store, cx)
|
||||||
.detach();
|
.detach();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -672,7 +670,6 @@ impl Session {
|
||||||
child_session_ids: HashSet::default(),
|
child_session_ids: HashSet::default(),
|
||||||
parent_session,
|
parent_session,
|
||||||
capabilities: Capabilities::default(),
|
capabilities: Capabilities::default(),
|
||||||
ignore_breakpoints: false,
|
|
||||||
variables: Default::default(),
|
variables: Default::default(),
|
||||||
stack_frames: Default::default(),
|
stack_frames: Default::default(),
|
||||||
thread_states: ThreadStates::default(),
|
thread_states: ThreadStates::default(),
|
||||||
|
@ -685,6 +682,8 @@ impl Session {
|
||||||
background_tasks: Vec::default(),
|
background_tasks: Vec::default(),
|
||||||
locations: Default::default(),
|
locations: Default::default(),
|
||||||
is_session_terminated: false,
|
is_session_terminated: false,
|
||||||
|
ignore_breakpoints: false,
|
||||||
|
breakpoint_store,
|
||||||
exception_breakpoints: Default::default(),
|
exception_breakpoints: Default::default(),
|
||||||
definition: template,
|
definition: template,
|
||||||
};
|
};
|
||||||
|
@ -704,7 +703,6 @@ impl Session {
|
||||||
&mut self,
|
&mut self,
|
||||||
binary: DebugAdapterBinary,
|
binary: DebugAdapterBinary,
|
||||||
worktree: Entity<Worktree>,
|
worktree: Entity<Worktree>,
|
||||||
breakpoint_store: Entity<BreakpointStore>,
|
|
||||||
dap_store: WeakEntity<DapStore>,
|
dap_store: WeakEntity<DapStore>,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Task<Result<()>> {
|
) -> Task<Result<()>> {
|
||||||
|
@ -750,7 +748,6 @@ impl Session {
|
||||||
id,
|
id,
|
||||||
parent_session,
|
parent_session,
|
||||||
worktree.downgrade(),
|
worktree.downgrade(),
|
||||||
breakpoint_store.clone(),
|
|
||||||
binary,
|
binary,
|
||||||
message_tx,
|
message_tx,
|
||||||
cx.clone(),
|
cx.clone(),
|
||||||
|
@ -991,6 +988,7 @@ impl Session {
|
||||||
&self.definition,
|
&self.definition,
|
||||||
initialize_rx,
|
initialize_rx,
|
||||||
dap_store,
|
dap_store,
|
||||||
|
self.breakpoint_store.clone(),
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
Mode::Building => Task::ready(Err(anyhow!("cannot initialize, still building"))),
|
Mode::Building => Task::ready(Err(anyhow!("cannot initialize, still building"))),
|
||||||
|
@ -1016,6 +1014,7 @@ impl Session {
|
||||||
let task = local_mode.send_breakpoints_from_path(
|
let task = local_mode.send_breakpoints_from_path(
|
||||||
path,
|
path,
|
||||||
BreakpointUpdatedReason::Toggled,
|
BreakpointUpdatedReason::Toggled,
|
||||||
|
&self.breakpoint_store,
|
||||||
cx,
|
cx,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1081,13 +1080,20 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_stopped_event(&mut self, event: StoppedEvent, cx: &mut Context<Self>) {
|
fn handle_stopped_event(&mut self, event: StoppedEvent, cx: &mut Context<Self>) {
|
||||||
|
// todo(debugger): Find a clean way to get around the clone
|
||||||
|
let breakpoint_store = self.breakpoint_store.clone();
|
||||||
if let Some((local, path)) = self.as_local_mut().and_then(|local| {
|
if let Some((local, path)) = self.as_local_mut().and_then(|local| {
|
||||||
let breakpoint = local.tmp_breakpoint.take()?;
|
let breakpoint = local.tmp_breakpoint.take()?;
|
||||||
let path = breakpoint.path.clone();
|
let path = breakpoint.path.clone();
|
||||||
Some((local, path))
|
Some((local, path))
|
||||||
}) {
|
}) {
|
||||||
local
|
local
|
||||||
.send_breakpoints_from_path(path, BreakpointUpdatedReason::Toggled, cx)
|
.send_breakpoints_from_path(
|
||||||
|
path,
|
||||||
|
BreakpointUpdatedReason::Toggled,
|
||||||
|
&breakpoint_store,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
.detach();
|
.detach();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1137,6 +1143,9 @@ impl Session {
|
||||||
Events::Continued(event) => {
|
Events::Continued(event) => {
|
||||||
if event.all_threads_continued.unwrap_or_default() {
|
if event.all_threads_continued.unwrap_or_default() {
|
||||||
self.thread_states.continue_all_threads();
|
self.thread_states.continue_all_threads();
|
||||||
|
self.breakpoint_store.update(cx, |store, cx| {
|
||||||
|
store.remove_active_position(Some(self.session_id()), cx)
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
self.thread_states
|
self.thread_states
|
||||||
.continue_thread(ThreadId(event.thread_id));
|
.continue_thread(ThreadId(event.thread_id));
|
||||||
|
@ -1434,7 +1443,7 @@ impl Session {
|
||||||
self.ignore_breakpoints = ignore;
|
self.ignore_breakpoints = ignore;
|
||||||
|
|
||||||
if let Some(local) = self.as_local() {
|
if let Some(local) = self.as_local() {
|
||||||
local.send_source_breakpoints(ignore, cx)
|
local.send_source_breakpoints(ignore, &self.breakpoint_store, cx)
|
||||||
} else {
|
} else {
|
||||||
// todo(debugger): We need to propagate this change to downstream sessions and send a message to upstream sessions
|
// todo(debugger): We need to propagate this change to downstream sessions and send a message to upstream sessions
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
|
@ -1516,7 +1525,12 @@ impl Session {
|
||||||
) -> impl FnOnce(&mut Self, Result<T::Response>, &mut Context<Self>) -> Option<T::Response> + 'static
|
) -> impl FnOnce(&mut Self, Result<T::Response>, &mut Context<Self>) -> Option<T::Response> + 'static
|
||||||
{
|
{
|
||||||
move |this, response, cx| match response.log_err() {
|
move |this, response, cx| match response.log_err() {
|
||||||
Some(response) => Some(response),
|
Some(response) => {
|
||||||
|
this.breakpoint_store.update(cx, |store, cx| {
|
||||||
|
store.remove_active_position(Some(this.session_id()), cx)
|
||||||
|
});
|
||||||
|
Some(response)
|
||||||
|
}
|
||||||
None => {
|
None => {
|
||||||
this.thread_states.stop_thread(thread_id);
|
this.thread_states.stop_thread(thread_id);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
|
@ -1536,10 +1550,7 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_active_debug_line(&mut self, cx: &mut Context<Session>) {
|
fn clear_active_debug_line(&mut self, cx: &mut Context<Session>) {
|
||||||
self.as_local()
|
self.breakpoint_store.update(cx, |store, cx| {
|
||||||
.expect("Message handler will only run in local mode")
|
|
||||||
.breakpoint_store
|
|
||||||
.update(cx, |store, cx| {
|
|
||||||
store.remove_active_position(Some(self.id), cx)
|
store.remove_active_position(Some(self.id), cx)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,12 +36,7 @@ pub fn intercept_debug_sessions<T: Fn(&Arc<DebugAdapterClient>) + 'static>(
|
||||||
|
|
||||||
fn register_default_handlers(session: &Session, client: &Arc<DebugAdapterClient>, cx: &mut App) {
|
fn register_default_handlers(session: &Session, client: &Arc<DebugAdapterClient>, cx: &mut App) {
|
||||||
client.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(Default::default()));
|
client.on_request::<dap::requests::Initialize, _>(move |_, _| Ok(Default::default()));
|
||||||
let paths = session
|
let paths = session.breakpoint_store.read(cx).breakpoint_paths();
|
||||||
.as_local()
|
|
||||||
.unwrap()
|
|
||||||
.breakpoint_store
|
|
||||||
.read(cx)
|
|
||||||
.breakpoint_paths();
|
|
||||||
|
|
||||||
client.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
|
client.on_request::<dap::requests::SetBreakpoints, _>(move |_, args| {
|
||||||
let p = Arc::from(Path::new(&args.source.path.unwrap()));
|
let p = Arc::from(Path::new(&args.source.path.unwrap()));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue