debugViewlet.ts 24.0 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8 9
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/debugViewlet';
import nls = require('vs/nls');
import dom = require('vs/base/browser/dom');
import builder = require('vs/base/browser/builder');
I
isidor 已提交
10
import { TPromise } from 'vs/base/common/winjs.base';
E
Erich Gamma 已提交
11 12 13 14 15 16
import errors = require('vs/base/common/errors');
import lifecycle = require('vs/base/common/lifecycle');
import events = require('vs/base/common/events');
import actions = require('vs/base/common/actions');
import actionbar = require('vs/base/browser/ui/actionbar/actionbar');
import actionbarregistry = require('vs/workbench/browser/actionBarRegistry');
J
Joao Moreno 已提交
17
import tree = require('vs/base/parts/tree/browser/tree');
E
Erich Gamma 已提交
18 19 20 21 22 23 24
import treeimpl = require('vs/base/parts/tree/browser/treeImpl');
import splitview = require('vs/base/browser/ui/splitview/splitview');
import memento = require('vs/workbench/common/memento');
import viewlet = require('vs/workbench/browser/viewlet');
import debug = require('vs/workbench/parts/debug/common/debug');
import model = require('vs/workbench/parts/debug/common/debugModel');
import viewer = require('vs/workbench/parts/debug/browser/debugViewer');
I
isidor 已提交
25
import debugactions = require('vs/workbench/parts/debug/electron-browser/debugActions');
E
Erich Gamma 已提交
26 27 28 29 30 31 32 33 34 35 36 37
import dbgactionitems = require('vs/workbench/parts/debug/browser/debugActionItems');
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IMessageService } from 'vs/platform/message/common/message';
import { IStorageService } from 'vs/platform/storage/common/storage';

import IDebugService = debug.IDebugService;

function renderViewTree(container: HTMLElement): HTMLElement {
I
isidor 已提交
38
	const treeContainer = document.createElement('div');
E
Erich Gamma 已提交
39 40 41 42 43
	dom.addClass(treeContainer, 'debug-view-content');
	container.appendChild(treeContainer);
	return treeContainer;
}

B
Benjamin Pasero 已提交
44 45 46 47 48 49
const debugTreeOptions = (ariaLabel: string) => {
	return <tree.ITreeOptions> {
		indentPixels: 8,
		twistiePixels: 20,
		ariaLabel
	};
E
Erich Gamma 已提交
50 51
};

I
isidor 已提交
52
const $ = builder.$;
E
Erich Gamma 已提交
53 54 55 56 57 58 59 60

class VariablesView extends viewlet.CollapsibleViewletView {

	private static MEMENTO = 'variablesview.memento';

	constructor(actionRunner: actions.IActionRunner, private settings: any,
		@IMessageService messageService: IMessageService,
		@IContextMenuService contextMenuService: IContextMenuService,
61
		@ITelemetryService private telemetryService: ITelemetryService,
E
Erich Gamma 已提交
62
		@IDebugService private debugService: IDebugService,
P
Pierson Lee 已提交
63
		@IInstantiationService private instantiationService: IInstantiationService
E
Erich Gamma 已提交
64
	) {
65
		super(actionRunner, !!settings[VariablesView.MEMENTO], nls.localize('variablesSection', "Variables Section"), messageService, contextMenuService);
E
Erich Gamma 已提交
66 67 68
	}

	public renderHeader(container: HTMLElement): void {
I
isidor 已提交
69
		const titleDiv = $('div.title').appendTo(container);
E
Erich Gamma 已提交
70
		$('span').text(nls.localize('variables', "Variables")).appendTo(titleDiv);
I
isidor 已提交
71 72

		super.renderHeader(container);
E
Erich Gamma 已提交
73 74 75
	}

