loadedScriptsView.ts 20.3 KB
Newer Older
I
isidor 已提交
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as nls from 'vs/nls';
import * as dom from 'vs/base/browser/dom';
8
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
9
import { normalize, isAbsolute, posix } from 'vs/base/common/path';
S
SteVen Batten 已提交
10
import { IViewPaneOptions, ViewPane } from 'vs/workbench/browser/parts/views/viewPaneContainer';
I
isidor 已提交
11 12 13 14
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
15
import { renderViewTree } from 'vs/workbench/contrib/debug/browser/baseDebugView';
16
import { IDebugSession, IDebugService, CONTEXT_LOADED_SCRIPTS_ITEM_TYPE } from 'vs/workbench/contrib/debug/common/debug';
17
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
18 19 20 21 22
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { tildify } from 'vs/base/common/labels';
import { isWindows } from 'vs/base/common/platform';
23
import { URI } from 'vs/base/common/uri';
24
import { ltrim } from 'vs/base/common/strings';
I
isidor 已提交
25
import { RunOnceScheduler } from 'vs/base/common/async';
26
import { ResourceLabels, IResourceLabelProps, IResourceLabelOptions, IResourceLabel } from 'vs/workbench/browser/labels';
27
import { FileKind } from 'vs/platform/files/common/files';
28
import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
J
Joao Moreno 已提交
29
import { ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, TreeFilterResult, ITreeElement } from 'vs/base/browser/ui/tree/tree';
30 31
import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
J
Joao Moreno 已提交
32
import { TreeResourceNavigator2, WorkbenchObjectTree } from 'vs/platform/list/browser/listService';
33
import { dispose } from 'vs/base/common/lifecycle';
I
isidor 已提交
34
import { createMatches, FuzzyScore } from 'vs/base/common/filters';
35
import { DebugContentProvider } from 'vs/workbench/contrib/debug/common/debugContentProvider';
36
import { ILabelService } from 'vs/platform/label/common/label';
37
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
38 39 40

const SMART = true;

41 42 43
// RFC 2396, Appendix A: https://www.ietf.org/rfc/rfc2396.txt
const URI_SCHEMA_PATTERN = /^[a-zA-Z][a-zA-Z0-9\+\-\.]+:/;

44 45
type LoadedScriptsItem = BaseTreeItem;

46 47
class BaseTreeItem {

48
	private _showedMoreThanOne: boolean;
I
isidor 已提交
49
	private _children = new Map<string, BaseTreeItem>();
I
isidor 已提交
50
	private _source: Source | undefined;
51

A
Andre Weinand 已提交
52
	constructor(private _parent: BaseTreeItem | undefined, private _label: string) {
53
		this._showedMoreThanOne = false;
54 55
	}

56
	isLeaf(): boolean {
I
isidor 已提交
57
		return this._children.size === 0;
58 59
	}

A
Andre Weinand 已提交
60
	getSession(): IDebugSession | undefined {
61 62 63 64 65 66
		if (this._parent) {
			return this._parent.getSession();
		}
		return undefined;
	}

67
	setSource(session: IDebugSession, source: Source): void {
68
		this._source = source;
I
isidor 已提交
69
		this._children.clear();
70 71
		if (source.raw && source.raw.sources) {
			for (const src of source.raw.sources) {
A
Andre Weinand 已提交
72 73
				if (src.name && src.path) {
					const s = new BaseTreeItem(this, src.name);
I
isidor 已提交
74
					this._children.set(src.path, s);
A
Andre Weinand 已提交
75 76 77
					const ss = session.getSource(src);
					s.setSource(session, ss);
				}
78 79
			}
		}
80 81
	}

82
	createIfNeeded<T extends BaseTreeItem>(key: string, factory: (parent: BaseTreeItem, label: string) => T): T {
I
isidor 已提交
83
		let child = <T>this._children.get(key);
84 85
		if (!child) {
			child = factory(this, key);
I
isidor 已提交
86
			this._children.set(key, child);
87
		}
88
		return child;
89 90
	}

I
isidor 已提交
91 92
	getChild(key: string): BaseTreeItem | undefined {
		return this._children.get(key);
93 94
	}

95
	remove(key: string): void {
I
isidor 已提交
96
		this._children.delete(key);
97 98
	}

99 100 101
	removeFromParent(): void {
		if (this._parent) {
			this._parent.remove(this._label);
I
isidor 已提交
102
			if (this._parent._children.size === 0) {
103 104 105 106 107
				this._parent.removeFromParent();
			}
		}
	}

108
	getTemplateId(): string {
109
		return 'id';
110 111
	}

112 113 114
	// a dynamic ID based on the parent chain; required for reparenting (see #55448)
	getId(): string {
		const parent = this.getParent();
115 116 117 118 119
		return parent ? `${parent.getId()}/${this.getInternalId()}` : this.getInternalId();
	}

