breakpointsView.ts 24.2 KB
Newer Older
I
isidor 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  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 * as resources from 'vs/base/common/resources';
import * as dom from 'vs/base/browser/dom';
I
isidor 已提交
9 10
import { IAction, Action } from 'vs/base/common/actions';
import { IDebugService, IBreakpoint, CONTEXT_BREAKPOINTS_FOCUSED, EDITOR_CONTRIBUTION_ID, State, DEBUG_SCHEME, IFunctionBreakpoint, IExceptionBreakpoint, IEnablement, IDebugEditorContribution } from 'vs/workbench/parts/debug/common/debug';
I
isidor 已提交
11
import { ExceptionBreakpoint, FunctionBreakpoint, Breakpoint } from 'vs/workbench/parts/debug/common/debugModel';
12
import { AddFunctionBreakpointAction, ToggleBreakpointsActivatedAction, RemoveAllBreakpointsAction, RemoveBreakpointAction, EnableAllBreakpointsAction, DisableAllBreakpointsAction, ReapplyBreakpointsAction } from 'vs/workbench/parts/debug/browser/debugActions';
13
import { IContextMenuService, IContextViewService } from 'vs/platform/contextview/browser/contextView';
I
isidor 已提交
14 15 16
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IThemeService } from 'vs/platform/theme/common/themeService';
17 18 19 20
import { Constants } from 'vs/editor/common/core/uint';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { TPromise } from 'vs/base/common/winjs.base';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
J
Joao Moreno 已提交
21
import { IVirtualDelegate, IListContextMenuEvent, IRenderer } from 'vs/base/browser/ui/list/list';
22
import { IEditor } from 'vs/workbench/common/editor';
23
import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox';
24
import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent';
25
import { KeyCode } from 'vs/base/common/keyCodes';
26
import { WorkbenchList } from 'vs/platform/list/browser/listService';
27
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
28
import { attachInputBoxStyler } from 'vs/platform/theme/common/styler';
I
isidor 已提交
29
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
30
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
31
import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
I
isidor 已提交
32
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
I
isidor 已提交
33
import { ILabelService } from 'vs/platform/label/common/label';
I
isidor 已提交
34

35
const $ = dom.$;
I
isidor 已提交
36

37 38 39 40 41 42 43 44
function createCheckbox(): HTMLInputElement {
	const checkbox = <HTMLInputElement>$('input');
	checkbox.type = 'checkbox';
	checkbox.tabIndex = -1;

	return checkbox;
}

45
export class BreakpointsView extends ViewletPanel {
I
isidor 已提交
46 47 48 49

	private static readonly MAX_VISIBLE_FILES = 9;
	private static readonly MEMENTO = 'breakopintsview.memento';
	private settings: any;
J
Joao Moreno 已提交
50
	private list: WorkbenchList<IEnablement>;
I
isidor 已提交
51
	private needsRefresh: boolean;
I
isidor 已提交
52 53 54 55 56 57 58

	constructor(
		options: IViewletViewOptions,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IDebugService private debugService: IDebugService,
		@IKeybindingService keybindingService: IKeybindingService,
		@IInstantiationService private instantiationService: IInstantiationService,
I
isidor 已提交
59
		@IThemeService private themeService: IThemeService,
60
		@IEditorService private editorService: IEditorService,
J
Joao Moreno 已提交
61
		@IContextViewService private contextViewService: IContextViewService,
62
		@IConfigurationService configurationService: IConfigurationService
I
isidor 已提交
63
	) {
I
isidor 已提交
64
		super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService);
I
isidor 已提交
65 66 67 68 69 70 71 72

