diff --git a/src/features/debugger/index.ts b/src/features/debugger/index.ts index 5c606dfa6..94eb7d0a2 100644 --- a/src/features/debugger/index.ts +++ b/src/features/debugger/index.ts @@ -3,7 +3,7 @@ * backend), DAP sessions driven by `IdeEvent::Debug`, the Debug tool window, * execution point + inline values, Evaluate / View Breakpoints dialogs. */ -import { lazyComponent } from "@/ui"; +import { lazyComponent, lazyWhen } from "@/ui"; import { onIdeEvent } from "@/platform/ipc"; import { useProject } from "@/platform/project"; import { selectionValueTooltip, valueTooltip } from "./editor/valueTooltip"; @@ -35,9 +35,13 @@ import { stopSession, useDebug, } from "./state"; -import { DebuggerOverlays } from "./ui/Overlays"; +import { useOverlays } from "./ui/popoverStore"; import { REMOTE_TYPES } from "./remote"; +/** Whether a breakpoint popover, debugger dialog or chooser is open. */ +const useAnyOverlay = () => + useOverlays((s) => !!(s.popover || s.evaluate || s.breakpoints || s.chooser || s.attach || s.smartStep)); + export function activate(): () => void { useDebugRunSessions.setState({ Console: lazyComponent(() => import("./ui/DebugConsole").then((m) => m.DebugServiceConsole)), @@ -62,7 +66,10 @@ export function activate(): () => void { component: lazyComponent(() => import("./ui/DebugToolWindow").then((m) => m.DebugToolWindow)), headerContent: lazyComponent(() => import("./ui/DebugToolWindow").then((m) => m.DebugTabs)), }), - registerOverlay({ id: "debugger", component: DebuggerOverlays }), + registerOverlay({ + id: "debugger", + component: lazyWhen(useAnyOverlay, () => import("./ui/Overlays").then((m) => m.DebuggerOverlays)), + }), registerMenuGroup({ id: "debugger.evaluate", menus: ["editor"], diff --git a/src/features/plugins/index.ts b/src/features/plugins/index.ts index e659b68ec..f91cd51a0 100644 --- a/src/features/plugins/index.ts +++ b/src/features/plugins/index.ts @@ -15,7 +15,7 @@ * `line-markers` providers (`lineMarkerGutter.ts`). */ import { registerEditorContribution } from "@/editor/api"; -import { lazyComponent } from "@/ui"; +import { lazyComponent, lazyWhen } from "@/ui"; import { executeAction, registerActions } from "@/platform/actions"; import { useProject } from "@/platform/project"; import { editorService, registerOverlay, registerSettingsPage } from "@/workbench/contributions"; @@ -31,8 +31,7 @@ import { trackIconTheme } from "./iconThemes"; import { pluginLineMarkerGutter } from "./lineMarkerGutter"; import { defineBuiltinUiPoints } from "./points"; import { startViewUi } from "./uiPoints"; -import { importIntellijTheme, showInstalledIntellijThemes } from "./intellijImport"; -import { IntellijThemesDialogHost } from "./IntellijThemesDialog"; +import { showInstalledIntellijThemes, useIntellijThemesDialog } from "./intellijThemesDialogStore"; import { installFromDisk, refreshPlugins, reloadPlugin, SETTINGS_PAGE_ID, updateAllPlugins, usePlugins } from "./store"; function registerPluginsPage(): () => void { @@ -47,6 +46,11 @@ function registerPluginsPage(): () => void { } /** Settings › Plugins for the Settings window: the page plus the plugin theme. */ +const useIntellijThemesOpen = () => useIntellijThemesDialog((s) => s.open); +const IntellijThemesDialogHost = lazyWhen(useIntellijThemesOpen, () => + import("./IntellijThemesDialog").then((m) => m.IntellijThemesDialogHost), +); + export function activateSettingsPages(): () => void { const disposers = [ registerPluginsPage(), @@ -108,7 +112,7 @@ export function activate(): () => void { // Installing needs a project's window. when: "projectOpen", run: async ({ arg }) => { - await importIntellijTheme(typeof arg === "string" ? arg : undefined); + await (await import("./intellijImport")).importIntellijTheme(typeof arg === "string" ? arg : undefined); }, }, { diff --git a/src/features/plugins/intellijImport.ts b/src/features/plugins/intellijImport.ts index 8a0f9f5aa..8ac03a363 100644 --- a/src/features/plugins/intellijImport.ts +++ b/src/features/plugins/intellijImport.ts @@ -5,7 +5,6 @@ * here (`intellijTheme.ts`), installed through the usual install page. Its * themes join the others; which one to use is chosen in Settings › Appearance. */ -import { create } from "zustand"; import { notifications } from "@/workbench/contributions"; import { pluginsBackend } from "./backend"; import { intellijThemePackage } from "./intellijTheme"; @@ -35,19 +34,8 @@ export async function importIntellijTheme(path?: string): Promise return installFromDisk(dir); } -interface DialogState { - open: boolean; - /** Called with the plugin id after an import from the dialog. */ - onImported: ((id: string) => void) | null; -} - -export const useIntellijThemesDialog = create(() => ({ open: false, onImported: null })); - -/** Shows the themes of the JetBrains IDEs on this machine to pick one to import. */ -export function showInstalledIntellijThemes(onImported?: (id: string) => void): void { - useIntellijThemesDialog.setState({ open: true, onImported: onImported ?? null }); -} - -export function closeInstalledIntellijThemes(): void { - useIntellijThemesDialog.setState({ open: false, onImported: null }); -} +export { + closeInstalledIntellijThemes, + showInstalledIntellijThemes, + useIntellijThemesDialog, +} from "./intellijThemesDialogStore"; diff --git a/src/features/plugins/intellijThemesDialogStore.ts b/src/features/plugins/intellijThemesDialogStore.ts new file mode 100644 index 000000000..e5aa45fdc --- /dev/null +++ b/src/features/plugins/intellijThemesDialogStore.ts @@ -0,0 +1,18 @@ +import { create } from "zustand"; + +interface DialogState { + open: boolean; + /** Called with the plugin id after an import from the dialog. */ + onImported: ((id: string) => void) | null; +} + +export const useIntellijThemesDialog = create(() => ({ open: false, onImported: null })); + +/** Shows the themes of the JetBrains IDEs on this machine to pick one to import. */ +export function showInstalledIntellijThemes(onImported?: (id: string) => void): void { + useIntellijThemesDialog.setState({ open: true, onImported: onImported ?? null }); +} + +export function closeInstalledIntellijThemes(): void { + useIntellijThemesDialog.setState({ open: false, onImported: null }); +} diff --git a/src/features/welcome/index.ts b/src/features/welcome/index.ts index 09cfcf53c..9107788fa 100644 --- a/src/features/welcome/index.ts +++ b/src/features/welcome/index.ts @@ -1,7 +1,7 @@ /** Welcome screen, recent projects (File › Open Recent) and reopening the last project on startup. */ import { registerActions } from "@/platform/actions"; +import { lazyComponent } from "@/ui"; import { provideProjectPopup, provideWelcomeView, registerOverlay } from "@/workbench/contributions"; -import { ProjectPopup } from "./ProjectPopup"; import { RecentProjectsPopup, showRecentProjectsPopup } from "./RecentProjectsPopup"; import { reopenLastProject, trackSession } from "./session"; import { WelcomeView } from "./WelcomeView"; @@ -10,7 +10,7 @@ export function activate(): () => void { const disposers = [ trackSession(), provideWelcomeView(WelcomeView), - provideProjectPopup(ProjectPopup), + provideProjectPopup(lazyComponent(() => import("./ProjectPopup").then((m) => m.ProjectPopup))), registerOverlay({ id: "welcome.recentProjects", component: RecentProjectsPopup }), registerActions([ { diff --git a/src/ui/lazy.tsx b/src/ui/lazy.tsx index 00aea73f4..565885a3e 100644 --- a/src/ui/lazy.tsx +++ b/src/ui/lazy.tsx @@ -40,16 +40,20 @@ export function lazyComponent

(load: () => Promise( useShown: () => boolean, load: () => Promise>, ): ComponentType

{ const Lazy = lazyComponent(load); + let shown = false; return function LazyWhen(props: P) { - return useShown() ? : null; + const now = useShown(); + shown ||= now; + return shown ? : null; }; }