UNPKG

alm

Version:

The best IDE for TypeScript

274 lines (247 loc) 9.39 kB
/** * The session manages the state associated with a browser window connection. * This allows us to restore tabs + userconfiguration etc. * We just drive the session id from the browser url */ /** Imports */ import * as flm from "../workers/fileListing/fileListingMaster"; import * as types from "../../common/types"; import * as json from "../../common/json"; import * as fsu from "../utils/fsu"; import * as utils from "../../common/utils"; import * as workingDir from "./workingDir"; import * as commandLine from "../commandLine"; import * as tsconfig from "../workers/lang/core/tsconfig"; const sessionFile = types.cacheDir + '/sessionsV2.json' /** * If there is no session then a default one will be created for you and sent over */ export function getDefaultOrNewSession(sessionId: string): types.SessionOnDisk { let sessions: types.SessionOnDisk[] = readDiskSessionsFile().sessions; /** * Cases to handle * if default select first (but if none create) * if duplicate then duplicate (but if none create and use that one) * if session id then search (but if none create) */ // if none create const ifNoneCreate = (session: types.SessionOnDisk, id = utils.createId()) => { if (!session) { session = { id, tabLayout: { type: 'stack', width: 100, height: 100, tabs: [], subItems: [], activeItemIndex: 0, }, lastUsed: new Date().getTime(), selectedTabId: null, } writeDiskSession(session); return session; } else { return session; } } let session: types.SessionOnDisk; if (commandLine.getOptions().debug) { session = ifNoneCreate(sessions.find(session => session.id === types.urlHashDebugSession), types.urlHashDebugSession); } else if (!sessionId || sessionId === types.urlHashNormal) { session = ifNoneCreate(sessions.filter(s => s.id !== types.urlHashDebugSession)[0]); } else if (sessionId === types.urlHashNewSession) { session = sessions[0]; // last used is always on top if (session) { session = { id: utils.createId(), tabLayout: session.tabLayout, lastUsed: new Date().getTime(), selectedTabId: session.selectedTabId, } writeDiskSession(session); } else { session = ifNoneCreate(session); } } else { session = ifNoneCreate(sessions.find(session => session.id === sessionId)); } /** * Update the session on disk for future calls to be stable */ let commandLineTabs = getCommandLineTabs(); if (commandLineTabs.length) { // Utility to find first `stack` and just add to its tabs let done = false; const tryAddingToStack = (layout: types.TabLayoutOnDisk) => { if (done) return; if (layout.type === 'stack') { layout.tabs = layout.tabs.concat(commandLineTabs); done = true; } else { layout.subItems.forEach(tryAddingToStack) } } // Start at root tryAddingToStack(session.tabLayout); /** Write it out */ writeDiskSession(session); } return session; } /** * Only returns the command line tabs once * Means you can call it as many times as you like */ function getCommandLineTabs(): types.TabInstanceOnDisk[] { /** Add any command line files to the session */ let files = commandLine.getOptions().filePaths; let tabs = files .map((file) => utils.getUrlFromFilePathAndProtocol({ protocol: 'file', filePath: file })) .map((url) => workingDir.makeRelativeUrl(url)) .map((relativeUrl) => ({ id: utils.createId(), relativeUrl, additionalData: null })); // clear for future // Doing it multiple times would mean that we would polute the user session on each new tab opening commandLine.getOptions().filePaths = []; return tabs; } /** * UI to disk and Disk to UI helpers */ function uiToDiskTab(uiTab: types.TabInstance): types.TabInstanceOnDisk { let relativeUrl = workingDir.makeRelativeUrl(uiTab.url); return { id: uiTab.id, relativeUrl, additionalData: uiTab.additionalData, }; } function diskToUITab(diskTab: types.TabInstanceOnDisk): types.TabInstance | null { let url = workingDir.makeAbsoluteUrl(diskTab.relativeUrl); const { filePath, protocol } = utils.getFilePathAndProtocolFromUrl(url); if (protocol === 'file' && !fsu.existsSync(filePath)) return null; return { id: diskTab.id, url, additionalData: diskTab.additionalData, }; } function uiToDiskTabLayout(uiLayout: types.TabLayout): types.TabLayoutOnDisk { return { type: uiLayout.type, width: uiLayout.width, height: uiLayout.height, tabs: uiLayout.tabs.map(uiToDiskTab), subItems: uiLayout.subItems.map(uiToDiskTabLayout), activeItemIndex: uiLayout.activeItemIndex, } } function diskToUITabLayout(diskLayout: types.TabLayoutOnDisk): types.TabLayout { return { type: diskLayout.type, width: diskLayout.width, height: diskLayout.height, tabs: diskLayout.tabs.map(diskToUITab).filter(x => !!x), subItems: diskLayout.subItems.map(diskToUITabLayout), activeItemIndex: diskLayout.activeItemIndex, } } export function readDiskSessionsFile() { let sessionFileContents: types.SessionsFileContents = { sessions: [] }; if (fsu.existsSync(sessionFile) && !commandLine.getOptions().safe) { let contents = json.parse<types.SessionsFileContents>(fsu.readFile(sessionFile)); if (contents.data) { sessionFileContents = contents.data; } } /** * Active project setup logic. In decreasing order * - If there is an active project in the command line * - If there is an active project in the last session * - Common locations */ let commonTsconfigLocations = [ '.', './src', './ts', './lib', './App-UI/src' ].map(x => x + '/tsconfig.json'); if (commandLine.getOptions().init) { sessionFileContents.relativePathToTsconfig = './tsconfig.json'; // Write the tsconfig.json file tsconfig.createProjectRootSync(workingDir.getProjectRoot()); writeDiskSessionFile(sessionFileContents); // Clear so we don't keep creating commandLine.getOptions().init = false; } else if (commandLine.getOptions().project) { sessionFileContents.relativePathToTsconfig = workingDir.makeRelative(commandLine.getOptions().project); writeDiskSessionFile(sessionFileContents); } else if (!sessionFileContents.relativePathToTsconfig) { let found = commonTsconfigLocations.find(cl => fsu.existsSync(cl)); if (found) { sessionFileContents.relativePathToTsconfig = found; writeDiskSessionFile(sessionFileContents); } } return sessionFileContents; } function writeDiskSession(session: types.SessionOnDisk) { // Update last used time session.lastUsed = new Date().getTime(); const sessionFileContents = readDiskSessionsFile(); // Merge with what is on disk by id const sessions = sessionFileContents.sessions .filter(sesh => sesh.id !== session.id); sessions.unshift(session); // last used is always on top sessionFileContents.sessions = sessions; writeDiskSessionFile(sessionFileContents); } function writeDiskSessionFile(sessionFileContents: types.SessionsFileContents) { fsu.writeFile(sessionFile, json.stringify(sessionFileContents)); } export function setTsconfigPath(tsconfigFilePath: string) { let sessionFileContents = readDiskSessionsFile(); sessionFileContents.relativePathToTsconfig = workingDir.makeRelative(tsconfigFilePath); writeDiskSessionFile(sessionFileContents); } export function setOpenUITabs(sessionId: string, layout: types.TabLayout, selectedTabId: string | null) { let session = getDefaultOrNewSession(sessionId); session.tabLayout = uiToDiskTabLayout(layout); session.selectedTabId = selectedTabId; writeDiskSession(session); } export function getOpenUITabs(sessionId: string) { let session = getDefaultOrNewSession(sessionId); return { tabLayout: diskToUITabLayout(session.tabLayout), selectedTabId: session.selectedTabId } } export function getValidSessionId(sessionId: string) { let session = getDefaultOrNewSession(sessionId); return { sessionId: session.id } } /** * For various simple settings * setter */ export function setSetting(config: { sessionId: string, settingId: string, value: any }) { let session = getDefaultOrNewSession(config.sessionId); session[config.settingId] = config.value; writeDiskSession(session); } /** * For various simple settings * getter */ export function getSetting(config: { sessionId: string, settingId: string }): any { let session = getDefaultOrNewSession(config.sessionId); return session[config.settingId]; }