		this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize();
		this.settings = options.viewletSettings;
		this.disposables.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange()));
	}

	public renderBody(container: HTMLElement): void {
		dom.addClass(container, 'debug-breakpoints');
73
		const delegate = new BreakpointsDelegate(this.debugService);
I
isidor 已提交
74

75
		this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [
I
isidor 已提交
76 77
			this.instantiationService.createInstance(BreakpointsRenderer),
			new ExceptionBreakpointsRenderer(this.debugService),
I
isidor 已提交
78
			this.instantiationService.createInstance(FunctionBreakpointsRenderer),
79
			new FunctionBreakpointInputRenderer(this.debugService, this.contextViewService, this.themeService)
I
isidor 已提交
80
		], {
I
isidor 已提交
81 82
				identityProvider: element => element.getId(),
				multipleSelectionSupport: false
83
			}) as WorkbenchList<IEnablement>;
J
Joao Moreno 已提交
84 85

		CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService);
I
isidor 已提交
86

I
isidor 已提交
87
		this.list.onContextMenu(this.onListContextMenu, this, this.disposables);
J
Joao Moreno 已提交
88

89 90 91
		this.disposables.push(this.list.onOpen(e => {
			let isSingleClick = false;
			let isDoubleClick = false;
92
			let isMiddleClick = false;
93 94 95 96 97 98
			let openToSide = false;

			const browserEvent = e.browserEvent;
			if (browserEvent instanceof MouseEvent) {
				isSingleClick = browserEvent.detail === 1;
				isDoubleClick = browserEvent.detail === 2;
99
				isMiddleClick = browserEvent.button === 1;
100 101 102
				openToSide = (browserEvent.ctrlKey || browserEvent.metaKey || browserEvent.altKey);
			}

103 104
			const focused = this.list.getFocusedElements();
			const element = focused.length ? focused[0] : undefined;
105 106 107

			if (isMiddleClick) {
				if (element instanceof Breakpoint) {
108
					this.debugService.removeBreakpoints(element.getId());
109
				} else if (element instanceof FunctionBreakpoint) {
110
					this.debugService.removeFunctionBreakpoints(element.getId());
111 112 113 114
				}
				return;
			}

115
			if (element instanceof Breakpoint) {
116
				openBreakpointSource(element, openToSide, isSingleClick, this.debugService, this.editorService);
117 118 119 120
			}
			if (isDoubleClick && element instanceof FunctionBreakpoint && element !== this.debugService.getViewModel().getSelectedFunctionBreakpoint()) {
				this.debugService.getViewModel().setSelectedFunctionBreakpoint(element);
				this.onBreakpointsChange();
121 122
			}
		}));
I
isidor 已提交
123

I
isidor 已提交
124
		this.list.splice(0, this.list.length, this.elements);
I
isidor 已提交
125
	}
I
isidor 已提交
126

I
isidor 已提交
127
	public focus(): void {
S
Sandeep Somavarapu 已提交
128
		super.focus();
I
isidor 已提交
129 130 131 132 133
		if (this.list) {
			this.list.domFocus();
		}
	}

