“56b6d3a372827d890bfdb9f6bc4da174989b84ef”上不存在“docs/git@gitcode.net:qq_34446485/zio-redis.git”
callStackView.ts 35.9 KB
Newer Older
I
isidor 已提交
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  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';
I
isidor 已提交
7
import { RunOnceScheduler, ignoreErrors, sequence } from 'vs/base/common/async';
I
isidor 已提交
8
import * as dom from 'vs/base/browser/dom';
I
isidor 已提交
9
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
10 11
import { IDebugService, State, IStackFrame, IDebugSession, IThread, CONTEXT_CALLSTACK_ITEM_TYPE, IDebugModel } from 'vs/workbench/contrib/debug/common/debug';
import { Thread, StackFrame, ThreadAndSessionIds } from 'vs/workbench/contrib/debug/common/debugModel';
I
isidor 已提交
12 13
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
I
isidor 已提交
14
import { MenuId, IMenu, IMenuService } from 'vs/platform/actions/common/actions';
I
isidor 已提交
15
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
I
isidor 已提交
16
import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
17
import { IAction, Action } from 'vs/base/common/actions';
18
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
19
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
20
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
21
import { ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
I
isidor 已提交
22
import { ILabelService } from 'vs/platform/label/common/label';
J
João Moreno 已提交
23
import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
24
import { createAndFillInContextMenuActions, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
I
isidor 已提交
25
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
J
Joao Moreno 已提交
26
import { ITreeRenderer, ITreeNode, ITreeContextMenuEvent, IAsyncDataSource } from 'vs/base/browser/ui/tree/tree';
J
João Moreno 已提交
27
import { TreeResourceNavigator, WorkbenchAsyncDataTree } from 'vs/platform/list/browser/listService';
I
isidor 已提交
28 29
import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel';
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
I
isidor 已提交
30
import { Event } from 'vs/base/common/event';
I
isidor 已提交
31
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
32 33 34 35
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { isSessionAttach } from 'vs/workbench/contrib/debug/common/debugUtils';
import { STOP_ID, STOP_LABEL, DISCONNECT_ID, DISCONNECT_LABEL, RESTART_SESSION_ID, RESTART_LABEL, STEP_OVER_ID, STEP_OVER_LABEL, STEP_INTO_LABEL, STEP_INTO_ID, STEP_OUT_LABEL, STEP_OUT_ID, PAUSE_ID, PAUSE_LABEL, CONTINUE_ID, CONTINUE_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
import { ICommandService } from 'vs/platform/commands/common/commands';
I
isidor 已提交
36
import { CollapseAction } from 'vs/workbench/browser/viewlet';
37
import { IViewDescriptorService } from 'vs/workbench/common/views';
I
isidor 已提交
38
import { textLinkForeground } from 'vs/platform/theme/common/colorRegistry';
39 40
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
41
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
I
isidor 已提交
42
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
I
isidor 已提交
43

44
const $ = dom.$;
I
isidor 已提交
45

I
isidor 已提交
46 47
type CallStackItem = IStackFrame | IThread | IDebugSession | string | ThreadAndSessionIds | IStackFrame[];

I
isidor 已提交
48
export function getContext(element: CallStackItem | null): any {
I
isidor 已提交
49 50 51 52 53 54 55 56 57 58 59 60
	return element instanceof StackFrame ? {
		sessionId: element.thread.session.getId(),
		threadId: element.thread.getId(),
		frameId: element.getId()
	} : element instanceof Thread ? {
		sessionId: element.session.getId(),
		threadId: element.getId()
	} : isDebugSession(element) ? {
		sessionId: element.getId()
	} : undefined;
}

I
isidor 已提交
61 62 63 64
// Extensions depend on this context, should not be changed even though it is not fully deterministic
export function getContextForContributedActions(element: CallStackItem | null): string | number {
	if (element instanceof StackFrame) {
		if (element.source.inMemory) {
I
isidor 已提交
65
			return element.source.raw.path || element.source.reference || element.source.name;
I
isidor 已提交
66 67 68 69 70 71 72 73 74 75 76 77 78 79
		}

		return element.source.uri.toString();
	}
	if (element instanceof Thread) {
		return element.threadId;
	}
	if (isDebugSession(element)) {
		return element.getId();
	}

	return '';
}

I
isidor 已提交
80
export class CallStackView extends ViewPane {
I
isidor 已提交
81 82
	private pauseMessage!: HTMLSpanElement;
	private pauseMessageLabel!: HTMLSpanElement;
I
isidor 已提交
83
	private onCallStackChangeScheduler: RunOnceScheduler;
I
isidor 已提交
84 85 86
	private needsRefresh = false;
	private ignoreSelectionChangedEvent = false;
	private ignoreFocusStackFrameEvent = false;
87
	private callStackItemType: IContextKey<string>;
I
isidor 已提交
88 89
	private dataSource!: CallStackDataSource;
	private tree!: WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>;
90
	private menu: IMenu;
I
isidor 已提交
91
	private parentSessionToExpand = new Set<IDebugSession>();
I
isidor 已提交
92
	private selectionNeedsUpdate = false;
I
isidor 已提交
93 94 95 96

	constructor(
		private options: IViewletViewOptions,
		@IContextMenuService contextMenuService: IContextMenuService,
97
		@IDebugService private readonly debugService: IDebugService,
I
isidor 已提交
98
		@IKeybindingService keybindingService: IKeybindingService,
99
		@IInstantiationService instantiationService: IInstantiationService,
100
		@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
101
		@IEditorService private readonly editorService: IEditorService,
102
		@IConfigurationService configurationService: IConfigurationService,
I
isidor 已提交
103
		@IMenuService menuService: IMenuService,
104
		@IContextKeyService readonly contextKeyService: IContextKeyService,
105 106
		@IOpenerService openerService: IOpenerService,
		@IThemeService themeService: IThemeService,
107
		@ITelemetryService telemetryService: ITelemetryService,
I
isidor 已提交
108
	) {
109
		super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
110
		this.callStackItemType = CONTEXT_CALLSTACK_ITEM_TYPE.bindTo(contextKeyService);
I
isidor 已提交
111

112 113
		this.menu = menuService.createMenu(MenuId.DebugCallStackContext, contextKeyService);
		this._register(this.menu);
I
isidor 已提交
114

I
isidor 已提交
115 116 117 118
		// Create scheduler to prevent unnecessary flashing of tree when reacting to changes
		this.onCallStackChangeScheduler = new RunOnceScheduler(() => {
			// Only show the global pause message if we do not display threads.
			// Otherwise there will be a pause message per thread and there is no need for a global one.
I
isidor 已提交
119
			const sessions = this.debugService.getModel().getSessions();
I
isidor 已提交
120 121
			const thread = sessions.length === 1 && sessions[0].getAllThreads().length === 1 ? sessions[0].getAllThreads()[0] : undefined;
			if (thread && thread.stoppedDetails) {
I
isidor 已提交
122 123
				this.pauseMessageLabel.textContent = thread.stoppedDetails.description || nls.localize('debugStopped', "Paused on {0}", thread.stoppedDetails.reason || '');
				this.pauseMessageLabel.title = thread.stoppedDetails.text || '';
I
isidor 已提交
124
				dom.toggleClass(this.pauseMessageLabel, 'exception', thread.stoppedDetails.reason === 'exception');
125
				this.pauseMessage.hidden = false;
I
isidor 已提交
126
				this.updateActions();
I
isidor 已提交
127

I
isidor 已提交
128
			} else {
129
				this.pauseMessage.hidden = true;
I
isidor 已提交
130
				this.updateActions();
I
isidor 已提交
131 132
			}

133
			this.needsRefresh = false;
I
isidor 已提交
134
			this.dataSource.deemphasizedStackFramesToShow = [];
I
isidor 已提交
135
			this.tree.updateChildren().then(() => {
I
isidor 已提交
136 137 138 139 140
				try {
					this.parentSessionToExpand.forEach(s => this.tree.expand(s));
				} catch (e) {
					// Ignore tree expand errors if element no longer present
				}
I
isidor 已提交
141
				this.parentSessionToExpand.clear();
I
isidor 已提交
142 143 144 145
				if (this.selectionNeedsUpdate) {
					this.selectionNeedsUpdate = false;
					this.updateTreeSelection();
				}
I
isidor 已提交
146
			});
I
isidor 已提交
147 148 149
		}, 50);
	}

J
Jackson Kearl 已提交
150
	protected renderHeaderTitle(container: HTMLElement): void {
I
isidor 已提交
151
		const titleContainer = dom.append(container, $('.debug-call-stack-title'));
J
Jackson Kearl 已提交
152 153 154
		super.renderHeaderTitle(titleContainer, this.options.title);

		this.pauseMessage = dom.append(titleContainer, $('span.pause-message'));
155 156
		this.pauseMessage.hidden = true;
		this.pauseMessageLabel = dom.append(this.pauseMessage, $('span.label'));
I
isidor 已提交
157 158
	}

I
isidor 已提交
159 160
	getActions(): IAction[] {
		if (this.pauseMessage.hidden) {
I
isidor 已提交
161
			return [new CollapseAction(() => this.tree, true, 'explorer-action codicon-collapse-all')];
I
isidor 已提交
162 163 164 165 166
		}

		return [];
	}

I
isidor 已提交
167
	renderBody(container: HTMLElement): void {
J
Joao Moreno 已提交
168
		super.renderBody(container);
I
isidor 已提交
169
		dom.addClass(this.element, 'debug-pane');
I
isidor 已提交
170
		dom.addClass(container, 'debug-call-stack');
I
isidor 已提交
171 172
		const treeContainer = renderViewTree(container);

I
isidor 已提交
173
		this.dataSource = new CallStackDataSource(this.debugService);
174
		this.tree = <WorkbenchAsyncDataTree<CallStackItem | IDebugModel, CallStackItem, FuzzyScore>>this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CallStackView', treeContainer, new CallStackDelegate(), [
175
			new SessionsRenderer(this.menu, this.instantiationService, this.debugService),
176
			new ThreadsRenderer(this.instantiationService),
I
isidor 已提交
177 178
			this.instantiationService.createInstance(StackFramesRenderer),
			new ErrorsRenderer(),
I
isidor 已提交
179 180
			new LoadMoreRenderer(this.themeService),
			new ShowMoreRenderer(this.themeService)
I
isidor 已提交
181
		], this.dataSource, {
M
Matt Bierner 已提交
182 183 184 185 186
			accessibilityProvider: new CallStackAccessibilityProvider(),
			identityProvider: {
				getId: (element: CallStackItem) => {
					if (typeof element === 'string') {
						return element;
187
					}
M
Matt Bierner 已提交
188 189
					if (element instanceof Array) {
						return `showMore ${element[0].getId()}`;
I
isidor 已提交
190
					}
M
Matt Bierner 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212

					return element.getId();
				}
			},
			keyboardNavigationLabelProvider: {
				getKeyboardNavigationLabel: (e: CallStackItem) => {
					if (isDebugSession(e)) {
						return e.getLabel();
					}
					if (e instanceof Thread) {
						return `${e.name} ${e.stateLabel}`;
					}
					if (e instanceof StackFrame || typeof e === 'string') {
						return e;
					}
					if (e instanceof ThreadAndSessionIds) {
						return LoadMoreRenderer.LABEL;
					}

					return nls.localize('showMoreStackFrames2', "Show More Stack Frames");
				}
			},
213 214
			expandOnlyOnTwistieClick: true,
			overrideStyles: {
S
SteVen Batten 已提交
215
				listBackground: this.getBackgroundColor()
216
			}
M
Matt Bierner 已提交
217
		});
I
isidor 已提交
218

219
		this.tree.setInput(this.debugService.getModel());
J
Joao Moreno 已提交
220

J
João Moreno 已提交
221
		const callstackNavigator = new TreeResourceNavigator(this.tree);
M
Matt Bierner 已提交
222 223
		this._register(callstackNavigator);
		this._register(callstackNavigator.onDidOpenResource(e => {
I
isidor 已提交
224 225 226 227
			if (this.ignoreSelectionChangedEvent) {
				return;
			}

I
isidor 已提交
228
			const focusStackFrame = (stackFrame: IStackFrame | undefined, thread: IThread | undefined, session: IDebugSession) => {
I
isidor 已提交
229 230 231 232 233 234 235 236
				this.ignoreFocusStackFrameEvent = true;
				try {
					this.debugService.focusStackFrame(stackFrame, thread, session, true);
				} finally {
					this.ignoreFocusStackFrameEvent = false;
				}
			};

I
isidor 已提交
237 238
			const element = e.element;
			if (element instanceof StackFrame) {
I
isidor 已提交
239
				focusStackFrame(element, element.thread, element.thread.session);
I
isidor 已提交
240 241 242
				element.openInEditor(this.editorService, e.editorOptions.preserveFocus, e.sideBySide, e.editorOptions.pinned);
			}
			if (element instanceof Thread) {
I
isidor 已提交
243
				focusStackFrame(undefined, element, element.session);
I
isidor 已提交
244
			}
I
isidor 已提交
245
			if (isDebugSession(element)) {
I
isidor 已提交
246
				focusStackFrame(undefined, undefined, element);
I
isidor 已提交
247 248
			}
			if (element instanceof ThreadAndSessionIds) {
249
				const session = this.debugService.getModel().getSession(element.sessionId);
I
isidor 已提交
250 251 252
				const thread = session && session.getThread(element.threadId);
				if (thread) {
					(<Thread>thread).fetchCallStack()
253
						.then(() => this.tree.updateChildren());
I
isidor 已提交
254 255 256 257
				}
			}
			if (element instanceof Array) {
				this.dataSource.deemphasizedStackFramesToShow.push(...element);
258
				this.tree.updateChildren();
I
isidor 已提交
259 260
			}
		}));
I
isidor 已提交
261

M
Matt Bierner 已提交
262
		this._register(this.debugService.getModel().onDidChangeCallStack(() => {
263
			if (!this.isBodyVisible()) {
264 265 266 267
				this.needsRefresh = true;
				return;
			}

I
isidor 已提交
268 269 270 271
			if (!this.onCallStackChangeScheduler.isScheduled()) {
				this.onCallStackChangeScheduler.schedule();
			}
		}));
I
isidor 已提交
272 273
		const onFocusChange = Event.any<any>(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession);
		this._register(onFocusChange(() => {
I
isidor 已提交
274 275 276
			if (this.ignoreFocusStackFrameEvent) {
				return;
			}
277
			if (!this.isBodyVisible()) {
278 279 280
				this.needsRefresh = true;
				return;
			}
I
isidor 已提交
281 282 283 284
			if (this.onCallStackChangeScheduler.isScheduled()) {
				this.selectionNeedsUpdate = true;
				return;
			}
285

286
			this.updateTreeSelection();
287
		}));
M
Matt Bierner 已提交
288
		this._register(this.tree.onContextMenu(e => this.onContextMenu(e)));
I
isidor 已提交
289 290 291

		// Schedule the update of the call stack tree if the viewlet is opened after a session started #14684
		if (this.debugService.state === State.Stopped) {
I
isidor 已提交
292
			this.onCallStackChangeScheduler.schedule(0);
I
isidor 已提交
293
		}
294

M
Matt Bierner 已提交
295
		this._register(this.onDidChangeBodyVisibility(visible => {
296 297 298 299
			if (visible && this.needsRefresh) {
				this.onCallStackChangeScheduler.schedule();
			}
		}));
I
isidor 已提交
300

M
Matt Bierner 已提交
301
		this._register(this.debugService.onDidNewSession(s => {
302
			this._register(s.onDidChangeName(() => this.tree.rerender(s)));
I
isidor 已提交
303 304 305 306 307
			if (s.parentSession) {
				// Auto expand sessions that have sub sessions
				this.parentSessionToExpand.add(s.parentSession);
			}
		}));
I
isidor 已提交
308 309
	}

310
	layoutBody(height: number, width: number): void {
J
João Moreno 已提交
311
		super.layoutBody(height, width);
312
		this.tree.layout(height, width);
S
Sandeep Somavarapu 已提交
313 314
	}

I
isidor 已提交
315 316 317 318
	focus(): void {
		this.tree.domFocus();
	}

I
isidor 已提交
319
	private updateTreeSelection(): void {
I
isidor 已提交
320
		if (!this.tree || !this.tree.getInput()) {
I
isidor 已提交
321
			// Tree not initialized yet
I
isidor 已提交
322
			return;
I
isidor 已提交
323 324
		}

I
isidor 已提交
325
		const updateSelectionAndReveal = (element: IStackFrame | IDebugSession) => {
326 327 328
			this.ignoreSelectionChangedEvent = true;
			try {
				this.tree.setSelection([element]);
329 330 331 332 333 334 335
				// If the element is outside of the screen bounds,
				// position it in the middle
				if (this.tree.getRelativeTop(element) === null) {
					this.tree.reveal(element, 0.5);
				} else {
					this.tree.reveal(element);
				}
I
isidor 已提交
336 337
			} catch (e) { }
			finally {
338 339 340 341
				this.ignoreSelectionChangedEvent = false;
			}
		};

I
isidor 已提交
342 343 344
		const thread = this.debugService.getViewModel().focusedThread;
		const session = this.debugService.getViewModel().focusedSession;
		const stackFrame = this.debugService.getViewModel().focusedStackFrame;
I
isidor 已提交
345
		if (!thread) {
I
isidor 已提交
346
			if (!session) {
I
isidor 已提交
347 348
				this.tree.setSelection([]);
			} else {
I
isidor 已提交
349
				updateSelectionAndReveal(session);
I
isidor 已提交
350
			}
I
isidor 已提交
351
		} else {
I
isidor 已提交
352 353 354 355 356 357
			const expandPromises = [() => ignoreErrors(this.tree.expand(thread))];
			let s: IDebugSession | undefined = thread.session;
			while (s) {
				const sessionToExpand = s;
				expandPromises.push(() => ignoreErrors(this.tree.expand(sessionToExpand)));
				s = s.parentSession;
I
isidor 已提交
358
			}
I
isidor 已提交
359 360 361 362 363 364 365

			sequence(expandPromises.reverse()).then(() => {
				const toReveal = stackFrame || session;
				if (toReveal) {
					updateSelectionAndReveal(toReveal);
				}
			});
I
isidor 已提交
366
		}
I
isidor 已提交
367 368
	}

I
isidor 已提交
369 370
	private onContextMenu(e: ITreeContextMenuEvent<CallStackItem>): void {
		const element = e.element;
I
isidor 已提交
371
		if (isDebugSession(element)) {
I
isidor 已提交
372
			this.callStackItemType.set('session');
373
		} else if (element instanceof Thread) {
I
isidor 已提交
374
			this.callStackItemType.set('thread');
375
		} else if (element instanceof StackFrame) {
I
isidor 已提交
376 377 378
			this.callStackItemType.set('stackFrame');
		} else {
			this.callStackItemType.reset();
379 380
		}

381 382 383 384 385

		const primary: IAction[] = [];
		const secondary: IAction[] = [];
		const result = { primary, secondary };
		const actionsDisposable = createAndFillInContextMenuActions(this.menu, { arg: getContextForContributedActions(element), shouldForwardArgs: true }, result, this.contextMenuService, g => g === 'inline');
386

I
isidor 已提交
387 388
		this.contextMenuService.showContextMenu({
			getAnchor: () => e.anchor,
389
			getActions: () => result.secondary,
I
isidor 已提交
390
			getActionsContext: () => getContext(element),
391
			onHide: () => dispose(actionsDisposable)
I
isidor 已提交
392
		});
393 394 395 396 397 398 399 400
	}
}

interface IThreadTemplateData {
	thread: HTMLElement;
	name: HTMLElement;
	state: HTMLElement;
	stateLabel: HTMLSpanElement;
I
isidor 已提交
401
	label: HighlightedLabel;
402
	actionBar: ActionBar;
403 404
}

I
isidor 已提交
405 406
interface ISessionTemplateData {
	session: HTMLElement;
407 408 409
	name: HTMLElement;
	state: HTMLElement;
	stateLabel: HTMLSpanElement;
I
isidor 已提交
410
	label: HighlightedLabel;
411
	actionBar: ActionBar;
412
	elementDisposable: IDisposable[];
413 414 415 416 417 418
}

interface IErrorTemplateData {
	label: HTMLElement;
}

I
isidor 已提交
419
interface ILabelTemplateData {
420
	label: HTMLElement;
I
isidor 已提交
421
	toDispose: IDisposable;
422 423 424 425 426 427 428
}

interface IStackFrameTemplateData {
	stackFrame: HTMLElement;
	file: HTMLElement;
	fileName: HTMLElement;
	lineNumber: HTMLElement;
I
isidor 已提交
429
	label: HighlightedLabel;
I
isidor 已提交
430
	actionBar: ActionBar;
431 432
}

I
isidor 已提交
433
class SessionsRenderer implements ITreeRenderer<IDebugSession, FuzzyScore, ISessionTemplateData> {
I
isidor 已提交
434
	static readonly ID = 'session';
435

436
	constructor(
437
		private menu: IMenu,
I
isidor 已提交
438 439
		private readonly instantiationService: IInstantiationService,
		private readonly debugService: IDebugService
440 441
	) { }

I
isidor 已提交
442 443
	get templateId(): string {
		return SessionsRenderer.ID;
444 445
	}

I
isidor 已提交
446
	renderTemplate(container: HTMLElement): ISessionTemplateData {
447
		const session = dom.append(container, $('.session'));
I
isidor 已提交
448
		dom.append(session, $('.codicon.codicon-bug'));
449 450 451 452
		const name = dom.append(session, $('.name'));
		const state = dom.append(session, $('.state'));
		const stateLabel = dom.append(state, $('span.label'));
		const label = new HighlightedLabel(name, false);
453
		const actionBar = new ActionBar(session);
454

455
		return { session, name, state, stateLabel, label, actionBar, elementDisposable: [] };
456 457
	}

458
	renderElement(element: ITreeNode<IDebugSession, FuzzyScore>, _: number, data: ISessionTemplateData): void {
I
isidor 已提交
459 460
		const session = element.element;
		data.session.title = nls.localize({ key: 'session', comment: ['Session is a noun'] }, "Session");
I
isidor 已提交
461
		data.label.set(session.getLabel(), createMatches(element.filterData));
I
isidor 已提交
462
		const thread = session.getAllThreads().filter(t => t.stopped).pop();
463

464 465 466
		const setActionBar = () => {
			data.actionBar.clear();
			const actions = getActions(this.instantiationService, element.element);
467

468 469 470 471
			const primary: IAction[] = actions;
			const secondary: IAction[] = [];
			const result = { primary, secondary };
			data.elementDisposable.push(createAndFillInActionBarActions(this.menu, { arg: getContextForContributedActions(session), shouldForwardArgs: true }, result, g => g === 'inline'));
472

I
isidor 已提交
473
			data.actionBar.push(primary, { icon: true, label: false });
474 475 476
		};
		setActionBar();
		data.elementDisposable.push(this.menu.onDidChange(() => setActionBar()));
I
isidor 已提交
477
		data.stateLabel.hidden = false;
478

I
isidor 已提交
479 480 481 482 483 484 485 486 487 488
		if (thread && thread.stoppedDetails) {
			data.stateLabel.textContent = thread.stoppedDetails.description || nls.localize('debugStopped', "Paused on {0}", thread.stoppedDetails.reason || '');
		} else {
			const hasChildSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === session).length > 0;
			if (!hasChildSessions) {
				data.stateLabel.textContent = nls.localize({ key: 'running', comment: ['indicates state'] }, "Running");
			} else {
				data.stateLabel.hidden = true;
			}
		}
I
isidor 已提交
489
	}
490

I
isidor 已提交
491
	disposeTemplate(templateData: ISessionTemplateData): void {
492
		templateData.actionBar.dispose();
493
	}
494 495

	disposeElement(_element: ITreeNode<IDebugSession, FuzzyScore>, _: number, templateData: ISessionTemplateData): void {
496
		dispose(templateData.elementDisposable);
497
	}
I
isidor 已提交
498
}
499

