Path: blob/main/src/vs/workbench/contrib/debug/browser/breakpointsView.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import * as dom from '../../../../base/browser/dom.js';6import { IKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';7import { Gesture } from '../../../../base/browser/touch.js';8import { ActionBar } from '../../../../base/browser/ui/actionbar/actionbar.js';9import { AriaRole } from '../../../../base/browser/ui/aria/aria.js';10import { getDefaultHoverDelegate } from '../../../../base/browser/ui/hover/hoverDelegateFactory.js';11import { IconLabel } from '../../../../base/browser/ui/iconLabel/iconLabel.js';12import { InputBox } from '../../../../base/browser/ui/inputbox/inputBox.js';13import { IListContextMenuEvent, IListRenderer, IListVirtualDelegate } from '../../../../base/browser/ui/list/list.js';14import { IListAccessibilityProvider } from '../../../../base/browser/ui/list/listWidget.js';15import { Orientation } from '../../../../base/browser/ui/splitview/splitview.js';16import { Action } from '../../../../base/common/actions.js';17import { equals } from '../../../../base/common/arrays.js';18import { RunOnceScheduler } from '../../../../base/common/async.js';19import { Codicon } from '../../../../base/common/codicons.js';20import { MarkdownString } from '../../../../base/common/htmlContent.js';21import { KeyCode } from '../../../../base/common/keyCodes.js';22import { DisposableStore, dispose } from '../../../../base/common/lifecycle.js';23import * as resources from '../../../../base/common/resources.js';24import { ThemeIcon } from '../../../../base/common/themables.js';25import { Constants } from '../../../../base/common/uint.js';26import { isCodeEditor } from '../../../../editor/browser/editorBrowser.js';27import { ServicesAccessor } from '../../../../editor/browser/editorExtensions.js';28import { ILanguageService } from '../../../../editor/common/languages/language.js';29import { localize, localize2 } from '../../../../nls.js';30import { getActionBarActions, getContextMenuActions } from '../../../../platform/actions/browser/menuEntryActionViewItem.js';31import { Action2, IMenu, IMenuService, MenuId, registerAction2 } from '../../../../platform/actions/common/actions.js';32import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';33import { ContextKeyExpr, IContextKey, IContextKeyService } from '../../../../platform/contextkey/common/contextkey.js';34import { IContextMenuService, IContextViewService } from '../../../../platform/contextview/browser/contextView.js';35import { TextEditorSelectionRevealType } from '../../../../platform/editor/common/editor.js';36import { IHoverService } from '../../../../platform/hover/browser/hover.js';37import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';38import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js';39import { ILabelService } from '../../../../platform/label/common/label.js';40import { WorkbenchList } from '../../../../platform/list/browser/listService.js';41import { INotificationService } from '../../../../platform/notification/common/notification.js';42import { IOpenerService } from '../../../../platform/opener/common/opener.js';43import { IQuickInputService } from '../../../../platform/quickinput/common/quickInput.js';44import { defaultInputBoxStyles } from '../../../../platform/theme/browser/defaultStyles.js';45import { IThemeService } from '../../../../platform/theme/common/themeService.js';46import { ViewAction, ViewPane } from '../../../browser/parts/views/viewPane.js';47import { IViewletViewOptions } from '../../../browser/parts/views/viewsViewlet.js';48import { IEditorPane } from '../../../common/editor.js';49import { IViewDescriptorService } from '../../../common/views.js';50import { ACTIVE_GROUP, IEditorService, SIDE_GROUP } from '../../../services/editor/common/editorService.js';51import { IViewsService } from '../../../services/views/common/viewsService.js';52import { BREAKPOINTS_VIEW_ID, BREAKPOINT_EDITOR_CONTRIBUTION_ID, CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAKPOINTS_FOCUSED, CONTEXT_BREAKPOINT_HAS_MODES, CONTEXT_BREAKPOINT_INPUT_FOCUSED, CONTEXT_BREAKPOINT_ITEM_IS_DATA_BYTES, CONTEXT_BREAKPOINT_ITEM_TYPE, CONTEXT_BREAKPOINT_SUPPORTS_CONDITION, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_IN_DEBUG_MODE, CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, DEBUG_SCHEME, DataBreakpointSetType, DataBreakpointSource, DebuggerString, IBaseBreakpoint, IBreakpoint, IBreakpointEditorContribution, IBreakpointUpdateData, IDataBreakpoint, IDataBreakpointInfoResponse, IDebugModel, IDebugService, IEnablement, IExceptionBreakpoint, IFunctionBreakpoint, IInstructionBreakpoint, State } from '../common/debug.js';53import { Breakpoint, DataBreakpoint, ExceptionBreakpoint, FunctionBreakpoint, InstructionBreakpoint } from '../common/debugModel.js';54import { DisassemblyViewInput } from '../common/disassemblyViewInput.js';55import * as icons from './debugIcons.js';56import { DisassemblyView } from './disassemblyView.js';5758const $ = dom.$;5960function createCheckbox(disposables: DisposableStore): HTMLInputElement {61const checkbox = <HTMLInputElement>$('input');62checkbox.type = 'checkbox';63checkbox.tabIndex = -1;64disposables.add(Gesture.ignoreTarget(checkbox));6566return checkbox;67}6869const MAX_VISIBLE_BREAKPOINTS = 9;70export function getExpandedBodySize(model: IDebugModel, sessionId: string | undefined, countLimit: number): number {71const length = model.getBreakpoints().length + model.getExceptionBreakpointsForSession(sessionId).length + model.getFunctionBreakpoints().length + model.getDataBreakpoints().length + model.getInstructionBreakpoints().length;72return Math.min(countLimit, length) * 22;73}74type BreakpointItem = IBreakpoint | IFunctionBreakpoint | IDataBreakpoint | IExceptionBreakpoint | IInstructionBreakpoint;7576interface InputBoxData {77breakpoint: IFunctionBreakpoint | IExceptionBreakpoint | IDataBreakpoint;78type: 'condition' | 'hitCount' | 'name';79}8081function getModeKindForBreakpoint(breakpoint: IBreakpoint) {82const kind = breakpoint instanceof Breakpoint ? 'source' : breakpoint instanceof InstructionBreakpoint ? 'instruction' : 'exception';83return kind;84}8586export class BreakpointsView extends ViewPane {8788private list!: WorkbenchList<BreakpointItem>;89private needsRefresh = false;90private needsStateChange = false;91private ignoreLayout = false;92private menu: IMenu;93private breakpointItemType: IContextKey<string | undefined>;94private breakpointIsDataBytes: IContextKey<boolean | undefined>;95private breakpointHasMultipleModes: IContextKey<boolean>;96private breakpointSupportsCondition: IContextKey<boolean>;97private _inputBoxData: InputBoxData | undefined;98breakpointInputFocused: IContextKey<boolean>;99private autoFocusedIndex = -1;100101private hintContainer: IconLabel | undefined;102private hintDelayer: RunOnceScheduler;103104constructor(105options: IViewletViewOptions,106@IContextMenuService contextMenuService: IContextMenuService,107@IDebugService private readonly debugService: IDebugService,108@IKeybindingService keybindingService: IKeybindingService,109@IInstantiationService instantiationService: IInstantiationService,110@IThemeService themeService: IThemeService,111@IEditorService private readonly editorService: IEditorService,112@IContextViewService private readonly contextViewService: IContextViewService,113@IConfigurationService configurationService: IConfigurationService,114@IViewDescriptorService viewDescriptorService: IViewDescriptorService,115@IContextKeyService contextKeyService: IContextKeyService,116@IOpenerService openerService: IOpenerService,117@ILabelService private readonly labelService: ILabelService,118@IMenuService menuService: IMenuService,119@IHoverService hoverService: IHoverService,120@ILanguageService private readonly languageService: ILanguageService,121) {122super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, hoverService);123124this.menu = menuService.createMenu(MenuId.DebugBreakpointsContext, contextKeyService);125this._register(this.menu);126this.breakpointItemType = CONTEXT_BREAKPOINT_ITEM_TYPE.bindTo(contextKeyService);127this.breakpointIsDataBytes = CONTEXT_BREAKPOINT_ITEM_IS_DATA_BYTES.bindTo(contextKeyService);128this.breakpointHasMultipleModes = CONTEXT_BREAKPOINT_HAS_MODES.bindTo(contextKeyService);129this.breakpointSupportsCondition = CONTEXT_BREAKPOINT_SUPPORTS_CONDITION.bindTo(contextKeyService);130this.breakpointInputFocused = CONTEXT_BREAKPOINT_INPUT_FOCUSED.bindTo(contextKeyService);131this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));132this._register(this.debugService.getViewModel().onDidFocusSession(() => this.onBreakpointsChange()));133this._register(this.debugService.onDidChangeState(() => this.onStateChange()));134this.hintDelayer = this._register(new RunOnceScheduler(() => this.updateBreakpointsHint(true), 4000));135}136137protected override renderBody(container: HTMLElement): void {138super.renderBody(container);139140this.element.classList.add('debug-pane');141container.classList.add('debug-breakpoints');142const delegate = new BreakpointsDelegate(this);143144this.list = this.instantiationService.createInstance(WorkbenchList, 'Breakpoints', container, delegate, [145this.instantiationService.createInstance(BreakpointsRenderer, this.menu, this.breakpointHasMultipleModes, this.breakpointSupportsCondition, this.breakpointItemType),146new ExceptionBreakpointsRenderer(this.menu, this.breakpointHasMultipleModes, this.breakpointSupportsCondition, this.breakpointItemType, this.debugService, this.hoverService),147new ExceptionBreakpointInputRenderer(this, this.debugService, this.contextViewService),148this.instantiationService.createInstance(FunctionBreakpointsRenderer, this.menu, this.breakpointSupportsCondition, this.breakpointItemType),149new FunctionBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.hoverService, this.labelService),150this.instantiationService.createInstance(DataBreakpointsRenderer, this.menu, this.breakpointHasMultipleModes, this.breakpointSupportsCondition, this.breakpointItemType, this.breakpointIsDataBytes),151new DataBreakpointInputRenderer(this, this.debugService, this.contextViewService, this.hoverService, this.labelService),152this.instantiationService.createInstance(InstructionBreakpointsRenderer),153], {154identityProvider: { getId: (element: IEnablement) => element.getId() },155multipleSelectionSupport: false,156keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IEnablement) => e },157accessibilityProvider: new BreakpointsAccessibilityProvider(this.debugService, this.labelService),158overrideStyles: this.getLocationBasedColors().listOverrideStyles159}) as WorkbenchList<BreakpointItem>;160161CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService);162163this._register(this.list.onContextMenu(this.onListContextMenu, this));164165this._register(this.list.onMouseMiddleClick(async ({ element }) => {166if (element instanceof Breakpoint) {167await this.debugService.removeBreakpoints(element.getId());168} else if (element instanceof FunctionBreakpoint) {169await this.debugService.removeFunctionBreakpoints(element.getId());170} else if (element instanceof DataBreakpoint) {171await this.debugService.removeDataBreakpoints(element.getId());172} else if (element instanceof InstructionBreakpoint) {173await this.debugService.removeInstructionBreakpoints(element.instructionReference, element.offset);174}175}));176177this._register(this.list.onDidOpen(async e => {178if (!e.element) {179return;180}181182if (dom.isMouseEvent(e.browserEvent) && e.browserEvent.button === 1) { // middle click183return;184}185186if (e.element instanceof Breakpoint) {187openBreakpointSource(e.element, e.sideBySide, e.editorOptions.preserveFocus || false, e.editorOptions.pinned || !e.editorOptions.preserveFocus, this.debugService, this.editorService);188}189if (e.element instanceof InstructionBreakpoint) {190const disassemblyView = await this.editorService.openEditor(DisassemblyViewInput.instance);191// Focus on double click192(disassemblyView as DisassemblyView).goToInstructionAndOffset(e.element.instructionReference, e.element.offset, dom.isMouseEvent(e.browserEvent) && e.browserEvent.detail === 2);193}194if (dom.isMouseEvent(e.browserEvent) && e.browserEvent.detail === 2 && e.element instanceof FunctionBreakpoint && e.element !== this.inputBoxData?.breakpoint) {195// double click196this.renderInputBox({ breakpoint: e.element, type: 'name' });197}198}));199200this.list.splice(0, this.list.length, this.elements);201202this._register(this.onDidChangeBodyVisibility(visible => {203if (visible) {204if (this.needsRefresh) {205this.onBreakpointsChange();206}207208if (this.needsStateChange) {209this.onStateChange();210}211}212}));213214const containerModel = this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerByViewId(this.id)!)!;215this._register(containerModel.onDidChangeAllViewDescriptors(() => {216this.updateSize();217}));218}219220protected override renderHeaderTitle(container: HTMLElement, title: string): void {221super.renderHeaderTitle(container, title);222223const iconLabelContainer = dom.append(container, $('span.breakpoint-warning'));224this.hintContainer = this._register(new IconLabel(iconLabelContainer, {225supportIcons: true, hoverDelegate: {226showHover: (options, focus?) => this.hoverService.showInstantHover({ content: options.content, target: this.hintContainer!.element }, focus),227delay: <number>this.configurationService.getValue('workbench.hover.delay')228}229}));230dom.hide(this.hintContainer.element);231}232233override focus(): void {234super.focus();235this.list?.domFocus();236}237238renderInputBox(data: InputBoxData | undefined): void {239this._inputBoxData = data;240this.onBreakpointsChange();241this._inputBoxData = undefined;242}243244get inputBoxData(): InputBoxData | undefined {245return this._inputBoxData;246}247248protected override layoutBody(height: number, width: number): void {249if (this.ignoreLayout) {250return;251}252253super.layoutBody(height, width);254this.list?.layout(height, width);255try {256this.ignoreLayout = true;257this.updateSize();258} finally {259this.ignoreLayout = false;260}261}262263private onListContextMenu(e: IListContextMenuEvent<IEnablement>): void {264const element = e.element;265const type = element instanceof Breakpoint ? 'breakpoint' : element instanceof ExceptionBreakpoint ? 'exceptionBreakpoint' :266element instanceof FunctionBreakpoint ? 'functionBreakpoint' : element instanceof DataBreakpoint ? 'dataBreakpoint' :267element instanceof InstructionBreakpoint ? 'instructionBreakpoint' : undefined;268this.breakpointItemType.set(type);269const session = this.debugService.getViewModel().focusedSession;270const conditionSupported = element instanceof ExceptionBreakpoint ? element.supportsCondition : (!session || !!session.capabilities.supportsConditionalBreakpoints);271this.breakpointSupportsCondition.set(conditionSupported);272this.breakpointIsDataBytes.set(element instanceof DataBreakpoint && element.src.type === DataBreakpointSetType.Address);273this.breakpointHasMultipleModes.set(this.debugService.getModel().getBreakpointModes(getModeKindForBreakpoint(element as IBreakpoint)).length > 1);274275const { secondary } = getContextMenuActions(this.menu.getActions({ arg: e.element, shouldForwardArgs: false }), 'inline');276277this.contextMenuService.showContextMenu({278getAnchor: () => e.anchor,279getActions: () => secondary,280getActionsContext: () => element281});282}283284private updateSize(): void {285const containerModel = this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerByViewId(this.id)!)!;286287// Adjust expanded body size288const sessionId = this.debugService.getViewModel().focusedSession?.getId();289this.minimumBodySize = this.orientation === Orientation.VERTICAL ? getExpandedBodySize(this.debugService.getModel(), sessionId, MAX_VISIBLE_BREAKPOINTS) : 170;290this.maximumBodySize = this.orientation === Orientation.VERTICAL && containerModel.visibleViewDescriptors.length > 1 ? getExpandedBodySize(this.debugService.getModel(), sessionId, Number.POSITIVE_INFINITY) : Number.POSITIVE_INFINITY;291}292293private updateBreakpointsHint(delayed = false): void {294if (!this.hintContainer) {295return;296}297298const currentType = this.debugService.getViewModel().focusedSession?.configuration.type;299const dbg = currentType ? this.debugService.getAdapterManager().getDebugger(currentType) : undefined;300const message = dbg?.strings?.[DebuggerString.UnverifiedBreakpoints];301const debuggerHasUnverifiedBps = message && this.debugService.getModel().getBreakpoints().filter(bp => {302if (bp.verified || !bp.enabled) {303return false;304}305306const langId = this.languageService.guessLanguageIdByFilepathOrFirstLine(bp.uri);307return langId && dbg.interestedInLanguage(langId);308});309310if (message && debuggerHasUnverifiedBps?.length && this.debugService.getModel().areBreakpointsActivated()) {311if (delayed) {312const mdown = new MarkdownString(undefined, { isTrusted: true }).appendMarkdown(message);313this.hintContainer.setLabel('$(warning)', undefined, { title: { markdown: mdown, markdownNotSupportedFallback: message } });314dom.show(this.hintContainer.element);315} else {316this.hintDelayer.schedule();317}318} else {319dom.hide(this.hintContainer.element);320}321}322323private onBreakpointsChange(): void {324if (this.isBodyVisible()) {325this.updateSize();326if (this.list) {327const lastFocusIndex = this.list.getFocus()[0];328// Check whether focused element was removed329const needsRefocus = lastFocusIndex && !this.elements.includes(this.list.element(lastFocusIndex));330this.list.splice(0, this.list.length, this.elements);331this.needsRefresh = false;332if (needsRefocus) {333this.list.focusNth(Math.min(lastFocusIndex, this.list.length - 1));334}335}336this.updateBreakpointsHint();337} else {338this.needsRefresh = true;339}340}341342private onStateChange(): void {343if (this.isBodyVisible()) {344this.needsStateChange = false;345const thread = this.debugService.getViewModel().focusedThread;346let found = false;347if (thread && thread.stoppedDetails && thread.stoppedDetails.hitBreakpointIds && thread.stoppedDetails.hitBreakpointIds.length > 0) {348const hitBreakpointIds = thread.stoppedDetails.hitBreakpointIds;349const elements = this.elements;350const index = elements.findIndex(e => {351const id = e.getIdFromAdapter(thread.session.getId());352return typeof id === 'number' && hitBreakpointIds.indexOf(id) !== -1;353});354if (index >= 0) {355this.list.setFocus([index]);356this.list.setSelection([index]);357found = true;358this.autoFocusedIndex = index;359}360}361if (!found) {362// Deselect breakpoint in breakpoint view when no longer stopped on it #125528363const focus = this.list.getFocus();364const selection = this.list.getSelection();365if (this.autoFocusedIndex >= 0 && equals(focus, selection) && focus.indexOf(this.autoFocusedIndex) >= 0) {366this.list.setFocus([]);367this.list.setSelection([]);368}369this.autoFocusedIndex = -1;370}371this.updateBreakpointsHint();372} else {373this.needsStateChange = true;374}375}376377private get elements(): BreakpointItem[] {378const model = this.debugService.getModel();379const sessionId = this.debugService.getViewModel().focusedSession?.getId();380const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpointsForSession(sessionId)).concat(model.getFunctionBreakpoints()).concat(model.getDataBreakpoints()).concat(model.getBreakpoints()).concat(model.getInstructionBreakpoints());381382return elements as BreakpointItem[];383}384}385386class BreakpointsDelegate implements IListVirtualDelegate<BreakpointItem> {387388constructor(private view: BreakpointsView) {389// noop390}391392getHeight(_element: BreakpointItem): number {393return 22;394}395396getTemplateId(element: BreakpointItem): string {397if (element instanceof Breakpoint) {398return BreakpointsRenderer.ID;399}400if (element instanceof FunctionBreakpoint) {401const inputBoxBreakpoint = this.view.inputBoxData?.breakpoint;402if (!element.name || (inputBoxBreakpoint && inputBoxBreakpoint.getId() === element.getId())) {403return FunctionBreakpointInputRenderer.ID;404}405406return FunctionBreakpointsRenderer.ID;407}408if (element instanceof ExceptionBreakpoint) {409const inputBoxBreakpoint = this.view.inputBoxData?.breakpoint;410if (inputBoxBreakpoint && inputBoxBreakpoint.getId() === element.getId()) {411return ExceptionBreakpointInputRenderer.ID;412}413return ExceptionBreakpointsRenderer.ID;414}415if (element instanceof DataBreakpoint) {416const inputBoxBreakpoint = this.view.inputBoxData?.breakpoint;417if (inputBoxBreakpoint && inputBoxBreakpoint.getId() === element.getId()) {418return DataBreakpointInputRenderer.ID;419}420421return DataBreakpointsRenderer.ID;422}423if (element instanceof InstructionBreakpoint) {424return InstructionBreakpointsRenderer.ID;425}426427return '';428}429}430431interface IBaseBreakpointTemplateData {432breakpoint: HTMLElement;433name: HTMLElement;434checkbox: HTMLInputElement;435context: BreakpointItem;436actionBar: ActionBar;437templateDisposables: DisposableStore;438elementDisposables: DisposableStore;439badge: HTMLElement;440}441442interface IBaseBreakpointWithIconTemplateData extends IBaseBreakpointTemplateData {443icon: HTMLElement;444}445446interface IBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {447filePath: HTMLElement;448}449450interface IExceptionBreakpointTemplateData extends IBaseBreakpointTemplateData {451condition: HTMLElement;452}453454interface IFunctionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {455condition: HTMLElement;456}457458interface IDataBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {459accessType: HTMLElement;460condition: HTMLElement;461}462463interface IInstructionBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {464address: HTMLElement;465}466467interface IFunctionBreakpointInputTemplateData {468inputBox: InputBox;469checkbox: HTMLInputElement;470icon: HTMLElement;471breakpoint: IFunctionBreakpoint;472templateDisposables: DisposableStore;473elementDisposables: DisposableStore;474type: 'hitCount' | 'condition' | 'name';475updating?: boolean;476}477478interface IDataBreakpointInputTemplateData {479inputBox: InputBox;480checkbox: HTMLInputElement;481icon: HTMLElement;482breakpoint: IDataBreakpoint;483elementDisposables: DisposableStore;484templateDisposables: DisposableStore;485type: 'hitCount' | 'condition' | 'name';486updating?: boolean;487}488489interface IExceptionBreakpointInputTemplateData {490inputBox: InputBox;491checkbox: HTMLInputElement;492currentBreakpoint?: IExceptionBreakpoint;493templateDisposables: DisposableStore;494elementDisposables: DisposableStore;495}496497const breakpointIdToActionBarDomeNode = new Map<string, HTMLElement>();498class BreakpointsRenderer implements IListRenderer<IBreakpoint, IBreakpointTemplateData> {499500constructor(501private menu: IMenu,502private breakpointHasMultipleModes: IContextKey<boolean>,503private breakpointSupportsCondition: IContextKey<boolean>,504private breakpointItemType: IContextKey<string | undefined>,505@IDebugService private readonly debugService: IDebugService,506@IHoverService private readonly hoverService: IHoverService,507@ILabelService private readonly labelService: ILabelService508) {509// noop510}511512static readonly ID = 'breakpoints';513514get templateId() {515return BreakpointsRenderer.ID;516}517518renderTemplate(container: HTMLElement): IBreakpointTemplateData {519const data: IBreakpointTemplateData = Object.create(null);520data.elementDisposables = new DisposableStore();521data.templateDisposables = new DisposableStore();522data.templateDisposables.add(data.elementDisposables);523524data.breakpoint = dom.append(container, $('.breakpoint'));525526data.icon = $('.icon');527data.checkbox = createCheckbox(data.templateDisposables);528529data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {530this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);531}));532533dom.append(data.breakpoint, data.icon);534dom.append(data.breakpoint, data.checkbox);535536data.name = dom.append(data.breakpoint, $('span.name'));537538data.filePath = dom.append(data.breakpoint, $('span.file-path'));539data.actionBar = new ActionBar(data.breakpoint);540data.templateDisposables.add(data.actionBar);541const badgeContainer = dom.append(data.breakpoint, $('.badge-container'));542data.badge = dom.append(badgeContainer, $('span.line-number.monaco-count-badge'));543544return data;545}546547renderElement(breakpoint: IBreakpoint, index: number, data: IBreakpointTemplateData): void {548data.context = breakpoint;549data.breakpoint.classList.toggle('disabled', !this.debugService.getModel().areBreakpointsActivated());550551data.name.textContent = resources.basenameOrAuthority(breakpoint.uri);552let badgeContent = breakpoint.lineNumber.toString();553if (breakpoint.column) {554badgeContent += `:${breakpoint.column}`;555}556if (breakpoint.modeLabel) {557badgeContent = `${breakpoint.modeLabel}: ${badgeContent}`;558}559data.badge.textContent = badgeContent;560data.filePath.textContent = this.labelService.getUriLabel(resources.dirname(breakpoint.uri), { relative: true });561data.checkbox.checked = breakpoint.enabled;562563const { message, icon } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), breakpoint, this.labelService, this.debugService.getModel());564data.icon.className = ThemeIcon.asClassName(icon);565data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, breakpoint.message || message || ''));566567const debugActive = this.debugService.state === State.Running || this.debugService.state === State.Stopped;568if (debugActive && !breakpoint.verified) {569data.breakpoint.classList.add('disabled');570}571572const session = this.debugService.getViewModel().focusedSession;573this.breakpointSupportsCondition.set(!session || !!session.capabilities.supportsConditionalBreakpoints);574this.breakpointItemType.set('breakpoint');575this.breakpointHasMultipleModes.set(this.debugService.getModel().getBreakpointModes('source').length > 1);576const { primary } = getActionBarActions(this.menu.getActions({ arg: breakpoint, shouldForwardArgs: true }), 'inline');577data.actionBar.clear();578data.actionBar.push(primary, { icon: true, label: false });579breakpointIdToActionBarDomeNode.set(breakpoint.getId(), data.actionBar.domNode);580}581582583584disposeElement(a: any, index: number, template: IBreakpointTemplateData): void {585template.elementDisposables.clear();586}587588disposeTemplate(templateData: IBreakpointTemplateData): void {589templateData.templateDisposables.dispose();590}591}592593class ExceptionBreakpointsRenderer implements IListRenderer<IExceptionBreakpoint, IExceptionBreakpointTemplateData> {594595constructor(596private menu: IMenu,597private breakpointHasMultipleModes: IContextKey<boolean>,598private breakpointSupportsCondition: IContextKey<boolean>,599private breakpointItemType: IContextKey<string | undefined>,600private debugService: IDebugService,601private readonly hoverService: IHoverService,602) {603// noop604}605606static readonly ID = 'exceptionbreakpoints';607608get templateId() {609return ExceptionBreakpointsRenderer.ID;610}611612renderTemplate(container: HTMLElement): IExceptionBreakpointTemplateData {613const data: IExceptionBreakpointTemplateData = Object.create(null);614data.elementDisposables = new DisposableStore();615data.templateDisposables = new DisposableStore();616data.templateDisposables.add(data.elementDisposables);617data.breakpoint = dom.append(container, $('.breakpoint'));618619data.checkbox = createCheckbox(data.templateDisposables);620data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {621this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);622}));623624dom.append(data.breakpoint, data.checkbox);625626data.name = dom.append(data.breakpoint, $('span.name'));627data.condition = dom.append(data.breakpoint, $('span.condition'));628data.breakpoint.classList.add('exception');629630data.actionBar = new ActionBar(data.breakpoint);631data.templateDisposables.add(data.actionBar);632const badgeContainer = dom.append(data.breakpoint, $('.badge-container'));633data.badge = dom.append(badgeContainer, $('span.line-number.monaco-count-badge'));634635return data;636}637638renderElement(exceptionBreakpoint: IExceptionBreakpoint, index: number, data: IExceptionBreakpointTemplateData): void {639data.context = exceptionBreakpoint;640data.name.textContent = exceptionBreakpoint.label || `${exceptionBreakpoint.filter} exceptions`;641const exceptionBreakpointtitle = exceptionBreakpoint.verified ? (exceptionBreakpoint.description || data.name.textContent) : exceptionBreakpoint.message || localize('unverifiedExceptionBreakpoint', "Unverified Exception Breakpoint");642data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, exceptionBreakpointtitle));643data.breakpoint.classList.toggle('disabled', !exceptionBreakpoint.verified);644data.checkbox.checked = exceptionBreakpoint.enabled;645data.condition.textContent = exceptionBreakpoint.condition || '';646data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.condition, localize('expressionCondition', "Expression condition: {0}", exceptionBreakpoint.condition)));647648if (exceptionBreakpoint.modeLabel) {649data.badge.textContent = exceptionBreakpoint.modeLabel;650data.badge.style.display = 'block';651} else {652data.badge.style.display = 'none';653}654655this.breakpointSupportsCondition.set((exceptionBreakpoint as ExceptionBreakpoint).supportsCondition);656this.breakpointItemType.set('exceptionBreakpoint');657this.breakpointHasMultipleModes.set(this.debugService.getModel().getBreakpointModes('exception').length > 1);658const { primary } = getActionBarActions(this.menu.getActions({ arg: exceptionBreakpoint, shouldForwardArgs: true }), 'inline');659data.actionBar.clear();660data.actionBar.push(primary, { icon: true, label: false });661breakpointIdToActionBarDomeNode.set(exceptionBreakpoint.getId(), data.actionBar.domNode);662}663664disposeElement(element: IExceptionBreakpoint, index: number, templateData: IExceptionBreakpointTemplateData): void {665templateData.elementDisposables.clear();666}667668disposeTemplate(templateData: IExceptionBreakpointTemplateData): void {669templateData.templateDisposables.dispose();670}671}672673class FunctionBreakpointsRenderer implements IListRenderer<FunctionBreakpoint, IFunctionBreakpointTemplateData> {674675constructor(676private menu: IMenu,677private breakpointSupportsCondition: IContextKey<boolean>,678private breakpointItemType: IContextKey<string | undefined>,679@IDebugService private readonly debugService: IDebugService,680@IHoverService private readonly hoverService: IHoverService,681@ILabelService private readonly labelService: ILabelService682) {683// noop684}685686static readonly ID = 'functionbreakpoints';687688get templateId() {689return FunctionBreakpointsRenderer.ID;690}691692renderTemplate(container: HTMLElement): IFunctionBreakpointTemplateData {693const data: IFunctionBreakpointTemplateData = Object.create(null);694data.elementDisposables = new DisposableStore();695data.templateDisposables = new DisposableStore();696data.templateDisposables.add(data.elementDisposables);697data.breakpoint = dom.append(container, $('.breakpoint'));698699data.icon = $('.icon');700data.checkbox = createCheckbox(data.templateDisposables);701data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {702this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);703}));704705dom.append(data.breakpoint, data.icon);706dom.append(data.breakpoint, data.checkbox);707708data.name = dom.append(data.breakpoint, $('span.name'));709data.condition = dom.append(data.breakpoint, $('span.condition'));710711data.actionBar = new ActionBar(data.breakpoint);712data.templateDisposables.add(data.actionBar);713const badgeContainer = dom.append(data.breakpoint, $('.badge-container'));714data.badge = dom.append(badgeContainer, $('span.line-number.monaco-count-badge'));715716return data;717}718719renderElement(functionBreakpoint: FunctionBreakpoint, _index: number, data: IFunctionBreakpointTemplateData): void {720data.context = functionBreakpoint;721data.name.textContent = functionBreakpoint.name;722const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), functionBreakpoint, this.labelService, this.debugService.getModel());723data.icon.className = ThemeIcon.asClassName(icon);724data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ? message : ''));725data.checkbox.checked = functionBreakpoint.enabled;726data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, message ? message : ''));727if (functionBreakpoint.condition && functionBreakpoint.hitCondition) {728data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", functionBreakpoint.condition, functionBreakpoint.hitCondition);729} else {730data.condition.textContent = functionBreakpoint.condition || functionBreakpoint.hitCondition || '';731}732733if (functionBreakpoint.modeLabel) {734data.badge.textContent = functionBreakpoint.modeLabel;735data.badge.style.display = 'block';736} else {737data.badge.style.display = 'none';738}739740// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099741const session = this.debugService.getViewModel().focusedSession;742data.breakpoint.classList.toggle('disabled', (session && !session.capabilities.supportsFunctionBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());743if (session && !session.capabilities.supportsFunctionBreakpoints) {744data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, localize('functionBreakpointsNotSupported', "Function breakpoints are not supported by this debug type")));745}746747this.breakpointSupportsCondition.set(!session || !!session.capabilities.supportsConditionalBreakpoints);748this.breakpointItemType.set('functionBreakpoint');749const { primary } = getActionBarActions(this.menu.getActions({ arg: functionBreakpoint, shouldForwardArgs: true }), 'inline');750data.actionBar.clear();751data.actionBar.push(primary, { icon: true, label: false });752breakpointIdToActionBarDomeNode.set(functionBreakpoint.getId(), data.actionBar.domNode);753}754755disposeElement(element: FunctionBreakpoint, index: number, templateData: IFunctionBreakpointTemplateData): void {756templateData.elementDisposables.clear();757}758759disposeTemplate(templateData: IFunctionBreakpointTemplateData): void {760templateData.templateDisposables.dispose();761}762}763764class DataBreakpointsRenderer implements IListRenderer<DataBreakpoint, IDataBreakpointTemplateData> {765766constructor(767private menu: IMenu,768private breakpointHasMultipleModes: IContextKey<boolean>,769private breakpointSupportsCondition: IContextKey<boolean>,770private breakpointItemType: IContextKey<string | undefined>,771private breakpointIsDataBytes: IContextKey<boolean | undefined>,772@IDebugService private readonly debugService: IDebugService,773@IHoverService private readonly hoverService: IHoverService,774@ILabelService private readonly labelService: ILabelService775) {776// noop777}778779static readonly ID = 'databreakpoints';780781get templateId() {782return DataBreakpointsRenderer.ID;783}784785renderTemplate(container: HTMLElement): IDataBreakpointTemplateData {786const data: IDataBreakpointTemplateData = Object.create(null);787data.breakpoint = dom.append(container, $('.breakpoint'));788data.elementDisposables = new DisposableStore();789data.templateDisposables = new DisposableStore();790data.templateDisposables.add(data.elementDisposables);791792data.icon = $('.icon');793data.checkbox = createCheckbox(data.templateDisposables);794data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {795this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);796}));797798dom.append(data.breakpoint, data.icon);799dom.append(data.breakpoint, data.checkbox);800801data.name = dom.append(data.breakpoint, $('span.name'));802data.accessType = dom.append(data.breakpoint, $('span.access-type'));803data.condition = dom.append(data.breakpoint, $('span.condition'));804805data.actionBar = new ActionBar(data.breakpoint);806data.templateDisposables.add(data.actionBar);807const badgeContainer = dom.append(data.breakpoint, $('.badge-container'));808data.badge = dom.append(badgeContainer, $('span.line-number.monaco-count-badge'));809810return data;811}812813renderElement(dataBreakpoint: DataBreakpoint, _index: number, data: IDataBreakpointTemplateData): void {814data.context = dataBreakpoint;815data.name.textContent = dataBreakpoint.description;816const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), dataBreakpoint, this.labelService, this.debugService.getModel());817data.icon.className = ThemeIcon.asClassName(icon);818data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ? message : ''));819data.checkbox.checked = dataBreakpoint.enabled;820data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, message ? message : ''));821822if (dataBreakpoint.modeLabel) {823data.badge.textContent = dataBreakpoint.modeLabel;824data.badge.style.display = 'block';825} else {826data.badge.style.display = 'none';827}828829// Mark data breakpoints as disabled if deactivated or if debug type does not support them830const session = this.debugService.getViewModel().focusedSession;831data.breakpoint.classList.toggle('disabled', (session && !session.capabilities.supportsDataBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());832if (session && !session.capabilities.supportsDataBreakpoints) {833data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, localize('dataBreakpointsNotSupported', "Data breakpoints are not supported by this debug type")));834}835if (dataBreakpoint.accessType) {836const accessType = dataBreakpoint.accessType === 'read' ? localize('read', "Read") : dataBreakpoint.accessType === 'write' ? localize('write', "Write") : localize('access', "Access");837data.accessType.textContent = accessType;838} else {839data.accessType.textContent = '';840}841if (dataBreakpoint.condition && dataBreakpoint.hitCondition) {842data.condition.textContent = localize('expressionAndHitCount', "Condition: {0} | Hit Count: {1}", dataBreakpoint.condition, dataBreakpoint.hitCondition);843} else {844data.condition.textContent = dataBreakpoint.condition || dataBreakpoint.hitCondition || '';845}846847this.breakpointSupportsCondition.set(!session || !!session.capabilities.supportsConditionalBreakpoints);848this.breakpointHasMultipleModes.set(this.debugService.getModel().getBreakpointModes('data').length > 1);849this.breakpointItemType.set('dataBreakpoint');850this.breakpointIsDataBytes.set(dataBreakpoint.src.type === DataBreakpointSetType.Address);851const { primary } = getActionBarActions(this.menu.getActions({ arg: dataBreakpoint, shouldForwardArgs: true }), 'inline');852data.actionBar.clear();853data.actionBar.push(primary, { icon: true, label: false });854breakpointIdToActionBarDomeNode.set(dataBreakpoint.getId(), data.actionBar.domNode);855this.breakpointIsDataBytes.reset();856}857858disposeElement(element: DataBreakpoint, index: number, templateData: IDataBreakpointTemplateData): void {859templateData.elementDisposables.clear();860}861862disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {863templateData.templateDisposables.dispose();864}865}866867class InstructionBreakpointsRenderer implements IListRenderer<IInstructionBreakpoint, IInstructionBreakpointTemplateData> {868869constructor(870@IDebugService private readonly debugService: IDebugService,871@IHoverService private readonly hoverService: IHoverService,872@ILabelService private readonly labelService: ILabelService873) {874// noop875}876877static readonly ID = 'instructionBreakpoints';878879get templateId() {880return InstructionBreakpointsRenderer.ID;881}882883renderTemplate(container: HTMLElement): IInstructionBreakpointTemplateData {884const data: IInstructionBreakpointTemplateData = Object.create(null);885data.elementDisposables = new DisposableStore();886data.templateDisposables = new DisposableStore();887data.templateDisposables.add(data.elementDisposables);888data.breakpoint = dom.append(container, $('.breakpoint'));889890data.icon = $('.icon');891data.checkbox = createCheckbox(data.templateDisposables);892data.templateDisposables.add(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {893this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);894}));895896dom.append(data.breakpoint, data.icon);897dom.append(data.breakpoint, data.checkbox);898899data.name = dom.append(data.breakpoint, $('span.name'));900901data.address = dom.append(data.breakpoint, $('span.file-path'));902data.actionBar = new ActionBar(data.breakpoint);903data.templateDisposables.add(data.actionBar);904const badgeContainer = dom.append(data.breakpoint, $('.badge-container'));905data.badge = dom.append(badgeContainer, $('span.line-number.monaco-count-badge'));906907return data;908}909910renderElement(breakpoint: IInstructionBreakpoint, index: number, data: IInstructionBreakpointTemplateData): void {911data.context = breakpoint;912data.breakpoint.classList.toggle('disabled', !this.debugService.getModel().areBreakpointsActivated());913914data.name.textContent = '0x' + breakpoint.address.toString(16);915data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.name, localize('debug.decimal.address', "Decimal Address: {0}", breakpoint.address.toString())));916data.checkbox.checked = breakpoint.enabled;917918const { message, icon } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), breakpoint, this.labelService, this.debugService.getModel());919data.icon.className = ThemeIcon.asClassName(icon);920data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.breakpoint, breakpoint.message || message || ''));921922const debugActive = this.debugService.state === State.Running || this.debugService.state === State.Stopped;923if (debugActive && !breakpoint.verified) {924data.breakpoint.classList.add('disabled');925}926927if (breakpoint.modeLabel) {928data.badge.textContent = breakpoint.modeLabel;929data.badge.style.display = 'block';930} else {931data.badge.style.display = 'none';932}933}934935936disposeElement(element: IInstructionBreakpoint, index: number, templateData: IInstructionBreakpointTemplateData): void {937templateData.elementDisposables.clear();938}939940disposeTemplate(templateData: IInstructionBreakpointTemplateData): void {941templateData.templateDisposables.dispose();942}943}944945class FunctionBreakpointInputRenderer implements IListRenderer<IFunctionBreakpoint, IFunctionBreakpointInputTemplateData> {946947constructor(948private view: BreakpointsView,949private debugService: IDebugService,950private contextViewService: IContextViewService,951private readonly hoverService: IHoverService,952private labelService: ILabelService953) { }954955static readonly ID = 'functionbreakpointinput';956957get templateId() {958return FunctionBreakpointInputRenderer.ID;959}960961renderTemplate(container: HTMLElement): IFunctionBreakpointInputTemplateData {962const template: IFunctionBreakpointInputTemplateData = Object.create(null);963const toDispose = new DisposableStore();964965const breakpoint = dom.append(container, $('.breakpoint'));966template.icon = $('.icon');967template.checkbox = createCheckbox(toDispose);968969dom.append(breakpoint, template.icon);970dom.append(breakpoint, template.checkbox);971this.view.breakpointInputFocused.set(true);972const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));973974975const inputBox = new InputBox(inputBoxContainer, this.contextViewService, { inputBoxStyles: defaultInputBoxStyles });976977toDispose.add(inputBox);978979const wrapUp = (success: boolean) => {980template.updating = true;981try {982this.view.breakpointInputFocused.set(false);983const id = template.breakpoint.getId();984985if (success) {986if (template.type === 'name') {987this.debugService.updateFunctionBreakpoint(id, { name: inputBox.value });988}989if (template.type === 'condition') {990this.debugService.updateFunctionBreakpoint(id, { condition: inputBox.value });991}992if (template.type === 'hitCount') {993this.debugService.updateFunctionBreakpoint(id, { hitCondition: inputBox.value });994}995} else {996if (template.type === 'name' && !template.breakpoint.name) {997this.debugService.removeFunctionBreakpoints(id);998} else {999this.view.renderInputBox(undefined);1000}1001}1002} finally {1003template.updating = false;1004}1005};10061007toDispose.add(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {1008const isEscape = e.equals(KeyCode.Escape);1009const isEnter = e.equals(KeyCode.Enter);1010if (isEscape || isEnter) {1011e.preventDefault();1012e.stopPropagation();1013wrapUp(isEnter);1014}1015}));1016toDispose.add(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {1017if (!template.updating) {1018wrapUp(!!inputBox.value);1019}1020}));10211022template.inputBox = inputBox;1023template.elementDisposables = new DisposableStore();1024template.templateDisposables = toDispose;1025template.templateDisposables.add(template.elementDisposables);1026return template;1027}10281029renderElement(functionBreakpoint: FunctionBreakpoint, _index: number, data: IFunctionBreakpointInputTemplateData): void {1030data.breakpoint = functionBreakpoint;1031data.type = this.view.inputBoxData?.type || 'name'; // If there is no type set take the 'name' as the default1032const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), functionBreakpoint, this.labelService, this.debugService.getModel());10331034data.icon.className = ThemeIcon.asClassName(icon);1035data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ? message : ''));1036data.checkbox.checked = functionBreakpoint.enabled;1037data.checkbox.disabled = true;1038data.inputBox.value = functionBreakpoint.name || '';10391040let placeholder = localize('functionBreakpointPlaceholder', "Function to break on");1041let ariaLabel = localize('functionBreakPointInputAriaLabel', "Type function breakpoint.");1042if (data.type === 'condition') {1043data.inputBox.value = functionBreakpoint.condition || '';1044placeholder = localize('functionBreakpointExpressionPlaceholder', "Break when expression evaluates to true");1045ariaLabel = localize('functionBreakPointExpresionAriaLabel', "Type expression. Function breakpoint will break when expression evaluates to true");1046} else if (data.type === 'hitCount') {1047data.inputBox.value = functionBreakpoint.hitCondition || '';1048placeholder = localize('functionBreakpointHitCountPlaceholder', "Break when hit count is met");1049ariaLabel = localize('functionBreakPointHitCountAriaLabel', "Type hit count. Function breakpoint will break when hit count is met.");1050}1051data.inputBox.setAriaLabel(ariaLabel);1052data.inputBox.setPlaceHolder(placeholder);10531054setTimeout(() => {1055data.inputBox.focus();1056data.inputBox.select();1057}, 0);1058}10591060disposeElement(element: IFunctionBreakpoint, index: number, templateData: IFunctionBreakpointInputTemplateData): void {1061templateData.elementDisposables.clear();1062}10631064disposeTemplate(templateData: IFunctionBreakpointInputTemplateData): void {1065templateData.templateDisposables.dispose();1066}1067}10681069class DataBreakpointInputRenderer implements IListRenderer<IDataBreakpoint, IDataBreakpointInputTemplateData> {10701071constructor(1072private view: BreakpointsView,1073private debugService: IDebugService,1074private contextViewService: IContextViewService,1075private readonly hoverService: IHoverService,1076private labelService: ILabelService1077) { }10781079static readonly ID = 'databreakpointinput';10801081get templateId() {1082return DataBreakpointInputRenderer.ID;1083}10841085renderTemplate(container: HTMLElement): IDataBreakpointInputTemplateData {1086const template: IDataBreakpointInputTemplateData = Object.create(null);1087const toDispose = new DisposableStore();10881089const breakpoint = dom.append(container, $('.breakpoint'));1090template.icon = $('.icon');1091template.checkbox = createCheckbox(toDispose);10921093dom.append(breakpoint, template.icon);1094dom.append(breakpoint, template.checkbox);1095this.view.breakpointInputFocused.set(true);1096const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));109710981099const inputBox = new InputBox(inputBoxContainer, this.contextViewService, { inputBoxStyles: defaultInputBoxStyles });1100toDispose.add(inputBox);11011102const wrapUp = (success: boolean) => {1103template.updating = true;1104try {1105this.view.breakpointInputFocused.set(false);1106const id = template.breakpoint.getId();11071108if (success) {1109if (template.type === 'condition') {1110this.debugService.updateDataBreakpoint(id, { condition: inputBox.value });1111}1112if (template.type === 'hitCount') {1113this.debugService.updateDataBreakpoint(id, { hitCondition: inputBox.value });1114}1115} else {1116this.view.renderInputBox(undefined);1117}1118} finally {1119template.updating = false;1120}1121};11221123toDispose.add(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {1124const isEscape = e.equals(KeyCode.Escape);1125const isEnter = e.equals(KeyCode.Enter);1126if (isEscape || isEnter) {1127e.preventDefault();1128e.stopPropagation();1129wrapUp(isEnter);1130}1131}));1132toDispose.add(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {1133if (!template.updating) {1134wrapUp(!!inputBox.value);1135}1136}));11371138template.inputBox = inputBox;1139template.elementDisposables = new DisposableStore();1140template.templateDisposables = toDispose;1141template.templateDisposables.add(template.elementDisposables);1142return template;1143}11441145renderElement(dataBreakpoint: DataBreakpoint, _index: number, data: IDataBreakpointInputTemplateData): void {1146data.breakpoint = dataBreakpoint;1147data.type = this.view.inputBoxData?.type || 'condition'; // If there is no type set take the 'condition' as the default1148const { icon, message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), dataBreakpoint, this.labelService, this.debugService.getModel());11491150data.icon.className = ThemeIcon.asClassName(icon);1151data.elementDisposables.add(this.hoverService.setupManagedHover(getDefaultHoverDelegate('mouse'), data.icon, message ?? ''));1152data.checkbox.checked = dataBreakpoint.enabled;1153data.checkbox.disabled = true;1154data.inputBox.value = '';1155let placeholder = '';1156let ariaLabel = '';1157if (data.type === 'condition') {1158data.inputBox.value = dataBreakpoint.condition || '';1159placeholder = localize('dataBreakpointExpressionPlaceholder', "Break when expression evaluates to true");1160ariaLabel = localize('dataBreakPointExpresionAriaLabel', "Type expression. Data breakpoint will break when expression evaluates to true");1161} else if (data.type === 'hitCount') {1162data.inputBox.value = dataBreakpoint.hitCondition || '';1163placeholder = localize('dataBreakpointHitCountPlaceholder', "Break when hit count is met");1164ariaLabel = localize('dataBreakPointHitCountAriaLabel', "Type hit count. Data breakpoint will break when hit count is met.");1165}1166data.inputBox.setAriaLabel(ariaLabel);1167data.inputBox.setPlaceHolder(placeholder);11681169setTimeout(() => {1170data.inputBox.focus();1171data.inputBox.select();1172}, 0);1173}11741175disposeElement(element: IDataBreakpoint, index: number, templateData: IDataBreakpointInputTemplateData): void {1176templateData.elementDisposables.clear();1177}11781179disposeTemplate(templateData: IDataBreakpointInputTemplateData): void {1180templateData.templateDisposables.dispose();1181}1182}11831184class ExceptionBreakpointInputRenderer implements IListRenderer<IExceptionBreakpoint, IExceptionBreakpointInputTemplateData> {11851186constructor(1187private view: BreakpointsView,1188private debugService: IDebugService,1189private contextViewService: IContextViewService,1190) {1191// noop1192}11931194static readonly ID = 'exceptionbreakpointinput';11951196get templateId() {1197return ExceptionBreakpointInputRenderer.ID;1198}11991200renderTemplate(container: HTMLElement): IExceptionBreakpointInputTemplateData {1201const toDispose = new DisposableStore();12021203const breakpoint = dom.append(container, $('.breakpoint'));1204breakpoint.classList.add('exception');1205const checkbox = createCheckbox(toDispose);12061207dom.append(breakpoint, checkbox);1208this.view.breakpointInputFocused.set(true);1209const inputBoxContainer = dom.append(breakpoint, $('.inputBoxContainer'));1210const inputBox = new InputBox(inputBoxContainer, this.contextViewService, {1211ariaLabel: localize('exceptionBreakpointAriaLabel', "Type exception breakpoint condition"),1212inputBoxStyles: defaultInputBoxStyles1213});121412151216toDispose.add(inputBox);1217const wrapUp = (success: boolean) => {1218if (!templateData.currentBreakpoint) {1219return;1220}12211222this.view.breakpointInputFocused.set(false);1223let newCondition = templateData.currentBreakpoint.condition;1224if (success) {1225newCondition = inputBox.value !== '' ? inputBox.value : undefined;1226}1227this.debugService.setExceptionBreakpointCondition(templateData.currentBreakpoint, newCondition);1228};12291230toDispose.add(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {1231const isEscape = e.equals(KeyCode.Escape);1232const isEnter = e.equals(KeyCode.Enter);1233if (isEscape || isEnter) {1234e.preventDefault();1235e.stopPropagation();1236wrapUp(isEnter);1237}1238}));1239toDispose.add(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {1240// Need to react with a timeout on the blur event due to possible concurent splices #564431241setTimeout(() => {1242wrapUp(true);1243});1244}));12451246const elementDisposables = new DisposableStore();1247toDispose.add(elementDisposables);12481249const templateData: IExceptionBreakpointInputTemplateData = {1250inputBox,1251checkbox,1252templateDisposables: toDispose,1253elementDisposables: new DisposableStore(),1254};12551256return templateData;1257}12581259renderElement(exceptionBreakpoint: ExceptionBreakpoint, _index: number, data: IExceptionBreakpointInputTemplateData): void {1260const placeHolder = exceptionBreakpoint.conditionDescription || localize('exceptionBreakpointPlaceholder', "Break when expression evaluates to true");1261data.inputBox.setPlaceHolder(placeHolder);1262data.currentBreakpoint = exceptionBreakpoint;1263data.checkbox.checked = exceptionBreakpoint.enabled;1264data.checkbox.disabled = true;1265data.inputBox.value = exceptionBreakpoint.condition || '';1266setTimeout(() => {1267data.inputBox.focus();1268data.inputBox.select();1269}, 0);1270}12711272disposeElement(element: IExceptionBreakpoint, index: number, templateData: IExceptionBreakpointInputTemplateData): void {1273templateData.elementDisposables.clear();1274}12751276disposeTemplate(templateData: IExceptionBreakpointInputTemplateData): void {1277templateData.templateDisposables.dispose();1278}1279}12801281class BreakpointsAccessibilityProvider implements IListAccessibilityProvider<BreakpointItem> {12821283constructor(1284private readonly debugService: IDebugService,1285private readonly labelService: ILabelService1286) { }12871288getWidgetAriaLabel(): string {1289return localize('breakpoints', "Breakpoints");1290}12911292getRole(): AriaRole {1293return 'checkbox';1294}12951296isChecked(breakpoint: IEnablement) {1297return breakpoint.enabled;1298}12991300getAriaLabel(element: BreakpointItem): string | null {1301if (element instanceof ExceptionBreakpoint) {1302return element.toString();1303}13041305const { message } = getBreakpointMessageAndIcon(this.debugService.state, this.debugService.getModel().areBreakpointsActivated(), element as IBreakpoint | IDataBreakpoint | IFunctionBreakpoint, this.labelService, this.debugService.getModel());1306const toString = element.toString();13071308return message ? `${toString}, ${message}` : toString;1309}1310}13111312export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolean, preserveFocus: boolean, pinned: boolean, debugService: IDebugService, editorService: IEditorService): Promise<IEditorPane | undefined> {1313if (breakpoint.uri.scheme === DEBUG_SCHEME && debugService.state === State.Inactive) {1314return Promise.resolve(undefined);1315}13161317const selection = breakpoint.endLineNumber ? {1318startLineNumber: breakpoint.lineNumber,1319endLineNumber: breakpoint.endLineNumber,1320startColumn: breakpoint.column || 1,1321endColumn: breakpoint.endColumn || Constants.MAX_SAFE_SMALL_INTEGER1322} : {1323startLineNumber: breakpoint.lineNumber,1324startColumn: breakpoint.column || 1,1325endLineNumber: breakpoint.lineNumber,1326endColumn: breakpoint.column || Constants.MAX_SAFE_SMALL_INTEGER1327};13281329return editorService.openEditor({1330resource: breakpoint.uri,1331options: {1332preserveFocus,1333selection,1334revealIfOpened: true,1335selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,1336pinned1337}1338}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);1339}13401341export function getBreakpointMessageAndIcon(state: State, breakpointsActivated: boolean, breakpoint: BreakpointItem, labelService: ILabelService, debugModel: IDebugModel): { message?: string; icon: ThemeIcon; showAdapterUnverifiedMessage?: boolean } {1342const debugActive = state === State.Running || state === State.Stopped;13431344const breakpointIcon = breakpoint instanceof DataBreakpoint ? icons.dataBreakpoint : breakpoint instanceof FunctionBreakpoint ? icons.functionBreakpoint : breakpoint.logMessage ? icons.logBreakpoint : icons.breakpoint;13451346if (!breakpoint.enabled || !breakpointsActivated) {1347return {1348icon: breakpointIcon.disabled,1349message: breakpoint.logMessage ? localize('disabledLogpoint', "Disabled Logpoint") : localize('disabledBreakpoint', "Disabled Breakpoint"),1350};1351}13521353const appendMessage = (text: string): string => {1354return ('message' in breakpoint && breakpoint.message) ? text.concat(', ' + breakpoint.message) : text;1355};13561357if (debugActive && breakpoint instanceof Breakpoint && breakpoint.pending) {1358return {1359icon: icons.breakpoint.pending1360};1361}13621363if (debugActive && !breakpoint.verified) {1364return {1365icon: breakpointIcon.unverified,1366message: ('message' in breakpoint && breakpoint.message) ? breakpoint.message : (breakpoint.logMessage ? localize('unverifiedLogpoint', "Unverified Logpoint") : localize('unverifiedBreakpoint', "Unverified Breakpoint")),1367showAdapterUnverifiedMessage: true1368};1369}13701371if (breakpoint instanceof DataBreakpoint) {1372if (!breakpoint.supported) {1373return {1374icon: breakpointIcon.unverified,1375message: localize('dataBreakpointUnsupported', "Data breakpoints not supported by this debug type"),1376};1377}13781379return {1380icon: breakpointIcon.regular,1381message: breakpoint.message || localize('dataBreakpoint', "Data Breakpoint")1382};1383}13841385if (breakpoint instanceof FunctionBreakpoint) {1386if (!breakpoint.supported) {1387return {1388icon: breakpointIcon.unverified,1389message: localize('functionBreakpointUnsupported', "Function breakpoints not supported by this debug type"),1390};1391}1392const messages: string[] = [];1393messages.push(breakpoint.message || localize('functionBreakpoint', "Function Breakpoint"));1394if (breakpoint.condition) {1395messages.push(localize('expression', "Condition: {0}", breakpoint.condition));1396}1397if (breakpoint.hitCondition) {1398messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));1399}14001401return {1402icon: breakpointIcon.regular,1403message: appendMessage(messages.join('\n'))1404};1405}14061407if (breakpoint instanceof InstructionBreakpoint) {1408if (!breakpoint.supported) {1409return {1410icon: breakpointIcon.unverified,1411message: localize('instructionBreakpointUnsupported', "Instruction breakpoints not supported by this debug type"),1412};1413}1414const messages: string[] = [];1415if (breakpoint.message) {1416messages.push(breakpoint.message);1417} else if (breakpoint.instructionReference) {1418messages.push(localize('instructionBreakpointAtAddress', "Instruction breakpoint at address {0}", breakpoint.instructionReference));1419} else {1420messages.push(localize('instructionBreakpoint', "Instruction breakpoint"));1421}14221423if (breakpoint.hitCondition) {1424messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));1425}14261427return {1428icon: breakpointIcon.regular,1429message: appendMessage(messages.join('\n'))1430};1431}14321433// can change this when all breakpoint supports dependent breakpoint condition1434let triggeringBreakpoint: IBreakpoint | undefined;1435if (breakpoint instanceof Breakpoint && breakpoint.triggeredBy) {1436triggeringBreakpoint = debugModel.getBreakpoints().find(bp => bp.getId() === breakpoint.triggeredBy);1437}14381439if (breakpoint.logMessage || breakpoint.condition || breakpoint.hitCondition || triggeringBreakpoint) {1440const messages: string[] = [];1441let icon = breakpoint.logMessage ? icons.logBreakpoint.regular : icons.conditionalBreakpoint.regular;1442if (!breakpoint.supported) {1443icon = icons.debugBreakpointUnsupported;1444messages.push(localize('breakpointUnsupported', "Breakpoints of this type are not supported by the debugger"));1445}14461447if (breakpoint.logMessage) {1448messages.push(localize('logMessage', "Log Message: {0}", breakpoint.logMessage));1449}1450if (breakpoint.condition) {1451messages.push(localize('expression', "Condition: {0}", breakpoint.condition));1452}1453if (breakpoint.hitCondition) {1454messages.push(localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));1455}1456if (triggeringBreakpoint) {1457messages.push(localize('triggeredBy', "Hit after breakpoint: {0}", `${labelService.getUriLabel(triggeringBreakpoint.uri, { relative: true })}: ${triggeringBreakpoint.lineNumber}`));1458}14591460return {1461icon,1462message: appendMessage(messages.join('\n'))1463};1464}14651466const message = ('message' in breakpoint && breakpoint.message) ? breakpoint.message : breakpoint instanceof Breakpoint && labelService ? labelService.getUriLabel(breakpoint.uri) : localize('breakpoint', "Breakpoint");1467return {1468icon: breakpointIcon.regular,1469message1470};1471}14721473registerAction2(class extends Action2 {1474constructor() {1475super({1476id: 'workbench.debug.viewlet.action.addFunctionBreakpointAction',1477title: {1478...localize2('addFunctionBreakpoint', "Add Function Breakpoint"),1479mnemonicTitle: localize({ key: 'miFunctionBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Function Breakpoint..."),1480},1481f1: true,1482icon: icons.watchExpressionsAddFuncBreakpoint,1483menu: [{1484id: MenuId.ViewTitle,1485group: 'navigation',1486order: 10,1487when: ContextKeyExpr.equals('view', BREAKPOINTS_VIEW_ID)1488}, {1489id: MenuId.MenubarNewBreakpointMenu,1490group: '1_breakpoints',1491order: 3,1492when: CONTEXT_DEBUGGERS_AVAILABLE1493}]1494});1495}14961497async run(accessor: ServicesAccessor): Promise<void> {1498const debugService = accessor.get(IDebugService);1499const viewService = accessor.get(IViewsService);1500await viewService.openView(BREAKPOINTS_VIEW_ID);1501debugService.addFunctionBreakpoint();1502}1503});15041505abstract class MemoryBreakpointAction extends Action2 {1506async run(accessor: ServicesAccessor, existingBreakpoint?: IDataBreakpoint): Promise<void> {1507const debugService = accessor.get(IDebugService);1508const session = debugService.getViewModel().focusedSession;1509if (!session) {1510return;1511}15121513let defaultValue = undefined;1514if (existingBreakpoint && existingBreakpoint.src.type === DataBreakpointSetType.Address) {1515defaultValue = `${existingBreakpoint.src.address} + ${existingBreakpoint.src.bytes}`;1516}15171518const quickInput = accessor.get(IQuickInputService);1519const notifications = accessor.get(INotificationService);1520const range = await this.getRange(quickInput, defaultValue);1521if (!range) {1522return;1523}15241525let info: IDataBreakpointInfoResponse | undefined;1526try {1527info = await session.dataBytesBreakpointInfo(range.address, range.bytes);1528} catch (e) {1529notifications.error(localize('dataBreakpointError', "Failed to set data breakpoint at {0}: {1}", range.address, e.message));1530}15311532if (!info?.dataId) {1533return;1534}15351536let accessType: DebugProtocol.DataBreakpointAccessType = 'write';1537if (info.accessTypes && info.accessTypes?.length > 1) {1538const accessTypes = info.accessTypes.map(type => ({ label: type }));1539const selectedAccessType = await quickInput.pick(accessTypes, { placeHolder: localize('dataBreakpointAccessType', "Select the access type to monitor") });1540if (!selectedAccessType) {1541return;1542}15431544accessType = selectedAccessType.label;1545}15461547const src: DataBreakpointSource = { type: DataBreakpointSetType.Address, ...range };1548if (existingBreakpoint) {1549await debugService.removeDataBreakpoints(existingBreakpoint.getId());1550}15511552await debugService.addDataBreakpoint({1553description: info.description,1554src,1555canPersist: true,1556accessTypes: info.accessTypes,1557accessType: accessType,1558initialSessionData: { session, dataId: info.dataId }1559});1560}15611562private getRange(quickInput: IQuickInputService, defaultValue?: string) {1563return new Promise<{ address: string; bytes: number } | undefined>(resolve => {1564const disposables = new DisposableStore();1565const input = disposables.add(quickInput.createInputBox());1566input.prompt = localize('dataBreakpointMemoryRangePrompt', "Enter a memory range in which to break");1567input.placeholder = localize('dataBreakpointMemoryRangePlaceholder', 'Absolute range (0x1234 - 0x1300) or range of bytes after an address (0x1234 + 0xff)');1568if (defaultValue) {1569input.value = defaultValue;1570input.valueSelection = [0, defaultValue.length];1571}1572disposables.add(input.onDidChangeValue(e => {1573const err = this.parseAddress(e, false);1574input.validationMessage = err?.error;1575}));1576disposables.add(input.onDidAccept(() => {1577const r = this.parseAddress(input.value, true);1578if ('error' in r) {1579input.validationMessage = r.error;1580} else {1581resolve(r);1582}1583input.dispose();1584}));1585disposables.add(input.onDidHide(() => {1586resolve(undefined);1587disposables.dispose();1588}));1589input.ignoreFocusOut = true;1590input.show();1591});1592}15931594private parseAddress(range: string, isFinal: false): { error: string } | undefined;1595private parseAddress(range: string, isFinal: true): { error: string } | { address: string; bytes: number };1596private parseAddress(range: string, isFinal: boolean): { error: string } | { address: string; bytes: number } | undefined {1597const parts = /^(\S+)\s*(?:([+-])\s*(\S+))?/.exec(range);1598if (!parts) {1599return { error: localize('dataBreakpointAddrFormat', 'Address should be a range of numbers the form "[Start] - [End]" or "[Start] + [Bytes]"') };1600}16011602const isNum = (e: string) => isFinal ? /^0x[0-9a-f]*|[0-9]*$/i.test(e) : /^0x[0-9a-f]+|[0-9]+$/i.test(e);1603const [, startStr, sign = '+', endStr = '1'] = parts;16041605for (const n of [startStr, endStr]) {1606if (!isNum(n)) {1607return { error: localize('dataBreakpointAddrStartEnd', 'Number must be a decimal integer or hex value starting with \"0x\", got {0}', n) };1608}1609}16101611if (!isFinal) {1612return;1613}16141615const start = BigInt(startStr);1616const end = BigInt(endStr);1617const address = `0x${start.toString(16)}`;1618if (sign === '-') {1619return { address, bytes: Number(start - end) };1620}16211622return { address, bytes: Number(end) };1623}1624}16251626registerAction2(class extends MemoryBreakpointAction {1627constructor() {1628super({1629id: 'workbench.debug.viewlet.action.addDataBreakpointOnAddress',1630title: {1631...localize2('addDataBreakpointOnAddress', "Add Data Breakpoint at Address"),1632mnemonicTitle: localize({ key: 'miDataBreakpoint', comment: ['&& denotes a mnemonic'] }, "&&Data Breakpoint..."),1633},1634f1: true,1635icon: icons.watchExpressionsAddDataBreakpoint,1636menu: [{1637id: MenuId.ViewTitle,1638group: 'navigation',1639order: 11,1640when: ContextKeyExpr.and(CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, ContextKeyExpr.equals('view', BREAKPOINTS_VIEW_ID))1641}, {1642id: MenuId.MenubarNewBreakpointMenu,1643group: '1_breakpoints',1644order: 4,1645when: CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED1646}]1647});1648}1649});16501651registerAction2(class extends MemoryBreakpointAction {1652constructor() {1653super({1654id: 'workbench.debug.viewlet.action.editDataBreakpointOnAddress',1655title: localize2('editDataBreakpointOnAddress', "Edit Address..."),1656menu: [{1657id: MenuId.DebugBreakpointsContext,1658when: ContextKeyExpr.and(CONTEXT_SET_DATA_BREAKPOINT_BYTES_SUPPORTED, CONTEXT_BREAKPOINT_ITEM_IS_DATA_BYTES),1659group: 'navigation',1660order: 15,1661}]1662});1663}1664});16651666registerAction2(class extends Action2 {1667constructor() {1668super({1669id: 'workbench.debug.viewlet.action.toggleBreakpointsActivatedAction',1670title: localize2('activateBreakpoints', 'Toggle Activate Breakpoints'),1671f1: true,1672icon: icons.breakpointsActivate,1673menu: {1674id: MenuId.ViewTitle,1675group: 'navigation',1676order: 20,1677when: ContextKeyExpr.equals('view', BREAKPOINTS_VIEW_ID)1678}1679});1680}16811682run(accessor: ServicesAccessor): void {1683const debugService = accessor.get(IDebugService);1684debugService.setBreakpointsActivated(!debugService.getModel().areBreakpointsActivated());1685}1686});16871688registerAction2(class extends Action2 {1689constructor() {1690super({1691id: 'workbench.debug.viewlet.action.removeBreakpoint',1692title: localize('removeBreakpoint', "Remove Breakpoint"),1693icon: Codicon.removeClose,1694menu: [{1695id: MenuId.DebugBreakpointsContext,1696group: '3_modification',1697order: 10,1698when: CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint')1699}, {1700id: MenuId.DebugBreakpointsContext,1701group: 'inline',1702order: 20,1703when: CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint')1704}]1705});1706}17071708async run(accessor: ServicesAccessor, breakpoint: IBaseBreakpoint): Promise<void> {1709const debugService = accessor.get(IDebugService);1710if (breakpoint instanceof Breakpoint) {1711await debugService.removeBreakpoints(breakpoint.getId());1712} else if (breakpoint instanceof FunctionBreakpoint) {1713await debugService.removeFunctionBreakpoints(breakpoint.getId());1714} else if (breakpoint instanceof DataBreakpoint) {1715await debugService.removeDataBreakpoints(breakpoint.getId());1716} else if (breakpoint instanceof InstructionBreakpoint) {1717await debugService.removeInstructionBreakpoints(breakpoint.instructionReference, breakpoint.offset);1718}1719}1720});17211722registerAction2(class extends Action2 {1723constructor() {1724super({1725id: 'workbench.debug.viewlet.action.removeAllBreakpoints',1726title: {1727...localize2('removeAllBreakpoints', "Remove All Breakpoints"),1728mnemonicTitle: localize({ key: 'miRemoveAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "Remove &&All Breakpoints"),1729},1730f1: true,1731icon: icons.breakpointsRemoveAll,1732menu: [{1733id: MenuId.ViewTitle,1734group: 'navigation',1735order: 30,1736when: ContextKeyExpr.equals('view', BREAKPOINTS_VIEW_ID)1737}, {1738id: MenuId.DebugBreakpointsContext,1739group: '3_modification',1740order: 20,1741when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint'))1742}, {1743id: MenuId.MenubarDebugMenu,1744group: '5_breakpoints',1745order: 3,1746when: CONTEXT_DEBUGGERS_AVAILABLE1747}]1748});1749}17501751run(accessor: ServicesAccessor): void {1752const debugService = accessor.get(IDebugService);1753debugService.removeBreakpoints();1754debugService.removeFunctionBreakpoints();1755debugService.removeDataBreakpoints();1756debugService.removeInstructionBreakpoints();1757}1758});17591760registerAction2(class extends Action2 {1761constructor() {1762super({1763id: 'workbench.debug.viewlet.action.enableAllBreakpoints',1764title: {1765...localize2('enableAllBreakpoints', "Enable All Breakpoints"),1766mnemonicTitle: localize({ key: 'miEnableAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "&&Enable All Breakpoints"),1767},1768f1: true,1769precondition: CONTEXT_DEBUGGERS_AVAILABLE,1770menu: [{1771id: MenuId.DebugBreakpointsContext,1772group: 'z_commands',1773order: 10,1774when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint'))1775}, {1776id: MenuId.MenubarDebugMenu,1777group: '5_breakpoints',1778order: 1,1779when: CONTEXT_DEBUGGERS_AVAILABLE1780}]1781});1782}17831784async run(accessor: ServicesAccessor): Promise<void> {1785const debugService = accessor.get(IDebugService);1786await debugService.enableOrDisableBreakpoints(true);1787}1788});17891790registerAction2(class extends Action2 {1791constructor() {1792super({1793id: 'workbench.debug.viewlet.action.disableAllBreakpoints',1794title: {1795...localize2('disableAllBreakpoints', "Disable All Breakpoints"),1796mnemonicTitle: localize({ key: 'miDisableAllBreakpoints', comment: ['&& denotes a mnemonic'] }, "Disable A&&ll Breakpoints"),1797},1798f1: true,1799precondition: CONTEXT_DEBUGGERS_AVAILABLE,1800menu: [{1801id: MenuId.DebugBreakpointsContext,1802group: 'z_commands',1803order: 20,1804when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint'))1805}, {1806id: MenuId.MenubarDebugMenu,1807group: '5_breakpoints',1808order: 2,1809when: CONTEXT_DEBUGGERS_AVAILABLE1810}]1811});1812}18131814async run(accessor: ServicesAccessor): Promise<void> {1815const debugService = accessor.get(IDebugService);1816await debugService.enableOrDisableBreakpoints(false);1817}1818});18191820registerAction2(class extends Action2 {1821constructor() {1822super({1823id: 'workbench.debug.viewlet.action.reapplyBreakpointsAction',1824title: localize2('reapplyAllBreakpoints', 'Reapply All Breakpoints'),1825f1: true,1826precondition: CONTEXT_IN_DEBUG_MODE,1827menu: [{1828id: MenuId.DebugBreakpointsContext,1829group: 'z_commands',1830order: 30,1831when: ContextKeyExpr.and(CONTEXT_BREAKPOINTS_EXIST, CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('exceptionBreakpoint'))1832}]1833});1834}18351836async run(accessor: ServicesAccessor): Promise<void> {1837const debugService = accessor.get(IDebugService);1838await debugService.setBreakpointsActivated(true);1839}1840});18411842registerAction2(class extends ViewAction<BreakpointsView> {1843constructor() {1844super({1845id: 'debug.editBreakpoint',1846viewId: BREAKPOINTS_VIEW_ID,1847title: localize('editCondition', "Edit Condition..."),1848icon: Codicon.edit,1849precondition: CONTEXT_BREAKPOINT_SUPPORTS_CONDITION,1850menu: [{1851id: MenuId.DebugBreakpointsContext,1852when: CONTEXT_BREAKPOINT_ITEM_TYPE.notEqualsTo('functionBreakpoint'),1853group: 'navigation',1854order: 101855}, {1856id: MenuId.DebugBreakpointsContext,1857group: 'inline',1858order: 101859}]1860});1861}18621863async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: ExceptionBreakpoint | Breakpoint | FunctionBreakpoint | DataBreakpoint): Promise<void> {1864const debugService = accessor.get(IDebugService);1865const editorService = accessor.get(IEditorService);1866if (breakpoint instanceof Breakpoint) {1867const editor = await openBreakpointSource(breakpoint, false, false, true, debugService, editorService);1868if (editor) {1869const codeEditor = editor.getControl();1870if (isCodeEditor(codeEditor)) {1871codeEditor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID)?.showBreakpointWidget(breakpoint.lineNumber, breakpoint.column);1872}1873}1874} else if (breakpoint instanceof FunctionBreakpoint) {1875const contextMenuService = accessor.get(IContextMenuService);1876const actions: Action[] = [new Action('breakpoint.editCondition', localize('editCondition', "Edit Condition..."), undefined, true, async () => view.renderInputBox({ breakpoint, type: 'condition' })),1877new Action('breakpoint.editCondition', localize('editHitCount', "Edit Hit Count..."), undefined, true, async () => view.renderInputBox({ breakpoint, type: 'hitCount' }))];1878const domNode = breakpointIdToActionBarDomeNode.get(breakpoint.getId());18791880if (domNode) {1881contextMenuService.showContextMenu({1882getActions: () => actions,1883getAnchor: () => domNode,1884onHide: () => dispose(actions)1885});1886}1887} else {1888view.renderInputBox({ breakpoint, type: 'condition' });1889}1890}1891});189218931894registerAction2(class extends ViewAction<BreakpointsView> {1895constructor() {1896super({1897id: 'debug.editFunctionBreakpoint',1898viewId: BREAKPOINTS_VIEW_ID,1899title: localize('editBreakpoint', "Edit Function Condition..."),1900menu: [{1901id: MenuId.DebugBreakpointsContext,1902group: 'navigation',1903order: 10,1904when: CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint')1905}]1906});1907}19081909runInView(_accessor: ServicesAccessor, view: BreakpointsView, breakpoint: IFunctionBreakpoint) {1910view.renderInputBox({ breakpoint, type: 'name' });1911}1912});19131914registerAction2(class extends ViewAction<BreakpointsView> {1915constructor() {1916super({1917id: 'debug.editFunctionBreakpointHitCount',1918viewId: BREAKPOINTS_VIEW_ID,1919title: localize('editHitCount', "Edit Hit Count..."),1920precondition: CONTEXT_BREAKPOINT_SUPPORTS_CONDITION,1921menu: [{1922id: MenuId.DebugBreakpointsContext,1923group: 'navigation',1924order: 20,1925when: ContextKeyExpr.or(CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('functionBreakpoint'), CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('dataBreakpoint'))1926}]1927});1928}19291930runInView(_accessor: ServicesAccessor, view: BreakpointsView, breakpoint: IFunctionBreakpoint) {1931view.renderInputBox({ breakpoint, type: 'hitCount' });1932}1933});19341935registerAction2(class extends ViewAction<BreakpointsView> {1936constructor() {1937super({1938id: 'debug.editBreakpointMode',1939viewId: BREAKPOINTS_VIEW_ID,1940title: localize('editMode', "Edit Mode..."),1941menu: [{1942id: MenuId.DebugBreakpointsContext,1943group: 'navigation',1944order: 20,1945when: ContextKeyExpr.and(1946CONTEXT_BREAKPOINT_HAS_MODES,1947ContextKeyExpr.or(CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('breakpoint'), CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('exceptionBreakpoint'), CONTEXT_BREAKPOINT_ITEM_TYPE.isEqualTo('instructionBreakpoint'))1948)1949}]1950});1951}19521953async runInView(accessor: ServicesAccessor, view: BreakpointsView, breakpoint: IBreakpoint) {1954const debugService = accessor.get(IDebugService);1955const kind = getModeKindForBreakpoint(breakpoint);1956const modes = debugService.getModel().getBreakpointModes(kind);1957const picked = await accessor.get(IQuickInputService).pick(1958modes.map(mode => ({ label: mode.label, description: mode.description, mode: mode.mode })),1959{ placeHolder: localize('selectBreakpointMode', "Select Breakpoint Mode") }1960);19611962if (!picked) {1963return;1964}19651966if (kind === 'source') {1967const data = new Map<string, IBreakpointUpdateData>();1968data.set(breakpoint.getId(), { mode: picked.mode, modeLabel: picked.label });1969debugService.updateBreakpoints(breakpoint.originalUri, data, false);1970} else if (breakpoint instanceof InstructionBreakpoint) {1971debugService.removeInstructionBreakpoints(breakpoint.instructionReference, breakpoint.offset);1972debugService.addInstructionBreakpoint({ ...breakpoint.toJSON(), mode: picked.mode, modeLabel: picked.label });1973} else if (breakpoint instanceof ExceptionBreakpoint) {1974breakpoint.mode = picked.mode;1975breakpoint.modeLabel = picked.label;1976debugService.setExceptionBreakpointCondition(breakpoint, breakpoint.condition); // no-op to trigger a re-send1977}1978}1979});198019811982