I
isidor 已提交
134
	protected layoutBody(size: number): void {
I
isidor 已提交
135 136 137
		if (this.list) {
			this.list.layout(size);
		}
I
isidor 已提交
138 139 140 141
	}

	private onListContextMenu(e: IListContextMenuEvent<IEnablement>): void {
		const actions: IAction[] = [];
I
isidor 已提交
142 143
		const element = e.element;

144
		const breakpointType = element instanceof Breakpoint && element.logMessage ? nls.localize('Logpoint', "Logpoint") : nls.localize('Breakpoint', "Breakpoint");
I
isidor 已提交
145
		if (element instanceof Breakpoint || element instanceof FunctionBreakpoint) {
I
isidor 已提交
146
			actions.push(new Action('workbench.action.debug.openEditorAndEditBreakpoint', nls.localize('editBreakpoint', "Edit {0}...", breakpointType), undefined, true, () => {
I
isidor 已提交
147 148 149 150 151 152 153 154 155 156 157 158
				if (element instanceof Breakpoint) {
					return openBreakpointSource(element, false, false, this.debugService, this.editorService).then(editor => {
						const codeEditor = editor.getControl();
						if (isCodeEditor(codeEditor)) {
							codeEditor.getContribution<IDebugEditorContribution>(EDITOR_CONTRIBUTION_ID).showBreakpointWidget(element.lineNumber, element.column);
						}
					});
				}

				this.debugService.getViewModel().setSelectedFunctionBreakpoint(element);
				this.onBreakpointsChange();
				return undefined;
I
isidor 已提交
159 160 161 162
			}));
			actions.push(new Separator());
		}

I
isidor 已提交
163
		actions.push(new RemoveBreakpointAction(RemoveBreakpointAction.ID, nls.localize('removeBreakpoint', "Remove {0}", breakpointType), this.debugService, this.keybindingService));
I
isidor 已提交
164

I
isidor 已提交
165 166 167
		if (this.debugService.getModel().getBreakpoints().length + this.debugService.getModel().getFunctionBreakpoints().length > 1) {
			actions.push(new RemoveAllBreakpointsAction(RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL, this.debugService, this.keybindingService));
			actions.push(new Separator());
I
isidor 已提交
168

I
isidor 已提交
169 170 171
			actions.push(new EnableAllBreakpointsAction(EnableAllBreakpointsAction.ID, EnableAllBreakpointsAction.LABEL, this.debugService, this.keybindingService));
			actions.push(new DisableAllBreakpointsAction(DisableAllBreakpointsAction.ID, DisableAllBreakpointsAction.LABEL, this.debugService, this.keybindingService));
		}
I
isidor 已提交
172

I
isidor 已提交
173 174
		actions.push(new Separator());
		actions.push(new ReapplyBreakpointsAction(ReapplyBreakpointsAction.ID, ReapplyBreakpointsAction.LABEL, this.debugService, this.keybindingService));
I
isidor 已提交
175

I
isidor 已提交
176 177 178
		this.contextMenuService.showContextMenu({
			getAnchor: () => e.anchor,
			getActions: () => TPromise.as(actions),
I
isidor 已提交
179
			getActionsContext: () => element
I
isidor 已提交
180
		});
I
isidor 已提交
181 182 183 184 185 186 187 188 189 190
	}

	public getActions(): IAction[] {
		return [
			new AddFunctionBreakpointAction(AddFunctionBreakpointAction.ID, AddFunctionBreakpointAction.LABEL, this.debugService, this.keybindingService),
			new ToggleBreakpointsActivatedAction(ToggleBreakpointsActivatedAction.ID, ToggleBreakpointsActivatedAction.ACTIVATE_LABEL, this.debugService, this.keybindingService),
			new RemoveAllBreakpointsAction(RemoveAllBreakpointsAction.ID, RemoveAllBreakpointsAction.LABEL, this.debugService, this.keybindingService)
		];
	}

I
isidor 已提交
191 192 193 194
	public setExpanded(expanded: boolean): void {
		super.setExpanded(expanded);
		if (expanded && this.needsRefresh) {
			this.onBreakpointsChange();
I
isidor 已提交
195
		}
I
isidor 已提交
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
	}

	public setVisible(visible: boolean): TPromise<void> {
		return super.setVisible(visible).then(() => {
			if (visible && this.needsRefresh) {
				this.onBreakpointsChange();
			}
		});
	}

	private onBreakpointsChange(): void {
		if (this.isExpanded() && this.isVisible()) {
			this.minimumBodySize = this.getExpandedBodySize();
			if (this.maximumBodySize < Number.POSITIVE_INFINITY) {
				this.maximumBodySize = this.minimumBodySize;
			}
			if (this.list) {
				this.list.splice(0, this.list.length, this.elements);
				this.needsRefresh = false;
			}
		} else {
			this.needsRefresh = true;
I
isidor 已提交
218 219 220
		}
	}