I
isidor 已提交
500
class ThreadsRenderer implements ITreeRenderer<IThread, FuzzyScore, IThreadTemplateData> {
I
isidor 已提交
501 502
	static readonly ID = 'thread';

503 504
	constructor(private readonly instantiationService: IInstantiationService) { }

I
isidor 已提交
505 506
	get templateId(): string {
		return ThreadsRenderer.ID;
507 508
	}

I
isidor 已提交
509
	renderTemplate(container: HTMLElement): IThreadTemplateData {
510 511 512 513 514
		const thread = dom.append(container, $('.thread'));
		const name = dom.append(thread, $('.name'));
		const state = dom.append(thread, $('.state'));
		const stateLabel = dom.append(state, $('span.label'));
		const label = new HighlightedLabel(name, false);
515
		const actionBar = new ActionBar(thread);
516

517
		return { thread, name, state, stateLabel, label, actionBar };
518 519
	}

I
isidor 已提交
520
	renderElement(element: ITreeNode<IThread, FuzzyScore>, index: number, data: IThreadTemplateData): void {
I
isidor 已提交
521
		const thread = element.element;
522
		data.thread.title = nls.localize('thread', "Thread");
I
isidor 已提交
523
		data.label.set(thread.name, createMatches(element.filterData));
524
		data.stateLabel.textContent = thread.stateLabel;
525 526 527 528

		data.actionBar.clear();
		const actions = getActions(this.instantiationService, thread);
		data.actionBar.push(actions, { icon: true, label: false });
529 530
	}

I
isidor 已提交
531
	disposeTemplate(templateData: IThreadTemplateData): void {
532
		templateData.actionBar.dispose();
533
	}
I
isidor 已提交
534
}
535