	getInternalId(): string {
		return this._label;
120 121 122
	}

	// skips intermediate single-child nodes
A
Andre Weinand 已提交
123
	getParent(): BaseTreeItem | undefined {
124
		if (this._parent) {
A
Andre Weinand 已提交
125
			if (this._parent.isSkipped()) {
126 127 128 129 130 131 132
				return this._parent.getParent();
			}
			return this._parent;
		}
		return undefined;
	}

A
Andre Weinand 已提交
133 134 135 136 137 138 139 140 141 142
	isSkipped(): boolean {
		if (this._parent) {
			if (this._parent.oneChild()) {
				return true;	// skipped if I'm the only child of my parents
			}
			return false;
		}
		return true;	// roots are never skipped
	}

143 144 145 146 147 148
	// skips intermediate single-child nodes
	hasChildren(): boolean {
		const child = this.oneChild();
		if (child) {
			return child.hasChildren();
		}
I
isidor 已提交
149
		return this._children.size > 0;
150 151 152
	}

	// skips intermediate single-child nodes
153
	getChildren(): BaseTreeItem[] {
154 155 156 157
		const child = this.oneChild();
		if (child) {
			return child.getChildren();
		}
158
		const array: BaseTreeItem[] = [];
I
isidor 已提交
159 160 161
		for (let child of this._children.values()) {
			array.push(child);
		}
162
		return array.sort((a, b) => this.compare(a, b));
163 164
	}

165
	// skips intermediate single-child nodes
166
	getLabel(separateRootFolder = true): string {
167 168
		const child = this.oneChild();
		if (child) {
B
Benjamin Pasero 已提交
169
			const sep = (this instanceof RootFolderTreeItem && separateRootFolder) ? '' : posix.sep;
170
			return `${this._label}${sep}${child.getLabel()}`;
171
		}
172
		return this._label;
173 174
	}

175
	// skips intermediate single-child nodes
A
Andre Weinand 已提交
176
	getHoverLabel(): string | undefined {
177 178 179
		if (this._source && this._parent && this._parent._source) {
			return this._source.raw.path || this._source.raw.name;
		}
180
		let label = this.getLabel(false);
A
Andre Weinand 已提交
181 182 183 184 185
		const parent = this.getParent();
		if (parent) {
			const hover = parent.getHoverLabel();
			if (hover) {
				return `${hover}/${label}`;
186 187 188 189 190 191
			}
		}
		return label;
	}

	// skips intermediate single-child nodes
I
isidor 已提交
192
	getSource(): Source | undefined {
193 194 195 196 197 198 199 200 201 202 203 204 205 206
		const child = this.oneChild();
		if (child) {
			return child.getSource();
		}
		return this._source;
	}

	protected compare(a: BaseTreeItem, b: BaseTreeItem): number {
		if (a._label && b._label) {
			return a._label.localeCompare(b._label);
		}
		return 0;
	}

A
Andre Weinand 已提交
207
	private oneChild(): BaseTreeItem | undefined {
208
		if (SMART && !this._source && !this._showedMoreThanOne && !(this instanceof RootFolderTreeItem) && !(this instanceof SessionTreeItem)) {
I
isidor 已提交
209 210
			if (this._children.size === 1) {
				return this._children.values().next().value;
211
			}
212
			// if a node had more than one child once, it will never be skipped again
I
isidor 已提交
213
			if (this._children.size > 1) {
214 215
				this._showedMoreThanOne = true;
			}
216 217 218 219 220 221 222 223 224 225 226 227 228 229
		}
		return undefined;
	}
}

class RootFolderTreeItem extends BaseTreeItem {

	constructor(parent: BaseTreeItem, public folder: IWorkspaceFolder) {
		super(parent, folder.name);
	}
}

class RootTreeItem extends BaseTreeItem {

230
	constructor(private _environmentService: IEnvironmentService, private _contextService: IWorkspaceContextService, private _labelService: ILabelService) {
231 232 233
		super(undefined, 'Root');
	}

234
	add(session: IDebugSession): SessionTreeItem {
235
		return this.createIfNeeded(session.getId(), () => new SessionTreeItem(this._labelService, this, session, this._environmentService, this._contextService));
236
	}
237 238 239 240

