diff --git a/src/vs/code/electron-main/lifecycle.ts b/src/vs/code/electron-main/lifecycle.ts index 7623a9170868b70ccf3b13ed682fbd62b963366a..895f8b056846c453ffbe93b4273451da89cd9004 100644 --- a/src/vs/code/electron-main/lifecycle.ts +++ b/src/vs/code/electron-main/lifecycle.ts @@ -17,10 +17,10 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation' export const ILifecycleService = createDecorator('lifecycleService'); export enum UnloadReason { - CLOSE, - QUIT, - RELOAD, - LOAD + CLOSE = 1, + QUIT = 2, + RELOAD = 3, + LOAD = 4 } export interface ILifecycleService { @@ -264,4 +264,4 @@ export class LifecycleService implements ILifecycleService { public isQuitRequested(): boolean { return !!this.quitRequested; } -} \ No newline at end of file +} diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index f1830ec4f7800f1f75a062262883380fbc57519a..f541796f5c52a5e0fc059fbb3961b14cab80f6ff 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -486,10 +486,11 @@ const editorConfiguration: IConfigurationNode = { 'default': EDITOR_DEFAULTS.contribInfo.folding, 'description': nls.localize('folding', "Controls whether the editor has code folding enabled") }, - 'editor.hideFoldIcons': { - 'type': 'boolean', - 'default': EDITOR_DEFAULTS.contribInfo.hideFoldIcons, - 'description': nls.localize('hideFoldIcons', "Controls whether the fold icons on the gutter are automatically hidden.") + 'editor.showFoldingControls': { + 'type': 'string', + 'enum': ['always', 'mouseover'], + 'default': EDITOR_DEFAULTS.contribInfo.showFoldingControls, + 'description': nls.localize('showFoldingControls', "Controls whether the fold controls on the gutter are automatically hidden.") }, 'editor.matchBrackets': { 'type': 'boolean', diff --git a/src/vs/editor/common/config/editorOptions.ts b/src/vs/editor/common/config/editorOptions.ts index 5c43033f67aba5263b8bc9c2fb0a0ed3611148c5..ce5208a05231f22e4687766b68f9e9419d04e9a9 100644 --- a/src/vs/editor/common/config/editorOptions.ts +++ b/src/vs/editor/common/config/editorOptions.ts @@ -420,10 +420,10 @@ export interface IEditorOptions { */ folding?: boolean; /** - * Enable automatic hiding of non-collapsed fold icons in the gutter. - * Defaults to true. + * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter. + * Defaults to 'mouseover'. */ - hideFoldIcons?: boolean; + showFoldingControls?: 'always' | 'mouseover'; /** * Enable highlighting of matching brackets. * Defaults to true. @@ -736,7 +736,7 @@ export interface EditorContribOptions { readonly occurrencesHighlight: boolean; readonly codeLens: boolean; readonly folding: boolean; - readonly hideFoldIcons: boolean; + readonly showFoldingControls: 'always' | 'mouseover'; readonly matchBrackets: boolean; } @@ -1045,7 +1045,7 @@ export class InternalEditorOptions { && a.occurrencesHighlight === b.occurrencesHighlight && a.codeLens === b.codeLens && a.folding === b.folding - && a.hideFoldIcons === b.hideFoldIcons + && a.showFoldingControls === b.showFoldingControls && a.matchBrackets === b.matchBrackets ); } @@ -1542,7 +1542,7 @@ export class EditorOptionsValidator { occurrencesHighlight: _boolean(opts.occurrencesHighlight, defaults.occurrencesHighlight), codeLens: _boolean(opts.codeLens, defaults.codeLens) && _boolean(opts.referenceInfos, true), folding: _boolean(opts.folding, defaults.folding), - hideFoldIcons: _boolean(opts.hideFoldIcons, defaults.hideFoldIcons), + showFoldingControls: _stringSet<'always' | 'mouseover'>(opts.showFoldingControls, defaults.showFoldingControls, ['always', 'mouseover']), matchBrackets: _boolean(opts.matchBrackets, defaults.matchBrackets), }; } @@ -1949,7 +1949,7 @@ export const EDITOR_DEFAULTS: IValidatedEditorOptions = { occurrencesHighlight: true, codeLens: true, folding: true, - hideFoldIcons: true, + showFoldingControls: 'mouseover', matchBrackets: true, }, }; diff --git a/src/vs/editor/contrib/folding/browser/folding.ts b/src/vs/editor/contrib/folding/browser/folding.ts index 24fe018b8de11637b18039aacff7a32b73d49ba2..f89d26c6536073e4646f145650378d16632e03bc 100644 --- a/src/vs/editor/contrib/folding/browser/folding.ts +++ b/src/vs/editor/contrib/folding/browser/folding.ts @@ -36,7 +36,7 @@ export class FoldingController implements IFoldingController { private editor: ICodeEditor; private _isEnabled: boolean; - private _hideFoldIcons: boolean; + private _showFoldingControls: 'always' | 'mouseover'; private globalToDispose: IDisposable[]; private computeToken: number; @@ -49,7 +49,7 @@ export class FoldingController implements IFoldingController { constructor(editor: ICodeEditor) { this.editor = editor; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; - this._hideFoldIcons = this.editor.getConfiguration().contribInfo.hideFoldIcons; + this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls; this.globalToDispose = []; this.localToDispose = []; @@ -63,9 +63,9 @@ export class FoldingController implements IFoldingController { if (oldIsEnabled !== this._isEnabled) { this.onModelChanged(); } - let oldHideFoldIcons = this._hideFoldIcons; - this._hideFoldIcons = this.editor.getConfiguration().contribInfo.hideFoldIcons; - if (oldHideFoldIcons !== this._hideFoldIcons) { + let oldShowFoldingControls = this._showFoldingControls; + this._showFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls; + if (oldShowFoldingControls !== this._showFoldingControls) { this.updateHideFoldIconClass(); } })); @@ -85,7 +85,7 @@ export class FoldingController implements IFoldingController { private updateHideFoldIconClass(): void { let domNode = this.editor.getDomNode(); if (domNode) { - dom.toggleClass(domNode, 'alwaysShowFoldIcons', this._hideFoldIcons === false); + dom.toggleClass(domNode, 'alwaysShowFoldIcons', this._showFoldingControls === 'always'); } } diff --git a/src/vs/editor/contrib/snippet/browser/snippetController2.ts b/src/vs/editor/contrib/snippet/browser/snippetController2.ts index 329caa67f7b91ed62c7e3f7954e00a4662812802..1b31742753b4e2a8e8fe1bb9ca58fd55d9bea6e5 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetController2.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetController2.ts @@ -57,21 +57,24 @@ export class SnippetController2 { overwriteBefore: number = 0, overwriteAfter: number = 0, undoStopBefore: boolean = true, undoStopAfter: boolean = true ): void { - if (this._snippet) { - this.cancel(); - } - this._snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter); if (undoStopBefore) { this._editor.getModel().pushStackElement(); } - this._snippet.insert(); + if (!this._snippet) { + // insert with new session + this._snippet = new SnippetSession(this._editor, template, overwriteBefore, overwriteAfter); + this._snippet.insert(); + this._snippetListener = [ + this._editor.onDidChangeModel(() => this.cancel()), + this._editor.onDidChangeCursorSelection(() => this._updateState()) + ]; + } else { + // insert nested + this._snippet.insertNested(template, overwriteBefore, overwriteAfter); + } if (undoStopAfter) { this._editor.getModel().pushStackElement(); } - this._snippetListener = [ - this._editor.onDidChangeModel(() => this.cancel()), - this._editor.onDidChangeCursorSelection(() => this._updateState()) - ]; this._updateState(); } diff --git a/src/vs/editor/contrib/snippet/browser/snippetSession.ts b/src/vs/editor/contrib/snippet/browser/snippetSession.ts index 5a5b590f93c248e200360bad7835b7242b21d874..2b2c9ca44f26c1f2dd7eec041759a4f669a16fe5 100644 --- a/src/vs/editor/contrib/snippet/browser/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/browser/snippetSession.ts @@ -291,6 +291,18 @@ export class SnippetSession { this._editor.setSelections(newSelections); } + insertNested(template: string, overwriteBefore: number = 0, overwriteAfter: number = 0): void { + const { edits } = SnippetSession.makeInsertEditsAndSnippets( + this._editor, template, overwriteBefore, overwriteAfter + ); + const model = this._editor.getModel(); + const selections = this._editor.getSelections(); + const newSelections = model.pushEditOperations(selections, edits, () => { + return this._move(true); + }); + this._editor.setSelections(newSelections); + } + next(): void { const newSelections = this._move(true); this._editor.setSelections(newSelections); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index a06eec92796f4408a0dced48640a063ff9442a80..140e5d7e7ae12a7dfc6827c28b9a5ac17fa08765 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -2978,10 +2978,10 @@ declare module monaco.editor { */ folding?: boolean; /** - * Enable automatic hiding of non-collapsed fold icons in the gutter. - * Defaults to true. + * Controls whether the fold actions in the gutter stay always visible or hide unless the mouse is over the gutter. + * Defaults to 'mouseover'. */ - hideFoldIcons?: boolean; + showFoldingControls?: 'always' | 'mouseover'; /** * Enable highlighting of matching brackets. * Defaults to true. @@ -3239,7 +3239,7 @@ declare module monaco.editor { readonly occurrencesHighlight: boolean; readonly codeLens: boolean; readonly folding: boolean; - readonly hideFoldIcons: boolean; + readonly showFoldingControls: 'always' | 'mouseover'; readonly matchBrackets: boolean; } diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index d6fdf34ddb569985bb884fdef6d5b285b64b0bfd..1cd1ab93cea11c4b1b30399bea16d89d45e88566 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -26,16 +26,22 @@ export interface ShutdownEvent { export enum ShutdownReason { /** Window is closed */ - CLOSE, + CLOSE = 1, /** Application is quit */ - QUIT, + QUIT = 2, /** Window is reloaded */ - RELOAD, + RELOAD = 3, /** Other configuration loaded into window */ - LOAD + LOAD = 4 +} + +export enum StartupKind { + NewWindow = 1, + ReloadedWindow = 3, + ReopenedWindow = 4, } /** @@ -46,17 +52,22 @@ export interface ILifecycleService { _serviceBrand: any; + /** + * Value indicates how this window got loaded. + */ + readonly startupKind: StartupKind; + /** * A flag indicating if the application is in the process of shutting down. This will be true * before the onWillShutdown event is fired and false if the shutdown is being vetoed. */ - willShutdown: boolean; + readonly willShutdown: boolean; /** * Fired before shutdown happens. Allows listeners to veto against the * shutdown. */ - onWillShutdown: Event; + readonly onWillShutdown: Event; /** * Fired when no client is preventing the shutdown from happening. Can be used to dispose heavy resources @@ -64,12 +75,13 @@ export interface ILifecycleService { * * The event carries a shutdown reason that indicates how the shutdown was triggered. */ - onShutdown: Event; + readonly onShutdown: Event; } export const NullLifecycleService: ILifecycleService = { _serviceBrand: null, + startupKind: StartupKind.NewWindow, willShutdown: false, onWillShutdown: () => ({ dispose() { } }), onShutdown: (reason) => ({ dispose() { } }) -}; \ No newline at end of file +}; diff --git a/src/vs/platform/update/electron-main/updateService.ts b/src/vs/platform/update/electron-main/updateService.ts index 77ef33d20fe48da3243d2a9a26f8f487be0499a6..aa3f75c6d5140bb8a8fc93b5595cc3ef1f4a28e4 100644 --- a/src/vs/platform/update/electron-main/updateService.ts +++ b/src/vs/platform/update/electron-main/updateService.ts @@ -177,6 +177,7 @@ export class UpdateService implements IUpdateService { this._availableUpdate = data; this._onUpdateAvailable.fire({ url: update.url, version: update.version }); this.state = State.UpdateAvailable; + this.telemetryService.publicLog('update:available', { explicit, version: update.version, currentVersion: product.commit }); } else { const data: IUpdate = { diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 59955d700498430455d7159d5373b2ff82cc2870..1f25faacf43035c3ca62b9ad3ed981c3f15fa844 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -132,6 +132,7 @@ export class WorkbenchShell { private windowIPCService: IWindowIPCService; private timerService: ITimerService; private themeService: WorkbenchThemeService; + private lifecycleService: ILifecycleService; private container: HTMLElement; private toUnbind: IDisposable[]; @@ -235,7 +236,10 @@ export class WorkbenchShell { theme: this.themeService.getColorTheme().id, language: platform.language, experiments: this.telemetryService.getExperiments(), - pinnedViewlets: info.pinnedViewlets + pinnedViewlets: info.pinnedViewlets, + restoredViewlet: info.restoredViewlet, + restoredEditors: info.restoredEditors.length, + startupKind: this.lifecycleService.startupKind }); // Telemetry: startup metrics @@ -355,6 +359,7 @@ export class WorkbenchShell { this.toUnbind.push(lifecycleService.onShutdown(reason => saveFontInfo(this.storageService))); serviceCollection.set(ILifecycleService, lifecycleService); disposables.add(lifecycleTelemetry(this.telemetryService, lifecycleService)); + this.lifecycleService = lifecycleService; const extensionManagementChannel = getDelayedChannel(sharedProcess.then(c => c.getChannel('extensions'))); serviceCollection.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementChannelClient, extensionManagementChannel)); diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 35a31823fd00d285eba8eafa2434fc334cf28333..56f626450b75342b9671f92d54a712126dc4959c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -120,6 +120,8 @@ export interface IWorkbenchStartedInfo { restoreViewletDuration: number; restoreEditorsDuration: number; pinnedViewlets: string[]; + restoredViewlet: string; + restoredEditors: string[]; } export interface IWorkbenchCallbacks { @@ -294,8 +296,8 @@ export class Workbench implements IPartService { // Restore last opened viewlet let viewletRestoreStopWatch: StopWatch; + let viewletIdToRestore: string; if (!this.sideBarHidden) { - let viewletIdToRestore: string; if (this.shouldRestoreLastOpenedViewlet()) { viewletIdToRestore = this.storageService.get(SidebarPart.activeViewletSettingsKey, StorageScope.WORKSPACE); @@ -321,6 +323,7 @@ export class Workbench implements IPartService { // Load Editors const editorRestoreStopWatch = StopWatch.create(); + const restoredEditors: string[] = []; compositeAndEditorPromises.push(this.resolveEditorsToOpen().then(inputs => { let editorOpenPromise: TPromise; if (inputs.length) { @@ -329,9 +332,16 @@ export class Workbench implements IPartService { editorOpenPromise = this.editorPart.restoreEditors(); } - return editorOpenPromise.then(() => { + return editorOpenPromise.then(editors => { this.onEditorsChanged(); // make sure we show the proper background in the editor area editorRestoreStopWatch.stop(); + for (const editor of editors) { + if (editor.input) { + restoredEditors.push(editor.input.getName()); + } else { + restoredEditors.push(`other:${editor.getId()}`); + } + } }); })); @@ -350,6 +360,8 @@ export class Workbench implements IPartService { restoreViewletDuration: viewletRestoreStopWatch ? Math.round(viewletRestoreStopWatch.elapsed()) : 0, restoreEditorsDuration: Math.round(editorRestoreStopWatch.elapsed()), pinnedViewlets: this.activitybarPart.getPinned(), + restoredViewlet: viewletIdToRestore, + restoredEditors }); } diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index 2646a7185f3ab6ac59d5daf3a8a77751db357606..68cf1af57758155230efd5e65226432280422312 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -17,6 +17,7 @@ import { VIEWLET_ID } from 'vs/workbench/parts/scm/common/scm'; import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; +import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { ISCMService } from 'vs/workbench/services/scm/common/scm'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -41,7 +42,8 @@ export class SwitchProvider extends Action { id = SwitchProvider.ID, label = SwitchProvider.LABEL, @ISCMService private scmService: ISCMService, - @IQuickOpenService private quickOpenService: IQuickOpenService + @IQuickOpenService private quickOpenService: IQuickOpenService, + @IViewletService private viewletService: IViewletService ) { super('scm.switchprovider', 'Switch SCM Provider', '', true); } @@ -51,6 +53,16 @@ export class SwitchProvider extends Action { label: provider.label, run: () => this.scmService.activeProvider = provider })); + picks.push({ + label: localize('installAdditionalSCMProviders', "Install Additional SCM Providers..."), run: () => { + this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true).then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search('category:"SCM Providers" @sort:installs'); + viewlet.focus(); + }); + return this.scmService.activeProvider; + } + }); return this.quickOpenService.pick(picks); } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts index f5cb2241de70bf56a2cf4cb3a3863e0a0cbc51f5..bfea5b8df9b91c2fb3ec3061633872fff91dcd01 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts @@ -16,6 +16,8 @@ import { IAction, Action } from 'vs/base/common/actions'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ContextSubMenu } from 'vs/platform/contextview/browser/contextView'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { IExtensionsViewlet, VIEWLET_ID as EXTENSIONS_VIEWLET_ID } from 'vs/workbench/parts/extensions/common/extensions'; import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm'; import { getSCMResourceContextKey } from './scmUtil'; @@ -38,6 +40,21 @@ class SwitchProviderAction extends Action { } } +class InstallAdditionalSCMProviders extends Action { + + constructor(private viewletService: IViewletService) { + super('scm.installAdditionalSCMProviders', localize('installAdditionalSCMProviders', "Install Additional SCM Providers..."), '', true); + } + + run(): TPromise { + return this.viewletService.openViewlet(EXTENSIONS_VIEWLET_ID, true).then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search('category:"SCM Providers" @sort:installs'); + viewlet.focus(); + }); + } +} + export class SCMMenus implements IDisposable { private disposables: IDisposable[] = []; @@ -52,7 +69,8 @@ export class SCMMenus implements IDisposable { constructor( @IContextKeyService private contextKeyService: IContextKeyService, @ISCMService private scmService: ISCMService, - @IMenuService private menuService: IMenuService + @IMenuService private menuService: IMenuService, + @IViewletService private viewletService: IViewletService ) { this.setActiveProvider(this.scmService.activeProvider); this.scmService.onDidChangeProvider(this.setActiveProvider, this, this.disposables); @@ -92,7 +110,7 @@ export class SCMMenus implements IDisposable { } getTitleSecondaryActions(): IAction[] { - const providerSwitchActions = this.scmService.providers + const providerSwitchActions: IAction[] = this.scmService.providers .map(p => new SwitchProviderAction(p, this.scmService)); let result = []; @@ -100,14 +118,16 @@ export class SCMMenus implements IDisposable { if (this.titleSecondaryActions.length > 0) { result = result.concat(this.titleSecondaryActions); } + if (providerSwitchActions.length > 0) { + providerSwitchActions.push(new Separator()); + } + providerSwitchActions.push(new InstallAdditionalSCMProviders(this.viewletService)); - if (result.length > 0 && providerSwitchActions.length > 0) { + if (result.length > 0) { result.push(new Separator()); } - if (providerSwitchActions.length > 0) { - result.push(new ContextSubMenu(localize('switch provider', "Switch SCM Provider..."), providerSwitchActions)); - } + result.push(new ContextSubMenu(localize('switch provider', "Switch SCM Provider..."), providerSwitchActions)); return result; } diff --git a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts index 105a9d202af364733d916ffa4cd80df07b16c7c6..e3c3f8e63ea749151b7c2e4ed744fff128f787e5 100644 --- a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts @@ -7,26 +7,46 @@ import { TPromise } from 'vs/base/common/winjs.base'; import Severity from 'vs/base/common/severity'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { ILifecycleService, ShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { IMessageService } from 'vs/platform/message/common/message'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IWindowIPCService } from 'vs/workbench/services/window/electron-browser/windowService'; import { ipcRenderer as ipc } from 'electron'; import Event, { Emitter } from 'vs/base/common/event'; export class LifecycleService implements ILifecycleService { + private static readonly _lastShutdownReasonKey = 'lifecyle.lastShutdownReason'; + public _serviceBrand: any; - private _onWillShutdown = new Emitter(); - private _onShutdown = new Emitter(); + private readonly _onWillShutdown = new Emitter(); + private readonly _onShutdown = new Emitter(); + private readonly _startupKind: StartupKind; private _willShutdown: boolean; constructor( - @IMessageService private messageService: IMessageService, - @IWindowIPCService private windowService: IWindowIPCService + @IMessageService private _messageService: IMessageService, + @IWindowIPCService private _windowService: IWindowIPCService, + @IStorageService private _storageService: IStorageService ) { - this.registerListeners(); + this._registerListeners(); + + const lastShutdownReason = this._storageService.getInteger(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE); + this._storageService.remove(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE); + if (lastShutdownReason === ShutdownReason.RELOAD) { + this._startupKind = StartupKind.ReloadedWindow; + } else if (lastShutdownReason === ShutdownReason.LOAD) { + this._startupKind = StartupKind.ReopenedWindow; + } else { + this._startupKind = StartupKind.NewWindow; + } + console.log(this.startupKind); + } + + public get startupKind(): StartupKind { + return this._startupKind; } public get willShutdown(): boolean { @@ -41,16 +61,18 @@ export class LifecycleService implements ILifecycleService { return this._onShutdown.event; } - private registerListeners(): void { - const windowId = this.windowService.getWindowId(); + private _registerListeners(): void { + const windowId = this._windowService.getWindowId(); // Main side indicates that window is about to unload, check for vetos ipc.on('vscode:beforeUnload', (event, reply: { okChannel: string, cancelChannel: string, reason: ShutdownReason }) => { this._willShutdown = true; + this._storageService.store(LifecycleService._lastShutdownReasonKey, JSON.stringify(reply.reason), StorageScope.WORKSPACE); // trigger onWillShutdown events and veto collecting this.onBeforeUnload(reply.reason).done(veto => { if (veto) { + this._storageService.remove(LifecycleService._lastShutdownReasonKey, StorageScope.WORKSPACE); this._willShutdown = false; // reset this flag since the shutdown has been vetoed! ipc.send(reply.cancelChannel, windowId); } else { @@ -92,11 +114,11 @@ export class LifecycleService implements ILifecycleService { } }, err => { // error, treated like a veto, done - this.messageService.show(Severity.Error, toErrorMessage(err)); + this._messageService.show(Severity.Error, toErrorMessage(err)); lazyValue = true; })); } } return TPromise.join(promises).then(() => lazyValue); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index bc6068ce24eeb4a0809723f3ba9c0cdd2e993d2b..bc6e0f5e11dff62f4ec91884f02e0639c911d94b 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -28,7 +28,7 @@ import { IEditorInput, IEditorOptions, Position, Direction, IEditor, IResourceIn import { IUntitledEditorService, UntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IMessageService, IConfirmation } from 'vs/platform/message/common/message'; import { IWorkspace, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ILifecycleService, ShutdownEvent, ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILifecycleService, ShutdownEvent, ShutdownReason, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; import { EditorStacksModel } from 'vs/workbench/common/editor/editorStacksModel'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; @@ -855,6 +855,7 @@ export class TestLifecycleService implements ILifecycleService { public _serviceBrand: any; public willShutdown: boolean; + public startupKind: StartupKind; private _onWillShutdown = new Emitter(); private _onShutdown = new Emitter(); @@ -1023,4 +1024,4 @@ export class TestThemeService implements IThemeService { onThemeChange(participant: IThemingParticipant): IDisposable { return { dispose: () => { } }; } -} \ No newline at end of file +}