	public renderBody(container: HTMLElement): void {
76
		dom.addClass(container, 'debug-variables');
E
Erich Gamma 已提交
77 78 79 80 81
		this.treeContainer = renderViewTree(container);

		this.tree = new treeimpl.Tree(this.treeContainer, {
			dataSource: new viewer.VariablesDataSource(this.debugService),
			renderer: this.instantiationService.createInstance(viewer.VariablesRenderer),
82
			accessibilityProvider: new viewer.VariablesAccessibilityProvider(),
E
Erich Gamma 已提交
83
			controller: new viewer.BaseDebugController(this.debugService, this.contextMenuService, new viewer.VariablesActionProvider(this.instantiationService))
84
		}, debugTreeOptions(nls.localize('variablesAriaTreeLabel', "Debug Variables")));
E
Erich Gamma 已提交
85

I
isidor 已提交
86
		const viewModel = this.debugService.getViewModel();
E
Erich Gamma 已提交
87 88 89

		this.tree.setInput(viewModel);

I
isidor 已提交
90
		const collapseAction = this.instantiationService.createInstance(viewlet.CollapseAction, this.tree, false, 'explorer-action collapse-explorer');
E
Erich Gamma 已提交
91 92 93 94 95 96
		this.toolBar.setActions(actionbarregistry.prepareActions([collapseAction]))();

		this.toDispose.push(viewModel.addListener2(debug.ViewModelEvents.FOCUSED_STACK_FRAME_UPDATED, () => this.onFocusedStackFrameUpdated()));
		this.toDispose.push(this.debugService.addListener2(debug.ServiceEvents.STATE_CHANGED, () => {
			collapseAction.enabled = this.debugService.getState() === debug.State.Running || this.debugService.getState() === debug.State.Stopped;
		}));
97

P
Pierson Lee 已提交
98
		this.toDispose.push(this.tree.addListener2(events.EventType.FOCUS, (e: tree.IFocusEvent) => {
I
isidor 已提交
99
			const isMouseClick = (e.payload && e.payload.origin === 'mouse');
P
Pierson Lee 已提交
100 101 102
			const isVariableType = (e.focus instanceof model.Variable);

			if(isMouseClick && isVariableType) {
I
isidor 已提交
103
				this.telemetryService.publicLog('debug/variables/selected');
P
Pierson Lee 已提交
104 105
			}
		}));
E
Erich Gamma 已提交
106 107 108 109
	}

	private onFocusedStackFrameUpdated(): void {
		this.tree.refresh().then(() => {
I
isidor 已提交
110
			const stackFrame = this.debugService.getViewModel().getFocusedStackFrame();
E
Erich Gamma 已提交
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
			if (stackFrame) {
				return stackFrame.getScopes(this.debugService).then(scopes => {
					if (scopes.length > 0) {
						return this.tree.expand(scopes[0]);
					}
				});
			}
		}).done(null, errors.onUnexpectedError);
	}

	public shutdown(): void {
		this.settings[VariablesView.MEMENTO] = (this.state === splitview.CollapsibleState.COLLAPSED);
		super.shutdown();
	}
}

class WatchExpressionsView extends viewlet.CollapsibleViewletView {

	private static MEMENTO = 'watchexpressionsview.memento';

	constructor(actionRunner: actions.IActionRunner, private settings: any,
		@IMessageService messageService: IMessageService,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IDebugService private debugService: IDebugService,
		@IInstantiationService private instantiationService: IInstantiationService
	) {
137
		super(actionRunner, !!settings[WatchExpressionsView.MEMENTO], nls.localize('expressionsSection', "Expressions Section"), messageService, contextMenuService);
E
Erich Gamma 已提交
138
		this.toDispose.push(this.debugService.getModel().addListener2(debug.ModelEvents.WATCH_EXPRESSIONS_UPDATED, (we) => {
I
isidor 已提交
139
			// only expand when a new watch expression is added.
E
Erich Gamma 已提交
140 141 142 143 144 145 146
			if (we instanceof model.Expression) {
				this.expand();
			}
		}));
	}

