debugSession.ts 35.5 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

I
isidor 已提交
6
import { URI } from 'vs/base/common/uri';
7
import * as resources from 'vs/base/common/resources';
I
isidor 已提交
8 9 10
import * as platform from 'vs/base/common/platform';
import severity from 'vs/base/common/severity';
import { Event, Emitter } from 'vs/base/common/event';
I
isidor 已提交
11
import { Position, IPosition } from 'vs/editor/common/core/position';
I
isidor 已提交
12
import * as aria from 'vs/base/browser/ui/aria/aria';
13
import { IDebugSession, IConfig, IThread, IRawModelUpdate, IDebugService, IRawStoppedDetails, State, LoadedSourceEvent, IFunctionBreakpoint, IExceptionBreakpoint, IBreakpoint, IExceptionInfo, AdapterEndEvent, IDebugger, VIEWLET_ID, IDebugConfiguration, IReplElement, IStackFrame, IExpression, IReplElementSource, IDataBreakpoint, IDebugSessionOptions } from 'vs/workbench/contrib/debug/common/debug';
14
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
15
import { mixin } from 'vs/base/common/objects';
16
import { Thread, ExpressionContainer, DebugModel } from 'vs/workbench/contrib/debug/common/debugModel';
A
Andre Weinand 已提交
17
import { RawDebugSession } from 'vs/workbench/contrib/debug/browser/rawDebugSession';
18
import { IProductService } from 'vs/platform/product/common/productService';
I
isidor 已提交
19
import { IWorkspaceFolder, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
I
isidor 已提交
20
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
21
import { RunOnceScheduler, Queue } from 'vs/base/common/async';
I
isidor 已提交
22
import { generateUuid } from 'vs/base/common/uuid';
23
import { IHostService } from 'vs/workbench/services/host/browser/host';
24
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
I
isidor 已提交
25
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
A
Andre Weinand 已提交
26
import { normalizeDriveLetter } from 'vs/base/common/labels';
I
isidor 已提交
27 28
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
29
import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel';
30
import { IOpenerService } from 'vs/platform/opener/common/opener';
31
import { variableSetEmitter } from 'vs/workbench/contrib/debug/browser/variablesView';
I
isidor 已提交
32
import { CancellationTokenSource, CancellationToken } from 'vs/base/common/cancellation';
I
isidor 已提交
33
import { distinct } from 'vs/base/common/arrays';
I
isidor 已提交
34
import { INotificationService } from 'vs/platform/notification/common/notification';
I
isidor 已提交
35
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
I
isidor 已提交
36
import { localize } from 'vs/nls';
I
isidor 已提交
37
import { canceled } from 'vs/base/common/errors';
I
isidor 已提交
38

39
export class DebugSession implements IDebugSession {
40 41

	private _subId: string | undefined;
I
isidor 已提交
42
	private raw: RawDebugSession | undefined;
I
isidor 已提交
43
	private initialized = false;
44
	private _options: IDebugSessionOptions;
A
Andre Weinand 已提交
45

I
isidor 已提交
46 47
	private sources = new Map<string, Source>();
	private threads = new Map<number, Thread>();
I
isidor 已提交
48
	private cancellationMap = new Map<number, CancellationTokenSource[]>();
I
isidor 已提交
49
	private rawListeners: IDisposable[] = [];
I
isidor 已提交
50
	private fetchThreadsScheduler: RunOnceScheduler | undefined;
51
	private repl: ReplModel;
A
Andre Weinand 已提交
52

53
	private readonly _onDidChangeState = new Emitter<void>();
A
Andre Weinand 已提交
54 55
	private readonly _onDidEndAdapter = new Emitter<AdapterEndEvent>();

I
isidor 已提交
56
	private readonly _onDidLoadedSource = new Emitter<LoadedSourceEvent>();
A
Andre Weinand 已提交
57
	private readonly _onDidCustomEvent = new Emitter<DebugProtocol.Event>();
58
	private readonly _onDidProgressStart = new Emitter<DebugProtocol.ProgressStartEvent>();
I
isidor 已提交
59
	private readonly _onDidProgressUpdate = new Emitter<DebugProtocol.ProgressUpdateEvent>();
60
	private readonly _onDidProgressEnd = new Emitter<DebugProtocol.ProgressEndEvent>();
A
Andre Weinand 已提交
61

I
isidor 已提交
62
	private readonly _onDidChangeREPLElements = new Emitter<void>();
63

64 65 66
	private name: string | undefined;
	private readonly _onDidChangeName = new Emitter<string>();

I
isidor 已提交
67
	constructor(
68
		private id: string,
I
isidor 已提交
69
		private _configuration: { resolved: IConfig, unresolved: IConfig | undefined },
I
isidor 已提交
70
		public root: IWorkspaceFolder | undefined,
71
		private model: DebugModel,
72
		options: IDebugSessionOptions | undefined,
73 74
		@IDebugService private readonly debugService: IDebugService,
		@ITelemetryService private readonly telemetryService: ITelemetryService,
75
		@IHostService private readonly hostService: IHostService,
76 77
		@IConfigurationService private readonly configurationService: IConfigurationService,
		@IViewletService private readonly viewletService: IViewletService,
A
Andre Weinand 已提交
78
		@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
A
Andre Weinand 已提交
79
		@IProductService private readonly productService: IProductService,
80
		@IExtensionHostDebugService private readonly extensionHostDebugService: IExtensionHostDebugService,
I
isidor 已提交
81
		@IOpenerService private readonly openerService: IOpenerService,
I
isidor 已提交
82 83
		@INotificationService private readonly notificationService: INotificationService,
		@ILifecycleService lifecycleService: ILifecycleService
I
isidor 已提交
84
	) {
85 86 87 88 89 90
		this._options = options || {};
		if (this.hasSeparateRepl()) {
			this.repl = new ReplModel();
		} else {
			this.repl = (this.parentSession as DebugSession).repl;
		}
I
isidor 已提交
91 92 93

		const toDispose: IDisposable[] = [];
		toDispose.push(this.repl.onDidChangeElements(() => this._onDidChangeREPLElements.fire()));
A
Alex Dima 已提交
94 95 96 97 98 99
		if (lifecycleService) {
			toDispose.push(lifecycleService.onShutdown(() => {
				this.shutdown();
				dispose(toDispose);
			}));
		}
100 101
	}

A
Andre Weinand 已提交
102 103 104 105
	getId(): string {
		return this.id;
	}

106 107 108 109 110 111 112 113
	setSubId(subId: string | undefined) {
		this._subId = subId;
	}

	get subId(): string | undefined {
		return this._subId;
	}

I
isidor 已提交
114
	get configuration(): IConfig {
115 116 117
		return this._configuration.resolved;
	}

I
isidor 已提交
118
	get unresolvedConfiguration(): IConfig | undefined {
119 120 121
		return this._configuration.unresolved;
	}

I
isidor 已提交
122
	get parentSession(): IDebugSession | undefined {
123
		return this._options.parentSession;
I
isidor 已提交
124 125
	}

I
isidor 已提交
126
	setConfiguration(configuration: { resolved: IConfig, unresolved: IConfig | undefined }) {
I
isidor 已提交
127 128 129
		this._configuration = configuration;
	}

I
isidor 已提交
130 131
	getLabel(): string {
		const includeRoot = this.workspaceContextService.getWorkspace().folders.length > 1;
132 133 134 135 136 137 138
		const name = this.name || this.configuration.name;
		return includeRoot && this.root ? `${name} (${resources.basenameOrAuthority(this.root.uri)})` : name;
	}

	setName(name: string): void {
		this.name = name;
		this._onDidChangeName.fire(name);
I
isidor 已提交
139 140 141
	}

	get state(): State {
I
isidor 已提交
142 143 144
		if (!this.initialized) {
			return State.Initializing;
		}
145 146 147 148
		if (!this.raw) {
			return State.Inactive;
		}

149
		const focusedThread = this.debugService.getViewModel().focusedThread;
I
isidor 已提交
150
		if (focusedThread && focusedThread.session === this) {
151 152 153 154
			return focusedThread.stopped ? State.Stopped : State.Running;
		}
		if (this.getAllThreads().some(t => t.stopped)) {
			return State.Stopped;
A
Andre Weinand 已提交
155
		}
156

157
		return State.Running;
A
Andre Weinand 已提交
158 159 160
	}

	get capabilities(): DebugProtocol.Capabilities {
161
		return this.raw ? this.raw.capabilities : Object.create(null);
162 163
	}

A
Andre Weinand 已提交
164
	//---- events
165
	get onDidChangeState(): Event<void> {
I
isidor 已提交
166
		return this._onDidChangeState.event;
167 168
	}

A
Andre Weinand 已提交
169 170 171 172
	get onDidEndAdapter(): Event<AdapterEndEvent> {
		return this._onDidEndAdapter.event;
	}

I
isidor 已提交
173 174 175 176
	get onDidChangeReplElements(): Event<void> {
		return this._onDidChangeREPLElements.event;
	}

177 178 179 180
	get onDidChangeName(): Event<string> {
		return this._onDidChangeName.event;
	}

A
Andre Weinand 已提交
181 182
	//---- DAP events

A
Andre Weinand 已提交
183
	get onDidCustomEvent(): Event<DebugProtocol.Event> {
I
isidor 已提交
184 185 186
		return this._onDidCustomEvent.event;
	}

A
Andre Weinand 已提交
187 188
	get onDidLoadedSource(): Event<LoadedSourceEvent> {
		return this._onDidLoadedSource.event;
189 190
	}

191 192 193 194
	get onDidProgressStart(): Event<DebugProtocol.ProgressStartEvent> {
		return this._onDidProgressStart.event;
	}

I
isidor 已提交
195 196 197 198
	get onDidProgressUpdate(): Event<DebugProtocol.ProgressUpdateEvent> {
		return this._onDidProgressUpdate.event;
	}

199 200 201 202
	get onDidProgressEnd(): Event<DebugProtocol.ProgressEndEvent> {
		return this._onDidProgressEnd.event;
	}

A
Andre Weinand 已提交
203 204 205 206 207
	//---- DAP requests

	/**
	 * create and initialize a new debug adapter for this session
	 */
I
isidor 已提交
208
	async initialize(dbgr: IDebugger): Promise<void> {
209

210
		if (this.raw) {
211
			// if there was already a connection make sure to remove old listeners
212
			this.shutdown();
I
isidor 已提交
213
		}
214

I
isidor 已提交
215 216 217
		try {
			const customTelemetryService = await dbgr.getCustomTelemetryService();
			const debugAdapter = await dbgr.createDebugAdapter(this);
I
isidor 已提交
218
			this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.extensionHostDebugService, this.openerService, this.notificationService);
I
isidor 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231

			await this.raw.start();
			this.registerListeners();
			await this.raw!.initialize({
				clientID: 'vscode',
				clientName: this.productService.nameLong,
				adapterID: this.configuration.type,
				pathFormat: 'path',
				linesStartAt1: true,
				columnsStartAt1: true,
				supportsVariableType: true, // #8858
				supportsVariablePaging: true, // #9537
				supportsRunInTerminalRequest: true, // #10574
232 233
				locale: platform.locale,
				supportsProgressReporting: true // #92253
I
isidor 已提交
234
			});
I
isidor 已提交
235

I
isidor 已提交
236 237
			this.initialized = true;
			this._onDidChangeState.fire();
I
isidor 已提交
238
			this.model.setExceptionBreakpoints((this.raw && this.raw.capabilities.exceptionBreakpointFilters) || []);
I
isidor 已提交
239 240 241
		} catch (err) {
			this.initialized = true;
			this._onDidChangeState.fire();
I
isidor 已提交
242
			this.shutdown();
I
isidor 已提交
243 244
			throw err;
		}
I
isidor 已提交
245 246
	}

A
Andre Weinand 已提交
247 248 249
	/**
	 * launch or attach to the debuggee
	 */
I
isidor 已提交
250 251
	async launchOrAttach(config: IConfig): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
252
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'launch or attach'));
I
isidor 已提交
253
		}
