Files
openidea/src/workbench/projectWindow.ts
T
l0ng-ai 2d7726cf53 feat(workbench): Edit single files without opening a project (#145)
Files can now be opened without a project. A file dropped on the Welcome screen, picked with File › Open File…, or passed on the command line or to a second instance opens in a lightweight window: editor tabs only, with no project tree, indexing, language servers, VCS or project tool windows. Syntax highlighting, find, save, undo and Local History still work. More files opened later join the same window as new tabs. Open as Project in the status bar opens the file's directory as a full project, following the open-project policy, and reopens the file there.

Backend: a light session reuses Project with an unindexed index, no LSP or VCS, and a flat watch on each opened file's directory. It is never reused as a project for the same root. Previously a file passed at launch opened its parent directory as a project.
2026-10-28 22:06:35 +08:00

68 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** Where a project opens when this window already has one: System Settings › Project › "Open project in". */
import { t } from "@/platform/i18n";
import { call, commands } from "@/platform/ipc";
import { confirmLeaveProject, useProject } from "@/platform/project";
import { connectRemote } from "@/platform/remote";
import { ask } from "./messages";
/** "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): Promise<"new" | "same" | null> {
const { project, lightEdit } = useProject.getState();
if (!project && !lightEdit) return "same";
const mode = openPolicy();
if (mode !== "ask") return mode;
const r = await ask({
title: t("app.window.askTitle"),
body: t("app.window.askBody", { name }),
buttons: [
{ id: "new", label: t("app.window.askNew") },
{ id: "same", label: t("app.window.askThis"), primary: true },
{ id: "cancel", label: t("common.cancel") },
],
checkbox: t("app.window.askRemember"),
});
if (r.button !== "same" && r.button !== "new") return null;
if (r.checked) {
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` on the host of SSH configuration `sshConfig`: 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(
sshConfig: string,
path: string,
here: () => Promise<unknown> = () => connectRemote(sshConfig, path),
): Promise<boolean> {
if ((await call(commands.windowOpenRemote(sshConfig, path, false))).kind === "focused") return true;
const mode = await chooseProjectWindow(path.replace(/\/+$/, "").split("/").pop() || path);
if (!mode) return false;
if (mode === "new") {
await call(commands.windowOpenRemote(sshConfig, path, true));
return true;
}
if (!(await confirmLeaveProject())) return false;
await here();
return true;
}