I
isidor 已提交
536
class StackFramesRenderer implements ITreeRenderer<IStackFrame, FuzzyScore, IStackFrameTemplateData> {
I
isidor 已提交
537 538
	static readonly ID = 'stackFrame';

539
	constructor(@ILabelService private readonly labelService: ILabelService) { }
I
isidor 已提交
540 541 542 543 544 545

	get templateId(): string {
		return StackFramesRenderer.ID;
	}

	renderTemplate(container: HTMLElement): IStackFrameTemplateData {
546 547 548 549 550 551 552
		const stackFrame = dom.append(container, $('.stack-frame'));
		const labelDiv = dom.append(stackFrame, $('span.label.expression'));
		const file = dom.append(stackFrame, $('.file'));
		const fileName = dom.append(file, $('span.file-name'));
		const wrapper = dom.append(file, $('span.line-number-wrapper'));
		const lineNumber = dom.append(wrapper, $('span.line-number'));
		const label = new HighlightedLabel(labelDiv, false);
I
isidor 已提交
553
		const actionBar = new ActionBar(stackFrame);
I
isidor 已提交
554

I
isidor 已提交
555
		return { file, fileName, label, lineNumber, stackFrame, actionBar };
I
isidor 已提交
556 557
	}

I
isidor 已提交
558
	renderElement(element: ITreeNode<IStackFrame, FuzzyScore>, index: number, data: IStackFrameTemplateData): void {
I
isidor 已提交
559
		const stackFrame = element.element;
I
isidor 已提交
560 561 562
		dom.toggleClass(data.stackFrame, 'disabled', !stackFrame.source || !stackFrame.source.available || isDeemphasized(stackFrame));
		dom.toggleClass(data.stackFrame, 'label', stackFrame.presentationHint === 'label');
		dom.toggleClass(data.stackFrame, 'subtle', stackFrame.presentationHint === 'subtle');
I
isidor 已提交
563
		const hasActions = !!stackFrame.thread.session.capabilities.supportsRestartFrame && stackFrame.presentationHint !== 'label' && stackFrame.presentationHint !== 'subtle';
I
isidor 已提交
564
		dom.toggleClass(data.stackFrame, 'has-actions', hasActions);
565

I
isidor 已提交
566
		data.file.title = stackFrame.source.inMemory ? stackFrame.source.uri.path : this.labelService.getUriLabel(stackFrame.source.uri);
567 568 569
		if (stackFrame.source.raw.origin) {
			data.file.title += `\n${stackFrame.source.raw.origin}`;
		}
I
isidor 已提交
570
		data.label.set(stackFrame.name, createMatches(element.filterData), stackFrame.name);
I
isidor 已提交
571
		data.fileName.textContent = stackFrame.getSpecificSourceName();
572 573 574 575 576 577 578 579 580
		if (stackFrame.range.startLineNumber !== undefined) {
			data.lineNumber.textContent = `${stackFrame.range.startLineNumber}`;
			if (stackFrame.range.startColumn) {
				data.lineNumber.textContent += `:${stackFrame.range.startColumn}`;
			}
			dom.removeClass(data.lineNumber, 'unavailable');
		} else {
			dom.addClass(data.lineNumber, 'unavailable');
		}
I
isidor 已提交
581 582 583

		data.actionBar.clear();
		if (hasActions) {
584
			const action = new Action('debug.callStack.restartFrame', nls.localize('restartFrame', "Restart Frame"), 'codicon-debug-restart-frame', true, () => {
I
isidor 已提交
585 586 587 588
				return stackFrame.restart();
			});
			data.actionBar.push(action, { icon: true, label: false });
		}
589 590
	}

I
isidor 已提交
591
	disposeTemplate(templateData: IStackFrameTemplateData): void {
I
isidor 已提交
592
		templateData.actionBar.dispose();
I
isidor 已提交
593 594 595
	}
}

