Skip to content

Commit

Permalink
Allow extensions to specify custom tree view resoure type
Browse files Browse the repository at this point in the history
The FileKind was previously guessed from the collapsability of the item,
extensions now have the capability to set it manually.

Fixes #43216
  • Loading branch information
vbfox committed Feb 23, 2018
1 parent 2d1f6d4 commit 03caa41
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 15 deletions.
27 changes: 24 additions & 3 deletions src/vs/vscode.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5063,6 +5063,25 @@ declare module 'vscode' {
getChildren(element?: T): ProviderResult<T[]>;
}

/**
* A category in a File Icon Theme, either [file](#ThemeIconCategory.file) or [folder](#ThemeIconCategory.folder)
*/
export class ThemeIconCategory {

This comment has been minimized.

Copy link
@jrieken

jrieken Feb 26, 2018

Member

@sandy081 Why is this a class (with a private ctor) and not an enum?

This comment has been minimized.

Copy link
@sandy081

sandy081 Feb 27, 2018

Member

@jrieken It can be enum.

@aeschli Do we have any plans in future to extend this class to have more properties?

This comment has been minimized.

Copy link
@aeschli

aeschli Feb 27, 2018

Contributor

@jrieken The constructor will become public once we allow user defined named icons.
The idea is to do the same as with ThemeColor

This comment has been minimized.

Copy link
@jrieken

jrieken Feb 27, 2018

Member

Ok, makes sense. Maybe then document the actual values of File and Folder

/**
* Use the File Icon Theme for files
*/
static readonly File: ThemeIconCategory;

/**
* Use the File Icon Theme for files
*/
static readonly Folder: ThemeIconCategory;

readonly id: string;

private constructor(id: string);
}

