дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-09 19:25:54 +02:00
Attach adds a trusted folder to the current project without reopening it or moving its root. Attachments live in the primary project's private .openidea/workspace.json, and detaching the last one restores a plain project. ProjectInfo.name stays the primary project's name; displayName supplies window titles, project tabs and Recent Projects. Attach is no longer a remembered opening policy, and File > Attach Project is available when the policy is not Ask. Attached folders must be trusted, and Restricted Mode names any attached folder that blocks trust. Explicit workspaces keep their behaviour and still cannot be created in or inside a linked project.
77 рядки
2.9 KiB
TypeScript
77 рядки
2.9 KiB
TypeScript
/** Where a project opens when this window already has one: System Settings › Project › "Open project in". */
|
||
import { t } from "@/platform/i18n";
|
||
import { call, commands, type RemoteTarget } from "@/platform/ipc";
|
||
import { confirmLeaveProject, useProject } from "@/platform/project";
|
||
import { connectRemote, isRemoteWindow } from "@/platform/remote";
|
||
import { ask } from "./messages";
|
||
import { maybeEditorService } from "./contributions";
|
||
|
||
/** "Open project in": `new` | `same` | `ask`. */
|
||
export function openPolicy(): "ask" | "new" | "same" {
|
||
const v = useProject.getState().settings?.general?.openProjectIn;
|
||
return v === "new" || v === "same" ? v : "ask";
|
||
}
|
||
|
||
/**
|
||
* The window to open project `name` in: this one when it has no project (or LightEdit session), else
|
||
* per "Open project in", asking when set to (and remembering "Don't ask again").
|
||
* `null`: cancelled.
|
||
*/
|
||
export async function chooseProjectWindow(name: string, allowAttach = true): Promise<"new" | "same" | "attach" | null> {
|
||
const { project, lightEdit } = useProject.getState();
|
||
if (!project && !lightEdit) return "same";
|
||
const canAttach = allowAttach && !!project && !isRemoteWindow();
|
||
const mode = openPolicy();
|
||
if (mode !== "ask") return mode;
|
||
const r = await ask({
|
||
title: t("app.window.askTitle"),
|
||
width: canAttach ? 640 : undefined,
|
||
body: t("app.window.askBody", { name }),
|
||
buttons: [
|
||
{ id: "cancel", label: t("common.cancel") },
|
||
...(canAttach ? [{ id: "attach", label: t("app.window.askAttach") }] : []),
|
||
{ id: "new", label: t("app.window.askNew") },
|
||
{ id: "same", label: t("app.window.askThis"), primary: true },
|
||
],
|
||
checkbox: t("app.window.askRemember"),
|
||
});
|
||
if (r.button !== "same" && r.button !== "new" && r.button !== "attach") return null;
|
||
if (r.checked && r.button !== "attach") {
|
||
try {
|
||
useProject.setState({
|
||
settings: await call(commands.settingsSet("global", "general.openProjectIn", JSON.stringify(r.button))),
|
||
});
|
||
} catch {
|
||
/* the choice still applies to this open */
|
||
}
|
||
}
|
||
return r.button;
|
||
}
|
||
|
||
/**
|
||
* Opens folder `path` of `target` (an SSH host or a WSL distribution): focuses the
|
||
* window that has it, else opens it in a new window or (`here`) this one per
|
||
* "Open project in". `false`: cancelled.
|
||
*/
|
||
export async function openRemoteProject(
|
||
target: RemoteTarget,
|
||
path: string,
|
||
here: () => Promise<unknown> = () => connectRemote(target, path),
|
||
): Promise<boolean> {
|
||
if ((await call(commands.windowOpenRemote(target, path, false))).kind === "focused") return true;
|
||
const mode = await chooseProjectWindow(path.replace(/\/+$/, "").split("/").pop() || path, false);
|
||
if (!mode) return false;
|
||
if (mode === "new") {
|
||
await call(commands.windowOpenRemote(target, path, true));
|
||
return true;
|
||
}
|
||
if (!(await confirmLeaveProject())) return false;
|
||
try {
|
||
await here();
|
||
return true;
|
||
} catch (e) {
|
||
maybeEditorService()?.cancelClose?.();
|
||
throw e;
|
||
}
|
||
}
|