	find(session: IDebugSession): SessionTreeItem {
		return <SessionTreeItem>this.getChild(session.getId());
	}
241 242 243 244
}

class SessionTreeItem extends BaseTreeItem {

245
	private static readonly URL_REGEXP = /^(https?:\/\/[^/]+)(\/.*)$/;
246

247
	private _session: IDebugSession;
I
isidor 已提交
248
	private _map = new Map<string, BaseTreeItem>();
249
	private _labelService: ILabelService;
250

251
	constructor(labelService: ILabelService, parent: BaseTreeItem, session: IDebugSession, private _environmentService: IEnvironmentService, private rootProvider: IWorkspaceContextService) {
I
isidor 已提交
252
		super(parent, session.getLabel());
253
		this._labelService = labelService;
254
		this._session = session;
255 256
	}

257 258 259 260
	getInternalId(): string {
		return this._session.getId();
	}

261 262
	getSession(): IDebugSession {
		return this._session;
263 264
	}

A
Andre Weinand 已提交
265
	getHoverLabel(): string | undefined {
266 267 268
		return undefined;
	}

269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
	hasChildren(): boolean {
		return true;
	}

	protected compare(a: BaseTreeItem, b: BaseTreeItem): number {
		const acat = this.category(a);
		const bcat = this.category(b);
		if (acat !== bcat) {
			return acat - bcat;
		}
		return super.compare(a, b);
	}

	private category(item: BaseTreeItem): number {

		// workspace scripts come at the beginning in "folder" order
		if (item instanceof RootFolderTreeItem) {
			return item.folder.index;
		}

		// <...> come at the very end
		const l = item.getLabel();
		if (l && /^<.+>$/.test(l)) {
			return 1000;
		}

		// everything else in between
		return 999;
	}

	addPath(source: Source): void {

A
Andre Weinand 已提交
301
		let folder: IWorkspaceFolder | null;
302 303 304
		let url: string;

		let path = source.raw.path;
A
Andre Weinand 已提交
305 306 307
		if (!path) {
			return;
		}
308

309 310 311 312
		if (this._labelService && URI_SCHEMA_PATTERN.test(path)) {
			path = this._labelService.getUriLabel(URI.parse(path));
		}

313 314 315 316 317 318 319 320 321 322 323 324
		const match = SessionTreeItem.URL_REGEXP.exec(path);
		if (match && match.length === 3) {
			url = match[1];
			path = decodeURI(match[2]);
		} else {
			if (isAbsolute(path)) {
				const resource = URI.file(path);

				// return early if we can resolve a relative path label from the root folder
				folder = this.rootProvider ? this.rootProvider.getWorkspaceFolder(resource) : null;
				if (folder) {
					// strip off the root folder path
B
Benjamin Pasero 已提交
325
					path = normalize(ltrim(resource.path.substr(folder.uri.path.length), posix.sep));
326 327
					const hasMultipleRoots = this.rootProvider.getWorkspace().folders.length > 1;
					if (hasMultipleRoots) {
B
Benjamin Pasero 已提交
328
						path = posix.sep + path;
329 330
					} else {
						// don't show root folder
A
Andre Weinand 已提交
331
						folder = null;
332 333 334
					}
				} else {
					// on unix try to tildify absolute paths
335
					path = normalize(path);
336 337 338 339 340 341 342
					if (!isWindows) {
						path = tildify(path, this._environmentService.userHome);
					}
				}
			}
		}

343
		let leaf: BaseTreeItem = this;
344 345
		path.split(/[\/\\]/).forEach((segment, i) => {
			if (i === 0 && folder) {
A
Andre Weinand 已提交
346 347
				const f = folder;
				leaf = leaf.createIfNeeded(folder.name, parent => new RootFolderTreeItem(parent, f));
348
			} else if (i === 0 && url) {
349
				leaf = leaf.createIfNeeded(url, parent => new BaseTreeItem(parent, url));
350
			} else {
351
				leaf = leaf.createIfNeeded(segment, parent => new BaseTreeItem(parent, segment));
352 353 354
			}
		});

355
		leaf.setSource(this._session, source);
A
Andre Weinand 已提交
356 357 358
		if (source.raw.path) {
			this._map.set(source.raw.path, leaf);
		}
359 360 361
	}