	public renderHeader(container: HTMLElement): void {
I
isidor 已提交
147
		const titleDiv = $('div.title').appendTo(container);
E
Erich Gamma 已提交
148
		$('span').text(nls.localize('watch', "Watch")).appendTo(titleDiv);
I
isidor 已提交
149 150

		super.renderHeader(container);
E
Erich Gamma 已提交
151 152 153
	}

	public renderBody(container: HTMLElement): void {
154
		dom.addClass(container, 'debug-watch');
E
Erich Gamma 已提交
155 156
		this.treeContainer = renderViewTree(container);

I
isidor 已提交
157
		const actionProvider = new viewer.WatchExpressionsActionProvider(this.instantiationService);
E
Erich Gamma 已提交
158 159 160
		this.tree = new treeimpl.Tree(this.treeContainer, {
			dataSource: new viewer.WatchExpressionsDataSource(this.debugService),
			renderer: this.instantiationService.createInstance(viewer.WatchExpressionsRenderer, actionProvider, this.actionRunner),
161
			accessibilityProvider: new viewer.WatchExpressionsAccessibilityProvider(),
E
Erich Gamma 已提交
162
			controller: new viewer.WatchExpressionsController(this.debugService, this.contextMenuService, actionProvider)
163
		}, debugTreeOptions(nls.localize('watchAriaTreeLabel', "Debug Watch Expressions")));
E
Erich Gamma 已提交
164 165 166

		this.tree.setInput(this.debugService.getModel());

I
isidor 已提交
167
		const addWatchExpressionAction = this.instantiationService.createInstance(debugactions.AddWatchExpressionAction, debugactions.AddWatchExpressionAction.ID, debugactions.AddWatchExpressionAction.LABEL);
I
isidor 已提交
168
		const collapseAction = this.instantiationService.createInstance(viewlet.CollapseAction, this.tree, false, 'explorer-action collapse-explorer');
I
isidor 已提交
169
		const removeAllWatchExpressionsAction = this.instantiationService.createInstance(debugactions.RemoveAllWatchExpressionsAction, debugactions.RemoveAllWatchExpressionsAction.ID, debugactions.RemoveAllWatchExpressionsAction.LABEL);
E
Erich Gamma 已提交
170 171 172 173 174 175 176 177 178 179
		this.toolBar.setActions(actionbarregistry.prepareActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction]))();

		this.toDispose.push(this.debugService.getModel().addListener2(debug.ModelEvents.WATCH_EXPRESSIONS_UPDATED, (we: model.Expression) => this.onWatchExpressionsUpdated(we)));
		this.toDispose.push(this.debugService.getViewModel().addListener2(debug.ViewModelEvents.SELECTED_EXPRESSION_UPDATED, (expression: debug.IExpression) => {
			if (!expression || !(expression instanceof model.Expression)) {
				return;
			}

			this.tree.refresh(expression, false).then(() => {
				this.tree.setHighlight(expression);
I
isidor 已提交
180
				this.tree.addOneTimeListener(events.EventType.HIGHLIGHT, (e: tree.IHighlightEvent) => {
E
Erich Gamma 已提交
181 182 183 184 185 186 187 188 189 190
					if (!e.highlight) {
						this.debugService.getViewModel().setSelectedExpression(null);
					}
				});
			}).done(null, errors.onUnexpectedError);
		}));
	}

	private onWatchExpressionsUpdated(we: model.Expression): void {
		this.tree.refresh().done(() => {
A
Alex Dima 已提交
191
			return we instanceof model.Expression ? this.tree.reveal(we): TPromise.as(true);
E
Erich Gamma 已提交
192 193 194 195 196 197 198 199 200 201 202 203
		}, errors.onUnexpectedError);
	}

	public shutdown(): void {
		this.settings[WatchExpressionsView.MEMENTO] = (this.state === splitview.CollapsibleState.COLLAPSED);
		super.shutdown();
	}
}

class CallStackView extends viewlet.CollapsibleViewletView {

	private static MEMENTO = 'callstackview.memento';
204 205
	private pauseMessage: builder.Builder;
	private pauseMessageLabel: builder.Builder;
E
Erich Gamma 已提交
206 207 208 209

