rust-analyzer: Fix for deserialization error of CargoRunnableArgs (#29291)

Peter Tripp and Kirill Bulatov created

Fix for error:

```log
2025-04-23T13:02:14-04:00 INFO  [lsp] starting language server process. binary path: "/Users/peter/Library/Application Support/Zed/languages/rust-analyzer/rust-analyzer-2025-04-21", working directory: "/Users/peter/zcode/zed", args: []
2025-04-23T13:02:16-04:00 ERROR [lsp] failed to deserialize response from language server: data did not match any variant of untagged enum RunnableArgs at line 1 column 199. response from language server: "[{\"label\":\"cargo check --workspace\",\"kind\":\"cargo\",\"args\":{\"cwd\":\"/Users/peter/zcode/zed/crates/gpui/src/platform/linux\",\"overrideCargo\":null,\"cargoArgs\":[\"check\",\"--workspace\"],\"executableArgs\":[]}}]"
2025-04-23T13:02:16-04:00 WARN  [project::lsp_store] LSP Runnables via rust-analyzer failed: failed to deserialize response
2025-04-23T13:02:16-04:00 ERROR [*unknown*] LSP Runnables via rust-analyzer failed: failed to deserialize response
```

Object is missing `environment`:
```json
[
  {
    "label": "cargo check --workspace",
    "kind": "cargo",
    "args": {
      "cwd": "/Users/peter/zcode/zed/crates/gpui/src/platform/linux",
      "overrideCargo": null,
      "cargoArgs": ["check", "--workspace"],
      "executableArgs": []
    }
  }
]
```

Follow-up to: https://github.com/zed-industries/zed/pull/28359

Release Notes:

- N/A

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>

Change summary

crates/project/src/lsp_store/lsp_ext_command.rs | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)

Detailed changes

crates/project/src/lsp_store/lsp_ext_command.rs 🔗

@@ -393,6 +393,7 @@ impl lsp::request::Request for Runnables {
 #[serde(rename_all = "camelCase")]
 pub struct RunnablesParams {
     pub text_document: lsp::TextDocumentIdentifier,
+    #[serde(default)]
     pub position: Option<lsp::Position>,
 }
 
@@ -400,7 +401,7 @@ pub struct RunnablesParams {
 #[serde(rename_all = "camelCase")]
 pub struct Runnable {
     pub label: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
     pub location: Option<lsp::LocationLink>,
     pub kind: RunnableKind,
     pub args: RunnableArgs,
@@ -424,26 +425,30 @@ pub enum RunnableKind {
 #[derive(Deserialize, Serialize, Debug, Clone)]
 #[serde(rename_all = "camelCase")]
 pub struct CargoRunnableArgs {
-    #[serde(skip_serializing_if = "HashMap::is_empty")]
+    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
     pub environment: HashMap<String, String>,
     pub cwd: PathBuf,
     /// Command to be executed instead of cargo
+    #[serde(default)]
     pub override_cargo: Option<String>,
-    #[serde(skip_serializing_if = "Option::is_none")]
+    #[serde(default, skip_serializing_if = "Option::is_none")]
     pub workspace_root: Option<PathBuf>,
     // command, --package and --lib stuff
+    #[serde(default)]
     pub cargo_args: Vec<String>,
     // stuff after --
+    #[serde(default)]
     pub executable_args: Vec<String>,
 }
 
 #[derive(Deserialize, Serialize, Debug, Clone)]
 #[serde(rename_all = "camelCase")]
 pub struct ShellRunnableArgs {
-    #[serde(skip_serializing_if = "HashMap::is_empty")]
+    #[serde(default, skip_serializing_if = "HashMap::is_empty")]
     pub environment: HashMap<String, String>,
     pub cwd: PathBuf,
     pub program: String,
+    #[serde(default)]
     pub args: Vec<String>,
 }