diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index c81ec0d551215..d5f4191a8598d 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1141,4 +1141,35 @@ declare module 'vscode' { alwaysShow?: boolean; } //#endregion + + //#region Tree Item Label Highlights + /** + * Label describing the [Tree item](#TreeItem) + */ + export interface TreeItemLabel { + + /** + * A human-readable string describing the [Tree item](#TreeItem). + */ + label: string; + + /** + * Ranges in the label to highlight. + */ + highlights?: [number, number][]; + + } + + export class TreeItem2 extends TreeItem { + /** + * Label describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri). + */ + label?: string | TreeItemLabel | /* for compilation */ any; + + /** + * @param label Label describing this item + * @param collapsibleState [TreeItemCollapsibleState](#TreeItemCollapsibleState) of the tree item. Default is [TreeItemCollapsibleState.None](#TreeItemCollapsibleState.None) + */ + constructor(label: TreeItemLabel, collapsibleState?: TreeItemCollapsibleState); + } } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index d82cae9a548ad..c5b4176b5bc22 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -794,6 +794,7 @@ export function createApiFactory( ThemeColor: extHostTypes.ThemeColor, ThemeIcon: extHostTypes.ThemeIcon, TreeItem: extHostTypes.TreeItem, + TreeItem2: extHostTypes.TreeItem, TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState, Uri: URI, ViewColumn: extHostTypes.ViewColumn, diff --git a/src/vs/workbench/api/node/extHostTreeViews.ts b/src/vs/workbench/api/node/extHostTreeViews.ts index a8333e2f958f8..487b76fa9a7b2 100644 --- a/src/vs/workbench/api/node/extHostTreeViews.ts +++ b/src/vs/workbench/api/node/extHostTreeViews.ts @@ -10,16 +10,36 @@ import { URI } from 'vs/base/common/uri'; import { debounceEvent, Emitter, Event } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol'; -import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views'; +import { ITreeItem, TreeViewItemHandleArg, ITreeItemLabel } from 'vs/workbench/common/views'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { asThenable } from 'vs/base/common/async'; import { TreeItemCollapsibleState, ThemeIcon } from 'vs/workbench/api/node/extHostTypes'; -import { isUndefinedOrNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, isString } from 'vs/base/common/types'; import { equals } from 'vs/base/common/arrays'; import { ILogService } from 'vs/platform/log/common/log'; type TreeItemHandle = string; +function toTreeItemLabel(label: any): ITreeItemLabel { + if (isString(label)) { + return { label }; + } + + if (label + && typeof label === 'object' + && typeof label.label === 'string') { + let highlights: [number, number][] = void 0; + if (Array.isArray(label.highlights)) { + highlights = (<[number, number][]>label.highlights).filter((highlight => highlight.length === 2 && typeof highlight[0] === 'number' && typeof highlight[1] === 'number')); + highlights = highlights.length ? highlights : void 0; + } + return { label: label.label, highlights }; + } + + return void 0; +} + + export class ExtHostTreeViews implements ExtHostTreeViewsShape { private treeViews: Map> = new Map>(); @@ -383,7 +403,7 @@ class ExtHostTreeView extends Disposable { const item = { handle, parentHandle: parent ? parent.item.handle : void 0, - label: extensionTreeItem.label, + label: toTreeItemLabel(extensionTreeItem.label), resourceUri: extensionTreeItem.resourceUri, tooltip: typeof extensionTreeItem.tooltip === 'string' ? extensionTreeItem.tooltip : void 0, command: extensionTreeItem.command ? this.commands.toInternal(extensionTreeItem.command) : void 0, @@ -402,8 +422,9 @@ class ExtHostTreeView extends Disposable { return `${ExtHostTreeView.ID_HANDLE_PREFIX}/${id}`; } + const treeItemLabel = toTreeItemLabel(label); const prefix: string = parent ? parent.item.handle : ExtHostTreeView.LABEL_HANDLE_PREFIX; - let elementId = label ? label : resourceUri ? basename(resourceUri.path) : ''; + let elementId = treeItemLabel ? treeItemLabel.label : resourceUri ? basename(resourceUri.path) : ''; elementId = elementId.indexOf('/') !== -1 ? elementId.replace('/', '//') : elementId; const existingHandle = this.nodes.has(element) ? this.nodes.get(element).item.handle : void 0; const childrenNodes = (this.getChildrenNodes(parent) || []); diff --git a/src/vs/workbench/api/node/extHostTypes.ts b/src/vs/workbench/api/node/extHostTypes.ts index 555c76511c7b3..3aee6feeb14ca 100644 --- a/src/vs/workbench/api/node/extHostTypes.ts +++ b/src/vs/workbench/api/node/extHostTypes.ts @@ -1791,16 +1791,16 @@ export enum ProgressLocation { export class TreeItem { - label?: string; + label?: string | vscode.TreeItemLabel; resourceUri?: URI; iconPath?: string | URI | { light: string | URI; dark: string | URI }; command?: vscode.Command; contextValue?: string; tooltip?: string; - constructor(label: string, collapsibleState?: vscode.TreeItemCollapsibleState) + constructor(label: string | vscode.TreeItemLabel, collapsibleState?: vscode.TreeItemCollapsibleState) constructor(resourceUri: URI, collapsibleState?: vscode.TreeItemCollapsibleState) - constructor(arg1: string | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) { + constructor(arg1: string | vscode.TreeItemLabel | URI, public collapsibleState: vscode.TreeItemCollapsibleState = TreeItemCollapsibleState.None) { if (arg1 instanceof URI) { this.resourceUri = arg1; } else { diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index b4abbb8fc870a..7fe21ac0b13d1 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -14,7 +14,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { ContextAwareMenuItemActionItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IViewsService, ITreeViewer, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ICustomViewDescriptor, ViewsRegistry, ViewContainer } from 'vs/workbench/common/views'; +import { IViewsService, ITreeViewer, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ICustomViewDescriptor, ViewsRegistry, ViewContainer, ITreeItemLabel } from 'vs/workbench/common/views'; import { IViewletViewOptions, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { INotificationService } from 'vs/platform/notification/common/notification'; @@ -164,7 +164,7 @@ class TitleMenus implements IDisposable { } class Root implements ITreeItem { - label = 'root'; + label = { label: 'root' }; handle = '0'; parentHandle = null; collapsibleState = TreeItemCollapsibleState.Expanded; @@ -513,7 +513,7 @@ class TreeRenderer implements IRenderer { DOM.addClass(container, 'custom-view-tree-node-item'); const icon = DOM.append(container, DOM.$('.custom-view-tree-node-item-icon')); - const resourceLabel = this.instantiationService.createInstance(ResourceLabel, container, {}); + const resourceLabel = this.instantiationService.createInstance(ResourceLabel, container, { supportHighlights: true }); DOM.addClass(resourceLabel.element, 'custom-view-tree-node-item-resourceLabel'); const actionsContainer = DOM.append(resourceLabel.element, DOM.$('.actions')); const actionBar = new ActionBar(actionsContainer, { @@ -526,7 +526,9 @@ class TreeRenderer implements IRenderer { renderElement(tree: ITree, node: ITreeItem, templateId: string, templateData: ITreeExplorerTemplateData): void { const resource = node.resourceUri ? URI.revive(node.resourceUri) : null; - const label = node.label ? node.label : resource ? basename(resource.path) : ''; + const treeItemLabel: ITreeItemLabel = node.label ? node.label : resource ? { label: basename(resource.path) } : void 0; + const label = treeItemLabel ? treeItemLabel.label : void 0; + const matches = treeItemLabel ? treeItemLabel.highlights.map(([start, end]) => ({ start, end })) : void 0; const icon = this.themeService.getTheme().type === LIGHT ? node.icon : node.iconDark; const iconUrl = icon ? URI.revive(icon) : null; const title = node.tooltip ? node.tooltip : resource ? void 0 : label; @@ -537,9 +539,9 @@ class TreeRenderer implements IRenderer { if (resource || node.themeIcon) { const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations'); - templateData.resourceLabel.setLabel({ name: label, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'] }); + templateData.resourceLabel.setLabel({ name: label, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches }); } else { - templateData.resourceLabel.setLabel({ name: label }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'] }); + templateData.resourceLabel.setLabel({ name: label }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches }); } templateData.icon.style.backgroundImage = iconUrl ? `url('${iconUrl.toString(true)}')` : ''; diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index 7d168a3455fcb..ab8d9857d8094 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -280,6 +280,14 @@ export enum TreeItemCollapsibleState { Expanded = 2 } +export interface ITreeItemLabel { + + label: string; + + highlights?: [number, number][]; + +} + export interface ITreeItem { handle: string; @@ -288,7 +296,7 @@ export interface ITreeItem { collapsibleState: TreeItemCollapsibleState; - label?: string; + label?: ITreeItemLabel; icon?: UriComponents; diff --git a/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts index 6e43ee0967c08..ee9704fd064c5 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTreeViews.test.ts @@ -74,6 +74,7 @@ suite('ExtHostTreeView', function () { onDidChangeTreeNodeWithId = new Emitter<{ key: string }>(); testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }); testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }); + testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }); return loadCompleteTree('testNodeTreeProvider'); }); @@ -134,6 +135,51 @@ suite('ExtHostTreeView', function () { }); }); + test('construct highlights tree', () => { + return testObject.$getChildren('testNodeWithHighlightsTreeProvider') + .then(elements => { + assert.deepEqual(removeUnsetKeys(elements), [{ + handle: '1/a', + label: { label: 'a', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.Collapsed + }, { + handle: '1/b', + label: { label: 'b', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.Collapsed + }]); + return Promise.all([ + testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/a') + .then(children => { + assert.deepEqual(removeUnsetKeys(children), [{ + handle: '1/aa', + parentHandle: '1/a', + label: { label: 'aa', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.None + }, { + handle: '1/ab', + parentHandle: '1/a', + label: { label: 'ab', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.None + }]); + }), + testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/b') + .then(children => { + assert.deepEqual(removeUnsetKeys(children), [{ + handle: '1/ba', + parentHandle: '1/b', + label: { label: 'ba', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.None + }, { + handle: '1/bb', + parentHandle: '1/b', + label: { label: 'bb', highlights: [[0, 2], [3, 5]] }, + collapsibleState: TreeItemCollapsibleState.None + }]); + }) + ]); + }); + }); + test('error is thrown if id is not unique', (done) => { tree['a'] = { 'aa': {}, @@ -169,7 +215,7 @@ suite('ExtHostTreeView', function () { assert.deepEqual(['0/0:b'], Object.keys(actuals)); assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', - label: 'b', + label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); c(null); @@ -184,7 +230,7 @@ suite('ExtHostTreeView', function () { assert.deepEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), { handle: '0/0:b/0:bb', parentHandle: '0/0:b', - label: 'bb', + label: { label: 'bb' }, collapsibleState: TreeItemCollapsibleState.None }); done(); @@ -197,13 +243,13 @@ suite('ExtHostTreeView', function () { assert.deepEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals)); assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', - label: 'b', + label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { handle: '0/0:a/0:aa', parentHandle: '0/0:a', - label: 'aa', + label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None }); done(); @@ -218,13 +264,13 @@ suite('ExtHostTreeView', function () { assert.deepEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals)); assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), { handle: '0/0:b', - label: 'b', + label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), { handle: '0/0:a/0:aa', parentHandle: '0/0:a', - label: 'aa', + label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None }); done(); @@ -240,7 +286,7 @@ suite('ExtHostTreeView', function () { assert.deepEqual(['0/0:a'], Object.keys(actuals)); assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), { handle: '0/0:aa', - label: 'aa', + label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.Collapsed }); done(); @@ -411,7 +457,7 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual({ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1])); assert.deepEqual([], revealTarget.args[0][2]); assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]); }); @@ -424,8 +470,8 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:a/0:aa', label: 'aa', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); + assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]); }); }); @@ -439,8 +485,8 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:a/0:aa', label: 'aa', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); + assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]); })); }); @@ -459,10 +505,10 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: 'bac', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: { label: 'bac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1])); assert.deepEqual([ - { handle: '0/0:b', label: 'b', collapsibleState: TreeItemCollapsibleState.Collapsed }, - { handle: '0/0:b/0:ba', label: 'ba', collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' } + { handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }, + { handle: '0/0:b/0:ba', label: { label: 'ba' }, collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' } ], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); assert.deepEqual({ select: false, focus: false }, revealTarget.args[0][3]); }); @@ -489,8 +535,8 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:a/0:ac', label: 'ac', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); + assert.deepEqual({ handle: '0/0:a/0:ac', label: { label: 'ac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]); }); }); @@ -528,8 +574,8 @@ suite('ExtHostTreeView', function () { .then(() => { assert.ok(revealTarget.calledOnce); assert.deepEqual('treeDataProvider', revealTarget.args[0][0]); - assert.deepEqual({ handle: '0/0:b/0:bc', label: 'bc', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1])); - assert.deepEqual([{ handle: '0/0:b', label: 'b', collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); + assert.deepEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1])); + assert.deepEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg))); assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]); }); }); @@ -542,13 +588,20 @@ suite('ExtHostTreeView', function () { } function removeUnsetKeys(obj: any): any { - const result = {}; - for (const key of Object.keys(obj)) { - if (obj[key] !== void 0) { - result[key] = obj[key]; + if (Array.isArray(obj)) { + return obj.map(o => removeUnsetKeys(o)); + } + + if (typeof obj === 'object') { + const result = {}; + for (const key of Object.keys(obj)) { + if (obj[key] !== void 0) { + result[key] = removeUnsetKeys(obj[key]); + } } + return result; } - return result; + return obj; } function aNodeTreeDataProvider(): TreeDataProvider<{ key: string }> { @@ -593,6 +646,20 @@ suite('ExtHostTreeView', function () { }; } + function aNodeWithHighlightedLabelTreeDataProvider(): TreeDataProvider<{ key: string }> { + return { + getChildren: (element: { key: string }): { key: string }[] => { + return getChildren(element ? element.key : undefined).map(key => getNode(key)); + }, + getTreeItem: (element: { key: string }): TreeItem => { + const treeItem = getTreeItem(element.key, [[0, 2], [3, 5]]); + treeItem.id = element.key; + return treeItem; + }, + onDidChangeTreeData: onDidChangeTreeNodeWithId.event + }; + } + function getTreeElement(element): any { let parent = tree; for (let i = 0; i < element.length; i++) { @@ -615,10 +682,10 @@ suite('ExtHostTreeView', function () { return []; } - function getTreeItem(key: string): TreeItem { + function getTreeItem(key: string, highlights?: [number, number][]): TreeItem { const treeElement = getTreeElement(key); return { - label: labels[key] || key, + label: { label: labels[key] || key, highlights }, collapsibleState: treeElement && Object.keys(treeElement).length ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None }; }