Compare commits

..
Author SHA1 Message Date
l0ng-ai 6402bd0bc2 fix(java): show a re-installed SNAPSHOT's classes after reloading the project
A SNAPSHOT installed again replaces its jar in place, so the path, the URIs
of its classes and jdtls' class handles stay the same. The compile model
picked up the new jar on reload, but an open decompiled class kept the old
contents, and reopening it did too: the backend's virtual document cache,
the editor's cache and jdtls' decompiler cache (keyed by class handle) all
still held what was read from the old jar.

The backend now records the archive's modification time with each cached
library class and reads the class again once it changed. After a build tool
sync it asks jdtls to refresh external archives, close the changed archives'
package fragment roots and drop its decompiled sources
(openidea.java.refreshArchives), then replaces the open classes whose jar
changed. The editor drops its cached virtual documents when project roots
change. Covers jar: and jdt: classes, decompiled or read from the archive.
2026-11-13 20:00:37 +08:00
3 changed files with 0 additions and 35 deletions

No files matched your search

-2
View File
@@ -34,7 +34,6 @@ import {
initProjectTree,
leadSelection,
reloadAll,
reloadArchiveDirs,
reloadLoadedDirs,
setChangedFiles,
setOpenFiles,
@@ -254,7 +253,6 @@ export function activate(): () => void {
initProjectTypes(),
onIdeEvent("fsChanged", (e) => void applyFsChange(e)),
onIdeEvent("excludedDirsChanged", (e) => void reloadLoadedDirs(e.dirs)),
onIdeEvent("projectRootsChanged", () => void reloadArchiveDirs()),
];
return () => {
disposers.reverse().forEach((d) => d());
-23
View File
@@ -3,7 +3,6 @@ import { MemoryFs, setProjectFsForTests } from "./fs";
import { visibleInfo } from "./model";
import {
applyFsChange,
reloadArchiveDirs,
reloadLoadedDirs,
currentModel,
expandAll,
@@ -115,28 +114,6 @@ describe("refresh of excluded folders", () => {
});
});
describe("refresh of library archives", () => {
it("re-reads the loaded folders inside archives only", async () => {
await fs.createFile("/m2/lib.jar!/p/A.class");
await loadDir(ROOT);
await loadDir("/m2/lib.jar!");
await loadDir("/m2/lib.jar!/p");
await fs.createFile("/m2/lib.jar!/p/B.class");
const spy = vi.spyOn(fs, "readDir");
await reloadArchiveDirs();
expect(spy.mock.calls.map(([p]) => p).sort()).toEqual(["/m2/lib.jar!", "/m2/lib.jar!/p"]);
expect(
useProjectTree
.getState()
.listings.get("/m2/lib.jar!/p")
?.map((e) => e.name),
).toEqual(["A.class", "B.class"]);
spy.mockRestore();
});
});
describe("refresh on ignore-rule changes", () => {
it("refreshes loaded descendants once, preserving selection and unrelated folders", async () => {
await fs.createFile("/p/docs/sub/note.md");
-10
View File
@@ -565,16 +565,6 @@ export async function reloadLoadedDirs(dirs: readonly string[]) {
await Promise.all(dirs.filter((p) => listings.has(p)).map((p) => loadDir(p, true)));
}
/**
* Re-reads the loaded folders inside archives (`<archive>!…`): a build tool sync may have replaced
* a library jar in place (a SNAPSHOT installed again), which no file watcher reports.
*/
export async function reloadArchiveDirs() {
const { listings } = get();
const inArchive = (p: string) => p.endsWith("!") || p.includes("!/") || p.includes("!\\");
await Promise.all([...listings.keys()].filter(inArchive).map((p) => loadDir(p, true)));
}
/** Re-reads every loaded folder (View › Reload from Disk). */
export async function reloadAll() {
const { listings } = get();