	removePath(source: Source): boolean {
A
Andre Weinand 已提交
362 363 364 365 366 367
		if (source.raw.path) {
			const leaf = this._map.get(source.raw.path);
			if (leaf) {
				leaf.removeFromParent();
				return true;
			}
368 369
		}
		return false;
370 371
	}
}
I
isidor 已提交
372

J
Joao Moreno 已提交
373 374 375 376 377 378 379 380 381 382 383 384 385
/**
 * This maps a model item into a view model item.
 */
function asTreeElement(item: BaseTreeItem): ITreeElement<LoadedScriptsItem> {
	const children = item.getChildren();

	return {
		element: item,
		collapsed: !(item instanceof SessionTreeItem),
		children: children.map(asTreeElement)
	};
}

S
SteVen Batten 已提交
386
export class LoadedScriptsView extends ViewPane {
I
isidor 已提交
387

I
isidor 已提交
388
	private treeContainer!: HTMLElement;
389
	private loadedScriptsItemType: IContextKey<string>;
J
Joao Moreno 已提交
390
	private tree!: WorkbenchObjectTree<LoadedScriptsItem, FuzzyScore>;
I
isidor 已提交
391 392 393 394
	private treeLabels!: ResourceLabels;
	private changeScheduler!: RunOnceScheduler;
	private treeNeedsRefreshOnVisible = false;
	private filter!: LoadedScriptsFilter;
I
isidor 已提交
395 396 397 398 399

	constructor(
		options: IViewletViewOptions,
		@IContextMenuService contextMenuService: IContextMenuService,
		@IKeybindingService keybindingService: IKeybindingService,
400
		@IInstantiationService instantiationService: IInstantiationService,
I
isidor 已提交
401
		@IConfigurationService configurationService: IConfigurationService,
402
		@IEditorService private readonly editorService: IEditorService,
403
		@IContextKeyService readonly contextKeyService: IContextKeyService,
404 405 406
		@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
		@IEnvironmentService private readonly environmentService: IEnvironmentService,
		@IDebugService private readonly debugService: IDebugService,
407
		@ILabelService private readonly labelService: ILabelService
I
isidor 已提交
408
	) {
409
		super({ ...(options as IViewPaneOptions), ariaHeaderLabel: nls.localize('loadedScriptsSection', "Loaded Scripts Section") }, keybindingService, contextMenuService, configurationService, contextKeyService, instantiationService);
410
		this.loadedScriptsItemType = CONTEXT_LOADED_SCRIPTS_ITEM_TYPE.bindTo(contextKeyService);
I
isidor 已提交
411 412
	}

413
	renderBody(container: HTMLElement): void {
I
isidor 已提交
414
		dom.addClass(container, 'debug-loaded-scripts');
415
		dom.addClass(container, 'show-file-icons');
416

I
isidor 已提交
417 418
		this.treeContainer = renderViewTree(container);

419 420
		this.filter = new LoadedScriptsFilter();

421
		const root = new RootTreeItem(this.environmentService, this.contextService, this.labelService);
422

423
		this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility });
M
Matt Bierner 已提交
424
		this._register(this.treeLabels);
425

J
Joao Moreno 已提交
426 427 428 429
		this.tree = this.instantiationService.createInstance(WorkbenchObjectTree,
			'LoadedScriptsView',
			this.treeContainer,
			new LoadedScriptsDelegate(),
B
Benjamin Pasero 已提交
430
			[new LoadedScriptsRenderer(this.treeLabels)],
431
			{
J
Joao Moreno 已提交
432
				collapseByDefault: true,
433
				identityProvider: {
B
Benjamin Pasero 已提交
434
					getId: (element: LoadedScriptsItem) => element.getId()
435
				},
J
Joao Moreno 已提交
436
				keyboardNavigationLabelProvider: {
B
Benjamin Pasero 已提交
437
					getKeyboardNavigationLabel: (element: LoadedScriptsItem) => element.getLabel()
438
				},
439
				filter: this.filter,
440
				accessibilityProvider: new LoadedSciptsAccessibilityProvider(),
441
				ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'loadedScriptsAriaLabel' }, "Debug Loaded Scripts"),
442 443 444
				overrideStyles: {
					listBackground: SIDE_BAR_BACKGROUND
				}
445
			}
446
		);
447

J
Joao Moreno 已提交
448 449 450
		const updateView = () => this.tree.setChildren(null, asTreeElement(root).children);

		updateView();
J
Joao Moreno 已提交
451

452 453 454
		this.changeScheduler = new RunOnceScheduler(() => {
			this.treeNeedsRefreshOnVisible = false;
			if (this.tree) {
J
Joao Moreno 已提交
455
				updateView();
456 457
			}
		}, 300);
