Compare commits

..
Author SHA1 Message Date
l0ng-ai 5e83d103cc fix(project-tree): list a re-installed SNAPSHOT's entries after reloading the project
A SNAPSHOT installed again replaces its jar in place, which no file watcher
reports, so folders already expanded inside it under External Libraries kept
the old entries, even after collapsing and expanding them again. The project
view now re-reads its loaded folders inside archives when project roots change
(a build tool sync); the backend's archive listing already follows the jar's
modification time and size.
2026-11-13 20:03:53 +08:00
l0ng-ai 6f83f8cad0 fix(java): show a re-installed SNAPSHOT's classes after reloading the project (#3157)
A SNAPSHOT installed again replaces its jar in place, so class URIs and jdtls' class handles stay the same; the backend's virtual document cache, the editor's cache and jdtls' decompiler cache all kept the old contents. Cached library classes now record their archive's modification time and are read again once it changes; after a build tool sync jdtls refreshes external archives, closes the changed roots and drops its decompiled sources (openidea.java.refreshArchives, java-usages 1.14.0), and open classes whose jar changed are replaced. The editor drops cached virtual documents when project roots change.
2026-11-13 20:01:02 +08:00
3 changed files with 35 additions and 0 deletions

No files matched your search

+2
View File
@@ -34,6 +34,7 @@ import {
initProjectTree,
leadSelection,
reloadAll,
reloadArchiveDirs,
reloadLoadedDirs,
setChangedFiles,
setOpenFiles,
@@ -253,6 +254,7 @@ 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,6 +3,7 @@ import { MemoryFs, setProjectFsForTests } from "./fs";
import { visibleInfo } from "./model";
import {
applyFsChange,
reloadArchiveDirs,
reloadLoadedDirs,
currentModel,
expandAll,
@@ -114,6 +115,28 @@ 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,6 +565,16 @@ 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();