Add Docker Compose language support - #48
Conversation
The Docker Language Server decides whether a document gets Compose support
by its LSP language id, and the id it looks for is `dockercompose`:
DockerComposeLanguage LanguageIdentifier = "dockercompose"
Every Compose feature in the server is gated on that value, so the
hyphenated `docker-compose` we were sending would have produced no Compose
behaviour at all. Verified against v0.20.1 over stdio — with `dockercompose`
a compose file returns hover, document symbols and completion; with
`docker-compose` or `yaml` it returns nothing.
This had no effect until now, since nothing defined a `Docker Compose`
language for the mapping to apply to.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Moves the Docker Compose language definition in from eth0net/zed-docker-compose, so Compose support lives alongside the Docker Language Server that already ships here rather than duplicating it in a separate extension. Compose files get their own language rather than extending YAML, which keeps the server off plain YAML files and gives services runnables — each entry under `services:` can be started from the gutter via docker compose, docker-compose, podman compose or podman-compose. The grammar is registered as `yaml` rather than `docker-compose` because grammar ids must be snake_case and must match the symbol the parser exports, which for tree-sitter-yaml is `tree_sitter_yaml`. Highlight queries are copied from Zed's own YAML queries, since queries can't be shared between languages. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR adds first-class Docker Compose support to the Dockerfile Zed extension by introducing a dedicated “Docker Compose” language (scoped to Compose-specific filenames) and wiring it to docker-language-server, plus service-level runnables.
Changes:
- Add a new
Docker Composelanguage (tree-sitter YAML grammar) with its own queries/config and filename matching. - Add service runnables under
services:with task definitions for Docker/Podman Compose variants. - Fix docker-language-server language id mapping for Compose (
dockercompose) and register the YAML grammar dependency.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Documents added Compose language support and service runnables. |
| extension.toml | Adds Compose language id mapping and YAML grammar registration; updates extension description. |
| languages/docker-compose/config.toml | Defines the Docker Compose language metadata, suffix matching, and editor behaviors. |
| languages/docker-compose/highlights.scm | Provides syntax highlighting queries (copied from YAML). |
| languages/docker-compose/brackets.scm | Defines bracket-pair matching for the Compose language. |
| languages/docker-compose/outline.scm | Adds outline query for YAML/Compose mappings. |
| languages/docker-compose/redactions.scm | Adds redaction query for values. |
| languages/docker-compose/runnables.scm | Adds runnable detection for services under services:. |
| languages/docker-compose/tasks.json | Defines runnable task commands for Docker/Podman Compose. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| ("[" @open "]" @close) | ||
| ("{" @open "}" @close) | ||
| ("\"" @open "\"" @close) |
| "label": "docker-compose run", | ||
| "command": "docker-compose -f $ZED_FILE run $ZED_CUSTOM_service", | ||
| "tags": ["docker-compose-service"] | ||
| }, | ||
| { | ||
| "label": "docker compose run", | ||
| "command": "docker compose -f $ZED_FILE run $ZED_CUSTOM_service", | ||
| "tags": ["docker-compose-service"] | ||
| }, | ||
| { | ||
| "label": "podman-compose run", | ||
| "command": "podman-compose -f $ZED_FILE run $ZED_CUSTOM_service", | ||
| "tags": ["docker-compose-service"] | ||
| }, | ||
| { | ||
| "label": "podman compose run", | ||
| "command": "podman compose -f $ZED_FILE run $ZED_CUSTOM_service", | ||
| "tags": ["docker-compose-service"] |
Compose support moves to zed-extensions/dockerfile, which already ships docker-language-server. Two extensions cannot define the same language or ship the same language server under Zed's publishing prerequisites, and v0.4.0 adopting that server is what made this one a duplicate. See zed-extensions/dockerfile#48. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The queries carried over were derived from Zed's YAML language as it stood in early 2024 and had drifted, in ways that matter: - brackets.scm was missing the single-quote pair, so `'` auto-closed per config.toml but never highlighted as a matched pair - overrides.scm was absent entirely, which is what defines the `string` override that the `not_in = ["string"]` clauses on the quote brackets refer to — without it those clauses have nothing to match and quotes auto-close inside strings - increase_indent_pattern predates Zed's fix for comments and for the first element of an array of objects - outline.scm now also captures the value as @context, giving outline entries their value rather than just the key Also corrects the README: the service runnables invoke `compose run`, which starts a one-off container, not `compose up <service>`. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both Copilot comments were fair, and chasing the first one turned up two more Single-quote brackets — correct, and worth comparing against Zed's own YAML
On whether to add Two things still not carried over from Zed's YAML, deliberately, and easy to add |
Only `run` was offered, which starts a one-off container. `up` and `down` are what you reach for to actually bring a service up and tear it back down. All four tools accept a positional service name for both: `docker compose` and the v2 `docker-compose` standalone per `[SERVICE...]` in the CLI reference, and podman-compose per its own argparse, which registers positional services for `["build", "up", "down", "start", "stop", "restart"]`. `up` is left attached rather than passing -d, so logs land in the task terminal, matching how `run` behaves. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Added the I checked that a positional service name is actually accepted before adding
One thing to weigh: this takes the runnable menu from 4 entries to 12, since each |
MrSubidubi
left a comment
There was a problem hiding this comment.
Sorry for the delayed review, this looks good! Thanks!
Moves Docker Compose support in from
eth0net/zed-docker-compose, per
the discussion on zed-industries/extensions#7105. Thanks @MrSubidubi — you were
right that shipping the language server twice was the wrong shape.
What's here
A
Docker Composelanguage, matched oncompose.yaml,compose.yml,docker-compose.yamlanddocker-compose.yml. Its own language rather than anextension of YAML, which is what keeps the server off plain YAML files — the
original extension attached to YAML wholesale and that caused unresolved-tag
warnings and
MULTIPLE_DOCSerrors on unrelated files(eth0net/zed-docker-compose#2, zed-industries/zed#12122).
Runnables for services. Each entry under
services:can be started from thegutter, offering
docker compose,docker-compose,podman composeandpodman-compose. This is @lnay's work from the original extension.A fix to the language id. The existing
language_idsmapping sentdocker-compose, but the server gates every Compose feature ondockercompose:So Compose features would have been silently dead. It had no effect before now
because nothing defined the language for the mapping to apply to.
The grammar is registered as
yaml, notdocker-compose— ids must besnake_case and match the symbol the parser exports, which for tree-sitter-yaml
is
tree_sitter_yaml. Registering under any other name fails to link:Highlight queries are copied from Zed's YAML queries rather than shared, since
queries can't be delegated between languages.
Verification
Driven against docker-language-server v0.20.1 over stdio with the exact
initializationOptionsthe extension sends:dockercomposedocker-composeyamlThe grammar was compiled with Zed's bundled wasi-sdk clang both ways to confirm
the symbol constraint above.
cargo build --release --target wasm32-wasip2passes.
Notes
extensions::bump_version. This probablywants the
minorlabel.lands, otherwise both extensions would define a
Docker Composelanguage andcollide. Happy to close it myself once you've had a look.
docker-composeextension redundant. It's stillpublished at 0.1.0, which predates the language definition, so there's no
collision in the meantime. I'm glad to retire it — let me know what you'd
prefer for existing users.
Not yet covered
The server also handles Bake files (HCL), which nothing here exposes. Out of
scope for this PR, but worth noting as the remaining gap.