I
isidor 已提交
596
class ErrorsRenderer implements ITreeRenderer<string, FuzzyScore, IErrorTemplateData> {
I
isidor 已提交
597 598 599 600 601 602 603
	static readonly ID = 'error';

	get templateId(): string {
		return ErrorsRenderer.ID;
	}

	renderTemplate(container: HTMLElement): IErrorTemplateData {
604
		const label = dom.append(container, $('.error'));
I
isidor 已提交
605

606
		return { label };
I
isidor 已提交
607 608
	}

I
isidor 已提交
609
	renderElement(element: ITreeNode<string, FuzzyScore>, index: number, data: IErrorTemplateData): void {
I
isidor 已提交
610 611 612 613 614 615 616 617 618 619
		const error = element.element;
		data.label.textContent = error;
		data.label.title = error;
	}

	disposeTemplate(templateData: IErrorTemplateData): void {
		// noop
	}
}

I
isidor 已提交
620
class LoadMoreRenderer implements ITreeRenderer<ThreadAndSessionIds, FuzzyScore, ILabelTemplateData> {
I
isidor 已提交
621
	static readonly ID = 'loadMore';
I
isidor 已提交
622
	static readonly LABEL = nls.localize('loadMoreStackFrames', "Load More Stack Frames");
I
isidor 已提交
623

I
isidor 已提交
624 625
	constructor(private readonly themeService: IThemeService) { }

I
isidor 已提交
626 627 628 629
	get templateId(): string {
		return LoadMoreRenderer.ID;
	}

I
isidor 已提交
630
	renderTemplate(container: HTMLElement): ILabelTemplateData {
631
		const label = dom.append(container, $('.load-more'));
I
isidor 已提交
632 633 634 635 636
		const toDispose = attachStylerCallback(this.themeService, { textLinkForeground }, colors => {
			if (colors.textLinkForeground) {
				label.style.color = colors.textLinkForeground.toString();
			}
		});
I
isidor 已提交
637

I
isidor 已提交
638
		return { label, toDispose };
I
isidor 已提交
639 640
	}

I
isidor 已提交
641
	renderElement(element: ITreeNode<ThreadAndSessionIds, FuzzyScore>, index: number, data: ILabelTemplateData): void {
I
isidor 已提交
642
		data.label.textContent = LoadMoreRenderer.LABEL;
I
isidor 已提交
643 644 645
	}