I
isidor 已提交
221 222
	private get elements(): IEnablement[] {
		const model = this.debugService.getModel();
I
isidor 已提交
223
		const elements = (<ReadonlyArray<IEnablement>>model.getExceptionBreakpoints()).concat(model.getFunctionBreakpoints()).concat(model.getBreakpoints());
I
isidor 已提交
224 225 226 227

		return elements;
	}

I
isidor 已提交
228 229 230 231 232 233 234 235 236 237
	private getExpandedBodySize(): number {
		const model = this.debugService.getModel();
		const length = model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length;
		return Math.min(BreakpointsView.MAX_VISIBLE_FILES, length) * 22;
	}

	public shutdown(): void {
		this.settings[BreakpointsView.MEMENTO] = !this.isExpanded();
	}
}
238

J
Joao Moreno 已提交
239
class BreakpointsDelegate implements IVirtualDelegate<IEnablement> {
240

241 242 243 244
	constructor(private debugService: IDebugService) {
		// noop
	}

I
isidor 已提交
245 246
	getHeight(element: IEnablement): number {
		return 22;
247 248
	}

I
isidor 已提交
249 250 251
	getTemplateId(element: IEnablement): string {
		if (element instanceof Breakpoint) {
			return BreakpointsRenderer.ID;
252
		}
I
isidor 已提交
253
		if (element instanceof FunctionBreakpoint) {
254
			const selected = this.debugService.getViewModel().getSelectedFunctionBreakpoint();
255 256 257 258
			if (!element.name || (selected && selected.getId() === element.getId())) {
				return FunctionBreakpointInputRenderer.ID;
			}

I
isidor 已提交
259 260 261 262
			return FunctionBreakpointsRenderer.ID;
		}
		if (element instanceof ExceptionBreakpoint) {
			return ExceptionBreakpointsRenderer.ID;
263 264
		}

I
isidor 已提交
265
		return undefined;
266 267 268 269 270 271 272 273 274 275 276
	}
}

interface IBaseBreakpointTemplateData {
	breakpoint: HTMLElement;
	name: HTMLElement;
	checkbox: HTMLInputElement;
	context: IEnablement;
	toDispose: IDisposable[];
}

I
isidor 已提交
277 278 279 280 281
interface IBaseBreakpointWithIconTemplateData extends IBaseBreakpointTemplateData {
	icon: HTMLElement;
}

interface IBreakpointTemplateData extends IBaseBreakpointWithIconTemplateData {
282 283 284 285
	lineNumber: HTMLElement;
	filePath: HTMLElement;
}

286 287 288
interface IInputTemplateData {
	inputBox: InputBox;
	breakpoint: IFunctionBreakpoint;
I
isidor 已提交
289
	reactedOnEvent: boolean;
290 291 292
	toDispose: IDisposable[];
}

I
isidor 已提交
293
class BreakpointsRenderer implements IRenderer<IBreakpoint, IBreakpointTemplateData> {
294 295 296

	constructor(
		@IDebugService private debugService: IDebugService,
297
		@ILabelService private labelService: ILabelService
298 299 300 301
	) {
		// noop
	}

302
	static readonly ID = 'breakpoints';
303

I
isidor 已提交
304 305
	get templateId() {
		return BreakpointsRenderer.ID;
306 307
	}

I
isidor 已提交
308
	renderTemplate(container: HTMLElement): IBreakpointTemplateData {
309 310 311
		const data: IBreakpointTemplateData = Object.create(null);
		data.breakpoint = dom.append(container, $('.breakpoint'));

I
isidor 已提交
312
		data.icon = $('.icon');
313
		data.checkbox = createCheckbox();
314 315 316 317 318
		data.toDispose = [];
		data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
			this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
		}));

I
isidor 已提交
319
		dom.append(data.breakpoint, data.icon);
320 321 322 323
		dom.append(data.breakpoint, data.checkbox);

		data.name = dom.append(data.breakpoint, $('span.name'));