I
isidor 已提交
254 255 256
		if (this.parentSession && this.parentSession.state === State.Inactive) {
			throw canceled();
		}
A
Andre Weinand 已提交
257

I
isidor 已提交
258 259
		// __sessionID only used for EH debugging (but we add it always for now...)
		config.__sessionId = this.getId();
I
isidor 已提交
260 261 262 263 264 265
		try {
			await this.raw.launchOrAttach(config);
		} catch (err) {
			this.shutdown();
			throw err;
		}
A
Andre Weinand 已提交
266 267 268 269 270
	}

	/**
	 * end the current debug adapter session
	 */
I
isidor 已提交
271 272
	async terminate(restart = false): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
273
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'terminate'));
I
isidor 已提交
274 275 276 277 278 279 280
		}

		this.cancelAllRequests();
		if (this.raw.capabilities.supportsTerminateRequest && this._configuration.resolved.request === 'launch') {
			await this.raw.terminate(restart);
		} else {
			await this.raw.disconnect(restart);
A
Andre Weinand 已提交
281 282 283 284 285 286
		}
	}

	/**
	 * end the current debug adapter session
	 */
I
isidor 已提交
287 288
	async disconnect(restart = false): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
289
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'disconnect'));
A
Andre Weinand 已提交
290
		}
