Add support for `--target-dir` for Rust tasks (#24725)

Coenen Benjamin created

This PR is an attempt to add support for `--target-dir` argument to
`cargo` commands when executing tasks with rust.
When using VSCode I was already using this trick to not block the
current binary compilation when I was trying a specific test. As it's a
different target directory it won't block the `cargo` commands I'm using
in my terminal.

I used the task variables to achieve this but I'm not sure it's the best
option to be honest. I didn't find any examples in your docs to see if
sometimes you had specific configuration for languages and tasks.

Let me know if this solution would be a good fit and if the
implementation is ok.

If so feel free to redirect me to an example I can reproduce to write a
unit test or so... And I will also update the docs.

Example of config:

```
{
  "languages": {
    "Rust": {
      "tasks": {
        "variables": {
          "RUST_TARGET_DIR": ".cargo_check"
        }
      }
    }
  }
}
```

it will run `cargo test -p XXX --target-dir .cargo-check`


Release Notes:

- Added support for `--target-dir` for Rust tasks

---------

Signed-off-by: Benjamin <5719034+bnjjj@users.noreply.github.com>

Change summary

crates/languages/src/rust.rs | 32 +++++++++++++++++++++++++++++---
1 file changed, 29 insertions(+), 3 deletions(-)

Detailed changes

crates/languages/src/rust.rs 🔗

@@ -526,17 +526,25 @@ impl ContextProvider for RustContextProvider {
         cx: &App,
     ) -> Option<TaskTemplates> {
         const DEFAULT_RUN_NAME_STR: &str = "RUST_DEFAULT_PACKAGE_RUN";
-        let package_to_run = language_settings(Some("Rust".into()), file.as_ref(), cx)
+        const CUSTOM_TARGET_DIR: &str = "RUST_TARGET_DIR";
+
+        let language_sets = language_settings(Some("Rust".into()), file.as_ref(), cx);
+        let package_to_run = language_sets
             .tasks
             .variables
             .get(DEFAULT_RUN_NAME_STR)
             .cloned();
+        let custom_target_dir = language_sets
+            .tasks
+            .variables
+            .get(CUSTOM_TARGET_DIR)
+            .cloned();
         let run_task_args = if let Some(package_to_run) = package_to_run {
             vec!["run".into(), "-p".into(), package_to_run]
         } else {
             vec!["run".into()]
         };
-        Some(TaskTemplates(vec![
+        let mut task_templates = vec![
             TaskTemplate {
                 label: format!(
                     "Check (package: {})",
@@ -661,7 +669,25 @@ impl ContextProvider for RustContextProvider {
                 cwd: Some("$ZED_DIRNAME".to_owned()),
                 ..TaskTemplate::default()
             },
-        ]))
+        ];
+
+        if let Some(custom_target_dir) = custom_target_dir {
+            task_templates = task_templates
+                .into_iter()
+                .map(|mut task_template| {
+                    let mut args = task_template.args.split_off(1);
+                    task_template.args.append(&mut vec![
+                        "--target-dir".to_string(),
+                        custom_target_dir.clone(),
+                    ]);
+                    task_template.args.append(&mut args);
+
+                    task_template
+                })
+                .collect();
+        }
+
+        Some(TaskTemplates(task_templates))
     }
 }