	disposeTemplate(templateData: ILabelTemplateData): void {
I
isidor 已提交
646
		templateData.toDispose.dispose();
I
isidor 已提交
647 648 649
	}
}

I
isidor 已提交
650
class ShowMoreRenderer implements ITreeRenderer<IStackFrame[], FuzzyScore, ILabelTemplateData> {
I
isidor 已提交
651 652
	static readonly ID = 'showMore';

I
isidor 已提交
653 654 655
	constructor(private readonly themeService: IThemeService) { }


I
isidor 已提交
656 657 658 659
	get templateId(): string {
		return ShowMoreRenderer.ID;
	}

I
isidor 已提交
660
	renderTemplate(container: HTMLElement): ILabelTemplateData {
661
		const label = dom.append(container, $('.show-more'));
I
isidor 已提交
662 663 664 665 666
		const toDispose = attachStylerCallback(this.themeService, { textLinkForeground }, colors => {
			if (colors.textLinkForeground) {
				label.style.color = colors.textLinkForeground.toString();
			}
		});
I
isidor 已提交
667

I
isidor 已提交
668
		return { label, toDispose };
I
isidor 已提交
669 670
	}

I
isidor 已提交
671
	renderElement(element: ITreeNode<IStackFrame[], FuzzyScore>, index: number, data: ILabelTemplateData): void {
I
isidor 已提交
672
		const stackFrames = element.element;
673
		if (stackFrames.every(sf => !!(sf.source && sf.source.origin && sf.source.origin === stackFrames[0].source.origin))) {
I
isidor 已提交
674 675 676 677 678 679 680
			data.label.textContent = nls.localize('showMoreAndOrigin', "Show {0} More: {1}", stackFrames.length, stackFrames[0].source.origin);
		} else {
			data.label.textContent = nls.localize('showMoreStackFrames', "Show {0} More Stack Frames", stackFrames.length);
		}
	}

