viewsExtensionPoint.ts 7.4 KB
Newer Older
S
Sandeep Somavarapu 已提交
1 2 3 4 5 6 7 8 9
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
'use strict';

import { localize } from 'vs/nls';
import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
10
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
S
Sandeep Somavarapu 已提交
11
import { ViewLocation, ViewsRegistry, ICustomViewDescriptor } from 'vs/workbench/common/views';
12
import { CustomTreeViewPanel, CustomTreeViewer } from 'vs/workbench/browser/parts/views/customView';
S
#27823  
Sandeep Somavarapu 已提交
13
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
S
Sandeep Somavarapu 已提交
14
import { coalesce, } from 'vs/base/common/arrays';
S
Sandeep Somavarapu 已提交
15
import { viewsContainersExtensionPoint } from 'vs/workbench/api/browser/viewsContainersExtensionPoint';
16 17 18 19 20
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ProgressLocation } from 'vs/platform/progress/common/progress';
S
Sandeep Somavarapu 已提交
21

22 23 24 25 26
interface IUserFriendlyViewDescriptor {
	id: string;
	name: string;
	when?: string;
}
S
Sandeep Somavarapu 已提交
27

28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
const viewDescriptor: IJSONSchema = {
	type: 'object',
	properties: {
		id: {
			description: localize('vscode.extension.contributes.view.id', 'Identifier of the view. Use this to register a data provider through `vscode.window.registerTreeDataProviderForView` API. Also to trigger activating your extension by registering `onView:${id}` event to `activationEvents`.'),
			type: 'string'
		},
		name: {
			description: localize('vscode.extension.contributes.view.name', 'The human-readable name of the view. Will be shown'),
			type: 'string'
		},
		when: {
			description: localize('vscode.extension.contributes.view.when', 'Condition which must be true to show this view'),
			type: 'string'
		},
S
Sandeep Somavarapu 已提交
43
	}
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
};

const viewsContribution: IJSONSchema = {
	description: localize('vscode.extension.contributes.views', "Contributes views to the editor"),
	type: 'object',
	properties: {
		'explorer': {
			description: localize('views.explorer', "Contributes views to Explorer container in the Activity bar"),
			type: 'array',
			items: viewDescriptor,
			default: []
		},
		'debug': {
			description: localize('views.debug', "Contributes views to Debug container in the Activity bar"),
			type: 'array',
			items: viewDescriptor,
			default: []
		},
		'scm': {
			description: localize('views.scm', "Contributes views to SCM container in the Activity bar"),
			type: 'array',
			items: viewDescriptor,
			default: []
		},
		'test': {
			description: localize('views.test', "Contributes views to Test container in the Activity bar"),
			type: 'array',
			items: viewDescriptor,
			default: []
		}
	},
	additionalProperties: {
		description: localize('views.contributed', "Contributes views to contributed views container"),
		type: 'array',
		items: viewDescriptor,
		default: []
	}
};


const viewsExtensionPoint: IExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }> = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }>('views', [viewsContainersExtensionPoint], viewsContribution);

class ViewsContainersExtensionHandler implements IWorkbenchContribution {
	constructor(
		@IInstantiationService private instantiationService: IInstantiationService
	) {
		this.handleAndRegisterCustomViews();
	}

	private handleAndRegisterCustomViews() {
		viewsExtensionPoint.setHandler(extensions => {
			for (let extension of extensions) {
				const { value, collector } = extension;
S
Sandeep Somavarapu 已提交
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
				forEach(value, entry => {
					if (!this.isValidViewDescriptors(entry.value, collector)) {
						return;
					}

					let location = this.getViewLocation(entry.key);
					if (!location) {
						collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
						location = ViewLocation.Explorer;
					}
					const registeredViews = ViewsRegistry.getViews(location);
					const viewIds = [];
					const viewDescriptors = coalesce(entry.value.map(item => {
						// validate
						if (viewIds.indexOf(item.id) !== -1) {
							collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the location `{1}`", item.id, location.id));
							return null;
						}
						if (registeredViews.some(v => v.id === item.id)) {
							collector.error(localize('duplicateView2', "A view with id `{0}` is already registered in the location `{1}`", item.id, location.id));
							return null;
						}

						const viewDescriptor = <ICustomViewDescriptor>{
							id: item.id,
							name: item.name,
							ctor: CustomTreeViewPanel,
							location,
							when: ContextKeyExpr.deserialize(item.when),
							canToggleVisibility: true,
							collapsed: this.showCollapsed(location),
							treeViewer: this.instantiationService.createInstance(CustomTreeViewer, item.id, this.getProgressLocation(location))
						};

						viewIds.push(viewDescriptor.id);
						return viewDescriptor;
					}));
					ViewsRegistry.registerViews(viewDescriptors);
				});
			}
		});
	}

	private getProgressLocation(location: ViewLocation): ProgressLocation {
		switch (location.id) {
			case ViewLocation.Explorer.id:
				return ProgressLocation.Explorer;
			case ViewLocation.SCM.id:
				return ProgressLocation.Scm;
			case ViewLocation.Debug.id:
				return null /* No debug progress location yet */;
		}
		return null;
	}

	private isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
S
Sandeep Somavarapu 已提交
154 155 156 157 158 159 160 161 162 163 164
		if (!Array.isArray(viewDescriptors)) {
			collector.error(localize('requirearray', "views must be an array"));
			return false;
		}

		for (let descriptor of viewDescriptors) {
			if (typeof descriptor.id !== 'string') {
				collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'id'));
				return false;
			}
			if (typeof descriptor.name !== 'string') {
S
Sandeep Somavarapu 已提交
165
				collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'name'));
S
Sandeep Somavarapu 已提交
166 167
				return false;
			}
S
#27823  
Sandeep Somavarapu 已提交
168 169 170 171
			if (descriptor.when && typeof descriptor.when !== 'string') {
				collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when'));
				return false;
			}
S
Sandeep Somavarapu 已提交
172 173 174 175 176 177
		}

		return true;
	}


178 179 180 181 182 183 184
	private getViewLocation(value: string): ViewLocation {
		switch (value) {
			case 'explorer': return ViewLocation.Explorer;
			case 'debug': return ViewLocation.Debug;
			case 'scm': return ViewLocation.SCM;
			default: return ViewLocation.get(`workbench.view.extension.${value}`);
		}
185 186
	}

187 188 189 190 191 192 193 194
	private showCollapsed(location: ViewLocation): boolean {
		switch (location) {
			case ViewLocation.Explorer:
			case ViewLocation.SCM:
			case ViewLocation.Debug:
				return true;
		}
		return false;
195 196 197
	}
}

198 199
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ViewsContainersExtensionHandler, LifecyclePhase.Starting);