I
isidor 已提交
291 292 293

		this.cancelAllRequests();
		await this.raw.disconnect(restart);
A
Andre Weinand 已提交
294 295 296 297 298
	}

	/**
	 * restart debug adapter session
	 */
I
isidor 已提交
299 300
	async restart(): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
301
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'restart'));
A
Andre Weinand 已提交
302 303
		}

I
isidor 已提交
304 305 306
		this.cancelAllRequests();
		await this.raw.restart();
	}
A
Andre Weinand 已提交
307

I
isidor 已提交
308
	async sendBreakpoints(modelUri: URI, breakpointsToSend: IBreakpoint[], sourceModified: boolean): Promise<void> {
309
		if (!this.raw) {
I
isidor 已提交
310
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'breakpoints'));
A
Andre Weinand 已提交
311 312
		}

313
		if (!this.raw.readyForBreakpoints) {
I
isidor 已提交
314
			return Promise.resolve(undefined);
A
Andre Weinand 已提交
315 316
		}

I
isidor 已提交
317
		const rawSource = this.getRawSource(modelUri);
A
Andre Weinand 已提交
318 319 320 321
		if (breakpointsToSend.length && !rawSource.adapterData) {
			rawSource.adapterData = breakpointsToSend[0].adapterData;
		}
		// Normalize all drive letters going out from vscode to debug adapters so we are consistent with our resolving #43959
I
isidor 已提交
322 323 324
		if (rawSource.path) {
			rawSource.path = normalizeDriveLetter(rawSource.path);
		}
A
Andre Weinand 已提交
325

I
isidor 已提交
326
		const response = await this.raw.setBreakpoints({
A
Andre Weinand 已提交
327
			source: rawSource,
328 329
			lines: breakpointsToSend.map(bp => bp.sessionAgnosticData.lineNumber),
			breakpoints: breakpointsToSend.map(bp => ({ line: bp.sessionAgnosticData.lineNumber, column: bp.sessionAgnosticData.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })),
A
Andre Weinand 已提交
330
			sourceModified
I
isidor 已提交
331 332 333 334 335 336 337 338 339 340 341 342 343
		});
		if (response && response.body) {
			const data = new Map<string, DebugProtocol.Breakpoint>();
			for (let i = 0; i < breakpointsToSend.length; i++) {
				data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]);
			}

			this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
		}
	}

	async sendFunctionBreakpoints(fbpts: IFunctionBreakpoint[]): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
344
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'function breakpoints'));
I
isidor 已提交
345 346 347 348
		}

		if (this.raw.readyForBreakpoints) {
			const response = await this.raw.setFunctionBreakpoints({ breakpoints: fbpts });
A
Andre Weinand 已提交
349
			if (response && response.body) {
I
isidor 已提交
350
				const data = new Map<string, DebugProtocol.Breakpoint>();
I
isidor 已提交
351 352
				for (let i = 0; i < fbpts.length; i++) {
					data.set(fbpts[i].getId(), response.body.breakpoints[i]);
A
Andre Weinand 已提交
353
				}
354
				this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
A
Andre Weinand 已提交
355
			}
I
isidor 已提交
356
		}
A
Andre Weinand 已提交
357 358
	}

I
isidor 已提交
359 360
	async sendExceptionBreakpoints(exbpts: IExceptionBreakpoint[]): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
361
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'exception breakpoints'));
A
Andre Weinand 已提交
362
		}
363

I
isidor 已提交
364 365 366
		if (this.raw.readyForBreakpoints) {
			await this.raw.setExceptionBreakpoints({ filters: exbpts.map(exb => exb.filter) });
		}
A
Andre Weinand 已提交
367 368
	}

I
isidor 已提交
369
	async dataBreakpointInfo(name: string, variablesReference?: number): Promise<{ dataId: string | null, description: string, canPersist?: boolean } | undefined> {
I
isidor 已提交
370
		if (!this.raw) {
I
isidor 已提交
371
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'data breakpoints info'));
A
Andre Weinand 已提交
372
		}
I
isidor 已提交
373
		if (!this.raw.readyForBreakpoints) {
I
isidor 已提交
374
			throw new Error(localize('sessionNotReadyForBreakpoints', "Session is not ready for breakpoints"));
I
isidor 已提交
375 376 377 378
		}

		const response = await this.raw.dataBreakpointInfo({ name, variablesReference });
		return response.body;
A
Andre Weinand 已提交
379 380
	}

I
isidor 已提交
381 382
	async sendDataBreakpoints(dataBreakpoints: IDataBreakpoint[]): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
