Skip to content

feat(proxy): support multi-level navigation from decompiled JAR classes - #305

Open
FanXingChunShui wants to merge 2 commits into
zed-extensions:mainfrom
FanXingChunShui:feature/multi-level-jar-navigation
Open

feat(proxy): support multi-level navigation from decompiled JAR classes#305
FanXingChunShui wants to merge 2 commits into
zed-extensions:mainfrom
FanXingChunShui:feature/multi-level-jar-navigation

Conversation

@FanXingChunShui

Copy link
Copy Markdown

Summary

When JDTLS resolves a symbol that lives inside a JAR, it returns jdt:// URIs. java-lsp-proxy already rewrites those into temporary decompiled .java files so Zed can open them, but navigation then stopped: Zed sends follow-up requests against the temporary file:// URI, which JDTLS does not understand.

This PR adds the reverse half of that mapping so navigation can continue from one decompiled class into another.

Changes

  • proxy-common: add file_uri_to_path (inverse of path_to_file_uri).
  • proxy (decompile.rs): persist a file:// -> jdt:// mapping as a <name>.java.jdt-uri sidecar next to each cached decompiled source.
  • proxy (main.rs):
    • rewrite incoming textDocument request URIs back from file:// to jdt:// before forwarding to JDTLS;
    • suppress didOpen/didChange/didSave/didClose for decompiled-source worktrees so JDTLS never treats them as editable project files.

The mapping is stored on disk rather than in memory because Zed opens decompiled files in their own worktree, which spawns a fresh java-lsp-proxy process.

Validation

  • cargo test -p proxy-common -p java-lsp-proxy: 53 + 11 tests pass (including 5 new tests).
  • cargo clippy -p proxy-common -p java-lsp-proxy --all-targets: clean.
  • cargo fmt --all: clean.
  • cargo check -p gradle-lsp-bridge: passes.
  • Manually verified in Zed that follow-up navigation from a decompiled JAR class now works.

@cla-bot

cla-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

Thank you for your pull request and welcome to our community. We could not parse the GitHub identity of the following contributors: ckwang.
This is most likely caused by a git client misconfiguration; please make sure to:

  1. check if your git client is configured with an email to sign commits git config --list | grep email
  2. If not, set it up using git config --global user.email email@example.com
  3. Make sure that the git commit email is configured in your GitHub account settings, see https://github.com/settings/emails

JDTLS reports classes inside jars with jdt:// URIs. The proxy already
rewrites those into temporary decompiled .java files so Zed can open them,
but navigation then stopped: Zed sends follow-up requests against the
temporary file:// URI, which JDTLS does not understand.

Persist the reverse mapping (file:// -> jdt://) next to each cached
decompiled source, and rewrite incoming textDocument request URIs back to
jdt:// before forwarding. Also suppress didOpen/didChange/didSave/didClose
for decompiled-source worktrees so JDTLS never treats them as editable
project files.

The mapping lives on disk because Zed opens decompiled files in their own
worktree, which spawns a fresh proxy process.
@FanXingChunShui
FanXingChunShui force-pushed the feature/multi-level-jar-navigation branch from 73d215f to 3de5084 Compare August 21, 2026 09:00
@cla-bot

cla-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

We require contributors to sign our Contributor License Agreement, and we don't have @FanXingChunShui on file. You can sign our CLA at https://zed.dev/cla. Once you've signed, post a comment here that says '@cla-bot check'.

@FanXingChunShui

Copy link
Copy Markdown
Author

@cla-bot check

@cla-bot cla-bot Bot added the cla-signed label Aug 21, 2026
@cla-bot

cla-bot Bot commented Aug 21, 2026

Copy link
Copy Markdown

The cla-bot has been summoned, and re-checked this pull request!

Comment thread proxy/src/decompile.rs Outdated
@tartarughina

tartarughina commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator

@FanXingChunShui Could you point to a readily available example where the issue you are addressing here exists?
I'd like to try the change myself before approving.

Comment thread proxy-common/src/uri.rs Outdated
let rest = uri.strip_prefix("file://")?;
let decoded = percent_decode_str(rest).decode_utf8().ok()?;

if cfg!(windows) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Let's please strive to use compile time checks rather than runtime

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Done in b490a90 — file_uri_to_path now uses #[cfg(windows)] / #[cfg(not(windows))] blocks, so only the branch for the current platform is compiled.

- Use compile-time cfg(windows) blocks instead of runtime cfg! in file_uri_to_path
- Simplify sidecar_path with Path::with_added_extension
@FanXingChunShui

Copy link
Copy Markdown
Author

@FanXingChunShui Could you point to a readily available example where the issue you are addressing here exists? I'd like to try the change myself before approving.

Any Java project reproduces it — no special dependencies required, the JDK alone is enough, since JDTLS returns jdt:// URIs for any class that lives in a JAR. Steps (with the Java extension built from this PR):

  1. Open any Java project in Zed.
  2. Go to Definition on a symbol defined in a JAR, e.g. println in System.out.println("hi"). Zed opens the decompiled class from the jdtls_decompiled temp directory — this already worked before this PR.
  3. From inside that decompiled class, Go to Definition on another symbol, e.g. a field type or method return type like PrintStream.

Before this PR, step 3 silently does nothing: Zed sends the follow-up request against the temporary file:// URI, which JDTLS does not recognize. This PR maps that URI back to the original jdt:// URI before forwarding, so navigation continues — and it chains, so you can navigate from one decompiled class into the next.

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.

2 participants