Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)

* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973

* disable strict null check
This commit is contained in:
Anthony Dresser
2019-07-15 22:35:46 -07:00
committed by GitHub
parent f720ec642f
commit 0b7e7ddbf9
2406 changed files with 59140 additions and 35464 deletions

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { localize } from 'vs/nls';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class BrowserLifecycleService extends AbstractLifecycleService {
_serviceBrand: ServiceIdentifier<ILifecycleService>;
constructor(
@ILogService readonly logService: ILogService
) {
super(logService);
this.registerListeners();
}
private registerListeners(): void {
window.onbeforeunload = () => this.beforeUnload();
}
private beforeUnload(): string | null {
let veto = false;
// Before Shutdown
this._onBeforeShutdown.fire({
veto(value) {
if (value === true) {
veto = true;
} else if (value instanceof Promise && !veto) {
console.warn(new Error('Long running onBeforeShutdown currently not supported'));
veto = true;
}
},
reason: ShutdownReason.QUIT
});
// Veto: signal back to browser by returning a non-falsify return value
if (veto) {
return localize('lifecycleVeto', "Changes that you made may not be saved. Please check press 'Cancel' and try again.");
}
// No Veto: continue with Will Shutdown
this._onWillShutdown.fire({
join() {
console.warn(new Error('Long running onWillShutdown currently not supported'));
},
reason: ShutdownReason.QUIT
});
return null;
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { isThenable } from 'vs/base/common/async';
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
@@ -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 {
@@ -123,7 +123,7 @@ export function LifecyclePhaseToString(phase: LifecyclePhase) {
*/
export interface ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<any>;
/**
* Value indicates how this window got loaded.
@@ -166,12 +166,16 @@ export interface ILifecycleService {
}
export const NullLifecycleService: ILifecycleService = {
_serviceBrand: null,
_serviceBrand: null as any,
onBeforeShutdown: Event.None,
onWillShutdown: Event.None,
onShutdown: Event.None,
phase: LifecyclePhase.Restored,
startupKind: StartupKind.NewWindow,
when() { return Promise.resolve(); }
};

View File

@@ -9,19 +9,20 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { ILifecycleService, BeforeShutdownEvent, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString } from 'vs/platform/lifecycle/common/lifecycle';
import { ILogService } from 'vs/platform/log/common/log';
import { mark } from 'vs/base/common/performance';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
protected readonly _onBeforeShutdown = this._register(new Emitter<BeforeShutdownEvent>());
get onBeforeShutdown(): Event<BeforeShutdownEvent> { return this._onBeforeShutdown.event; }
readonly onBeforeShutdown: Event<BeforeShutdownEvent> = this._onBeforeShutdown.event;
protected readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
get onWillShutdown(): Event<WillShutdownEvent> { return this._onWillShutdown.event; }
readonly onWillShutdown: Event<WillShutdownEvent> = this._onWillShutdown.event;
protected readonly _onShutdown = this._register(new Emitter<void>());
get onShutdown(): Event<void> { return this._onShutdown.event; }
readonly onShutdown: Event<void> = this._onShutdown.event;
protected _startupKind: StartupKind;
get startupKind(): StartupKind { return this._startupKind; }

View File

@@ -4,20 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { ipcRenderer as ipc } from 'electron';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { ILogService } from 'vs/platform/log/common/log';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { onUnexpectedError } from 'vs/base/common/errors';
import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService';
import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
export class LifecycleService extends AbstractLifecycleService {
private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason';
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
private shutdownReason: ShutdownReason;
@@ -89,8 +90,10 @@ export class LifecycleService extends AbstractLifecycleService {
});
// Save shutdown reason to retrieve on next startup
this.storageService.onWillSaveState(() => {
this.storageService.store(LifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE);
this.storageService.onWillSaveState(e => {
if (e.reason === WillSaveStateReason.SHUTDOWN) {
this.storageService.store(LifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE);
}
});
}

View File

@@ -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,15 +101,41 @@ 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 {
_serviceBrand: any;
_serviceBrand: ServiceIdentifier<ILifecycleService>;
private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted
private windowToCloseRequest: { [windowId: string]: boolean } = Object.create(null);
private windowToCloseRequest: Set<number> = new Set();
private oneTimeListenerTokenGenerator = 0;
private windowCounter = 0;
@@ -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
@@ -248,8 +317,8 @@ export class LifecycleService extends Disposable implements ILifecycleService {
// The window already acknowledged to be closed
const windowId = window.id;
if (this.windowToCloseRequest[windowId]) {
delete this.windowToCloseRequest[windowId];
if (this.windowToCloseRequest.has(windowId)) {
this.windowToCloseRequest.delete(windowId);
return;
}
@@ -260,11 +329,11 @@ export class LifecycleService extends Disposable implements ILifecycleService {
e.preventDefault();
this.unload(window, UnloadReason.CLOSE).then(veto => {
if (veto) {
delete this.windowToCloseRequest[windowId];
this.windowToCloseRequest.delete(windowId);
return;
}
this.windowToCloseRequest[windowId] = true;
this.windowToCloseRequest.add(windowId);
// Fire onBeforeWindowClose before actually closing
this.logService.trace(`Lifecycle#onBeforeWindowClose.fire() - window ID ${windowId}`);
@@ -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;