I
isidor 已提交
324 325 326
		data.filePath = dom.append(data.breakpoint, $('span.file-path'));
		const lineNumberContainer = dom.append(data.breakpoint, $('.line-number-container'));
		data.lineNumber = dom.append(lineNumberContainer, $('span.line-number'));
327 328 329 330

		return data;
	}

I
isidor 已提交
331 332 333
	renderElement(breakpoint: IBreakpoint, index: number, data: IBreakpointTemplateData): void {
		data.context = breakpoint;
		dom.toggleClass(data.breakpoint, 'disabled', !this.debugService.getModel().areBreakpointsActivated());
334

I
isidor 已提交
335
		data.name.textContent = resources.basenameOrAuthority(breakpoint.uri);
336 337 338 339
		data.lineNumber.textContent = breakpoint.lineNumber.toString();
		if (breakpoint.column) {
			data.lineNumber.textContent += `:${breakpoint.column}`;
		}
I
isidor 已提交
340
		data.filePath.textContent = this.labelService.getUriLabel(resources.dirname(breakpoint.uri), true);
341 342
		data.checkbox.checked = breakpoint.enabled;

343
		const { message, className } = getBreakpointMessageAndClassName(this.debugService, breakpoint);
I
isidor 已提交
344
		data.icon.className = className + ' icon';
I
isidor 已提交
345
		data.breakpoint.title = breakpoint.message || message || '';
I
isidor 已提交
346

347 348
		const debugActive = this.debugService.state === State.Running || this.debugService.state === State.Stopped;
		if (debugActive && !breakpoint.verified) {
I
isidor 已提交
349
			dom.addClass(data.breakpoint, 'disabled');
I
isidor 已提交
350
		}
351 352
	}

J
Joao Moreno 已提交
353 354 355 356
	disposeElement(): void {
		// noop
	}

I
isidor 已提交
357
	disposeTemplate(templateData: IBreakpointTemplateData): void {
358 359 360 361
		dispose(templateData.toDispose);
	}
}

I
isidor 已提交
362
class ExceptionBreakpointsRenderer implements IRenderer<IExceptionBreakpoint, IBaseBreakpointTemplateData> {
363

I
isidor 已提交
364 365 366
	constructor(
		private debugService: IDebugService
	) {
367 368 369
		// noop
	}

370
	static readonly ID = 'exceptionbreakpoints';
371

I
isidor 已提交
372 373 374 375 376 377 378 379
	get templateId() {
		return ExceptionBreakpointsRenderer.ID;
	}

	renderTemplate(container: HTMLElement): IBaseBreakpointTemplateData {
		const data: IBreakpointTemplateData = Object.create(null);
		data.breakpoint = dom.append(container, $('.breakpoint'));

380
		data.checkbox = createCheckbox();
I
isidor 已提交
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
		data.toDispose = [];
		data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
			this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
		}));

		dom.append(data.breakpoint, data.checkbox);

		data.name = dom.append(data.breakpoint, $('span.name'));
		dom.addClass(data.breakpoint, 'exception');

		return data;
	}

	renderElement(exceptionBreakpoint: IExceptionBreakpoint, index: number, data: IBaseBreakpointTemplateData): void {
		data.context = exceptionBreakpoint;
		data.name.textContent = exceptionBreakpoint.label || `${exceptionBreakpoint.filter} exceptions`;
		data.breakpoint.title = data.name.textContent;
		data.checkbox.checked = exceptionBreakpoint.enabled;
	}

J
Joao Moreno 已提交
401 402 403 404
	disposeElement(): void {
		// noop
	}

I
isidor 已提交
405 406
	disposeTemplate(templateData: IBaseBreakpointTemplateData): void {
		dispose(templateData.toDispose);
407 408 409
	}
}