M
Matt Bierner 已提交
458
		this._register(this.changeScheduler);
459

I
isidor 已提交
460
		const loadedScriptsNavigator = new TreeResourceNavigator2(this.tree);
M
Matt Bierner 已提交
461 462
		this._register(loadedScriptsNavigator);
		this._register(loadedScriptsNavigator.onDidOpenResource(e => {
463 464
			if (e.element instanceof BaseTreeItem) {
				const source = e.element.getSource();
465 466
				if (source && source.available) {
					const nullRange = { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 };
467
					source.openInEditor(this.editorService, nullRange, e.editorOptions.preserveFocus, e.sideBySide, e.editorOptions.pinned);
468 469 470 471
				}
			}
		}));

M
Matt Bierner 已提交
472
		this._register(this.tree.onDidChangeFocus(() => {
473 474 475 476 477 478 479 480
			const focus = this.tree.getFocus();
			if (focus instanceof SessionTreeItem) {
				this.loadedScriptsItemType.set('session');
			} else {
				this.loadedScriptsItemType.reset();
			}
		}));

481 482 483 484 485 486 487 488
		const scheduleRefreshOnVisible = () => {
			if (this.isBodyVisible()) {
				this.changeScheduler.schedule();
			} else {
				this.treeNeedsRefreshOnVisible = true;
			}
		};

489 490 491 492 493 494 495 496
		const addSourcePathsToSession = (session: IDebugSession) => {
			const sessionNode = root.add(session);
			return session.getLoadedSources().then(paths => {
				paths.forEach(path => sessionNode.addPath(path));
				scheduleRefreshOnVisible();
			});
		};

497 498 499 500
		const registerSessionListeners = (session: IDebugSession) => {
			this._register(session.onDidChangeName(() => {
				// Re-add session, this will trigger proper sorting and id recalculation.
				root.remove(session.getId());
501
				addSourcePathsToSession(session);
502
			}));
M
Matt Bierner 已提交
503
			this._register(session.onDidLoadedSource(event => {
504 505 506
				let sessionRoot: SessionTreeItem;
				switch (event.reason) {
					case 'new':
507
					case 'changed':
508 509
						sessionRoot = root.add(session);
						sessionRoot.addPath(event.source);
510
						scheduleRefreshOnVisible();
511 512 513
						if (event.reason === 'changed') {
							DebugContentProvider.refreshDebugContent(event.source.uri);
						}
514
						break;
515 516 517
					case 'removed':
						sessionRoot = root.find(session);
						if (sessionRoot && sessionRoot.removePath(event.source)) {
518
							scheduleRefreshOnVisible();
519 520
						}
						break;
521 522 523 524
					default:
						this.filter.setFilter(event.source.name);
						this.tree.refilter();
						break;
525
				}
I
isidor 已提交
526
			}));
527 528
		};

529 530
		this._register(this.debugService.onDidNewSession(registerSessionListeners));
		this.debugService.getModel().getSessions().forEach(registerSessionListeners);
531

M
Matt Bierner 已提交
532
		this._register(this.debugService.onDidEndSession(session => {
533
			root.remove(session.getId());
534
			this.changeScheduler.schedule();
535
		}));
536 537

		this.changeScheduler.schedule(0);
538

M
Matt Bierner 已提交
539
		this._register(this.onDidChangeBodyVisibility(visible => {
540 541 542 543
			if (visible && this.treeNeedsRefreshOnVisible) {
				this.changeScheduler.schedule();
			}
		}));
544 545 546

		// populate tree model with source paths from all debug sessions
		this.debugService.getModel().getSessions().forEach(session => addSourcePathsToSession(session));
I
isidor 已提交
547 548
	}

549 550
	layoutBody(height: number, width: number): void {
		this.tree.layout(height, width);
551 552
	}

I
isidor 已提交
553
	dispose(): void {
554
		this.tree = dispose(this.tree);
B
Benjamin Pasero 已提交
555
		this.treeLabels = dispose(this.treeLabels);
556
		super.dispose();
I
isidor 已提交
557
	}
I
isidor 已提交
558 559
}

560
class LoadedScriptsDelegate implements IListVirtualDelegate<LoadedScriptsItem> {
I
isidor 已提交
561

562 563
	getHeight(element: LoadedScriptsItem): number {
		return 22;
I
isidor 已提交
564 565
	}

566
	getTemplateId(element: LoadedScriptsItem): string {
A
Andre Weinand 已提交
567
		return LoadedScriptsRenderer.ID;
I
isidor 已提交
568
	}
569
}
I
isidor 已提交
570