	disposeTemplate(templateData: ILabelTemplateData): void {
I
isidor 已提交
681
		templateData.toDispose.dispose();
682 683 684
	}
}

I
isidor 已提交
685 686 687
class CallStackDelegate implements IListVirtualDelegate<CallStackItem> {

	getHeight(element: CallStackItem): number {
688
		if (element instanceof StackFrame && element.presentationHint === 'label') {
I
isidor 已提交
689
			return 16;
690 691
		}
		if (element instanceof ThreadAndSessionIds || element instanceof Array) {
I
isidor 已提交
692
			return 16;
693
		}
694

I
isidor 已提交
695 696 697 698
		return 22;
	}

	getTemplateId(element: CallStackItem): string {
I
isidor 已提交
699
		if (isDebugSession(element)) {
I
isidor 已提交
700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
			return SessionsRenderer.ID;
		}
		if (element instanceof Thread) {
			return ThreadsRenderer.ID;
		}
		if (element instanceof StackFrame) {
			return StackFramesRenderer.ID;
		}
		if (typeof element === 'string') {
			return ErrorsRenderer.ID;
		}
		if (element instanceof ThreadAndSessionIds) {
			return LoadMoreRenderer.ID;
		}

I
isidor 已提交
715 716
		// element instanceof Array
		return ShowMoreRenderer.ID;
I
isidor 已提交
717 718 719
	}
}

J
Joao Moreno 已提交
720 721 722
function isDebugModel(obj: any): obj is IDebugModel {
	return typeof obj.getSessions === 'function';
}
I
isidor 已提交
723