	constructor(actionRunner: actions.IActionRunner, private settings: any,
		@IMessageService messageService: IMessageService,
		@IContextMenuService contextMenuService: IContextMenuService,
210
		@ITelemetryService private telemetryService: ITelemetryService,
E
Erich Gamma 已提交
211
		@IDebugService private debugService: IDebugService,
P
Pierson Lee 已提交
212
		@IInstantiationService private instantiationService: IInstantiationService
E
Erich Gamma 已提交
213
	) {
214
		super(actionRunner, !!settings[CallStackView.MEMENTO], nls.localize('callstackSection', "Call Stack Section"), messageService, contextMenuService);
E
Erich Gamma 已提交
215 216 217
	}

	public renderHeader(container: HTMLElement): void {
218 219 220 221 222
		const title = $('div.debug-call-stack-title').appendTo(container);
		$('span.title').text(nls.localize('callStack', "Call Stack")).appendTo(title);
		this.pauseMessage = $('span.pause-message').appendTo(title);
		this.pauseMessage.hide();
		this.pauseMessageLabel = $('span.label').appendTo(this.pauseMessage);
I
isidor 已提交
223 224

		super.renderHeader(container);
E
Erich Gamma 已提交
225 226 227
	}

	public renderBody(container: HTMLElement): void {
228
		dom.addClass(container, 'debug-call-stack');
E
Erich Gamma 已提交
229 230 231
		this.treeContainer = renderViewTree(container);

		this.tree = new treeimpl.Tree(this.treeContainer, {
232
			dataSource: this.instantiationService.createInstance(viewer.CallStackDataSource),
233 234
			renderer: this.instantiationService.createInstance(viewer.CallStackRenderer),
			accessibilityProvider: this.instantiationService.createInstance(viewer.CallstackAccessibilityProvider)
235
		}, debugTreeOptions(nls.localize('callStackAriaLabel', "Debug Call Stack")));
E
Erich Gamma 已提交
236

I
isidor 已提交
237
		const debugModel = this.debugService.getModel();
E
Erich Gamma 已提交
238 239 240 241 242 243 244

		this.tree.setInput(debugModel);

		this.toDispose.push(this.tree.addListener2('selection', (e: tree.ISelectionEvent) => {
			if (!e.selection.length) {
				return;
			}
I
isidor 已提交
245
			const element = e.selection[0];
E
Erich Gamma 已提交
246

I
isidor 已提交
247 248 249
			if (element instanceof model.StackFrame) {
				const stackFrame = <debug.IStackFrame> element;
				this.debugService.setFocusedStackFrameAndEvaluate(stackFrame);
E
Erich Gamma 已提交
250

I
isidor 已提交
251 252
				const isMouse = (e.payload.origin === 'mouse');
				let preserveFocus = isMouse;
E
Erich Gamma 已提交
253

I
isidor 已提交
254 255 256 257 258 259 260 261
				const originalEvent:KeyboardEvent|MouseEvent = e && e.payload && e.payload.originalEvent;
				if (originalEvent && isMouse && originalEvent.detail === 2) {
					preserveFocus = false;
					originalEvent.preventDefault();  // focus moves to editor, we need to prevent default
				}

				const sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey));
				this.debugService.openOrRevealEditor(stackFrame.source, stackFrame.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError);
E
Erich Gamma 已提交
262 263
			}

I
isidor 已提交
264 265 266 267 268 269 270
			// user clicked on 'Load More Stack Frames', get those stack frames and refresh the tree.
			if (typeof element === 'number') {
				const thread = this.debugService.getModel().getThreads()[element];
				if (thread) {
					thread.getCallStack(this.debugService, true).then(() => this.tree.refresh()).done(null, errors.onUnexpectedError);
				}
			}
E
Erich Gamma 已提交
271
		}));
I
isidor 已提交
272

