Recent Eclipse JDT LS releases need Java 25 to run, so projects on JDK 21 had no Java language support until the user downloaded a newer JDK by hand. When JDT LS is about to start, no installed JDK is new enough, and no language-server JDK is set explicitly, the IDE now downloads the Temurin JRE of the required version (about 50 MB, falling back to the JDK image where no JRE build exists) with a cancellable background task, then starts the server on it. The runtime lives in its own folder under the app data directory, outside the roots scanned for project JDKs, so the project JDK, run configurations and JDT LS's project runtimes are unchanged. One download runs at a time across windows and is reused; a failed attempt falls back to the existing manual Download JDK action and is not retried until the next start.
Fixes#258
Refs #271
未在 Windows / Linux 实机验证。
Toolchain detection only knew fixed install locations (SDKMAN, nvm, pyenv…), so per-version managers were invisible and project-pinned versions were ignored; mise also only reaches PATH through an interactive-shell hook. JDK, Node.js, Python, Go and Maven installs under mise (MISE_DATA_DIR / XDG) and asdf (ASDF_DATA_DIR) are now detected, pinned versions from mise.toml variants and .tool-versions are resolved and used when the SDK setting is Automatic, and the managers' shims/installs are added to PATH when the login shell didn't.
Fixes#207
Claude-Session: https://claude.ai/code/session_01Dq6jQQn8ZhRfkkyj3PRutA
jdtls was launched with -Xms1G and no heap cap or GC choice, so the JVM grew to a quarter of physical RAM during import and kept it. Default VM args are now ParallelGC with GCTimeRatio/AdaptiveSizePolicyWeight, -Xmx2G -Xms100m, disabled memory-mapped zips and VM-install detection, prepended as --jvm-arg so both the direct and launcher-script paths get them. User JVM options replace the matching default (heap, -D/-XX by name, any -Xlog, any GC flag drops the whole GC group).
Fixes#193
Claude-Session: https://claude.ai/code/session_01Dq6jQQn8ZhRfkkyj3PRutA
* feat(editor): Drag tabs and files between split panes
HTML5 drag and drop never reaches the webview while native file drop is
enabled, so tab, project-file and changelist drags did nothing. They now
run on pointer events:
- Drag an editor tab onto another pane, or onto a pane's edge to split it.
- Drag files from the Project view into an editor pane (center opens them
there, an edge opens them in a new split).
- Drag files between changelists in the Commit view.
- "Drag-and-drop with Alt pressed only" applies to tabs and stripe buttons.
* fix(lsp): Deliver server settings and start servers on a supported JDK
- workspace/configuration answers a server's own section (basedpyright)
from its settings block; basedpyright runs in "standard" mode and keeps
auto search paths on, so `src/` layouts resolve from `tests/`.
- jdtls: formatting follows the editor indent, calls complete without
guessed arguments, and JDK internals stay out of completion.
- `max-java` in a language server config picks an installed JDK no newer
than that (kotlin-language-server fails on JDK 25).
- Server initialization may take up to 5 minutes (first Gradle import).
- `lsp_resend_diagnostics` re-emits stored diagnostics after a reload.
- Spelling only checks declared names (not called methods like
`substring`) and accepts plurals of known software terms.
* feat(editor): Quick fixes, completion and navigation while typing
Quick fixes
- Errors get a red quick-fix bulb; Apply Quick Fix (⌥⇧↵) fixes the most
severe problem at the caret, and the error hover offers the fix directly.
- Code generated by a code action is re-indented to the file's style.
- Python: Implement abstract methods (⌃I or the bulb) from the bases.
- Duplicate code actions are listed once.
Completion
- Overloads sharing a name, and a name importable from several modules,
are no longer merged into one entry.
- Auto-import entries show the module they import from.
- Call snippets without a stop (`new ArrayList<>()`) leave the caret inside
the parentheses with parameter info, or past them when nothing takes
arguments; parameter info also opens after server call snippets.
- The selected item is resolved ahead of acceptance, so its auto-import
is applied (rust-analyzer).
Navigation and diagnostics
- Language server requests wait for pending edits, so Go to Declaration
right after typing answers for the current text; an empty answer right
after an edit is retried while the server catches up.
- Diagnostics come back after a window reload; error underlines stay
visible under typo / unused highlighting.
- Implementation gutter markers no longer refresh in a loop while the
server reports progress.
- A missing alternative server no longer shows as a server error.
* chore(lint): Skip agent worktrees under .claude
* fix(editor): Skip cancelled LSP requests and limit generated-code reformat
- Requests cancelled while waiting for pending edits are not sent.
- Code generated by an action is reformatted per changed hunk, so an added
import doesn't reformat the code between it and the generated lines.
- A long busy spell caused by a settle refresh re-runs it only once.
- Files dropped on a file row of another changelist move to that changelist.
- Python Implement methods: a nested class without bases ends the lookup,
class bodies continue through unindented string lines, and
`@abstractproperty` stubs become `@property`.
- Resend diagnostics goes through the host ops, and custom servers get
`max_java`.
* fix(editor): Rank the exact type first in Java constructor completion
jdtls appends the call or body to filterText (`String(${0})`); matching
on the label instead lets typing `String` rank `String` above
`StringBuilder` and the other types sharing its sort text.
* fix(editor): List identical completion items once
kotlin-language-server repeats a class once per classpath entry declaring
it, so `String()` and `String` were listed three times each.
* fix(editor): Keep the internal cancellation message out of the UI text catalog
Root cause: the IDE only detected installed JDKs and had no way to get one, so any launch needing a newer JDK than the machine has (latest jdtls needs JDK 25) dead-ended in an error.
Fix: IDEA-style Download JDK (Eclipse Temurin via the Adoptium API, sha256-verified, reusing ide-tools' download/verify code; Windows zip, Linux tar.gz, macOS Contents/Home) into <app-data>/tools/jdks, registered with JDK discovery and rescanned after each download. "Download JDK…" in the Project SDK and Language Server JDK pickers; a one-click `java.downloadJdk` "Download JDK N" on "needs JDK N" errors, which also repoints a too-old language server JDK and restarts jdtls.
Siblings: language server status popup, jdtls launch notification, run console classpath error, debug launch, run configurations without a JDK ≥ the module's Java version, Maven/Gradle sync failures, single-file Java run without `java` on PATH.
Verified in the app on macOS: vendor/version/location queries, the Download JDK dialog from the Language Server JDK picker, a real Temurin 25.0.5 download that runs. Not verified on Windows/Linux.
Fixes#49https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Root cause: missing_runtime_message only suggested JAVA_HOME (process-wide) although a per-app Language Server JDK setting exists since #21.
Siblings covered: server_jdk_too_old_message now names the same Settings page via a shared SERVER_JDK_SETTING const; both asserted in tests.
- Languages & Frameworks › Java › Language Server › JDK (languages.java.jdtlsJdk) runs jdtls on its own JDK, like IDEA's JDK for importer; the project keeps compiling and running with the Project JDK.
- Toolchain pages get the Global / This project switch (default This project); Global shows and edits the global layer.
- File › New Projects Setup › Settings for New Projects… edits only the global layer, which new projects inherit.
- Configuration errors (launch_error) show as "Not started" instead of "Crashed".
Fixes#18Fixes#19
Claude-Session: https://claude.ai/code/session_01SaPPsVPuk6ZTNsoUCNCbMv
The JDK was always picked automatically (JAVA_HOME, PATH, the usual install dirs, by the
module's Java version) and Maven was the project's mvnw or mvn on PATH, with no way to
override either. languages.java.jdk (Languages & Frameworks › Java › Project JDK) now sets
the default jdtls runtime, the JDK of Run/Debug and JAVA_HOME for Maven and Gradle;
languages.java.maven (Build Tools › Maven) sets the Maven home, -s and
-Dmaven.repo.local for sync, builds, tool-window goals and detected run configurations.
JDKs and Maven installations are detected for the pickers.
Closes#13
* fix(java): Run jdtls with a Lombok agent and show build errors at launch
jdtls compiles with ECJ, which only generates Lombok members when the
server JVM runs -javaagent:lombok.jar. Nothing put it there, so @Data /
@Setter classes lost their accessors and Run launched stale classes
with "Unresolved compilation problem" stubs and no explanation.
- Projects whose build files mention Lombok get the newest jar: the
IDE-managed one (new "Lombok (jdtls agent)" tool, latest release from
Maven Central), else ~/.m2 (incl. settings.xml localRepository) or the
Gradle cache. Each agent gets its own jdtls workspace so everything is
rebuilt with it.
- Settings › Languages & Frameworks › Java › JVM options
(java.jdt.ls.vmargs); a Lombok agent there wins.
- Run (and Debug, as a notification) list the first compile errors when
the build has errors, plus a hint when Lombok is missing or older than
1.18.34.
Fixes#3
* fix(java): Base the Lombok hint on the agent jdtls actually runs
A Lombok agent in Settings › Java › JVM options wins over the managed
and cached jars, but the launch hint still looked only at those: with
no cached jar it said Lombok was missing, and with an old cached one it
blamed that version although jdtls ran the user's. The hint and the
startup warning now use the user's agent (version from its file name).
* fix: Stop the status refresh loop and the double project open at startup
Every status rewrote .git/index, even with nothing to persist: gix's
`write_changes` writes an empty change set too. The watcher reports
.git/index writes as VCS changes, so each status triggered the next one,
together with an ahead/behind walk. On a repository with a long history
(freqtrade, 33k commits behind upstream) that kept a core busy for as long
as the project was open. Write back only when `has_changes()`.
A project passed on the command line was opened twice: the launch and the
"reopen last project" restore ran concurrently, and the restore checked
for an open project before the launch had finished. The second open found
the index cache locked and indexed in memory only; with a different last
project, the window ended up on whichever finished last. The restore now
waits for the startup launch.
* fix(lsp): Run jdtls on the Java version its bundles need
jdtls's launcher checks for Java 21, and so did JDTLS_MIN_JAVA, but the
Eclipse platform a release ships moves on: 1.63 bundles
org.eclipse.core.filesystem with JavaSE-25, so on a JDK 21 the server died
resolving its bundles ("jdtls is not ready (Crashed)") and the error told
users to install the 21 they already had.
Read the requirement from the installed jdtls instead: the highest osgi.ee
capability / Bundle-RequiredExecutionEnvironment among its plugins'
manifests (cached per install), never below 21. The runtime choice, the
rescan while no JDK fits and the "needs JDK N" message use it.
Fixes#4
* fix(lsp): Run jdtls on a JDK 21+ and offer Install in the server popup
jdtls refuses to start on Java < 21, and its launcher took whatever
JAVA_HOME / PATH pointed at, so it crash-looped with a Python traceback
when that was an older JDK (#1). Pick the first detected JDK 21+ and pass
it via JAVA_HOME; projects still compile against their own runtimes.
When none is found, report a clear message instead of launching, and
rescan on restart so a newly installed JDK is picked up. JDK detection
now also covers the java on PATH and Windows vendor directories.
The Language Servers status popup showed the manual install hint for
missing servers; it now has an Install button that runs tools.install,
which opens the Language Servers settings page for tools the IDE cannot
install itself.
Fixes#1
Claude-Session: https://claude.ai/code/session_01B65qLEKnkeYTGdbwhLpjCu
* fix(lsp): Address review of the jdtls runtime check
- Cache the JDK scan and rescan at most every 10s while no JDK 21+ is
found, refreshing the shared list instead of discarding it; skip
duplicate Windows Program Files roots.
- Check `launch_error` in the manager (inside the blocking launch task)
rather than in ProcessLauncher, and skip such servers in batch
inspection.
- Keep the install hint visible next to the Install button; when the tool
list failed to load, try the install so the error is reported.
- Don't let a server snapshot requested before a status event overwrite
that newer status (left jdtls showing "Starting…" while missing).
Use the Windows wrapper name for Maven, compare walked paths with `/`,
relax the own-process footprint floor, skip tests that assert Unix paths
or shells on Windows, and stop Git converting fixture line endings in CI.
Claude-Session: https://claude.ai/code/session_01B65qLEKnkeYTGdbwhLpjCu