I
isidor 已提交
410
class FunctionBreakpointsRenderer implements IRenderer<FunctionBreakpoint, IBaseBreakpointWithIconTemplateData> {
411

I
isidor 已提交
412
	constructor(
413
		@IDebugService private debugService: IDebugService
I
isidor 已提交
414 415 416 417
	) {
		// noop
	}

418
	static readonly ID = 'functionbreakpoints';
419

I
isidor 已提交
420 421
	get templateId() {
		return FunctionBreakpointsRenderer.ID;
422 423
	}

I
isidor 已提交
424
	renderTemplate(container: HTMLElement): IBaseBreakpointWithIconTemplateData {
I
isidor 已提交
425 426
		const data: IBreakpointTemplateData = Object.create(null);
		data.breakpoint = dom.append(container, $('.breakpoint'));
427

I
isidor 已提交
428
		data.icon = $('.icon');
429
		data.checkbox = createCheckbox();
I
isidor 已提交
430 431 432 433 434
		data.toDispose = [];
		data.toDispose.push(dom.addStandardDisposableListener(data.checkbox, 'change', (e) => {
			this.debugService.enableOrDisableBreakpoints(!data.context.enabled, data.context);
		}));

I
isidor 已提交
435
		dom.append(data.breakpoint, data.icon);
I
isidor 已提交
436 437 438 439 440 441 442
		dom.append(data.breakpoint, data.checkbox);

		data.name = dom.append(data.breakpoint, $('span.name'));

		return data;
	}

I
isidor 已提交
443
	renderElement(functionBreakpoint: FunctionBreakpoint, index: number, data: IBaseBreakpointWithIconTemplateData): void {
I
isidor 已提交
444
		data.context = functionBreakpoint;
445
		data.name.textContent = functionBreakpoint.name;
446
		const { className, message } = getBreakpointMessageAndClassName(this.debugService, functionBreakpoint);
I
isidor 已提交
447 448
		data.icon.className = className + ' icon';
		data.icon.title = message ? message : '';
449 450 451 452
		data.checkbox.checked = functionBreakpoint.enabled;
		data.breakpoint.title = functionBreakpoint.name;

		// Mark function breakpoints as disabled if deactivated or if debug type does not support them #9099
I
isidor 已提交
453
		const session = this.debugService.getViewModel().focusedSession;
454 455
		dom.toggleClass(data.breakpoint, 'disalbed', (session && !session.capabilities.supportsFunctionBreakpoints) || !this.debugService.getModel().areBreakpointsActivated());
		if (session && !session.capabilities.supportsFunctionBreakpoints) {
456
			data.breakpoint.title = nls.localize('functionBreakpointsNotSupported', "Function breakpoints are not supported by this debug type");
I
isidor 已提交
457 458 459
		}
	}

J
Joao Moreno 已提交
460 461 462 463
	disposeElement(): void {
		// noop
	}

I
isidor 已提交
464
	disposeTemplate(templateData: IBaseBreakpointWithIconTemplateData): void {
I
isidor 已提交
465
		dispose(templateData.toDispose);
466 467
	}
}
I
isidor 已提交
468

469 470 471 472 473 474 475 476 477 478
class FunctionBreakpointInputRenderer implements IRenderer<IFunctionBreakpoint, IInputTemplateData> {

	constructor(
		private debugService: IDebugService,
		private contextViewService: IContextViewService,
		private themeService: IThemeService
	) {
		// noop
	}

479
	static readonly ID = 'functionbreakpointinput';
480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495

	get templateId() {
		return FunctionBreakpointInputRenderer.ID;
	}