383
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'data breakpoints'));
I
isidor 已提交
384 385
		}

I
isidor 已提交
386 387 388 389 390 391 392 393
		if (this.raw.readyForBreakpoints) {
			const response = await this.raw.setDataBreakpoints({ breakpoints: dataBreakpoints });
			if (response && response.body) {
				const data = new Map<string, DebugProtocol.Breakpoint>();
				for (let i = 0; i < dataBreakpoints.length; i++) {
					data.set(dataBreakpoints[i].getId(), response.body.breakpoints[i]);
				}
				this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
I
isidor 已提交
394 395 396 397
			}
		}
	}

I
isidor 已提交
398
	async breakpointsLocations(uri: URI, lineNumber: number): Promise<IPosition[]> {
I
isidor 已提交
399
		if (!this.raw) {
I
isidor 已提交
400
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'breakpoints locations'));
I
isidor 已提交
401
		}
I
isidor 已提交
402

I
isidor 已提交
403 404 405 406
		const source = this.getRawSource(uri);
		const response = await this.raw.breakpointLocations({ source, line: lineNumber });
		if (!response.body || !response.body.breakpoints) {
			return [];
I
isidor 已提交
407
		}
I
isidor 已提交
408 409 410 411

		const positions = response.body.breakpoints.map(bp => ({ lineNumber: bp.line, column: bp.column || 1 }));

		return distinct(positions, p => `${p.lineNumber}:${p.column}`);
I
isidor 已提交
412 413
	}

414
	customRequest(request: string, args: any): Promise<DebugProtocol.Response> {
I
isidor 已提交
415
		if (!this.raw) {
I
isidor 已提交
416
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", request));
A
Andre Weinand 已提交
417
		}
I
isidor 已提交
418 419

		return this.raw.custom(request, args);
A
Andre Weinand 已提交
420 421
	}

422
	stackTrace(threadId: number, startFrame: number, levels: number): Promise<DebugProtocol.StackTraceResponse> {
I
isidor 已提交
423
		if (!this.raw) {
I
isidor 已提交
424
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stackTrace'));
A
Andre Weinand 已提交
425
		}
I
isidor 已提交
426 427 428

		const token = this.getNewCancellationToken(threadId);
		return this.raw.stackTrace({ threadId, startFrame, levels }, token);
A
Andre Weinand 已提交
429 430
	}

I
isidor 已提交
431 432
	async exceptionInfo(threadId: number): Promise<IExceptionInfo | undefined> {
		if (!this.raw) {
I
isidor 已提交
433
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'exceptionInfo'));
I
isidor 已提交
434 435 436 437 438 439 440 441 442 443
		}

		const response = await this.raw.exceptionInfo({ threadId });
		if (response) {
			return {
				id: response.body.exceptionId,
				description: response.body.description,
				breakMode: response.body.breakMode,
				details: response.body.details
			};
A
Andre Weinand 已提交
444
		}
I
isidor 已提交
445 446

		return undefined;
A
Andre Weinand 已提交
447 448
	}

I
isidor 已提交
449
	scopes(frameId: number, threadId: number): Promise<DebugProtocol.ScopesResponse> {
I
isidor 已提交
450
		if (!this.raw) {
I
isidor 已提交
451
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'scopes'));
A
Andre Weinand 已提交
452
		}
I
isidor 已提交
453 454 455

		const token = this.getNewCancellationToken(threadId);
		return this.raw.scopes({ frameId }, token);
A
Andre Weinand 已提交
456 457
	}

I
isidor 已提交
458
	variables(variablesReference: number, threadId: number | undefined, filter: 'indexed' | 'named' | undefined, start: number | undefined, count: number | undefined): Promise<DebugProtocol.VariablesResponse> {
I
isidor 已提交
459
		if (!this.raw) {
I
isidor 已提交
460
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'variables'));
A
Andre Weinand 已提交
461
		}
I
isidor 已提交
462 463 464

		const token = threadId ? this.getNewCancellationToken(threadId) : undefined;
		return this.raw.variables({ variablesReference, filter, start, count }, token);
A
Andre Weinand 已提交
465 466
	}

467
	evaluate(expression: string, frameId: number, context?: string): Promise<DebugProtocol.EvaluateResponse> {
I
isidor 已提交
468
		if (!this.raw) {
I
isidor 已提交
469
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'evaluate'));
A
Andre Weinand 已提交
470
		}
I
isidor 已提交
471 472

		return this.raw.evaluate({ expression, frameId, context });
A
Andre Weinand 已提交
473 474
	}

I
isidor 已提交
475 476
	async restartFrame(frameId: number, threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
477
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'restartFrame'));
A
Andre Weinand 已提交
478
		}
I
isidor 已提交
479 480

		await this.raw.restartFrame({ frameId }, threadId);
A
Andre Weinand 已提交
481 482
	}

I
isidor 已提交
483 484
	async next(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
485
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'next'));
A
Andre Weinand 已提交
486
		}
I
isidor 已提交
487 488

		await this.raw.next({ threadId });
A
Andre Weinand 已提交
489 490
	}

I
isidor 已提交
491 492
	async stepIn(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
493
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepIn'));
A
Andre Weinand 已提交
494
		}
I
isidor 已提交
495 496

		await this.raw.stepIn({ threadId });
A
Andre Weinand 已提交
497 498
	}

I
isidor 已提交
499 500
	async stepOut(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
501
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepOut'));
A
Andre Weinand 已提交
502
		}
I
isidor 已提交
503 504

		await this.raw.stepOut({ threadId });
A
Andre Weinand 已提交
505 506
	}

I
isidor 已提交
507 508
	async stepBack(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
509
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'stepBack'));
A
Andre Weinand 已提交
510
		}
I
isidor 已提交
511 512

		await this.raw.stepBack({ threadId });
A
Andre Weinand 已提交
513 514
	}

I
isidor 已提交
515 516
	async continue(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
517
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'continue'));
A
Andre Weinand 已提交
518
		}
I
isidor 已提交
519 520

		await this.raw.continue({ threadId });