export class TreeItem {
/**
* A human-readable string describing this item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri).
Expand All @@ -5077,15 +5096,17 @@ declare module 'vscode' {
id?: string;

/**
* The icon path for the tree item. When `falsy`, it is derived from [resourceUri](#TreeItem.resourceUri).
* The icon path for the tree item.
* When `falsy` it is derived from [resourceUri](#TreeItem.resourceUri) and the current theme (As a file if the node isn't collapsible or for folders otherwise)
* When a [ThemeIconCategory](#ThemeIconCategory) is specified it is derived from [resourceUri](#TreeItem.resourceUri) and the current theme for the specified category.
*/
iconPath?: string | Uri | { light: string | Uri; dark: string | Uri };
iconPath?: string | Uri | { light: string | Uri | ThemeIconCategory; dark: string | Uri | ThemeIconCategory } | ThemeIconCategory;

/**
* The [uri](#Uri) of the resource representing this item.
*
* Will be used to derive the [label](#TreeItem.label), when it is not provided.
* Will be used to derive the icon from current file icon theme, when [iconPath](#TreeItem.iconPath) is not provided.
* Will be used to derive the icon from current icon theme, when [iconPath](#TreeItem.iconPath) is not provided or is a [ThemeIconCategory](#ThemeIconCategory).
*/
resourceUri?: Uri;

Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/api/node/extHost.api.impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ export function createApiFactory(
WorkspaceEdit: extHostTypes.WorkspaceEdit,
ProgressLocation: extHostTypes.ProgressLocation,
TreeItemCollapsibleState: extHostTypes.TreeItemCollapsibleState,
ThemeIconCategory: extHostTypes.ThemeIconCategory,
TreeItem: extHostTypes.TreeItem,
ThemeColor: extHostTypes.ThemeColor,
// functions
Expand Down
17 changes: 11 additions & 6 deletions src/vs/workbench/api/node/extHostTreeViews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import { debounceEvent } from 'vs/base/common/event';
import { TPromise } from 'vs/base/common/winjs.base';
import { Disposable } from 'vs/base/common/lifecycle';
import { ExtHostTreeViewsShape, MainThreadTreeViewsShape } from './extHost.protocol';
import { ITreeItem, TreeViewItemHandleArg } from 'vs/workbench/common/views';
import { ITreeItem, TreeViewItemHandleArg, IThemeIconCategory } from 'vs/workbench/common/views';
import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands';
import { asWinJsPromise } from 'vs/base/common/async';
import { coalesce } from 'vs/base/common/arrays';
import { TreeItemCollapsibleState } from 'vs/workbench/api/node/extHostTypes';
import { TreeItemCollapsibleState, ThemeIconCategory as ExtHostThemeIconCategory } from 'vs/workbench/api/node/extHostTypes';
import { isUndefinedOrNull } from 'vs/base/common/types';

type TreeItemHandle = string;
Expand Down Expand Up @@ -214,27 +214,32 @@ class ExtHostTreeView<T> extends Disposable {
throw new Error('This should not be reached');
}

private getLightIconPath(extensionTreeItem: vscode.TreeItem): string {
private getLightIconPath(extensionTreeItem: vscode.TreeItem): string | IThemeIconCategory {
if (extensionTreeItem.iconPath) {
if (typeof extensionTreeItem.iconPath === 'string' || extensionTreeItem.iconPath instanceof URI) {
if (typeof extensionTreeItem.iconPath === 'string'
|| extensionTreeItem.iconPath instanceof URI
|| extensionTreeItem.iconPath instanceof ExtHostThemeIconCategory) {
return this.getIconPath(extensionTreeItem.iconPath);
}
return this.getIconPath(extensionTreeItem.iconPath['light']);
}
return void 0;
}

private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string {
private getDarkIconPath(extensionTreeItem: vscode.TreeItem): string | IThemeIconCategory {
if (extensionTreeItem.iconPath && extensionTreeItem.iconPath['dark']) {
return this.getIconPath(extensionTreeItem.iconPath['dark']);
}
return void 0;
}

private getIconPath(iconPath: string | URI): string {
private getIconPath(iconPath: string | URI | ExtHostThemeIconCategory): string | IThemeIconCategory {
if (iconPath instanceof URI) {
return iconPath.toString();
}
if (iconPath instanceof ExtHostThemeIconCategory) {
return { id: iconPath.id };
}
return URI.file(iconPath).toString();
}

Expand Down
12 changes: 12 additions & 0 deletions src/vs/workbench/api/node/extHostTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1544,6 +1544,18 @@ export enum TreeItemCollapsibleState {
Expanded = 2
}

export class ThemeIconCategory {
static readonly File = new ThemeIconCategory('file');

static readonly Folder = new ThemeIconCategory('folder');

readonly id: string;

private constructor(id: string) {
this.id = id;
}
}

export class ThemeColor {
id: string;
constructor(id: string) {
Expand Down
19 changes: 15 additions & 4 deletions src/vs/workbench/browser/parts/views/customView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import * as DOM from 'vs/base/browser/dom';
import { $ } from 'vs/base/browser/builder';
import { LIGHT } from 'vs/platform/theme/common/themeService';
import { ITree, IDataSource, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
import { TreeItemCollapsibleState, ITreeItem, ITreeViewer, ICustomViewsService, ITreeViewDataProvider, ViewsRegistry, IViewDescriptor, TreeViewItemHandleArg, ICustomViewDescriptor } from 'vs/workbench/common/views';
import { TreeItemCollapsibleState, ITreeItem, ITreeViewer, ICustomViewsService, ITreeViewDataProvider, ViewsRegistry, IViewDescriptor, TreeViewItemHandleArg, ICustomViewDescriptor, FileThemeIconCategoryId, FolderThemeIconCategoryId } from 'vs/workbench/common/views';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IExtensionService } from 'vs/platform/extensions/common/extensions';
import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress';
Expand Down Expand Up @@ -414,8 +414,19 @@ class TreeRenderer implements IRenderer {
DOM.removeClass(templateData.label, 'custom-view-tree-node-item-label');
DOM.removeClass(templateData.resourceLabel.element, 'custom-view-tree-node-item-resourceLabel');

if (resource && !icon) {
templateData.resourceLabel.setLabel({ name: label, resource }, { fileKind: node.collapsibleState === TreeItemCollapsibleState.Collapsed || node.collapsibleState === TreeItemCollapsibleState.Expanded ? FileKind.FOLDER : FileKind.FILE, title: node.tooltip });
if (resource && (typeof icon !== 'string')) {
let fileKind = node.collapsibleState === TreeItemCollapsibleState.Collapsed || node.collapsibleState === TreeItemCollapsibleState.Expanded ? FileKind.FOLDER : FileKind.FILE;
if (icon && icon.id) {
switch (icon.id) {
case FileThemeIconCategoryId:
fileKind = FileKind.FILE;
break;
case FolderThemeIconCategoryId:
fileKind = FileKind.FOLDER;
break;
}
}
templateData.resourceLabel.setLabel({ name: label, resource }, { fileKind, title: node.tooltip });
DOM.addClass(templateData.resourceLabel.element, 'custom-view-tree-node-item-resourceLabel');
} else {
templateData.label.textContent = label;
Expand Down Expand Up @@ -460,7 +471,7 @@ class TreeItemIcon extends Disposable {
const fileIconTheme = this.themeService.getFileIconTheme();
const contributedIcon = this.themeService.getTheme().type === LIGHT ? this._treeItem.icon : this._treeItem.iconDark;

const hasContributedIcon = !!contributedIcon;
const hasContributedIcon = typeof contributedIcon === 'string';
const hasChildren = this._treeItem.collapsibleState !== TreeItemCollapsibleState.None;
const hasResource = !!this._treeItem.resourceUri;
const isFolder = hasResource && hasChildren;
Expand Down
11 changes: 9 additions & 2 deletions src/vs/workbench/common/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,13 @@ export enum TreeItemCollapsibleState {
Expanded = 2
}

export const FileThemeIconCategoryId = 'file';
export const FolderThemeIconCategoryId = 'folder';

export interface IThemeIconCategory {
readonly id: string;
}

export interface ITreeItem {

handle: string;
Expand All @@ -208,9 +215,9 @@ export interface ITreeItem {

label?: string;

icon?: string;
icon?: string | IThemeIconCategory;

iconDark?: string;
iconDark?: string | IThemeIconCategory;

resourceUri?: UriComponents;

Expand Down

0 comments on commit 03caa41

Please sign in to comment.