	renderTemplate(container: HTMLElement): IInputTemplateData {
		const template: IInputTemplateData = Object.create(null);
		const inputBoxContainer = dom.append(container, $('.inputBoxContainer'));
		const inputBox = new InputBox(inputBoxContainer, this.contextViewService, {
			placeholder: nls.localize('functionBreakpointPlaceholder', "Function to break on"),
			ariaLabel: nls.localize('functionBreakPointInputAriaLabel', "Type function breakpoint")
		});
		const styler = attachInputBoxStyler(inputBox, this.themeService);
		const toDispose: IDisposable[] = [inputBox, styler];

		const wrapUp = (renamed: boolean) => {
I
isidor 已提交
496 497 498 499
			if (!template.reactedOnEvent) {
				template.reactedOnEvent = true;
				this.debugService.getViewModel().setSelectedFunctionBreakpoint(undefined);
				if (inputBox.value && (renamed || template.breakpoint.name)) {
500
					this.debugService.renameFunctionBreakpoint(template.breakpoint.getId(), renamed ? inputBox.value : template.breakpoint.name);
I
isidor 已提交
501
				} else {
502
					this.debugService.removeFunctionBreakpoints(template.breakpoint.getId());
I
isidor 已提交
503
				}
504 505 506 507 508 509 510 511 512 513 514 515 516
			}
		};

		toDispose.push(dom.addStandardDisposableListener(inputBox.inputElement, 'keydown', (e: IKeyboardEvent) => {
			const isEscape = e.equals(KeyCode.Escape);
			const isEnter = e.equals(KeyCode.Enter);
			if (isEscape || isEnter) {
				e.preventDefault();
				e.stopPropagation();
				wrapUp(isEnter);
			}
		}));
		toDispose.push(dom.addDisposableListener(inputBox.inputElement, 'blur', () => {
517 518 519 520 521 522
			// Need to react with a timeout on the blur event due to possible concurent splices #56443
			setTimeout(() => {
				if (!template.breakpoint.name) {
					wrapUp(true);
				}
			});
523 524 525 526 527 528 529 530 531
		}));

		template.inputBox = inputBox;
		template.toDispose = toDispose;
		return template;
	}

	renderElement(functionBreakpoint: IFunctionBreakpoint, index: number, data: IInputTemplateData): void {
		data.breakpoint = functionBreakpoint;
I
isidor 已提交
532
		data.reactedOnEvent = false;
533 534 535 536 537
		data.inputBox.value = functionBreakpoint.name || '';
		data.inputBox.focus();
		data.inputBox.select();
	}

J
Joao Moreno 已提交
538 539 540 541
	disposeElement(): void {
		// noop
	}

542 543 544 545 546
	disposeTemplate(templateData: IInputTemplateData): void {
		dispose(templateData.toDispose);
	}
}

547
export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolean, preserveFocus: boolean, debugService: IDebugService, editorService: IEditorService): TPromise<IEditor> {
I
isidor 已提交
548
	if (breakpoint.uri.scheme === DEBUG_SCHEME && debugService.state === State.Inactive) {
I
isidor 已提交
549
		return TPromise.as(null);
I
isidor 已提交
550 551 552 553 554 555 556 557 558 559 560 561 562 563
	}

	const selection = breakpoint.endLineNumber ? {
		startLineNumber: breakpoint.lineNumber,
		endLineNumber: breakpoint.endLineNumber,
		startColumn: breakpoint.column,
		endColumn: breakpoint.endColumn
	} : {
			startLineNumber: breakpoint.lineNumber,
			startColumn: breakpoint.column || 1,
			endLineNumber: breakpoint.lineNumber,
			endColumn: breakpoint.column || Constants.MAX_SAFE_SMALL_INTEGER
		};

I
isidor 已提交
564
	return editorService.openEditor({
I
isidor 已提交
565 566 567 568 569 570 571 572
		resource: breakpoint.uri,
		options: {
			preserveFocus,
			selection,
			revealIfVisible: true,
			revealInCenterIfOutsideViewport: true,
			pinned: !preserveFocus
		}
I
isidor 已提交
573
	}, sideBySide ? SIDE_GROUP : ACTIVE_GROUP);
I
isidor 已提交
574
}
575

