debugger: Fix DebugAdapterDelegate::worktree_root always using the first visible worktree (#32585)

Closes #32577

Release Notes:

- Fixed debugger malfunctioning when using ZED_WORKTREE_ROOT env
variable in multi-worktree workspaces.
This commit is contained in:
Piotr Osiewicz 2025-06-12 01:40:41 +02:00 committed by GitHub
parent 1083c0ac53
commit 04223f304b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 45 additions and 15 deletions

View file

@ -179,6 +179,19 @@ impl DebugPanel {
cx, cx,
) )
}); });
let worktree = worktree_id.or_else(|| {
active_buffer
.as_ref()
.and_then(|buffer| buffer.read(cx).file())
.map(|f| f.worktree_id(cx))
});
let Some(worktree) = worktree
.and_then(|id| self.project.read(cx).worktree_for_id(id, cx))
.or_else(|| self.project.read(cx).visible_worktrees(cx).next())
else {
log::debug!("Could not find a worktree to spawn the debug session in");
return;
};
self.debug_scenario_scheduled_last = true; self.debug_scenario_scheduled_last = true;
if let Some(inventory) = self if let Some(inventory) = self
.project .project
@ -213,7 +226,7 @@ impl DebugPanel {
.await?; .await?;
dap_store dap_store
.update(cx, |dap_store, cx| { .update(cx, |dap_store, cx| {
dap_store.boot_session(session.clone(), definition, cx) dap_store.boot_session(session.clone(), definition, worktree, cx)
})? })?
.await .await
} }

View file

@ -180,15 +180,12 @@ impl DapStore {
&mut self, &mut self,
definition: DebugTaskDefinition, definition: DebugTaskDefinition,
session_id: SessionId, session_id: SessionId,
worktree: &Entity<Worktree>,
console: UnboundedSender<String>, console: UnboundedSender<String>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<DebugAdapterBinary>> { ) -> Task<Result<DebugAdapterBinary>> {
match &self.mode { match &self.mode {
DapStoreMode::Local(_) => { DapStoreMode::Local(_) => {
let Some(worktree) = self.worktree_store.read(cx).visible_worktrees(cx).next()
else {
return Task::ready(Err(anyhow!("Failed to find a worktree")));
};
let Some(adapter) = DapRegistry::global(cx).adapter(&definition.adapter) else { let Some(adapter) = DapRegistry::global(cx).adapter(&definition.adapter) else {
return Task::ready(Err(anyhow!("Failed to find a debug adapter"))); return Task::ready(Err(anyhow!("Failed to find a debug adapter")));
}; };
@ -229,6 +226,7 @@ impl DapStore {
let request = ssh.upstream_client.request(proto::GetDebugAdapterBinary { let request = ssh.upstream_client.request(proto::GetDebugAdapterBinary {
session_id: session_id.to_proto(), session_id: session_id.to_proto(),
project_id: ssh.upstream_project_id, project_id: ssh.upstream_project_id,
worktree_id: worktree.read(cx).id().to_proto(),
definition: Some(definition.to_proto()), definition: Some(definition.to_proto()),
}); });
let ssh_client = ssh.ssh_client.clone(); let ssh_client = ssh.ssh_client.clone();
@ -401,12 +399,9 @@ impl DapStore {
&self, &self,
session: Entity<Session>, session: Entity<Session>,
definition: DebugTaskDefinition, definition: DebugTaskDefinition,
worktree: Entity<Worktree>,
cx: &mut Context<Self>, cx: &mut Context<Self>,
) -> Task<Result<()>> { ) -> Task<Result<()>> {
let Some(worktree) = self.worktree_store.read(cx).visible_worktrees(cx).next() else {
return Task::ready(Err(anyhow!("Failed to find a worktree")));
};
let dap_store = cx.weak_entity(); let dap_store = cx.weak_entity();
let console = session.update(cx, |session, cx| session.console_output(cx)); let console = session.update(cx, |session, cx| session.console_output(cx));
let session_id = session.read(cx).session_id(); let session_id = session.read(cx).session_id();
@ -416,7 +411,13 @@ impl DapStore {
async move |this, cx| { async move |this, cx| {
let binary = this let binary = this
.update(cx, |this, cx| { .update(cx, |this, cx| {
this.get_debug_adapter_binary(definition.clone(), session_id, console, cx) this.get_debug_adapter_binary(
definition.clone(),
session_id,
&worktree,
console,
cx,
)
})? })?
.await?; .await?;
session session
@ -780,9 +781,22 @@ impl DapStore {
}) })
.detach(); .detach();
let worktree = this
.update(&mut cx, |this, cx| {
this.worktree_store
.read(cx)
.worktree_for_id(WorktreeId::from_proto(envelope.payload.worktree_id), cx)
})?
.context("Failed to find worktree with a given ID")?;
let binary = this let binary = this
.update(&mut cx, |this, cx| { .update(&mut cx, |this, cx| {
this.get_debug_adapter_binary(definition, SessionId::from_proto(session_id), tx, cx) this.get_debug_adapter_binary(
definition,
SessionId::from_proto(session_id),
&worktree,
tx,
cx,
)
})? })?
.await?; .await?;
Ok(binary.to_proto()) Ok(binary.to_proto())

View file

@ -493,6 +493,7 @@ message GetDebugAdapterBinary {
uint64 project_id = 1; uint64 project_id = 1;
uint64 session_id = 3; uint64 session_id = 3;
DebugTaskDefinition definition = 2; DebugTaskDefinition definition = 2;
uint64 worktree_id = 4;
} }
message DebugAdapterBinary { message DebugAdapterBinary {

View file

@ -285,10 +285,12 @@ pub fn task_contexts(
.worktree_for_id(*worktree_id, cx) .worktree_for_id(*worktree_id, cx)
.map_or(false, |worktree| is_visible_directory(&worktree, cx)) .map_or(false, |worktree| is_visible_directory(&worktree, cx))
}) })
.or(workspace .or_else(|| {
.visible_worktrees(cx) workspace
.next() .visible_worktrees(cx)
.map(|tree| tree.read(cx).id())); .next()
.map(|tree| tree.read(cx).id())
});
let active_editor = active_item.and_then(|item| item.act_as::<Editor>(cx)); let active_editor = active_item.and_then(|item| item.act_as::<Editor>(cx));