A
Andre Weinand 已提交
521 522
	}

I
isidor 已提交
523 524
	async reverseContinue(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
525
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'reverse continue'));
A
Andre Weinand 已提交
526
		}
I
isidor 已提交
527 528

		await this.raw.reverseContinue({ threadId });
A
Andre Weinand 已提交
529 530
	}

I
isidor 已提交
531 532
	async pause(threadId: number): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
533
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'pause'));
A
Andre Weinand 已提交
534
		}
I
isidor 已提交
535 536

		await this.raw.pause({ threadId });
A
Andre Weinand 已提交
537 538
	}

I
isidor 已提交
539 540
	async terminateThreads(threadIds?: number[]): Promise<void> {
		if (!this.raw) {
I
isidor 已提交
541
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'terminateThreads'));
A
Andre Weinand 已提交
542
		}
I
isidor 已提交
543 544

		await this.raw.terminateThreads({ threadIds });
A
Andre Weinand 已提交
545 546
	}

547
	setVariable(variablesReference: number, name: string, value: string): Promise<DebugProtocol.SetVariableResponse> {
I
isidor 已提交
548
		if (!this.raw) {
I
isidor 已提交
549
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'setVariable'));
A
Andre Weinand 已提交
550
		}
I
isidor 已提交
551 552

		return this.raw.setVariable({ variablesReference, name, value });
A
Andre Weinand 已提交
553 554
	}

I
isidor 已提交
555
	gotoTargets(source: DebugProtocol.Source, line: number, column?: number): Promise<DebugProtocol.GotoTargetsResponse> {
I
isidor 已提交
556
		if (!this.raw) {
I
isidor 已提交
557
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'gotoTargets'));
I
isidor 已提交
558
		}
I
isidor 已提交
559 560

		return this.raw.gotoTargets({ source, line, column });
I
isidor 已提交
561 562 563
	}

	goto(threadId: number, targetId: number): Promise<DebugProtocol.GotoResponse> {
I
isidor 已提交
564
		if (!this.raw) {
I
isidor 已提交
565
			throw new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'goto'));
I
isidor 已提交
566
		}
I
isidor 已提交
567 568

		return this.raw.goto({ threadId, targetId });
I
isidor 已提交
569 570
	}

571
	loadSource(resource: URI): Promise<DebugProtocol.SourceResponse> {
572
		if (!this.raw) {
I
isidor 已提交
573
			return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'loadSource')));
A
Andre Weinand 已提交
574 575 576 577 578 579 580 581
		}

		const source = this.getSourceForUri(resource);
		let rawSource: DebugProtocol.Source;
		if (source) {
			rawSource = source.raw;
		} else {
			// create a Source
582 583
			const data = Source.getEncodedDebugData(resource);
			rawSource = { path: data.path, sourceReference: data.sourceReference };
A
Andre Weinand 已提交
584 585
		}

I
isidor 已提交
586
		return this.raw.source({ sourceReference: rawSource.sourceReference || 0, source: rawSource });
A
Andre Weinand 已提交
587 588
	}

I
isidor 已提交
589 590
	async getLoadedSources(): Promise<Source[]> {
		if (!this.raw) {
I
isidor 已提交
591
			return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'getLoadedSources')));
I
isidor 已提交
592 593 594
		}

		const response = await this.raw.loadedSources({});
I
isidor 已提交
595
		if (response && response.body && response.body.sources) {
I
isidor 已提交
596 597 598
			return response.body.sources.map(src => this.getSource(src));
		} else {
			return [];
A
Andre Weinand 已提交
599 600 601
		}
	}

602
	async completions(frameId: number | undefined, text: string, position: Position, overwriteBefore: number, token: CancellationToken): Promise<DebugProtocol.CompletionsResponse> {
I
isidor 已提交
603
		if (!this.raw) {
I
isidor 已提交
604
			return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'completions')));
I
isidor 已提交
605 606
		}

607
		return this.raw.completions({
I
isidor 已提交
608 609 610 611 612
			frameId,
			text,
			column: position.column,
			line: position.lineNumber,
		}, token);
A
Andre Weinand 已提交
613 614
	}

I
isidor 已提交
615 616 617 618 619 620 621 622
	async cancel(progressId: string): Promise<DebugProtocol.CancelResponse> {
		if (!this.raw) {
			return Promise.reject(new Error(localize('noDebugAdapter', "No debug adapter, can not send '{0}'", 'cancel')));
		}

		return this.raw.cancel({ progressId });
	}

A
Andre Weinand 已提交
623 624
	//---- threads

I
isidor 已提交
625
	getThread(threadId: number): Thread | undefined {
A
Andre Weinand 已提交
626 627 628 629 630 631 632 633 634
		return this.threads.get(threadId);
	}

	getAllThreads(): IThread[] {
		const result: IThread[] = [];
		this.threads.forEach(t => result.push(t));
		return result;
	}