P
Pierson Lee 已提交
273
		this.toDispose.push(this.tree.addListener2(events.EventType.FOCUS, (e: tree.IFocusEvent) => {
I
isidor 已提交
274
			const isMouseClick = (e.payload && e.payload.origin === 'mouse');
P
Pierson Lee 已提交
275 276 277
			const isStackFrameType = (e.focus instanceof model.StackFrame);

			if (isMouseClick && isStackFrameType) {
I
isidor 已提交
278
				this.telemetryService.publicLog('debug/callStack/selected');
P
Pierson Lee 已提交
279 280
			}
		}));
E
Erich Gamma 已提交
281 282 283 284

		this.toDispose.push(debugModel.addListener2(debug.ModelEvents.CALLSTACK_UPDATED, () => {
			this.tree.refresh().done(null, errors.onUnexpectedError);
		}));
I
isidor 已提交
285

286 287
		this.toDispose.push(this.debugService.getViewModel().addListener2(debug.ViewModelEvents.FOCUSED_STACK_FRAME_UPDATED, () => {
			const focussedThread = this.debugService.getModel().getThreads()[this.debugService.getViewModel().getFocusedThreadId()];
I
isidor 已提交
288 289 290 291 292 293 294
			if (!focussedThread) {
				return;
			}

			this.tree.expand(focussedThread);
			this.tree.select(this.debugService.getViewModel().getFocusedStackFrame());
			if (focussedThread.stoppedDetails && focussedThread.stoppedDetails.reason) {
I
isidor 已提交
295 296 297 298 299
				this.pauseMessageLabel.text(nls.localize('debugStopped', "Paused on {0}", focussedThread.stoppedDetails.reason));
				if (focussedThread.stoppedDetails.text) {
					this.pauseMessageLabel.title(focussedThread.stoppedDetails.text);
				}
				focussedThread.stoppedDetails.reason === 'exception' ? this.pauseMessageLabel.addClass('exception') : this.pauseMessageLabel.removeClass('exception');
300
				this.pauseMessage.show();
301
			} else {
302
				this.pauseMessage.hide();
E
Erich Gamma 已提交
303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
			}
		}));
	}

	public shutdown(): void {
		this.settings[CallStackView.MEMENTO] = (this.state === splitview.CollapsibleState.COLLAPSED);
		super.shutdown();
	}
}

class BreakpointsView extends viewlet.AdaptiveCollapsibleViewletView {

	private static MAX_VISIBLE_FILES = 9;
	private static MEMENTO = 'breakopintsview.memento';

	constructor(actionRunner: actions.IActionRunner, private settings: any,
		@IMessageService messageService: IMessageService,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IDebugService private debugService: IDebugService,
		@IInstantiationService private instantiationService: IInstantiationService
	) {
		super(actionRunner, BreakpointsView.getExpandedBodySize(
325
			debugService.getModel().getBreakpoints().length + debugService.getModel().getFunctionBreakpoints().length + debugService.getModel().getExceptionBreakpoints().length),
326
			!!settings[BreakpointsView.MEMENTO], nls.localize('breakpointsSection', "Breakpoints Section"), messageService, contextMenuService);
E
Erich Gamma 已提交
327 328 329 330 331

		this.toDispose.push(this.debugService.getModel().addListener2(debug.ModelEvents.BREAKPOINTS_UPDATED,() => this.onBreakpointsChange()));
	}

	public renderHeader(container: HTMLElement): void {
I
isidor 已提交
332
		const titleDiv = $('div.title').appendTo(container);
E
Erich Gamma 已提交
333
		$('span').text(nls.localize('breakpoints', "Breakpoints")).appendTo(titleDiv);
I
isidor 已提交
334 335

		super.renderHeader(container);
E
Erich Gamma 已提交
336 337 338
	}

