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
This commit is contained in:
l0ng-ai
2026-11-05 02:35:25 +08:00
committed by GitHub
parent 9f2e6b570f
commit 89309e40ba
2 changed files with 31 additions and 2 deletions
+13 -2
View File
@@ -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);
},
},
@@ -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(