fix(project-tree): reveal files of linked workspace projects (#915) (#1035)

In a workspace the tree's root is the workspace directory, and the linked projects are separate top-level roots outside it. Select Opened File (and other reveals) only looked inside that root and contributed folders, so a file of a linked project was never expanded, selected or scrolled to. Reveal now resolves the innermost linked project containing the path first; the Project Files pane also counts linked projects as shown.

Co-authored-by: Claude Opus 5.5 <[email protected]>
This commit is contained in:
JawandClaude Opus 5.5 authored and GitHub committed 2026-11-03 20:30:07 +08:00
1 parent 4b1614af1f
commit a57267fa32
2 files changed
+23 -2

No files matched your search

+11
View File
@@ -146,6 +146,17 @@ describe("reveal and expand", () => {
expect(visibleInfo(currentModel(), s.expanded).visible.has("/p/docs/guide.md")).toBe(true);
});
it("reveals files of linked workspace projects outside the workspace directory", async () => {
fs = new MemoryFs({ "/ws/.openidea/workspace.json": "x", "/a/src/app.ts": "x", "/b/lib/util.ts": "x" }, "/");
setProjectFsForTests(fs, "/ws");
initProjectTree("/ws", "ws", ["/a", "/b"]);
expect(revealPath("/b/lib/util.ts")).toBe(true);
await vi.waitFor(() => expect(childLabels("/b/lib")).toEqual(["util.ts"]));
const s = useProjectTree.getState();
expect(s.revealRequest?.path).toBe("/b/lib/util.ts");
expect(visibleInfo(currentModel(), s.expanded).visible.has("/b/lib/util.ts")).toBe(true);
});
it("expands everything below a folder", async () => {
await expandAll();
const s = useProjectTree.getState();
+12 -2
View File
@@ -548,7 +548,7 @@ let revealSeq = 0;
export function revealPath(path: string, focus = false) {
const { expanded } = get();
const project = get().root;
const root = project && isSameOrInside(path, project) ? project : project ? extraRootOf(path) : null;
const root = project ? (memberRootOf(path) ?? (isSameOrInside(path, project) ? project : extraRootOf(path))) : null;
if (!root) return false;
// Library folders sit below group nodes (External Libraries › SDK), keyed in their own namespace.
const model = currentModel();
@@ -568,6 +568,16 @@ export function revealPath(path: string, focus = false) {
return true;
}
/**
* The linked workspace project containing `path`, if any (the innermost one). A
* workspace's root is its own directory; its projects are separate top-level roots.
*/
function memberRootOf(path: string): string | null {
let found: string | null = null;
for (const m of get().members ?? []) if (isSameOrInside(path, m) && (!found || m.length > found.length)) found = m;
return found;
}
/** The contributed folder (scratches, a library root…) containing `path`, if any. */
export function extraRootOf(path: string): string | null {
for (const r of extraFolders(projectViewRoots(useProjectViewRoots.getState().roots)))
@@ -583,7 +593,7 @@ export function modeShows(path: string): boolean {
case "project":
return true;
case "projectFiles":
return isSameOrInside(path, root);
return memberRootOf(path) !== null || (!get().members && isSameOrInside(path, root));
case "scratches":
return projectViewRoots(useProjectViewRoots.getState().roots).some(
(r) => r.scope === "scratches" && r.path !== undefined && isSameOrInside(path, r.path),