	public renderBody(container: HTMLElement): void {
339
		dom.addClass(container, 'debug-breakpoints');
E
Erich Gamma 已提交
340
		this.treeContainer = renderViewTree(container);
I
isidor 已提交
341
		const actionProvider = new viewer.BreakpointsActionProvider(this.instantiationService);
E
Erich Gamma 已提交
342 343 344 345

		this.tree = new treeimpl.Tree(this.treeContainer, {
			dataSource: new viewer.BreakpointsDataSource(),
			renderer: this.instantiationService.createInstance(viewer.BreakpointsRenderer, actionProvider, this.actionRunner),
346
			accessibilityProvider: this.instantiationService.createInstance(viewer.BreakpointsAccessibilityProvider),
E
Erich Gamma 已提交
347 348 349
			controller: new viewer.BreakpointsController(this.debugService, this.contextMenuService, actionProvider),
			sorter: {
				compare(tree: tree.ITree, element: any, otherElement: any): number {
I
isidor 已提交
350 351
					const first = <debug.IBreakpoint> element;
					const second = <debug.IBreakpoint> otherElement;
E
Erich Gamma 已提交
352 353 354
					if (first instanceof model.ExceptionBreakpoint) {
						return -1;
					}
355
					if (second instanceof model.ExceptionBreakpoint) {
E
Erich Gamma 已提交
356 357
						return 1;
					}
358 359 360
					if (first instanceof model.FunctionBreakpoint) {
						return -1;
					}
361 362 363
					if(second instanceof model.FunctionBreakpoint) {
						return 1;
					}
E
Erich Gamma 已提交
364 365 366 367 368 369 370 371

					if (first.source.uri.toString() !== second.source.uri.toString()) {
						return first.source.uri.toString().localeCompare(second.source.uri.toString());
					}

					return first.desiredLineNumber - second.desiredLineNumber;
				}
			}
372
		}, debugTreeOptions(nls.localize('breakpointsAriaTreeLabel', "Debug Breakpoints")));
E
Erich Gamma 已提交
373

I
isidor 已提交
374
		const debugModel = this.debugService.getModel();
E
Erich Gamma 已提交
375 376 377 378 379 380 381

		this.tree.setInput(debugModel);

		this.toDispose.push(this.tree.addListener2('selection', (e: tree.ISelectionEvent) => {
			if (!e.selection.length) {
				return;
			}
I
isidor 已提交
382
			const element = e.selection[0];
E
Erich Gamma 已提交
383 384 385 386
			if (!(element instanceof model.Breakpoint)) {
				return;
			}

I
isidor 已提交
387
			const breakpoint = <debug.IBreakpoint> element;
E
Erich Gamma 已提交
388
			if (!breakpoint.source.inMemory) {
I
isidor 已提交
389 390
				const isMouse = (e.payload.origin === 'mouse');
				let preserveFocus = isMouse;
E
Erich Gamma 已提交
391

I
isidor 已提交
392
				const originalEvent:KeyboardEvent|MouseEvent = e && e.payload && e.payload.originalEvent;
E
Erich Gamma 已提交
393 394 395 396 397
				if (originalEvent && isMouse && originalEvent.detail === 2) {
					preserveFocus = false;
					originalEvent.preventDefault();  // focus moves to editor, we need to prevent default
				}

I
isidor 已提交
398
				const sideBySide = (originalEvent && (originalEvent.ctrlKey || originalEvent.metaKey));
E
Erich Gamma 已提交
399 400 401
				this.debugService.openOrRevealEditor(breakpoint.source, breakpoint.lineNumber, preserveFocus, sideBySide).done(null, errors.onUnexpectedError);
			}
		}));
I
isidor 已提交
402 403 404 405 406 407 408 409 410 411 412 413 414 415 416

		this.toDispose.push(this.debugService.getViewModel().addListener2(debug.ViewModelEvents.SELECTED_FUNCTION_BREAKPOINT_UPDATED, (fbp: debug.IFunctionBreakpoint) => {
			if (!fbp || !(fbp instanceof model.FunctionBreakpoint)) {
				return;
			}

			this.tree.refresh(fbp, false).then(() => {
				this.tree.setHighlight(fbp);
				this.tree.addOneTimeListener(events.EventType.HIGHLIGHT, (e: tree.IHighlightEvent) => {
					if (!e.highlight) {
						this.debugService.getViewModel().setSelectedFunctionBreakpoint(null);
					}
				});
			}).done(null, errors.onUnexpectedError);
		}));
E
Erich Gamma 已提交
417 418 419 420
	}

