Skip to content

feat: Add google-java-format and palantir-java-format support#264

Open
fredyw wants to merge 1 commit into
zed-extensions:mainfrom
fredyw:formatters
Open

feat: Add google-java-format and palantir-java-format support#264
fredyw wants to merge 1 commit into
zed-extensions:mainfrom
fredyw:formatters

Conversation

@fredyw
Copy link
Copy Markdown
Contributor

@fredyw fredyw commented May 29, 2026

Integrates google-java-format and palantir-java-format support into the LSP proxy wrapper using a generic Formatter trait by intercepting document formatting requests at the LSP proxy layer.

Key architecture and features:

  1. Introduces generic Formatter to allow future formatting backends to be plugged in easily.
  2. Automatically downloads google-java-format binaries from GitHub Releases and palantir-java-format binaries from Maven Central.
  3. Intercepts textDocument/formatting requests, retrieves the document from the cache, spawns the formatter command, and responds with the replaced document changes.
  4. Add supports for runtime toggling and hot-swapping formatters dynamically by listening to configuration notifications.

Integrates [google-java-format](https://github.com/google/google-java-format) and
[palantir-java-format](https://github.com/palantir/palantir-java-format) support
into the LSP proxy wrapper using a generic `Formatter trait` by intercepting document
formatting requests at the LSP proxy layer.

Key architecture and features:
1. Introduces generic `Formatter` to allow future formatting backends to be plugged
   in easily.
2. Automatically downloads `google-java-format` binaries from GitHub Releases and
   `palantir-java-format` binaries from Maven Central.
3. Intercepts `textDocument/formatting` requests, retrieves the document from the cache,
   spawns the formatter command, and responds with the replaced document changes.
4. Add supports for runtime toggling and hot-swapping formatters dynamically by listening
   to configuration notifications.
@cla-bot cla-bot Bot added the cla-signed label May 29, 2026
@tartarughina
Copy link
Copy Markdown
Collaborator

Thanks for the PR but is this really needed?
JDTLS already offers the option to provide a .xml file describing how it should format the code.
This is for example how I've been handling my formats.

What are the benefits of including these two specific formatters?

@fredyw
Copy link
Copy Markdown
Contributor Author

fredyw commented May 29, 2026

The XML option is basically using Eclipse formatter that tries to match Google Java Style or Palantir Java Style (fork of Google Java Format). It's an approximation and never 100% the same. Ideally when we code and when we run it in CI (using spotless for instance), we want the formatting to be 100% compatible to reduce friction for developers.

The option to use the Eclipse formatter still exists for those that prefer that. It's just an additional feature that I thought might benefit others.

@tartarughina
Copy link
Copy Markdown
Collaborator

I see, I assumed that the end result of those formatters was the xml then consumed by JDTLS.

Rather than integrating in the proxy the two formatters we could follow a different approach, similar to what Zed is doing with Ruff, for example.

https://github.com/zed-industries/zed/blob/e2e7a6769e693c843c82cea2dcf65917c139cc0f/assets/settings/default.json#L2261-L2272

    "Python": {
      "code_actions_on_format": {
        "source.organizeImports.ruff": true,
      },
      "formatter": {
        "language_server": {
          "name": "ruff",
        },
      },
      "debuggers": ["Debugpy"],
      "language_servers": ["basedpyright", "ruff", "!ty", "!pyrefly", "!pyright", "!pylsp", "..."],
    }

We vend from the extension the two LSP implementations wrapping the formatters and then the user, in order to enable them, uses the Java language settings, rather than the one for the extension, setting a different language server whose job is to format the code.

I see some clear benefits following this path:

  1. this is the intended way to define formatters with Zed
  2. clear separation between JDTLS and the different formatters
  3. simpler logic, format requests are sent by Zed to the assigned formatter rather than being intercepted and redirected

I'm happy to further discuss about this.
@MrSubidubi, since you are the one with more experience, what is your take, or Zed's team generally speaking, onto this matter?

@MrSubidubi
Copy link
Copy Markdown
Contributor

I think for this use-case, having formatter: { external: ...} would be more appropriate, since we also support that and these are just formatters, are they not?

With that though, we would currently lose the ability to auto-download these if they are needed, see zed-industries/zed#31904. I am happy to discuss (intermediate) solutions for this, but at least that would be the "best" way for supporting this I think.

@fredyw
Copy link
Copy Markdown
Contributor Author

fredyw commented Jun 3, 2026

Thanks for the feedback.

I agree that using formatter: { external: ... } is the most appropriate approach here. The main reason I went with the LSP proxy interception was to achieve a seamless user experience, especially being able to download the formatters and having to create separate LSPs just for formatting would be an overkill.

I'm completely open to changing it. What do you think is the best intermediate path forward?

@tartarughina
Copy link
Copy Markdown
Collaborator

We can update the README with instructions for installing both formatters and adding them to the PATH. Currently only Google’s formatter is available via Homebrew; Palantir’s is not. If both were available from Homebrew or another package manager, installing via package manager would be the simplest solution.

Otherwise we can consider
Option 1: Let the extension download the formatters

As this PR already shows, the extension can download the formatters for users.
This requires updating settings in two places:

  • The Java language settings (set the external formatter).
  • The extension settings (enable the download).

Downside: the external formatter must be configured to point to the exact location where the extension downloaded the executable, because it won’t be on the PATH as a normal install would. That’s not ideal for users.

Option 2: Use an LSP proxy (most user-friendly)

Provide a single place to configure formatting behavior.
Users only need extra settings if they want specific formatter behaviors.
This is the most seamless experience for users, but it’s also the most complex to implement.

For now, the simplest path is to document the manual installation (delegate the download to the user). In the future, if/when it’s supported, add an automatic-download option in the extension.

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