提交 07eb3487 编写于 作者: B Benjamin Pasero

debt - introduce lifecycle phases on electron-main and adopt

上级 ca35e2c8
......@@ -109,10 +109,10 @@ export class ConfigWatcher<T> implements IConfigWatcher<T>, IDisposable {
try {
this.parseErrors = [];
res = this.options.parse ? this.options.parse(raw, this.parseErrors) : json.parse(raw, this.parseErrors);
return res || this.options.defaultConfig;
} catch (error) {
// Ignore parsing errors
return this.options.defaultConfig;
return this.options.defaultConfig; // Ignore parsing errors
}
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/platform/update/node/update.config.contribution';
\ No newline at end of file
此差异已折叠。
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nativeKeymap from 'native-keymap';
import { IDisposable } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
export class KeyboardLayoutMonitor {
public static readonly INSTANCE = new KeyboardLayoutMonitor();
private readonly _emitter: Emitter<void>;
private _registered: boolean;
private constructor() {
this._emitter = new Emitter<void>();
this._registered = false;
}
public onDidChangeKeyboardLayout(callback: () => void): IDisposable {
if (!this._registered) {
this._registered = true;
nativeKeymap.onDidChangeKeyboardLayout(() => {
this._emitter.fire();
});
}
return this._emitter.event(callback);
}
}
\ No newline at end of file
......@@ -22,10 +22,10 @@ interface PostResult {
class Endpoint {
private constructor(
public readonly url: string
readonly url: string
) { }
public static getFromProduct(): Endpoint | undefined {
static getFromProduct(): Endpoint | undefined {
const logUploaderUrl = product.logUploaderUrl;
return logUploaderUrl ? new Endpoint(logUploaderUrl) : undefined;
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/code/code.main';
import 'vs/platform/update/node/update.config.contribution';
import { app, dialog } from 'electron';
import { assign } from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
......@@ -39,6 +39,7 @@ import { uploadLogs } from 'vs/code/electron-main/logUploader';
import { setUnexpectedErrorHandler } from 'vs/base/common/errors';
import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { Client } from 'vs/base/parts/ipc/common/ipc.net';
import { once } from 'vs/base/common/functional';
class ExpectedError extends Error {
readonly isExpected = true;
......@@ -90,17 +91,14 @@ class CodeMain {
// log file access on Windows (https://github.com/Microsoft/vscode/issues/41218)
const bufferLogService = new BufferLogService();
const instantiationService = this.createServices(args, bufferLogService);
const [instantiationService, instanceEnvironment] = this.createServices(args, bufferLogService);
try {
// Init services
await instantiationService.invokeFunction(async accessor => {
const environmentService = accessor.get(IEnvironmentService);
const stateService = accessor.get(IStateService);
const logService = accessor.get(ILogService);
// Patch `process.env` with the instance's environment
const instanceEnvironment = this.patchEnvironment(environmentService);
// Startup
try {
await this.initServices(environmentService, stateService as StateService);
} catch (error) {
......@@ -110,9 +108,19 @@ class CodeMain {
throw error;
}
});
// Startup
await instantiationService.invokeFunction(async accessor => {
const environmentService = accessor.get(IEnvironmentService);
const logService = accessor.get(ILogService);
const lifecycleService = accessor.get(ILifecycleService);
const configurationService = accessor.get(IConfigurationService);
const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true);
const mainIpcServer = await this.doStartup(logService, environmentService, instantiationService, true);
bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel());
once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose());
return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup();
});
......@@ -121,16 +129,17 @@ class CodeMain {
}
}
private createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService {
private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, typeof process.env] {
const services = new ServiceCollection();
const environmentService = new EnvironmentService(args, process.execPath);
const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment
services.set(IEnvironmentService, environmentService);
const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]);
process.once('exit', () => logService.dispose());
services.set(IEnvironmentService, environmentService);
services.set(ILogService, logService);
services.set(ILifecycleService, new SyncDescriptor(LifecycleService));
services.set(IStateService, new SyncDescriptor(StateService));
services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath]));
......@@ -138,12 +147,12 @@ class CodeMain {
services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService));
services.set(IThemeMainService, new SyncDescriptor(ThemeMainService));
return new InstantiationService(services, true);
return [new InstantiationService(services, true), instanceEnvironment];
}
private initServices(environmentService: IEnvironmentService, stateService: StateService): Promise<unknown> {
// Ensure paths for environment service exist
// Environment service (paths)
const environmentServiceInitialization = Promise.all<void | undefined>([
environmentService.extensionsPath,
environmentService.nodeCachedDataDir,
......@@ -175,7 +184,7 @@ class CodeMain {
return instanceEnvironment;
}
private async doStartup(logService: ILogService, environmentService: IEnvironmentService, instantiationService: IInstantiationService, retry: boolean): Promise<Server> {
private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleService, instantiationService: IInstantiationService, retry: boolean): Promise<Server> {
// Try to setup a server for running. If that succeeds it means
// we are the first instance to startup. Otherwise it is likely
......@@ -183,6 +192,7 @@ class CodeMain {
let server: Server;
try {
server = await serve(environmentService.mainIPCHandle);
once(lifecycleService.onWillShutdown)(() => server.dispose());
} catch (error) {
// Handle unexpected errors (the only expected error is EADDRINUSE that
......@@ -226,10 +236,11 @@ class CodeMain {
fs.unlinkSync(environmentService.mainIPCHandle);
} catch (error) {
logService.warn('Could not delete obsolete instance handle', error);
throw error;
}
return this.doStartup(logService, environmentService, instantiationService, false);
return this.doStartup(logService, environmentService, lifecycleService, instantiationService, false);
}
// Tests from CLI require to be the only instance currently
......@@ -261,8 +272,8 @@ class CodeMain {
if (environmentService.args.status) {
return instantiationService.invokeFunction(async accessor => {
const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(launchClient);
console.log(diagnostics);
throw new ExpectedError();
});
}
......@@ -300,12 +311,14 @@ class CodeMain {
// Print --status usage info
if (environmentService.args.status) {
logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.');
throw new ExpectedError('Terminating...');
}
// Log uploader usage info
if (typeof environmentService.args['upload-logs'] !== 'undefined') {
logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.');
throw new ExpectedError('Terminating...');
}
......
......@@ -203,12 +203,6 @@ export class CodeWindow extends Disposable implements ICodeWindow {
return !!this.config.extensionTestsPath;
}
/*
get extensionDevelopmentPaths(): string | string[] | undefined {
return this.config.extensionDevelopmentPath;
}
*/
get config(): IWindowConfiguration {
return this.currentConfig;
}
......
......@@ -15,7 +15,7 @@ import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window';
import { hasArgs, asArray } from 'vs/platform/environment/node/argv';
import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron';
import { parseLineAndColumnAware } from 'vs/code/node/paths';
import { ILifecycleService, UnloadReason, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows';
......@@ -38,6 +38,7 @@ import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage';
import { getWorkspaceIdentifier } from 'vs/platform/workspaces/electron-main/workspacesMainService';
import { once } from 'vs/base/common/functional';
const enum WindowError {
UNRESPONSIVE = 1,
......@@ -159,9 +160,7 @@ export class WindowsManager implements IWindowsMainService {
private static readonly windowsStateStorageKey = 'windowsState';
private static WINDOWS: ICodeWindow[] = [];
private initialUserEnv: IProcessEnvironment;
private static readonly WINDOWS: ICodeWindow[] = [];
private readonly windowsState: IWindowsState;
private lastClosedWindowState?: IWindowState;
......@@ -170,19 +169,20 @@ export class WindowsManager implements IWindowsMainService {
private readonly workspacesManager: WorkspacesManager;
private _onWindowReady = new Emitter<ICodeWindow>();
onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
readonly onWindowReady: CommonEvent<ICodeWindow> = this._onWindowReady.event;
private _onWindowClose = new Emitter<number>();
onWindowClose: CommonEvent<number> = this._onWindowClose.event;
readonly onWindowClose: CommonEvent<number> = this._onWindowClose.event;
private _onWindowLoad = new Emitter<number>();
onWindowLoad: CommonEvent<number> = this._onWindowLoad.event;
readonly onWindowLoad: CommonEvent<number> = this._onWindowLoad.event;
private _onWindowsCountChanged = new Emitter<IWindowsCountChangedEvent>();
onWindowsCountChanged: CommonEvent<IWindowsCountChangedEvent> = this._onWindowsCountChanged.event;
readonly onWindowsCountChanged: CommonEvent<IWindowsCountChangedEvent> = this._onWindowsCountChanged.event;
constructor(
private readonly machineId: string,
private readonly initialUserEnv: IProcessEnvironment,
@ILogService private readonly logService: ILogService,
@IStateService private readonly stateService: IStateService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
......@@ -203,12 +203,50 @@ export class WindowsManager implements IWindowsMainService {
this.dialogs = new Dialogs(stateService, this);
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers());
}
ready(initialUserEnv: IProcessEnvironment): void {
this.initialUserEnv = initialUserEnv;
private setupNativeHelpers(): void {
if (isWindows) {
// Setup Windows mutex
try {
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
const mutex = new WindowsMutex(product.win32MutexName);
once(this.lifecycleService.onWillShutdown)(() => mutex.release());
} catch (e) {
this.logService.error(e);
if (!this.environmentService.isBuilt) {
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-mutex!',
detail: e.toString(),
noLink: true
});
}
}
this.registerListeners();
// Dev only: Ensure Windows foreground love module is present
if (!this.environmentService.isBuilt) {
try {
require.__$__nodeRequire('windows-foreground-love');
} catch (e) {
this.logService.error(e);
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-foreground-love!',
detail: e.toString(),
noLink: true
});
}
}
}
}
private registerListeners(): void {
......@@ -543,6 +581,7 @@ export class WindowsManager implements IWindowsMainService {
// Find suitable window or folder path to open files in
const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0];
// only look at the windows with correct authority
const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority);
......@@ -639,7 +678,6 @@ export class WindowsManager implements IWindowsMainService {
// Handle folders to open (instructed and to restore)
const allFoldersToOpen = arrays.distinct(foldersToOpen, folder => getComparisonKey(folder.folderUri)); // prevent duplicates
if (allFoldersToOpen.length > 0) {
// Check for existing instances
......@@ -713,7 +751,9 @@ export class WindowsManager implements IWindowsMainService {
if (fileInputs && !emptyToOpen) {
emptyToOpen++;
}
const remoteAuthority = fileInputs ? fileInputs.remoteAuthority : (openConfig.cli && openConfig.cli.remote || undefined);
for (let i = 0; i < emptyToOpen; i++) {
usedWindows.push(this.openInBrowserWindow({
userEnv: openConfig.userEnv,
......
......@@ -57,6 +57,7 @@ export async function main(argv: string[]): Promise<any> {
else if (shouldSpawnCliProcess(args)) {
const cli = await new Promise<IMainCli>((c, e) => require(['vs/code/node/cliProcessMain'], c, e));
await cli.main(args);
return;
}
......
......@@ -287,6 +287,7 @@ export function parseDebugPort(debugArg: string | undefined, debugBrkArg: string
const portStr = debugBrkArg || debugArg;
const port = Number(portStr) || (!isBuild ? defaultBuildPort : null);
const brk = port ? Boolean(!!debugBrkArg) : false;
return { port, break: brk, debugId };
}
......@@ -301,9 +302,9 @@ function parsePathArg(arg: string | undefined, process: NodeJS.Process): string
if (path.normalize(arg) === resolved) {
return resolved;
} else {
return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg);
}
return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg);
}
export function parseUserDataDir(args: ParsedArgs, process: NodeJS.Process): string {
......
......@@ -22,6 +22,8 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label';
import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/electron-main/historyStorage';
import { exists } from 'vs/base/node/pfs';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain';
export class HistoryMainService implements IHistoryMainService {
......@@ -37,10 +39,10 @@ export class HistoryMainService implements IHistoryMainService {
private static readonly recentlyOpenedStorageKey = 'openedPathsList';
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<IHistoryMainService>;
private _onRecentlyOpenedChange = new Emitter<void>();
onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
readonly onRecentlyOpenedChange: CommonEvent<void> = this._onRecentlyOpenedChange.event;
private macOSRecentDocumentsUpdater: ThrottledDelayer<void>;
......@@ -48,9 +50,21 @@ export class HistoryMainService implements IHistoryMainService {
@IStateService private readonly stateService: IStateService,
@ILogService private readonly logService: ILogService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ILifecycleService lifecycleService: ILifecycleService
) {
this.macOSRecentDocumentsUpdater = new ThrottledDelayer<void>(800);
lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList());
}
private handleWindowsJumpList(): void {
if (!isWindows) {
return; // only on windows
}
this.updateWindowsJumpList();
this.onRecentlyOpenedChange(() => this.updateWindowsJumpList());
}
addRecentlyOpened(newlyAdded: IRecent[]): void {
......
......@@ -8,7 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IURLService } from 'vs/platform/url/common/url';
import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform';
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { OpenContext, IWindowSettings } from 'vs/platform/windows/common/windows';
import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { whenDeleted } from 'vs/base/node/pfs';
......@@ -107,7 +107,7 @@ export class LaunchChannel implements IServerChannel {
export class LaunchChannelClient implements ILaunchService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILaunchService>;
constructor(private channel: IChannel) { }
......@@ -134,7 +134,7 @@ export class LaunchChannelClient implements ILaunchService {
export class LaunchService implements ILaunchService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILaunchService>;
constructor(
@ILogService private readonly logService: ILogService,
......
......@@ -29,7 +29,7 @@ export interface BeforeShutdownEvent {
/**
* The reason why the application will be shutting down.
*/
reason: ShutdownReason;
readonly reason: ShutdownReason;
}
/**
......@@ -51,7 +51,7 @@ export interface WillShutdownEvent {
/**
* The reason why the application is shutting down.
*/
reason: ShutdownReason;
readonly reason: ShutdownReason;
}
export const enum ShutdownReason {
......
......@@ -7,11 +7,12 @@ import { ipcMain as ipc, app } from 'electron';
import { ILogService } from 'vs/platform/log/common/log';
import { IStateService } from 'vs/platform/state/common/state';
import { Event, Emitter } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
import { isMacintosh, isWindows } from 'vs/base/common/platform';
import { Disposable } from 'vs/base/common/lifecycle';
import { Barrier } from 'vs/base/common/async';
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
......@@ -38,42 +39,48 @@ export interface ShutdownEvent {
}
export interface ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
/**
* Will be true if the program was restarted (e.g. due to explicit request or update).
*/
wasRestarted: boolean;
readonly wasRestarted: boolean;
/**
* Will be true if the program was requested to quit.
*/
quitRequested: boolean;
readonly quitRequested: boolean;
/**
* A flag indicating in what phase of the lifecycle we currently are.
*/
phase: LifecycleMainPhase;
/**
* An event that fires when the application is about to shutdown before any window is closed.
* The shutdown can still be prevented by any window that vetos this event.
*/
onBeforeShutdown: Event<void>;
readonly onBeforeShutdown: Event<void>;
/**
* An event that fires after the onBeforeShutdown event has been fired and after no window has
* vetoed the shutdown sequence. At this point listeners are ensured that the application will
* quit without veto.
*/
onWillShutdown: Event<ShutdownEvent>;
readonly onWillShutdown: Event<ShutdownEvent>;
/**
* An event that fires before a window closes. This event is fired after any veto has been dealt
* with so that listeners know for sure that the window will close without veto.
*/
onBeforeWindowClose: Event<ICodeWindow>;
readonly onBeforeWindowClose: Event<ICodeWindow>;
/**
* An event that fires before a window is about to unload. Listeners can veto this event to prevent
* the window from unloading.
*/
onBeforeWindowUnload: Event<IWindowUnloadEvent>;
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent>;
/**
* Unload a window for the provided reason. All lifecycle event handlers are triggered.
......@@ -94,6 +101,32 @@ export interface ILifecycleService {
* Forcefully shutdown the application. No livecycle event handlers are triggered.
*/
kill(code?: number): void;
/**
* Returns a promise that resolves when a certain lifecycle phase
* has started.
*/
when(phase: LifecycleMainPhase): Promise<void>;
}
export const enum LifecycleMainPhase {
/**
* The first phase signals that we are about to startup.
*/
Starting = 1,
/**
* Services are ready and first window is about to open.
*/
Ready = 2,
/**
* This phase signals a point in time after the window has opened
* and is typically the best place to do work that is not required
* for the window to open.
*/
AfterWindowOpen = 3
}
export class LifecycleService extends Disposable implements ILifecycleService {
......@@ -129,6 +162,11 @@ export class LifecycleService extends Disposable implements ILifecycleService {
private readonly _onBeforeWindowUnload = this._register(new Emitter<IWindowUnloadEvent>());
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent> = this._onBeforeWindowUnload.event;
private _phase: LifecycleMainPhase = LifecycleMainPhase.Starting;
get phase(): LifecycleMainPhase { return this._phase; }
private phaseWhen = new Map<LifecycleMainPhase, Barrier>();
constructor(
@ILogService private readonly logService: ILogService,
@IStateService private readonly stateService: IStateService
......@@ -136,6 +174,7 @@ export class LifecycleService extends Disposable implements ILifecycleService {
super();
this.handleRestarted();
this.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
}
private handleRestarted(): void {
......@@ -146,10 +185,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
}
}
ready(): void {
this.registerListeners();
}
private registerListeners(): void {
// before-quit: an event that is fired if application quit was
......@@ -238,6 +273,40 @@ export class LifecycleService extends Disposable implements ILifecycleService {
return this.pendingWillShutdownPromise;
}
set phase(value: LifecycleMainPhase) {
if (value < this.phase) {
throw new Error('Lifecycle cannot go backwards');
}
if (this._phase === value) {
return;
}
this.logService.trace(`lifecycle (main): phase changed (value: ${value})`);
this._phase = value;
const barrier = this.phaseWhen.get(this._phase);
if (barrier) {
barrier.open();
this.phaseWhen.delete(this._phase);
}
}
async when(phase: LifecycleMainPhase): Promise<void> {
if (phase <= this._phase) {
return;
}
let barrier = this.phaseWhen.get(phase);
if (!barrier) {
barrier = new Barrier();
this.phaseWhen.set(phase, barrier);
}
await barrier.wait();
}
registerWindow(window: ICodeWindow): void {
// track window count
......@@ -390,10 +459,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
});
}
/**
* A promise that completes to indicate if the quit request has been veto'd
* by the user or not.
*/
quit(fromUpdate?: boolean): Promise<boolean /* veto */> {
if (this.pendingQuitPromise) {
return this.pendingQuitPromise;
......
......@@ -27,27 +27,36 @@ export class FileStorage {
}
async init(): Promise<void> {
if (this._database) {
return; // return if database was already loaded
}
const database = await this.loadAsync();
if (this._database) {
return; // return if database was already loaded
}
this._database = database;
}
private loadSync(): object {
try {
const contents = await readFile(this.dbPath);
this.lastFlushedSerializedDatabase = fs.readFileSync(this.dbPath).toString();
try {
this.lastFlushedSerializedDatabase = contents.toString();
this._database = JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
this._database = {};
}
return JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
if (error.code !== 'ENOENT') {
this.onError(error);
}
this._database = {};
return {};
}
}
private loadSync(): object {
private async loadAsync(): Promise<object> {
try {
this.lastFlushedSerializedDatabase = fs.readFileSync(this.dbPath).toString();
this.lastFlushedSerializedDatabase = (await readFile(this.dbPath)).toString();
return JSON.parse(this.lastFlushedSerializedDatabase);
} catch (error) {
......
......@@ -92,7 +92,6 @@ export interface IWindowsMainService {
readonly onWindowClose: Event<number>;
// methods
ready(initialUserEnv: IProcessEnvironment): void;
reload(win: ICodeWindow, cli?: ParsedArgs): void;
enterWorkspace(win: ICodeWindow, path: URI): Promise<IEnterWorkspaceResult | undefined>;
closeWorkspace(win: ICodeWindow): void;
......
......@@ -541,7 +541,6 @@
"**/vs/base/parts/**/{common,browser,node,electron-main}/**",
"**/vs/platform/**/{common,browser,node,electron-main}/**",
"**/vs/code/**/{common,browser,node,electron-main}/**",
"**/vs/code/code.main",
"*" // node modules
]
},
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册