	public getActions(): actions.IAction[] {
		return [
I
isidor 已提交
421
			this.instantiationService.createInstance(debugactions.AddFunctionBreakpointAction, debugactions.AddFunctionBreakpointAction.ID, debugactions.AddFunctionBreakpointAction.LABEL),
I
isidor 已提交
422 423
			this.instantiationService.createInstance(debugactions.ToggleBreakpointsActivatedAction, debugactions.ToggleBreakpointsActivatedAction.ID, debugactions.ToggleBreakpointsActivatedAction.LABEL),
			this.instantiationService.createInstance(debugactions.RemoveAllBreakpointsAction, debugactions.RemoveAllBreakpointsAction.ID, debugactions.RemoveAllBreakpointsAction.LABEL)
E
Erich Gamma 已提交
424 425 426 427
		];
	}

	private onBreakpointsChange(): void {
428 429 430
		const model = this.debugService.getModel();
		this.expandedBodySize = BreakpointsView.getExpandedBodySize(
			model.getBreakpoints().length + model.getExceptionBreakpoints().length + model.getFunctionBreakpoints().length);
E
Erich Gamma 已提交
431 432 433 434 435 436 437

		if (this.tree) {
			this.tree.refresh();
		}
	}

	private static getExpandedBodySize(length: number): number {
I
isidor 已提交
438
		return Math.min(BreakpointsView.MAX_VISIBLE_FILES, length) * 22;
E
Erich Gamma 已提交
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457
	}

	public shutdown(): void {
		this.settings[BreakpointsView.MEMENTO] = (this.state === splitview.CollapsibleState.COLLAPSED);
		super.shutdown();
	}
}

export class DebugViewlet extends viewlet.Viewlet {

	private toDispose: lifecycle.IDisposable[];
	private actions: actions.IAction[];
	private progressRunner: IProgressRunner;
	private viewletSettings: any;

	private $el: builder.Builder;
	private splitView: splitview.SplitView;
	private views: viewlet.IViewletView[];

458 459
	private lastFocusedView: viewlet.CollapsibleViewletView | viewlet.AdaptiveCollapsibleViewletView;

E
Erich Gamma 已提交
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478
	constructor(
		@ITelemetryService telemetryService: ITelemetryService,
		@IProgressService private progressService: IProgressService,
		@IDebugService private debugService: IDebugService,
		@IInstantiationService private instantiationService: IInstantiationService,
		@IWorkspaceContextService private contextService: IWorkspaceContextService,
		@IStorageService storageService: IStorageService
	) {
		super(debug.VIEWLET_ID, telemetryService);

		this.progressRunner = null;
		this.viewletSettings = this.getMemento(storageService, memento.Scope.WORKSPACE);
		this.views = [];
		this.toDispose = [];
		this.toDispose.push(this.debugService.addListener2(debug.ServiceEvents.STATE_CHANGED, () => {
			this.onDebugServiceStateChange();
		}));
	}

I
isidor 已提交
479
	// viewlet
E
Erich Gamma 已提交
480 481 482 483 484 485

