feat: multi-project workspaces and project window groups (#448)

Workspaces open several local project folders in one IDE session (File › New / Open / Manage Workspace…, or Attach when opening a project, which creates a workspace automatically for a plain project window). Member folders are the Project view roots and take part in indexing, Find in Files, Git, language servers, run configurations and builds; agent tasks choose which member they work in. Window › Merge All Project Windows groups project windows into one window with project tabs (switch, reorder, close, move to a new window), restored on reopen.

Closes #241
Closes #198
Closes #286
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-10-30 22:45:42 +08:00
1 джерело 5bab140968
коміт 01defdefe4
88 files changed
+2689 -151

No files matched your search

+2 -2
Переглянути файл
@@ -7,7 +7,7 @@
import { BUILTIN_THEME_IDS, type BuiltinThemeId } from "@/platform/themes";
export type Antialiasing = "subpixel" | "greyscale" | "none";
export type OpenProjectIn = "ask" | "new" | "same";
export type OpenProjectIn = "ask" | "new" | "same" | "attach";
export type NotificationDisplay = "balloon" | "sticky" | "none";
/** Themes selectable as "preferred" when syncing with the OS. */
export type ConcreteTheme = BuiltinThemeId;
@@ -140,7 +140,7 @@ export function validateGeneralExtras(raw: unknown): GeneralExtras {
const d = DEFAULT_GENERAL_EXTRAS;
const df = obj(g.dateFormat);
return {
openProjectIn: oneOf(g.openProjectIn, ["ask", "new", "same"] as const, d.openProjectIn),
openProjectIn: oneOf(g.openProjectIn, ["ask", "new", "same", "attach"] as const, d.openProjectIn),
defaultProjectDirectory: typeof g.defaultProjectDirectory === "string" ? g.defaultProjectDirectory : "",
saveOnIdle: bool(g.saveOnIdle, d.saveOnIdle),
idleSeconds: int(g.idleSeconds, d.idleSeconds, IDLE_LIMITS),
+2 -1
Переглянути файл
@@ -281,6 +281,7 @@ function ToolWindowsGrid() {
const OPEN_IN: Array<{ value: OpenProjectIn; label: string }> = [
{ value: "new", label: "New window" },
{ value: "attach", label: "Attach" },
{ value: "same", label: "Current window" },
{ value: "ask", label: "Ask" },
];
@@ -566,7 +567,7 @@ export const BEHAVIOR_PAGES: PageSpec[] = [
{
kind: "custom",
label: "Open project in",
keywords: ["New window", "Current window", "Ask"],
keywords: ["New window", "Current window", "Attach", "Ask"],
component: OpenProjectInRow,
},
{ kind: "custom", label: "Default directory", component: DefaultDirectoryRow },