635
	clearThreads(removeThreads: boolean, reference: number | undefined = undefined): void {
A
Andre Weinand 已提交
636
		if (reference !== undefined && reference !== null) {
637 638
			const thread = this.threads.get(reference);
			if (thread) {
A
Andre Weinand 已提交
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
				thread.clearCallStack();
				thread.stoppedDetails = undefined;
				thread.stopped = false;

				if (removeThreads) {
					this.threads.delete(reference);
				}
			}
		} else {
			this.threads.forEach(thread => {
				thread.clearCallStack();
				thread.stoppedDetails = undefined;
				thread.stopped = false;
			});

			if (removeThreads) {
				this.threads.clear();
				ExpressionContainer.allValues.clear();
			}
		}
	}

	rawUpdate(data: IRawModelUpdate): void {
662
		const threadIds: number[] = [];
I
isidor 已提交
663
		data.threads.forEach(thread => {
664
			threadIds.push(thread.id);
I
isidor 已提交
665 666 667 668 669 670 671 672 673
			if (!this.threads.has(thread.id)) {
				// A new thread came in, initialize it.
				this.threads.set(thread.id, new Thread(this, thread.name, thread.id));
			} else if (thread.name) {
				// Just the thread name got updated #18244
				const oldThread = this.threads.get(thread.id);
				if (oldThread) {
					oldThread.name = thread.name;
				}
I
isidor 已提交
674
			}
I
isidor 已提交
675
		});
676 677 678 679 680 681
		this.threads.forEach(t => {
			// Remove all old threads which are no longer part of the update #75980
			if (threadIds.indexOf(t.threadId) === -1) {
				this.threads.delete(t.threadId);
			}
		});
A
Andre Weinand 已提交
682

I
isidor 已提交
683 684
		const stoppedDetails = data.stoppedDetails;
		if (stoppedDetails) {
A
Andre Weinand 已提交
685 686
			// Set the availability of the threads' callstacks depending on
			// whether the thread is stopped or not
I
isidor 已提交
687
			if (stoppedDetails.allThreadsStopped) {
A
Andre Weinand 已提交
688
				this.threads.forEach(thread => {
I
isidor 已提交
689
					thread.stoppedDetails = thread.threadId === stoppedDetails.threadId ? stoppedDetails : { reason: undefined };
A
Andre Weinand 已提交
690 691 692
					thread.stopped = true;
					thread.clearCallStack();
				});
I
isidor 已提交
693
			} else {
I
isidor 已提交
694
				const thread = typeof stoppedDetails.threadId === 'number' ? this.threads.get(stoppedDetails.threadId) : undefined;
I
isidor 已提交
695 696
				if (thread) {
					// One thread is stopped, only update that thread.
I
isidor 已提交
697
					thread.stoppedDetails = stoppedDetails;
I
isidor 已提交
698 699 700
					thread.clearCallStack();
					thread.stopped = true;
				}
A
Andre Weinand 已提交
701 702 703 704
			}
		}
	}

I
isidor 已提交
705 706 707
	private async fetchThreads(stoppedDetails?: IRawStoppedDetails): Promise<void> {
		if (this.raw) {
			const response = await this.raw.threads();
A
Andre Weinand 已提交
708
			if (response && response.body && response.body.threads) {
I
isidor 已提交
709 710 711 712
				this.model.rawUpdate({
					sessionId: this.getId(),
					threads: response.body.threads,
					stoppedDetails
A
Andre Weinand 已提交
713 714
				});
			}
I
isidor 已提交
715
		}
A
Andre Weinand 已提交
716 717
	}

718 719 720 721 722
	initializeForTest(raw: RawDebugSession): void {
		this.raw = raw;
		this.registerListeners();
	}

A
Andre Weinand 已提交
723 724
	//---- private