	public create(parent: builder.Builder): TPromise<void> {
		super.create(parent);
		this.$el = parent.div().addClass('debug-viewlet');

		if (this.contextService.getWorkspace()) {
I
isidor 已提交
486
			const actionRunner = this.getActionRunner();
E
Erich Gamma 已提交
487 488 489 490 491 492 493 494
			this.views.push(this.instantiationService.createInstance(VariablesView, actionRunner, this.viewletSettings));
			this.views.push(this.instantiationService.createInstance(WatchExpressionsView, actionRunner, this.viewletSettings));
			this.views.push(this.instantiationService.createInstance(CallStackView, actionRunner, this.viewletSettings));
			this.views.push(this.instantiationService.createInstance(BreakpointsView, actionRunner, this.viewletSettings));

			this.splitView = new splitview.SplitView(this.$el.getHTMLElement());
			this.toDispose.push(this.splitView);
			this.views.forEach(v => this.splitView.addView(<any> v));
495 496 497 498 499

			// Track focus
			this.toDispose.push(this.splitView.onFocus((view: viewlet.CollapsibleViewletView | viewlet.AdaptiveCollapsibleViewletView) => {
				this.lastFocusedView = view;
			}));
E
Erich Gamma 已提交
500 501 502 503 504 505 506 507 508
		} else {
			this.$el.append($([
				'<div class="noworkspace-view">',
				'<p>', nls.localize('noWorkspace', "There is no currently opened folder."), '</p>',
				'<p>', nls.localize('pleaseRestartToDebug', "Open a folder in order to start debugging."), '</p>',
				'</div>'
			].join('')));
		}

A
Alex Dima 已提交
509
		return TPromise.as(null);
E
Erich Gamma 已提交
510 511
	}

I
isidor 已提交
512
	public setVisible(visible: boolean): TPromise<any> {
513
		return super.setVisible(visible).then(() => {
I
isidor 已提交
514
			return TPromise.join(this.views.map((view) => view.setVisible(visible)));
515 516 517
		});
	}

E
Erich Gamma 已提交
518 519 520 521 522 523
	public layout(dimension: builder.Dimension): void {
		if (this.splitView) {
			this.splitView.layout(dimension.height);
		}
	}

I
isidor 已提交
524 525
	public focus(): void {
		super.focus();
526

527 528 529 530 531
		if (this.lastFocusedView && this.lastFocusedView.isExpanded()) {
			this.lastFocusedView.focusBody();
			return;
		}

I
isidor 已提交
532
		if (this.views.length > 0) {
533
			(<VariablesView>this.views[0]).focusBody();
I
isidor 已提交
534 535 536
		}
	}

E
Erich Gamma 已提交
537 538 539 540 541 542 543
	public getActions(): actions.IAction[] {
		if (this.debugService.getState() === debug.State.Disabled) {
			return [];
		}

		if (!this.actions) {
			this.actions = [
I
isidor 已提交
544 545 546 547
				this.instantiationService.createInstance(debugactions.StartDebugAction, debugactions.StartDebugAction.ID, debugactions.StartDebugAction.LABEL),
				this.instantiationService.createInstance(debugactions.SelectConfigAction, debugactions.SelectConfigAction.ID, debugactions.SelectConfigAction.LABEL),
				this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL),
				this.instantiationService.createInstance(debugactions.ToggleReplAction, debugactions.ToggleReplAction.ID, debugactions.ToggleReplAction.LABEL)
E
Erich Gamma 已提交
548 549 550 551 552 553 554 555 556 557 558
			];

			this.actions.forEach(a => {
				this.toDispose.push(a);
			});
		}

		return this.actions;
	}

	public getActionItem(action: actions.IAction): actionbar.IActionItem {
I
isidor 已提交
559
		if (action.id === debugactions.SelectConfigAction.ID) {
E
Erich Gamma 已提交
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
			return this.instantiationService.createInstance(dbgactionitems.SelectConfigActionItem, action);
		}

		return null;
	}

	private onDebugServiceStateChange(): void {
		if (this.progressRunner) {
			this.progressRunner.done();
		}

		if (this.debugService.getState() === debug.State.Initializing) {
			this.progressRunner = this.progressService.show(true);
		} else {
			this.progressRunner = null;
		}
	}

	public dispose(): void {
J
Joao Moreno 已提交
579
		this.toDispose = lifecycle.dispose(this.toDispose);
E
Erich Gamma 已提交
580 581 582 583 584 585 586 587 588

		super.dispose();
	}

	public shutdown(): void {
		this.views.forEach(v => v.shutdown());
		super.shutdown();
	}
}