// Copyright 2024, Command Line Inc. // SPDX-License-Identifier: Apache-2.0 import { App } from "@/app/app"; import { globalRefocus, registerControlShiftStateUpdateHandler, registerElectronReinjectKeyHandler, registerGlobalKeys, } from "@/app/store/keymodel"; import { modalsModel } from "@/app/store/modalmodel"; import { FileService } from "@/app/store/services"; import { RpcApi } from "@/app/store/wshclientapi"; import { initWshrpc, TabRpcClient } from "@/app/store/wshrpcutil"; import { loadMonaco } from "@/app/view/codeeditor/codeeditor"; import { getLayoutModelForStaticTab } from "@/layout/index"; import { atoms, countersClear, countersPrint, getApi, globalStore, initGlobal, initGlobalWaveEventSubs, loadConnStatus, pushFlashError, pushNotification, removeNotificationById, subscribeToConnEvents, } from "@/store/global"; import * as WOS from "@/store/wos"; import { loadFonts } from "@/util/fontutil"; import { setKeyUtilPlatform } from "@/util/keyutil"; import { createElement } from "react"; import { createRoot } from "react-dom/client"; const platform = getApi().getPlatform(); document.title = `Wave Terminal`; let savedInitOpts: WaveInitOpts = null; (window as any).WOS = WOS; (window as any).globalStore = globalStore; (window as any).globalAtoms = atoms; (window as any).RpcApi = RpcApi; (window as any).isFullScreen = false; (window as any).countersPrint = countersPrint; (window as any).countersClear = countersClear; (window as any).getLayoutModelForStaticTab = getLayoutModelForStaticTab; (window as any).pushFlashError = pushFlashError; (window as any).pushNotification = pushNotification; (window as any).removeNotificationById = removeNotificationById; (window as any).modalsModel = modalsModel; async function initBare() { getApi().sendLog("Init Bare"); document.body.style.visibility = "hidden"; document.body.style.opacity = "0"; document.body.classList.add("is-transparent"); getApi().onWaveInit(initWaveWrap); setKeyUtilPlatform(platform); loadFonts(); document.fonts.ready.then(() => { console.log("Init Bare Done"); getApi().setWindowInitStatus("ready"); }); } document.addEventListener("DOMContentLoaded", initBare); async function initWaveWrap(initOpts: WaveInitOpts) { try { if (savedInitOpts) { await reinitWave(); return; } savedInitOpts = initOpts; await initWave(initOpts); } catch (e) { getApi().sendLog("Error in initWave " + e.message); console.error("Error in initWave", e); } finally { document.body.style.visibility = null; document.body.style.opacity = null; document.body.classList.remove("is-transparent"); } } async function reinitWave() { console.log("Reinit Wave"); getApi().sendLog("Reinit Wave"); // We use this hack to prevent a flicker of the previously-hovered tab when this view was last active. document.body.classList.add("nohover"); requestAnimationFrame(() => setTimeout(() => { document.body.classList.remove("nohover"); }, 100) ); await WOS.reloadWaveObject(WOS.makeORef("client", savedInitOpts.clientId)); const waveWindow = await WOS.reloadWaveObject(WOS.makeORef("window", savedInitOpts.windowId)); const ws = await WOS.reloadWaveObject(WOS.makeORef("workspace", waveWindow.workspaceid)); const initialTab = await WOS.reloadWaveObject(WOS.makeORef("tab", savedInitOpts.tabId)); await WOS.reloadWaveObject(WOS.makeORef("layout", initialTab.layoutstate)); reloadAllWorkspaceTabs(ws); document.title = `Wave Terminal - ${initialTab.name}`; // TODO update with tab name change getApi().setWindowInitStatus("wave-ready"); globalStore.set(atoms.reinitVersion, globalStore.get(atoms.reinitVersion) + 1); globalStore.set(atoms.updaterStatusAtom, getApi().getUpdaterStatus()); setTimeout(() => { globalRefocus(); }, 50); } function reloadAllWorkspaceTabs(ws: Workspace) { if (ws == null || (!ws.tabids?.length && !ws.pinnedtabids?.length)) { return; } ws.tabids?.forEach((tabid) => { WOS.reloadWaveObject(WOS.makeORef("tab", tabid)); }); ws.pinnedtabids?.forEach((tabid) => { WOS.reloadWaveObject(WOS.makeORef("tab", tabid)); }); } function loadAllWorkspaceTabs(ws: Workspace) { if (ws == null || (!ws.tabids?.length && !ws.pinnedtabids?.length)) { return; } ws.tabids?.forEach((tabid) => { WOS.getObjectValue(WOS.makeORef("tab", tabid)); }); ws.pinnedtabids?.forEach((tabid) => { WOS.getObjectValue(WOS.makeORef("tab", tabid)); }); } async function initWave(initOpts: WaveInitOpts) { getApi().sendLog("Init Wave " + JSON.stringify(initOpts)); console.log( "Wave Init", "tabid", initOpts.tabId, "clientid", initOpts.clientId, "windowid", initOpts.windowId, "platform", platform ); initGlobal({ tabId: initOpts.tabId, clientId: initOpts.clientId, windowId: initOpts.windowId, platform, environment: "renderer", }); (window as any).globalAtoms = atoms; // Init WPS event handlers const globalWS = initWshrpc(initOpts.tabId); (window as any).globalWS = globalWS; (window as any).TabRpcClient = TabRpcClient; await loadConnStatus(); initGlobalWaveEventSubs(); subscribeToConnEvents(); // ensures client/window/workspace are loaded into the cache before rendering const [client, waveWindow, initialTab] = await Promise.all([ WOS.loadAndPinWaveObject(WOS.makeORef("client", initOpts.clientId)), WOS.loadAndPinWaveObject(WOS.makeORef("window", initOpts.windowId)), WOS.loadAndPinWaveObject(WOS.makeORef("tab", initOpts.tabId)), ]); const [ws, layoutState] = await Promise.all([ WOS.loadAndPinWaveObject(WOS.makeORef("workspace", waveWindow.workspaceid)), WOS.reloadWaveObject(WOS.makeORef("layout", initialTab.layoutstate)), ]); loadAllWorkspaceTabs(ws); WOS.wpsSubscribeToObject(WOS.makeORef("workspace", waveWindow.workspaceid)); document.title = `Wave Terminal - ${initialTab.name}`; // TODO update with tab name change registerGlobalKeys(); registerElectronReinjectKeyHandler(); registerControlShiftStateUpdateHandler(); setTimeout(loadMonaco, 30); const fullConfig = await FileService.GetFullConfig(); console.log("fullconfig", fullConfig); globalStore.set(atoms.fullConfigAtom, fullConfig); console.log("Wave First Render"); let firstRenderResolveFn: () => void = null; let firstRenderPromise = new Promise((resolve) => { firstRenderResolveFn = resolve; }); const reactElem = createElement(App, { onFirstRender: firstRenderResolveFn }, null); const elem = document.getElementById("main"); const root = createRoot(elem); root.render(reactElem); await firstRenderPromise; console.log("Wave First Render Done"); getApi().setWindowInitStatus("wave-ready"); }