Pass project environment to runInTerminal requests (#32720)

Conrad Irwin created

Closes #ISSUE

Release Notes:

- debugger: Pass environment to run in terminal requests

Change summary

crates/dap_adapters/src/go.rs             |  3 ++-
crates/debugger_ui/src/debugger_panel.rs  | 14 +++++++++++---
crates/debugger_ui/src/session/running.rs |  3 ++-
crates/project/src/debugger/dap_store.rs  |  8 ++++++--
crates/project/src/debugger/session.rs    |  8 ++++++++
5 files changed, 29 insertions(+), 7 deletions(-)

Detailed changes

crates/dap_adapters/src/go.rs 🔗

@@ -1,4 +1,5 @@
 use anyhow::{Context as _, bail};
+use collections::HashMap;
 use dap::{
     StartDebuggingRequestArguments,
     adapters::{
@@ -9,7 +10,7 @@ use dap::{
 
 use gpui::{AsyncApp, SharedString};
 use language::LanguageName;
-use std::{collections::HashMap, env::consts, ffi::OsStr, path::PathBuf, sync::OnceLock};
+use std::{env::consts, ffi::OsStr, path::PathBuf, sync::OnceLock};
 use task::TcpArgumentsTemplate;
 use util;
 

crates/debugger_ui/src/debugger_panel.rs 🔗

@@ -176,6 +176,7 @@ impl DebugPanel {
             dap_store.new_session(
                 scenario.label.clone(),
                 DebugAdapterName(scenario.adapter.clone()),
+                task_context.clone(),
                 None,
                 cx,
             )
@@ -338,12 +339,13 @@ impl DebugPanel {
         let adapter = curr_session.read(cx).adapter().clone();
         let binary = curr_session.read(cx).binary().cloned().unwrap();
         let task = curr_session.update(cx, |session, cx| session.shutdown(cx));
+        let task_context = curr_session.read(cx).task_context().clone();
 
         cx.spawn_in(window, async move |this, cx| {
             task.await;
 
             let (session, task) = dap_store_handle.update(cx, |dap_store, cx| {
-                let session = dap_store.new_session(label, adapter, None, cx);
+                let session = dap_store.new_session(label, adapter, task_context, None, cx);
 
                 let task = session.update(cx, |session, cx| {
                     session.boot(binary, worktree, dap_store_handle.downgrade(), cx)
@@ -393,11 +395,17 @@ impl DebugPanel {
             log::error!("Attempted to start a child-session without a binary");
             return;
         };
+        let task_context = parent_session.read(cx).task_context().clone();
         binary.request_args = request.clone();
         cx.spawn_in(window, async move |this, cx| {
             let (session, task) = dap_store_handle.update(cx, |dap_store, cx| {
-                let session =
-                    dap_store.new_session(label, adapter, Some(parent_session.clone()), cx);
+                let session = dap_store.new_session(
+                    label,
+                    adapter,
+                    task_context,
+                    Some(parent_session.clone()),
+                    cx,
+                );
 
                 let task = session.update(cx, |session, cx| {
                     session.boot(binary, worktree, dap_store_handle.downgrade(), cx)

crates/debugger_ui/src/session/running.rs 🔗

@@ -1012,7 +1012,8 @@ impl RunningState {
             None
         };
 
-        let mut envs: HashMap<String, String> = Default::default();
+        let mut envs: HashMap<String, String> =
+            self.session.read(cx).task_context().project_env.clone();
         if let Some(Value::Object(env)) = &request.env {
             for (key, value) in env {
                 let value_str = match (key.as_str(), value) {

crates/project/src/debugger/dap_store.rs 🔗

@@ -49,7 +49,7 @@ use std::{
     path::{Path, PathBuf},
     sync::{Arc, Once},
 };
-use task::{DebugScenario, SpawnInTerminal, TaskTemplate};
+use task::{DebugScenario, SpawnInTerminal, TaskContext, TaskTemplate};
 use util::ResultExt as _;
 use worktree::Worktree;
 
@@ -362,6 +362,7 @@ impl DapStore {
         &mut self,
         label: SharedString,
         adapter: DebugAdapterName,
+        task_context: TaskContext,
         parent_session: Option<Entity<Session>>,
         cx: &mut Context<Self>,
     ) -> Entity<Session> {
@@ -379,6 +380,7 @@ impl DapStore {
             parent_session,
             label,
             adapter,
+            task_context,
             cx,
         );
 
@@ -889,7 +891,9 @@ impl dap::adapters::DapDelegate for DapAdapterDelegate {
     }
 
     async fn which(&self, command: &OsStr) -> Option<PathBuf> {
-        which::which(command).ok()
+        let worktree_abs_path = self.worktree.abs_path();
+        let shell_path = self.shell_env().await.get("PATH").cloned();
+        which::which_in(command, shell_path.as_ref(), worktree_abs_path).ok()
     }
 
     async fn shell_env(&self) -> HashMap<String, String> {

crates/project/src/debugger/session.rs 🔗

@@ -49,6 +49,7 @@ use std::{
     path::Path,
     sync::Arc,
 };
+use task::TaskContext;
 use text::{PointUtf16, ToPointUtf16};
 use util::ResultExt;
 use worktree::Worktree;
@@ -619,6 +620,7 @@ pub struct Session {
     ignore_breakpoints: bool,
     exception_breakpoints: BTreeMap<String, (ExceptionBreakpointsFilter, IsEnabled)>,
     background_tasks: Vec<Task<()>>,
+    task_context: TaskContext,
 }
 
 trait CacheableCommand: Any + Send + Sync {
@@ -733,6 +735,7 @@ impl Session {
         parent_session: Option<Entity<Session>>,
         label: SharedString,
         adapter: DebugAdapterName,
+        task_context: TaskContext,
         cx: &mut App,
     ) -> Entity<Self> {
         cx.new::<Self>(|cx| {
@@ -783,12 +786,17 @@ impl Session {
                 exception_breakpoints: Default::default(),
                 label,
                 adapter,
+                task_context,
             };
 
             this
         })
     }
 
+    pub fn task_context(&self) -> &TaskContext {
+        &self.task_context
+    }
+
     pub fn worktree(&self) -> Option<Entity<Worktree>> {
         match &self.mode {
             Mode::Building => None,