571
interface ILoadedScriptsItemTemplateData {
B
Benjamin Pasero 已提交
572
	label: IResourceLabel;
573 574
}

I
isidor 已提交
575
class LoadedScriptsRenderer implements ITreeRenderer<BaseTreeItem, FuzzyScore, ILoadedScriptsItemTemplateData> {
576 577

	static readonly ID = 'lsrenderer';
I
isidor 已提交
578

579
	constructor(
580
		private labels: ResourceLabels
581 582 583
	) {
	}

584 585
	get templateId(): string {
		return LoadedScriptsRenderer.ID;
I
isidor 已提交
586 587
	}

588
	renderTemplate(container: HTMLElement): ILoadedScriptsItemTemplateData {
589 590
		const label = this.labels.create(container, { supportHighlights: true });
		return { label };
591
	}
592

I
isidor 已提交
593
	renderElement(node: ITreeNode<BaseTreeItem, FuzzyScore>, index: number, data: ILoadedScriptsItemTemplateData): void {
594 595

		const element = node.element;
596

B
Benjamin Pasero 已提交
597
		const label: IResourceLabelProps = {
598 599 600 601 602
			name: element.getLabel()
		};
		const options: IResourceLabelOptions = {
			title: element.getHoverLabel()
		};
603

604
		if (element instanceof RootFolderTreeItem) {
I
isidor 已提交
605

606
			options.fileKind = FileKind.ROOT_FOLDER;
I
isidor 已提交
607

608
		} else if (element instanceof SessionTreeItem) {
609

610 611 612 613 614 615 616 617 618 619 620 621 622
			options.title = nls.localize('loadedScriptsSession', "Debug Session");
			options.hideIcon = true;

		} else if (element instanceof BaseTreeItem) {

			const src = element.getSource();
			if (src && src.uri) {
				label.resource = src.uri;
				options.fileKind = FileKind.FILE;
			} else {
				options.fileKind = FileKind.FOLDER;
			}
		}
I
isidor 已提交
623
		options.matches = createMatches(node.filterData);
624

B
Benjamin Pasero 已提交
625
		data.label.setResource(label, options);
626 627
	}

628
	disposeTemplate(templateData: ILoadedScriptsItemTemplateData): void {
J
Joao Moreno 已提交
629
		templateData.label.dispose();
I
isidor 已提交
630 631 632
	}
}

633
class LoadedSciptsAccessibilityProvider implements IAccessibilityProvider<LoadedScriptsItem> {
I
isidor 已提交
634

635
	getAriaLabel(element: LoadedScriptsItem): string {
636 637 638 639 640 641 642 643 644

		if (element instanceof RootFolderTreeItem) {
			return nls.localize('loadedScriptsRootFolderAriaLabel', "Workspace folder {0}, loaded script, debug", element.getLabel());
		}

		if (element instanceof SessionTreeItem) {
			return nls.localize('loadedScriptsSessionAriaLabel', "Session {0}, loaded script, debug", element.getLabel());
		}

A
Andre Weinand 已提交
645 646 647 648
		if (element.hasChildren()) {
			return nls.localize('loadedScriptsFolderAriaLabel', "Folder {0}, loaded script, debug", element.getLabel());
		} else {
			return nls.localize('loadedScriptsSourceAriaLabel', "{0}, loaded script, debug", element.getLabel());
649
		}
I
isidor 已提交
650 651
	}
}
652

I
isidor 已提交
653
class LoadedScriptsFilter implements ITreeFilter<BaseTreeItem, FuzzyScore> {
654

I
isidor 已提交
655
	private filterText: string | undefined;
656 657 658 659 660

	setFilter(filterText: string) {
		this.filterText = filterText;
	}

I
isidor 已提交
661
	filter(element: BaseTreeItem, parentVisibility: TreeVisibility): TreeFilterResult<FuzzyScore> {
662 663 664 665 666 667 668 669 670 671 672 673 674 675

		if (!this.filterText) {
			return TreeVisibility.Visible;
		}

		if (element.isLeaf()) {
			const name = element.getLabel();
			if (name.indexOf(this.filterText) >= 0) {
				return TreeVisibility.Visible;
			}
			return TreeVisibility.Hidden;
		}
		return TreeVisibility.Recurse;
	}
I
isidor 已提交
676
}