I
isidor 已提交
724
function isDebugSession(obj: any): obj is IDebugSession {
I
isidor 已提交
725
	return obj && typeof obj.getAllThreads === 'function';
I
isidor 已提交
726 727
}

728 729 730 731
function isDeemphasized(frame: IStackFrame): boolean {
	return frame.source.presentationHint === 'deemphasize' || frame.presentationHint === 'deemphasize';
}

J
Joao Moreno 已提交
732
class CallStackDataSource implements IAsyncDataSource<IDebugModel, CallStackItem> {
I
isidor 已提交
733
	deemphasizedStackFramesToShow: IStackFrame[] = [];
I
isidor 已提交
734

I
isidor 已提交
735 736
	constructor(private debugService: IDebugService) { }

J
Joao Moreno 已提交
737
	hasChildren(element: IDebugModel | CallStackItem): boolean {
738 739 740 741 742 743
		if (isDebugSession(element)) {
			const threads = element.getAllThreads();
			return (threads.length > 1) || (threads.length === 1 && threads[0].stopped) || (this.debugService.getModel().getSessions().filter(s => s.parentSession === element).length > 0);
		}

		return isDebugModel(element) || (element instanceof Thread && element.stopped);
I
isidor 已提交
744 745
	}

746
	async getChildren(element: IDebugModel | CallStackItem): Promise<CallStackItem[]> {
J
Joao Moreno 已提交
747 748
		if (isDebugModel(element)) {
			const sessions = element.getSessions();
749 750 751
			if (sessions.length === 0) {
				return Promise.resolve([]);
			}
752
			if (sessions.length > 1 || this.debugService.getViewModel().isMultiSessionView()) {
I
isidor 已提交
753
				return Promise.resolve(sessions.filter(s => !s.parentSession));
I
isidor 已提交
754 755 756 757 758
			}

			const threads = sessions[0].getAllThreads();
			// Only show the threads in the call stack if there is more than 1 thread.
			return threads.length === 1 ? this.getThreadChildren(<Thread>threads[0]) : Promise.resolve(threads);
I
isidor 已提交
759
		} else if (isDebugSession(element)) {
I
isidor 已提交
760
			const childSessions = this.debugService.getModel().getSessions().filter(s => s.parentSession === element);
I
isidor 已提交
761
			const threads: CallStackItem[] = element.getAllThreads();
762
			if (threads.length === 1) {
763
				// Do not show thread when there is only one to be compact.
764 765
				const children = await this.getThreadChildren(<Thread>threads[0]);
				return children.concat(childSessions);
766
			}
I
isidor 已提交
767

I
isidor 已提交
768
			return Promise.resolve(threads.concat(childSessions));
J
Joao Moreno 已提交
769 770
		} else {
			return this.getThreadChildren(<Thread>element);
I
isidor 已提交
771 772 773
		}
	}

I
isidor 已提交
774
	private getThreadChildren(thread: Thread): Promise<CallStackItem[]> {
I
isidor 已提交
775 776
		return this.getThreadCallstack(thread).then(children => {
			// Check if some stack frames should be hidden under a parent element since they are deemphasized
I
isidor 已提交
777
			const result: CallStackItem[] = [];
I
isidor 已提交
778
			children.forEach((child, index) => {
779
				if (child instanceof StackFrame && child.source && isDeemphasized(child)) {
I
isidor 已提交
780 781
					// Check if the user clicked to show the deemphasized source
					if (this.deemphasizedStackFramesToShow.indexOf(child) === -1) {
I
isidor 已提交
782 783 784 785 786 787 788
						if (result.length) {
							const last = result[result.length - 1];
							if (last instanceof Array) {
								// Collect all the stackframes that will be "collapsed"
								last.push(child);
								return;
							}
I
isidor 已提交
789 790 791
						}

						const nextChild = index < children.length - 1 ? children[index + 1] : undefined;
792
						if (nextChild instanceof StackFrame && nextChild.source && isDeemphasized(nextChild)) {
I
isidor 已提交
793 794 795 796 797 798 799 800 801 802 803 804 805 806
							// Start collecting stackframes that will be "collapsed"
							result.push([child]);
							return;
						}
					}
				}

				result.push(child);
			});

			return result;
		});
	}

807
	private getThreadCallstack(thread: Thread): Promise<Array<IStackFrame | string | ThreadAndSessionIds>> {
I
isidor 已提交
808 809 810 811 812 813 814
		let callStack: any[] = thread.getCallStack();
		let callStackPromise: Promise<any> = Promise.resolve(null);
		if (!callStack || !callStack.length) {
			callStackPromise = thread.fetchCallStack().then(() => callStack = thread.getCallStack());
		}

		return callStackPromise.then(() => {
I
isidor 已提交
815
			if (callStack.length === 1 && thread.session.capabilities.supportsDelayedStackTraceLoading && thread.stoppedDetails && thread.stoppedDetails.totalFrames && thread.stoppedDetails.totalFrames > 1) {
I
isidor 已提交
816 817 818 819 820 821 822 823
				// To reduce flashing of the call stack view simply append the stale call stack
				// once we have the correct data the tree will refresh and we will no longer display it.
				callStack = callStack.concat(thread.getStaleCallStack().slice(1));
			}

			if (thread.stoppedDetails && thread.stoppedDetails.framesErrorMessage) {
				callStack = callStack.concat([thread.stoppedDetails.framesErrorMessage]);
			}
I
isidor 已提交
824
			if (thread.stoppedDetails && thread.stoppedDetails.totalFrames && thread.stoppedDetails.totalFrames > callStack.length && callStack.length > 1) {
I
isidor 已提交
825 826 827 828 829 830 831 832
				callStack = callStack.concat([new ThreadAndSessionIds(thread.session.getId(), thread.threadId)]);
			}

			return callStack;
		});
	}
}

J
João Moreno 已提交
833
class CallStackAccessibilityProvider implements IListAccessibilityProvider<CallStackItem> {
834 835 836 837 838

	getWidgetAriaLabel(): string {
		return nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'callStackAriaLabel' }, "Debug Call Stack");
	}

