From 89309e40babc602e0781f318fe595ec563c286a7 Mon Sep 17 00:00:00 2001 From: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com> Date: Thu, 5 Nov 2026 02:35:25 +0800 Subject: [PATCH] fix(project): Open in Terminal from the editor opens the edited file's folder (#1348) Open in Terminal and Reveal in Finder / Explorer invoked without a target (a shortcut, Find Action) always used the Project view's selection, so in the editor they opened the folder of whatever was selected there (the project root after reopening a project) instead of the edited file's. Without a target they now use the Project view's selection only while it has focus, and the active editor's file otherwise. Refs #1327 --- src/features/project-tree/actions.ts | 15 +++++++++++++-- src/features/project-tree/selectIn.test.ts | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/features/project-tree/actions.ts b/src/features/project-tree/actions.ts index f871a768..5e02d211 100644 --- a/src/features/project-tree/actions.ts +++ b/src/features/project-tree/actions.ts @@ -1,6 +1,7 @@ /** Actions of the project view (Find Action, keymap, other features via `executeAction`). */ import { activeEditor } from "@/editor/api"; import { getAction, registerActions, type Action } from "@/platform/actions"; +import { getContext } from "@/platform/context"; import { dirname, useProject } from "@/platform/project"; import { showContextMenu, type MenuItem } from "@/ui"; import { maybeEditorService, menuGroupItems, toolWindowService } from "@/workbench/contributions"; @@ -74,6 +75,16 @@ function nodesFrom(arg: unknown): ProjectNode[] { }); } +/** + * The target of an action invoked without one: the Project view's selection while it has focus, + * otherwise the active editor's file (a shortcut pressed in the editor acts on the edited file). + */ +function contextTarget(arg: unknown): unknown { + if (arg !== undefined && arg !== null) return arg; + if (getContext().projectViewFocus) return arg; + return maybeEditorService()?.activePath() ?? arg; +} + function folderFrom(arg: unknown): string | null { if (typeof arg === "string") return useProjectTree.getState().listings.has(arg) ? arg : parentOf(arg); return folderOf(leadNode()); @@ -379,7 +390,7 @@ export function registerProjectActions(): () => void { icon: "external-link", when: OPEN, keywords: ["show in explorer", "open in finder"], - run: ({ arg }) => revealInFinder(nodesFrom(arg)), + run: ({ arg }) => revealInFinder(nodesFrom(contextTarget(arg))), }, { id: "project.openInTerminal", @@ -388,7 +399,7 @@ export function registerProjectActions(): () => void { icon: "terminal", when: OPEN, run: ({ arg }) => { - const dir = folderFrom(arg); + const dir = folderFrom(contextTarget(arg)); if (dir) delegate("terminal.openAt", dir); }, }, diff --git a/src/features/project-tree/selectIn.test.ts b/src/features/project-tree/selectIn.test.ts index 046b3480..751cc235 100644 --- a/src/features/project-tree/selectIn.test.ts +++ b/src/features/project-tree/selectIn.test.ts @@ -14,6 +14,24 @@ afterEach(() => { useContextMenuStore.setState({ menu: null }); }); +describe("Open in Terminal", () => { + it("opens the edited file's folder unless the Project view has focus", async () => { + const opened: unknown[] = []; + disposers.push( + registerProjectActions(), + registerActions([{ id: "terminal.openAt", title: "Open Terminal At", run: ({ arg }) => void opened.push(arg) }]), + () => setContext("projectOpen", false), + () => setContext("projectViewFocus", false), + ); + setContext("projectOpen", true); + provideEditorService({ activePath: () => "/p/src/a.ts" } as unknown as EditorService); + await executeAction("project.openInTerminal"); + expect(opened).toEqual(["/p/src"]); + await executeAction("project.openInTerminal", "/p/docs/readme.md"); + expect(opened.at(-1)).toBe("/p/docs"); + }); +}); + describe("Select In (⌥F1)", () => { it("lists the project view, contributed targets, Finder and the terminal", () => { disposers.push(