576
export function getBreakpointMessageAndClassName(debugService: IDebugService, breakpoint: IBreakpoint | FunctionBreakpoint): { message?: string, className: string } {
577 578 579 580 581
	const state = debugService.state;
	const debugActive = state === State.Running || state === State.Stopped;

	if (!breakpoint.enabled || !debugService.getModel().areBreakpointsActivated()) {
		return {
I
isidor 已提交
582
			className: breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-disabled' : breakpoint.logMessage ? 'debug-breakpoint-log-disabled' : 'debug-breakpoint-disabled',
583
			message: breakpoint.logMessage ? nls.localize('disabledLogpoint', "Disabled logpoint") : nls.localize('disabledBreakpoint', "Disabled breakpoint"),
584 585 586 587
		};
	}

	const appendMessage = (text: string): string => {
I
isidor 已提交
588
		return !(breakpoint instanceof FunctionBreakpoint) && breakpoint.message ? text.concat(', ' + breakpoint.message) : text;
589 590 591
	};
	if (debugActive && !breakpoint.verified) {
		return {
I
isidor 已提交
592
			className: breakpoint instanceof FunctionBreakpoint ? 'debug-function-breakpoint-unverified' : breakpoint.logMessage ? 'debug-breakpoint-log-unverified' : 'debug-breakpoint-unverified',
593
			message: breakpoint.logMessage ? nls.localize('unverifiedLogpoint', "Unverified logpoint") : nls.localize('unverifiedBreakopint', "Unverified breakpoint"),
594 595 596
		};
	}

I
isidor 已提交
597
	const session = debugService.getViewModel().focusedSession;
598
	if (breakpoint instanceof FunctionBreakpoint) {
599
		if (session && !session.capabilities.supportsFunctionBreakpoints) {
600
			return {
601
				className: 'debug-function-breakpoint-unverified',
602 603 604 605
				message: nls.localize('functionBreakpointUnsupported', "Function breakpoints not supported by this debug type"),
			};
		}

I
isidor 已提交
606
		return {
607
			className: 'debug-function-breakpoint',
I
isidor 已提交
608
		};
609 610
	}

I
isidor 已提交
611 612 613
	if (breakpoint.logMessage || breakpoint.condition || breakpoint.hitCondition) {
		const messages = [];
		if (breakpoint.logMessage) {
614
			if (session && !session.capabilities.supportsLogPoints) {
I
isidor 已提交
615 616 617 618 619 620 621 622
				return {
					className: 'debug-breakpoint-unsupported',
					message: nls.localize('logBreakpointUnsupported', "Logpoints not supported by this debug type"),
				};
			}

			messages.push(nls.localize('logMessage', "Log Message: {0}", breakpoint.logMessage));
		}
I
isidor 已提交
623

624
		if (session && breakpoint.condition && !session.capabilities.supportsConditionalBreakpoints) {
625
			return {
626
				className: 'debug-breakpoint-unsupported',
627 628 629
				message: nls.localize('conditionalBreakpointUnsupported', "Conditional breakpoints not supported by this debug type"),
			};
		}
630
		if (session && breakpoint.hitCondition && !session.capabilities.supportsHitConditionalBreakpoints) {
631
			return {
632
				className: 'debug-breakpoint-unsupported',
633 634 635 636
				message: nls.localize('hitBreakpointUnsupported', "Hit conditional breakpoints not supported by this debug type"),
			};
		}

I
isidor 已提交
637 638 639 640 641
		if (breakpoint.condition) {
			messages.push(nls.localize('expression', "Expression: {0}", breakpoint.condition));
		}
		if (breakpoint.hitCondition) {
			messages.push(nls.localize('hitCount', "Hit Count: {0}", breakpoint.hitCondition));
642 643 644
		}

		return {
I
isidor 已提交
645 646
			className: breakpoint.logMessage ? 'debug-breakpoint-log' : 'debug-breakpoint-conditional',
			message: appendMessage(messages.join('\n'))
647 648 649 650
		};
	}

	return {
651
		className: 'debug-breakpoint',
652 653 654
		message: breakpoint.message
	};
}