diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index a09e3d739c1..d9572ef3095 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -55,6 +55,7 @@ import { DisassemblyView, DisassemblyViewContribution } from 'vs/workbench/contr import { EditorPaneDescriptor, IEditorPaneRegistry } from 'vs/workbench/browser/editor'; import { DisassemblyViewInput } from 'vs/workbench/contrib/debug/common/disassemblyViewInput'; import { Codicon } from 'vs/base/common/codicons'; +import { DebugLifecycle } from 'vs/workbench/contrib/debug/common/debugLifecycle'; const debugCategory = nls.localize('debugCategory', "Debug"); registerColors(); @@ -70,6 +71,7 @@ Registry.as(WorkbenchExtensions.Workbench).regi Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Eventually); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually); Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DisassemblyViewContribution, LifecyclePhase.Eventually); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugLifecycle, LifecyclePhase.Eventually); // Register Quick Access Registry.as(QuickAccessExtensions.Quickaccess).registerQuickAccessProvider({ @@ -524,6 +526,16 @@ configurationRegistry.registerConfiguration({ ], default: 'allEditorsInActiveGroup', scope: ConfigurationScope.LANGUAGE_OVERRIDABLE + }, + 'debug.confirmOnExit': { + description: nls.localize('debug.confirmOnExit', "Controls whether to confirm when the window closes if there are active debug sessions."), + type: 'string', + enum: ['never', 'always'], + enumDescriptions: [ + nls.localize('debug.confirmOnExit.never', "Never confirm."), + nls.localize('debug.confirmOnExit.always', "Always confirm if there are debug sessions."), + ], + default: 'never' } } }); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index c585d8131aa..ea4e5c14fc1 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -547,6 +547,7 @@ export interface IDebugConfiguration { onTaskErrors: 'debugAnyway' | 'showErrors' | 'prompt' | 'abort'; showBreakpointsInOverviewRuler: boolean; showInlineBreakpointCandidates: boolean; + confirmOnExit: 'always' | 'never'; } export interface IGlobalConfig { diff --git a/src/vs/workbench/contrib/debug/common/debugLifecycle.ts b/src/vs/workbench/contrib/debug/common/debugLifecycle.ts new file mode 100644 index 00000000000..5cce9304f75 --- /dev/null +++ b/src/vs/workbench/contrib/debug/common/debugLifecycle.ts @@ -0,0 +1,50 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IDebugConfiguration, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { ILifecycleService, ShutdownReason } from 'vs/workbench/services/lifecycle/common/lifecycle'; + +export class DebugLifecycle implements IWorkbenchContribution { + constructor( + @ILifecycleService lifecycleService: ILifecycleService, + @IDebugService private readonly debugService: IDebugService, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IDialogService private readonly dialogService: IDialogService, + ) { + lifecycleService.onBeforeShutdown(async e => e.veto(this.shouldVetoShutdown(e.reason), 'veto.debug')); + } + + private shouldVetoShutdown(_reason: ShutdownReason): boolean | Promise { + const rootSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === undefined); + if (rootSessions.length === 0) { + return false; + } + + const shouldConfirmOnExit = this.configurationService.getValue('debug').confirmOnExit; + if (shouldConfirmOnExit === 'never') { + return false; + } + + return this._showWindowCloseConfirmation(rootSessions.length); + } + + protected async _showWindowCloseConfirmation(numSessions: number): Promise { + let message: string; + if (numSessions === 1) { + message = nls.localize('debug.debugSessionCloseConfirmationSingular', "There is an active debug session, are you sure you want to terminate it?"); + } else { + message = nls.localize('debug.debugSessionCloseConfirmationPlural', "There are active debug sessions, are you sure you want to terminate them?"); + } + const res = await this.dialogService.confirm({ + message, + type: 'warning', + }); + return !res.confirmed; + } +}