I
isidor 已提交
725
	private registerListeners(): void {
I
isidor 已提交
726 727 728 729
		if (!this.raw) {
			return;
		}

I
isidor 已提交
730
		this.rawListeners.push(this.raw.onDidInitialize(async () => {
I
isidor 已提交
731
			aria.status(localize('debuggingStarted', "Debugging started."));
I
isidor 已提交
732
			const sendConfigurationDone = async () => {
733
				if (this.raw && this.raw.capabilities.supportsConfigurationDoneRequest) {
I
isidor 已提交
734 735 736
					try {
						await this.raw.configurationDone();
					} catch (e) {
I
isidor 已提交
737
						// Disconnect the debug session on configuration done error #10596
I
isidor 已提交
738
						this.notificationService.error(e);
739 740
						if (this.raw) {
							this.raw.disconnect();
I
isidor 已提交
741
						}
I
isidor 已提交
742
					}
I
isidor 已提交
743
				}
744 745

				return undefined;
I
isidor 已提交
746 747 748
			};

			// Send all breakpoints
I
isidor 已提交
749 750
			try {
				await this.debugService.sendAllBreakpoints(this);
I
isidor 已提交
751
			} finally {
I
isidor 已提交
752
				await sendConfigurationDone();
I
isidor 已提交
753
				await this.fetchThreads();
I
isidor 已提交
754
			}
I
isidor 已提交
755 756
		}));

I
isidor 已提交
757 758 759 760 761 762 763 764 765 766 767 768 769
		this.rawListeners.push(this.raw.onDidStop(async event => {
			await this.fetchThreads(event.body);
			const thread = typeof event.body.threadId === 'number' ? this.getThread(event.body.threadId) : undefined;
			if (thread) {
				// Call fetch call stack twice, the first only return the top stack frame.
				// Second retrieves the rest of the call stack. For performance reasons #25605
				const promises = this.model.fetchCallStack(<Thread>thread);
				const focus = async () => {
					if (!event.body.preserveFocusHint && thread.getCallStack().length) {
						await this.debugService.focusStackFrame(undefined, thread);
						if (thread.stoppedDetails) {
							if (this.configurationService.getValue<IDebugConfiguration>('debug').openDebug === 'openOnDebugBreak') {
								this.viewletService.openViewlet(VIEWLET_ID);
I
isidor 已提交
770
							}
771

I
isidor 已提交
772 773 774
							if (this.configurationService.getValue<IDebugConfiguration>('debug').focusWindowOnBreak) {
								this.hostService.focus();
							}
775
						}
I
isidor 已提交
776 777 778 779 780 781 782 783 784
					}
				};

				await promises.topCallStack;
				focus();
				await promises.wholeCallStack;
				if (!this.debugService.getViewModel().focusedStackFrame) {
					// The top stack frame can be deemphesized so try to focus again #68616
					focus();
I
isidor 已提交
785
				}
I
isidor 已提交
786 787
			}
			this._onDidChangeState.fire();
I
isidor 已提交
788 789
		}));

790
		this.rawListeners.push(this.raw.onDidThread(event => {
I
isidor 已提交
791 792 793 794
			if (event.body.reason === 'started') {
				// debounce to reduce threadsRequest frequency and improve performance
				if (!this.fetchThreadsScheduler) {
					this.fetchThreadsScheduler = new RunOnceScheduler(() => {
795
						this.fetchThreads();
I
isidor 已提交
796 797 798 799 800 801 802 803
					}, 100);
					this.rawListeners.push(this.fetchThreadsScheduler);
				}
				if (!this.fetchThreadsScheduler.isScheduled()) {
					this.fetchThreadsScheduler.schedule();
				}
			} else if (event.body.reason === 'exited') {
				this.model.clearThreads(this.getId(), true, event.body.threadId);
I
isidor 已提交
804 805 806 807 808 809
				const viewModel = this.debugService.getViewModel();
				const focusedThread = viewModel.focusedThread;
				if (focusedThread && event.body.threadId === focusedThread.threadId) {
					// De-focus the thread in case it was focused
					this.debugService.focusStackFrame(undefined, undefined, viewModel.focusedSession, false);
				}
I
isidor 已提交
810 811 812
			}
		}));

I
isidor 已提交
813
		this.rawListeners.push(this.raw.onDidTerminateDebugee(async event => {
I
isidor 已提交
814
			aria.status(localize('debuggingStopped', "Debugging stopped."));
I
isidor 已提交
815
			if (event.body && event.body.restart) {
I
isidor 已提交
816
				await this.debugService.restartSession(this, event.body.restart);
I
isidor 已提交
817
			} else if (this.raw) {
I
isidor 已提交
818
				await this.raw.disconnect();
I
isidor 已提交
819 820 821
			}
		}));

822
		this.rawListeners.push(this.raw.onDidContinued(event => {
I
isidor 已提交
823
			const threadId = event.body.allThreadsContinued !== false ? undefined : event.body.threadId;
I
isidor 已提交
824 825 826 827 828 829 830 831 832 833
			if (threadId) {
				const tokens = this.cancellationMap.get(threadId);
				this.cancellationMap.delete(threadId);
				if (tokens) {
					tokens.forEach(t => t.cancel());
				}
			} else {
				this.cancelAllRequests();
			}

I
isidor 已提交
834
			this.model.clearThreads(this.getId(), false, threadId);
835
			this._onDidChangeState.fire();
I
isidor 已提交
836 837
		}));

838
		const outputQueue = new Queue<void>();
I
isidor 已提交
839
		this.rawListeners.push(this.raw.onDidOutput(async event => {
840 841 842 843 844 845 846 847 848 849 850 851 852
			outputQueue.queue(async () => {
				if (!event.body || !this.raw) {
					return;
				}

				const outputSeverity = event.body.category === 'stderr' ? severity.Error : event.body.category === 'console' ? severity.Warning : severity.Info;
				if (event.body.category === 'telemetry') {
					// only log telemetry events from debug adapter if the debug extension provided the telemetry key
					// and the user opted in telemetry
					if (this.raw.customTelemetryService && this.telemetryService.isOptedIn) {
						// __GDPR__TODO__ We're sending events in the name of the debug extension and we can not ensure that those are declared correctly.
						this.raw.customTelemetryService.publicLog(event.body.output, event.body.data);
					}
I
isidor 已提交
853

854
					return;
I
isidor 已提交
855 856
				}

857 858 859 860 861 862
				// Make sure to append output in the correct order by properly waiting on preivous promises #33822
				const source = event.body.source && event.body.line ? {
					lineNumber: event.body.line,
					column: event.body.column ? event.body.column : 1,
					source: this.getSource(event.body.source)
				} : undefined;
I
isidor 已提交
863

864 865 866
				if (event.body.group === 'start' || event.body.group === 'startCollapsed') {
					const expanded = event.body.group === 'start';
					this.repl.startGroup(event.body.output || '', expanded, source);
867 868
					return;
				}
869 870 871 872 873 874 875
				if (event.body.group === 'end') {
					this.repl.endGroup();
					if (!event.body.output) {
						// Only return if the end event does not have additional output in it
						return;
					}
				}
I
isidor 已提交
876

877 878 879 880 881 882 883 884
				if (event.body.variablesReference) {
					const container = new ExpressionContainer(this, undefined, event.body.variablesReference, generateUuid());
					await container.getChildren().then(children => {
						children.forEach(child => {
							// Since we can not display multiple trees in a row, we are displaying these variables one after the other (ignoring their names)
							(<any>child).name = null;
							this.appendToRepl(child, outputSeverity, source);
						});
I
isidor 已提交
885
					});
886 887 888 889
				} else if (typeof event.body.output === 'string') {
					this.appendToRepl(event.body.output, outputSeverity, source);
				}
			});
I
isidor 已提交
890 891
		}));

892
		this.rawListeners.push(this.raw.onDidBreakpoint(event => {
I
isidor 已提交
893
			const id = event.body && event.body.breakpoint ? event.body.breakpoint.id : undefined;
I
isidor 已提交
894 895
			const breakpoint = this.model.getBreakpoints().find(bp => bp.getIdFromAdapter(this.getId()) === id);
			const functionBreakpoint = this.model.getFunctionBreakpoints().find(bp => bp.getIdFromAdapter(this.getId()) === id);
I
isidor 已提交
896

I
isidor 已提交
897
			if (event.body.reason === 'new' && event.body.breakpoint.source && event.body.breakpoint.line) {
I
isidor 已提交
898 899 900 901 902 903 904
				const source = this.getSource(event.body.breakpoint.source);
				const bps = this.model.addBreakpoints(source.uri, [{
					column: event.body.breakpoint.column,
					enabled: true,
					lineNumber: event.body.breakpoint.line,
				}], false);
				if (bps.length === 1) {
I
isidor 已提交
905
					const data = new Map<string, DebugProtocol.Breakpoint>([[bps[0].getId(), event.body.breakpoint]]);
906
					this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
I
isidor 已提交
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923
				}
			}

			if (event.body.reason === 'removed') {
				if (breakpoint) {
					this.model.removeBreakpoints([breakpoint]);
				}
				if (functionBreakpoint) {
					this.model.removeFunctionBreakpoints(functionBreakpoint.getId());
				}
			}

			if (event.body.reason === 'changed') {
				if (breakpoint) {
					if (!breakpoint.column) {
						event.body.breakpoint.column = undefined;
					}
I
isidor 已提交
924
					const data = new Map<string, DebugProtocol.Breakpoint>([[breakpoint.getId(), event.body.breakpoint]]);
925
					this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
I
isidor 已提交
926 927
				}
				if (functionBreakpoint) {
I
isidor 已提交
928
					const data = new Map<string, DebugProtocol.Breakpoint>([[functionBreakpoint.getId(), event.body.breakpoint]]);
929
					this.model.setBreakpointSessionData(this.getId(), this.capabilities, data);
I
isidor 已提交
930 931 932 933
				}
			}
		}));

934
		this.rawListeners.push(this.raw.onDidLoadedSource(event => {
I
isidor 已提交
935 936 937 938 939 940
			this._onDidLoadedSource.fire({
				reason: event.body.reason,
				source: this.getSource(event.body.source)
			});
		}));

941
		this.rawListeners.push(this.raw.onDidCustomEvent(event => {
I
isidor 已提交
942 943 944
			this._onDidCustomEvent.fire(event);
		}));

945 946 947
		this.rawListeners.push(this.raw.onDidProgressStart(event => {
			this._onDidProgressStart.fire(event);
		}));
I
isidor 已提交
948 949 950
		this.rawListeners.push(this.raw.onDidProgressUpdate(event => {
			this._onDidProgressUpdate.fire(event);
		}));
951 952 953 954
		this.rawListeners.push(this.raw.onDidProgressEnd(event => {
			this._onDidProgressEnd.fire(event);
		}));

955
		this.rawListeners.push(this.raw.onDidExitAdapter(event => {
I
isidor 已提交
956
			this.initialized = true;
957
			this.model.setBreakpointSessionData(this.getId(), this.capabilities, undefined);
I
isidor 已提交
958
			this.shutdown();
A
Andre Weinand 已提交
959
			this._onDidEndAdapter.fire(event);
960 961 962
		}));
	}