I
isidor 已提交
839
	getAriaLabel(element: CallStackItem): string {
840 841 842 843
		if (element instanceof Thread) {
			return nls.localize('threadAriaLabel', "Thread {0}, callstack, debug", (<Thread>element).name);
		}
		if (element instanceof StackFrame) {
I
isidor 已提交
844
			return nls.localize('stackFrameAriaLabel', "Stack Frame {0} line {1} {2}, callstack, debug", element.name, element.range.startLineNumber, element.getSpecificSourceName());
845
		}
I
isidor 已提交
846
		if (isDebugSession(element)) {
I
isidor 已提交
847 848 849 850 851 852 853 854
			return nls.localize('sessionLabel', "Debug Session {0}", element.getLabel());
		}
		if (typeof element === 'string') {
			return element;
		}
		if (element instanceof Array) {
			return nls.localize('showMoreStackFrames', "Show {0} More Stack Frames", element.length);
		}
855

I
isidor 已提交
856 857
		// element instanceof ThreadAndSessionIds
		return nls.localize('loadMoreStackFrames', "Load More Stack Frames");
858 859
	}
}
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898

function getActions(instantiationService: IInstantiationService, element: IDebugSession | IThread): IAction[] {
	const getThreadActions = (thread: IThread): IAction[] => {
		return [
			thread.stopped ? instantiationService.createInstance(ContinueAction, thread) : instantiationService.createInstance(PauseAction, thread),
			instantiationService.createInstance(StepOverAction, thread),
			instantiationService.createInstance(StepIntoAction, thread),
			instantiationService.createInstance(StepOutAction, thread)
		];
	};

	if (element instanceof Thread) {
		return getThreadActions(element);
	}

	const session = <IDebugSession>element;
	const stopOrDisconectAction = isSessionAttach(session) ? instantiationService.createInstance(DisconnectAction, session) : instantiationService.createInstance(StopAction, session);
	const restartAction = instantiationService.createInstance(RestartAction, session);
	const threads = session.getAllThreads();
	if (threads.length === 1) {
		return getThreadActions(threads[0]).concat([
			restartAction,
			stopOrDisconectAction
		]);
	}

	return [
		restartAction,
		stopOrDisconectAction
	];
}


class StopAction extends Action {

	constructor(
		private readonly session: IDebugSession,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
899
		super(`action.${STOP_ID}`, STOP_LABEL, 'debug-action codicon-debug-stop');
900 901 902
	}

	public run(): Promise<any> {
I
isidor 已提交
903
		return this.commandService.executeCommand(STOP_ID, undefined, getContext(this.session));
904 905 906 907 908 909 910 911 912
	}
}

class DisconnectAction extends Action {

	constructor(
		private readonly session: IDebugSession,
		@ICommandService private readonly commandService: ICommandService
	) {
I
isidor 已提交
913
		super(`action.${DISCONNECT_ID}`, DISCONNECT_LABEL, 'debug-action codicon-debug-disconnect');
914 915 916
	}

	public run(): Promise<any> {
I
isidor 已提交
917
		return this.commandService.executeCommand(DISCONNECT_ID, undefined, getContext(this.session));
918 919 920 921 922 923 924 925 926
	}
}

class RestartAction extends Action {

	constructor(
		private readonly session: IDebugSession,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
927
		super(`action.${RESTART_SESSION_ID}`, RESTART_LABEL, 'debug-action codicon-debug-restart');
928 929 930
	}

	public run(): Promise<any> {
I
isidor 已提交
931
		return this.commandService.executeCommand(RESTART_SESSION_ID, undefined, getContext(this.session));
932 933 934 935 936 937 938 939 940
	}
}

class StepOverAction extends Action {

	constructor(
		private readonly thread: IThread,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
941
		super(`action.${STEP_OVER_ID}`, STEP_OVER_LABEL, 'debug-action codicon-debug-step-over', thread.stopped);
942 943 944
	}

	public run(): Promise<any> {
I
isidor 已提交
945
		return this.commandService.executeCommand(STEP_OVER_ID, undefined, getContext(this.thread));
946 947 948 949 950 951 952 953 954
	}
}

class StepIntoAction extends Action {

	constructor(
		private readonly thread: IThread,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
955
		super(`action.${STEP_INTO_ID}`, STEP_INTO_LABEL, 'debug-action codicon-debug-step-into', thread.stopped);
956 957 958
	}

	public run(): Promise<any> {
I
isidor 已提交
959
		return this.commandService.executeCommand(STEP_INTO_ID, undefined, getContext(this.thread));
960 961 962 963 964 965 966 967 968
	}
}

class StepOutAction extends Action {

	constructor(
		private readonly thread: IThread,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
969
		super(`action.${STEP_OUT_ID}`, STEP_OUT_LABEL, 'debug-action codicon-debug-step-out', thread.stopped);
970 971 972
	}

	public run(): Promise<any> {
I
isidor 已提交
973
		return this.commandService.executeCommand(STEP_OUT_ID, undefined, getContext(this.thread));
974 975 976 977 978 979 980 981 982
	}
}

class PauseAction extends Action {

	constructor(
		private readonly thread: IThread,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
983
		super(`action.${PAUSE_ID}`, PAUSE_LABEL, 'debug-action codicon-debug-pause', !thread.stopped);
984 985 986
	}

	public run(): Promise<any> {
I
isidor 已提交
987
		return this.commandService.executeCommand(PAUSE_ID, undefined, getContext(this.thread));
988 989 990 991 992 993 994 995 996
	}
}

class ContinueAction extends Action {

	constructor(
		private readonly thread: IThread,
		@ICommandService private readonly commandService: ICommandService
	) {
M
Miguel Solorio 已提交
997
		super(`action.${CONTINUE_ID}`, CONTINUE_LABEL, 'debug-action codicon-debug-continue', thread.stopped);
998 999 1000
	}

	public run(): Promise<any> {
I
isidor 已提交
1001
		return this.commandService.executeCommand(CONTINUE_ID, undefined, getContext(this.thread));
1002 1003
	}
}