project: Use runnable kind to disambiguate between cargo and shell commands (#54011)

Found this bug while investigating why configuring nextest based on the
instructions at
https://github.com/rust-lang/rust-analyzer/issues/21137#issuecomment-4254611341
wasn't working within Zed.

Previously, we'd use `serde(untagged)`, preferring cargo over shell
commands. The problem is that every instance of a shell command is a
valid instance of a cargo command. For example, the shell command:

```json
{
    "label": "test my_test",
    "kind": "shell",
    "args": {
        "environment": {"RUSTC_TOOLCHAIN": "/path/to/toolchain"},
        "cwd": "/project",
        "program": "cargo",
        "args": ["nextest", "run", "--package", "my-crate", "--lib", "--", "my_test", "--exact", "--include-ignored"]
    }
}
```

would end up getting deserialized as a Cargo command, silently dropping
`program` and `args`.

With this fix, we now use the provided `kind` as a tag. We do have to
introduce a `#[serde(flatten)]` unfortunately, which has a few side
effects due to internal buffering, but `#[serde(untagged)]` also does
internal buffering so this doesn't make things worse.

I've manually tested this by configuring:

```json
{
    "lsp": {
        "rust-analyzer": {
            "initialization_options": {
                "runnables": {
                    "test": {
                        "overrideCommand": [
                            "cargo",
                            "nextest",
                            "run",
                            "--package",
                            "${package}",
                            "${target_arg}",
                            "${target}",
                            "--",
                            "${test_name}",
                            "${exact}",
                            "${include_ignored}"
                        ]
                    }
                }
            }
        }
    }
}
```

and ensuring that nextest is correctly invoked.

Self-Review Checklist:

- [x] I've reviewed my own diff for quality, security, and reliability
- [x] Unsafe blocks (if any) have justifying comments
- [x] The content is consistent with the [UI/UX
checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist)
- [x] Tests cover the new/changed behavior
- [x] Performance impact has been considered and is acceptable

Release Notes:

- Fixed deserialization of rust-analyzer shell runnables.

---------

Co-authored-by: Kirill Bulatov <kirill@zed.dev>
47fb164f28Rain committed on 4/27/2026, 7:36:43 AM· committed by GitHubparentda866b4
2 files changedLine totals unavailable