I
isidor 已提交
963 964
	// Disconnects and clears state. Session can be initialized again for a new connection.
	private shutdown(): void {
965
		dispose(this.rawListeners);
I
isidor 已提交
966
		if (this.raw) {
I
isidor 已提交
967 968
			this.raw.disconnect();
			this.raw.dispose();
I
isidor 已提交
969 970
			this.raw = undefined;
		}
I
isidor 已提交
971 972
		this.fetchThreadsScheduler = undefined;
		this.model.clearThreads(this.getId(), true);
973
		this._onDidChangeState.fire();
974 975 976 977
	}

	//---- sources

I
isidor 已提交
978
	getSourceForUri(uri: URI): Source | undefined {
I
isidor 已提交
979
		return this.sources.get(this.getUriKey(uri));
980 981
	}

I
isidor 已提交
982
	getSource(raw?: DebugProtocol.Source): Source {
983
		let source = new Source(raw, this.getId());
I
isidor 已提交
984
		const uriKey = this.getUriKey(source.uri);
A
Andre Weinand 已提交
985 986 987 988
		const found = this.sources.get(uriKey);
		if (found) {
			source = found;
			// merge attributes of new into existing
989 990 991 992 993 994
			source.raw = mixin(source.raw, raw);
			if (source.raw && raw) {
				// Always take the latest presentation hint from adapter #42139
				source.raw.presentationHint = raw.presentationHint;
			}
		} else {
I
isidor 已提交
995
			this.sources.set(uriKey, source);
996 997 998 999
		}

		return source;
	}
I
isidor 已提交
1000

I
isidor 已提交
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010
	private getRawSource(uri: URI): DebugProtocol.Source {
		const source = this.getSourceForUri(uri);
		if (source) {
			return source.raw;
		} else {
			const data = Source.getEncodedDebugData(uri);
			return { name: data.name, path: data.path, sourceReference: data.sourceReference };
		}
	}

I
isidor 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
	private getNewCancellationToken(threadId: number): CancellationToken {
		const tokenSource = new CancellationTokenSource();
		const tokens = this.cancellationMap.get(threadId) || [];
		tokens.push(tokenSource);
		this.cancellationMap.set(threadId, tokens);

		return tokenSource.token;
	}

	private cancelAllRequests(): void {
		this.cancellationMap.forEach(tokens => tokens.forEach(t => t.cancel()));
		this.cancellationMap.clear();
	}

I
isidor 已提交
1025
	private getUriKey(uri: URI): string {
A
Andre Weinand 已提交
1026
		// TODO: the following code does not make sense if uri originates from a different platform
I
isidor 已提交
1027 1028
		return platform.isLinux ? uri.toString() : uri.toString().toLowerCase();
	}
I
isidor 已提交
1029 1030 1031

	// REPL

I
isidor 已提交
1032
	getReplElements(): IReplElement[] {
1033 1034 1035
		return this.repl.getReplElements();
	}

1036 1037 1038 1039
	hasSeparateRepl(): boolean {
		return !this.parentSession || this._options.repl !== 'mergeWithParent';
	}

1040 1041
	removeReplExpressions(): void {
		this.repl.removeReplExpressions();
I
isidor 已提交
1042 1043
	}

1044
	async addReplExpression(stackFrame: IStackFrame | undefined, name: string): Promise<void> {
1045
		await this.repl.addReplExpression(this, stackFrame, name);
1046 1047
		// Evaluate all watch expressions and fetch variables again since repl evaluation might have changed some.
		variableSetEmitter.fire();
I
isidor 已提交
1048 1049
	}

1050
	appendToRepl(data: string | IExpression, severity: severity, source?: IReplElementSource): void {
D
Dmitry Gozman 已提交
1051
		this.repl.appendToRepl(this, data, severity, source);
I
isidor 已提交
1052 1053
	}

1054
	logToRepl(sev: severity, args: any[], frame?: { uri: URI, line: number, column: number }) {
1055
		this.repl.logToRepl(this, sev, args, frame);
I
isidor 已提交
1056
	}
1057
}