Skip to content

Add Docker Compose language support - #48

Merged
MrSubidubi merged 5 commits into
zed-extensions:mainfrom
eth0net:feat/docker-compose-language
Aug 21, 2026
Merged

Add Docker Compose language support#48
MrSubidubi merged 5 commits into
zed-extensions:mainfrom
eth0net:feat/docker-compose-language

Conversation

@eth0net

@eth0net eth0net commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

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 Compose language, matched on compose.yaml, compose.yml,
docker-compose.yaml and docker-compose.yml. Its own language rather than an
extension 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_DOCS errors on unrelated files
(eth0net/zed-docker-compose#2, zed-industries/zed#12122).

Runnables for services. Each entry under services: can be started from the
gutter, offering docker compose, docker-compose, podman compose and
podman-compose. This is @lnay's work from the original extension.

A fix to the language id. The existing language_ids mapping sent
docker-compose, but the server gates every Compose feature on
dockercompose:

DockerComposeLanguage LanguageIdentifier = "dockercompose"

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, not docker-compose — ids must be
snake_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:

wasm-ld: error: symbol exported via --export not found: tree_sitter_docker_compose

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
initializationOptions the extension sends:

languageId Result
dockercompose hover with compose-spec schema docs, symbols, completion, rename
docker-compose nothing
yaml nothing

The grammar was compiled with Zed's bundled wasi-sdk clang both ways to confirm
the symbol constraint above. cargo build --release --target wasm32-wasip2
passes.

Notes

  • No version bump — I left that to extensions::bump_version. This probably
    wants the minor label.
  • Update docker-compose to v0.4.1 zed-industries/extensions#7105 should be closed rather than merged if this
    lands, otherwise both extensions would define a Docker Compose language and
    collide. Happy to close it myself once you've had a look.
  • That leaves the standalone docker-compose extension redundant. It's still
    published 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.

eth0net and others added 2 commits August 10, 2026 15:43
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>
Copilot AI lite review requested due to automatic review settings August 10, 2026 14:43
@cla-bot cla-bot Bot added the cla-signed label Aug 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 Compose language (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.

Comment thread languages/docker-compose/brackets.scm Outdated
Comment on lines +1 to +3
("[" @open "]" @close)
("{" @open "}" @close)
("\"" @open "\"" @close)
Comment on lines +3 to +20
"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"]
eth0net added a commit to eth0net/zed-docker-compose that referenced this pull request Aug 10, 2026
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>
@eth0net

eth0net commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Both Copilot comments were fair, and chasing the first one turned up two more
problems. Fixed in a259b50.

Single-quote brackets — correct, and worth comparing against Zed's own YAML
queries, which do include the pair. Ours were derived from Zed's YAML as it stood
in early 2024 and had drifted since. Now matched, including the
rainbow.exclude directives upstream sets.

overrides.scm was missing entirely. This is the one I'm glad the first
comment led me to. It defines the string override that the
not_in = ["string"] clauses on the quote brackets refer to — without it those
clauses had nothing to resolve against, so quotes would auto-close inside
strings. Added.

increase_indent_pattern was also the 2024 version, predating Zed's fix for
comments and for the first element of an array of objects. Updated.

outline.scm now captures the value as @context as upstream does, so
outline entries show their value and not just the key.

compose run vs compose up — the task labels were accurate (docker compose run), but my README line said services could be "started", which
misdescribes it. Reworded to say it starts a one-off container rather than
bringing the service up.

On whether to add compose up <service> runnables: I've left that alone for
now, since the run tasks are @lnay's original design and I didn't want to
change intent while moving them. Happy to add up variants alongside if you
think users would expect them — it's four more entries in tasks.json.

Two things still not carried over from Zed's YAML, deliberately, and easy to add
if you'd like them: textobjects.scm and injections.scm.

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>
@eth0net

eth0net commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

Added the up and down runnables in edc48e4, so each service now offers
up / run / down rather than just run.

I checked that a positional service name is actually accepted before adding
them, since a broken gutter task is worse than a missing one:

  • docker composedocker compose up [SERVICE...] and
    docker compose down [OPTIONS] [SERVICES] per the CLI reference
  • docker-compose — same, via the Compose v2 standalone binary. Worth noting
    Compose v1 didn't accept services for down, but it's been EOL since 2023
  • podman-compose — its argparse registers positional services for
    ["build", "up", "down", "start", "stop", "restart"], so both are covered

up is left attached rather than passing -d, so logs land in the task terminal
the way run already does. Easy to flip if you'd rather it detached.

One thing to weigh: this takes the runnable menu from 4 entries to 12, since each
of the three verbs is offered for all four tools. It's consistent, but it is a
longer list. If you'd prefer it trimmed, dropping the podman compose /
podman-compose split — or offering only docker compose and podman-compose
would halve it.

MrSubidubi
MrSubidubi previously approved these changes Aug 21, 2026

@MrSubidubi MrSubidubi left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delayed review, this looks good! Thanks!

@MrSubidubi
MrSubidubi merged commit a6d5205 into zed-extensions:main Aug 21, 2026
5 checks passed
@eth0net
eth0net deleted the feat/docker-compose-language branch August 21, 2026 12:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants