Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -1,216 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import * as resources from 'vs/base/common/resources';
import { createCSSRule } from 'vs/base/browser/dom';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions, ShowViewletAction } from 'vs/workbench/browser/viewlet';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IExtensionService, IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { Extensions as ViewContainerExtensions, IViewContainersRegistry, TEST_VIEW_CONTAINER_ID } from 'vs/workbench/common/views';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { forEach } from 'vs/base/common/collections';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { URI } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
export interface IUserFriendlyViewsContainerDescriptor {
id: string;
title: string;
icon: string;
}
export interface IUserFriendlyViewsContainerDescriptor2 {
id: string;
title: string;
icon: URI;
}
const viewsContainerSchema: IJSONSchema = {
type: 'object',
properties: {
id: {
description: localize({ key: 'vscode.extension.contributes.views.containers.id', comment: ['Contribution refers to those that an extension contributes to VS Code through an extension/contribution point. '] }, "Unique id used to identify the container in which views can be contributed using 'views' contribution point"),
type: 'string',
pattern: '^[a-zA-Z0-9_-]+$'
},
title: {
description: localize('vscode.extension.contributes.views.containers.title', 'Human readable string used to render the container'),
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.views.containers.icon', "Path to the container icon. Icons are 24x24 centered on a 50x40 block and have a fill color of 'rgb(215, 218, 224)' or '#d7dae0'. It is recommended that icons be in SVG, though any image file type is accepted."),
type: 'string'
}
}
};
export const viewsContainersContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.viewsContainers', 'Contributes views containers to the editor'),
type: 'object',
properties: {
'activitybar': {
description: localize('views.container.activitybar', "Contribute views containers to Activity Bar"),
type: 'array',
items: viewsContainerSchema
}
}
};
export const viewsContainersExtensionPoint: IExtensionPoint<{ [loc: string]: IUserFriendlyViewsContainerDescriptor[] }> = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: IUserFriendlyViewsContainerDescriptor[] }>('viewsContainers', [], viewsContainersContribution);
const TEST_VIEW_CONTAINER_ORDER = 6;
class ViewsContainersExtensionHandler implements IWorkbenchContribution {
constructor() {
this.registerTestViewContainer();
this.handleAndRegisterCustomViewContainers();
}
private registerTestViewContainer(): void {
const title = localize('test', "Test");
const cssClass = `extensionViewlet-test`;
const icon = URI.parse(require.toUrl('./media/test.svg'));
this.registerCustomViewlet({ id: TEST_VIEW_CONTAINER_ID, title, icon }, TEST_VIEW_CONTAINER_ORDER, cssClass, void 0);
}
private handleAndRegisterCustomViewContainers() {
let order = TEST_VIEW_CONTAINER_ORDER + 1;
viewsContainersExtensionPoint.setHandler((extensions) => {
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!this.isValidViewsContainer(entry.value, collector)) {
return;
}
switch (entry.key) {
case 'activitybar':
order = this.registerCustomViewContainers(entry.value, extension.description, order);
break;
}
});
}
});
}
private isValidViewsContainer(viewsContainersDescriptors: IUserFriendlyViewsContainerDescriptor[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(viewsContainersDescriptors)) {
collector.error(localize('requirearray', "views containers must be an array"));
return false;
}
for (let descriptor of viewsContainersDescriptors) {
if (typeof descriptor.id !== 'string') {
collector.error(localize('requireidstring', "property `{0}` is mandatory and must be of type `string`. Only alphanumeric characters, '_', and '-' are allowed.", 'id'));
return false;
}
if (!(/^[a-z0-9_-]+$/i.test(descriptor.id))) {
collector.error(localize('requireidstring', "property `{0}` is mandatory and must be of type `string`. Only alphanumeric characters, '_', and '-' are allowed.", 'id'));
return false;
}
if (typeof descriptor.title !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'title'));
return false;
}
if (typeof descriptor.icon !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'icon'));
return false;
}
}
return true;
}
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number): number {
containers.forEach(descriptor => {
const cssClass = `extensionViewlet-${descriptor.id}`;
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
this.registerCustomViewlet({ id: `workbench.view.extension.${descriptor.id}`, title: descriptor.title, icon }, order++, cssClass, extension.id);
});
return order;
}
private registerCustomViewlet(descriptor: IUserFriendlyViewsContainerDescriptor2, order: number, cssClass: string, extensionId: string): void {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);
const id = descriptor.id;
if (!viewletRegistry.getViewlet(id)) {
viewContainersRegistry.registerViewContainer(id, extensionId);
// Register as viewlet
class CustomViewlet extends ViewContainerViewlet {
constructor(
@IConfigurationService configurationService: IConfigurationService,
@IPartService partService: IPartService,
@ITelemetryService telemetryService: ITelemetryService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService,
@IEditorService editorService: IEditorService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextMenuService contextMenuService: IContextMenuService,
@IExtensionService extensionService: IExtensionService
) {
super(id, `${id}.state`, true, configurationService, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
}
}
const viewletDescriptor = new ViewletDescriptor(
CustomViewlet,
id,
descriptor.title,
cssClass,
order,
descriptor.icon
);
viewletRegistry.registerViewlet(viewletDescriptor);
// Register Action to Open Viewlet
class OpenCustomViewletAction extends ShowViewletAction {
constructor(
id: string, label: string,
@IViewletService viewletService: IViewletService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPartService partService: IPartService
) {
super(id, label, id, viewletService, editorGroupService, partService);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(
new SyncActionDescriptor(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", descriptor.title)),
'View: Show {0}',
localize('view', "View")
);
// Generate CSS to show the icon in the activity bar
const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${cssClass}`;
createCSSRule(iconClass, `-webkit-mask: url('${descriptor.icon}') no-repeat 50% 50%`);
}
}
}
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ViewsContainersExtensionHandler, LifecyclePhase.Starting);

View File

@@ -6,12 +6,12 @@
import { localize } from 'vs/nls';
import { forEach } from 'vs/base/common/collections';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewContainer, ViewsRegistry, ICustomViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions } from 'vs/workbench/common/views';
import * as resources from 'vs/base/common/resources';
import { ExtensionMessageCollector, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry';
import { ViewContainer, ViewsRegistry, ITreeViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IViewDescriptor } from 'vs/workbench/common/views';
import { CustomTreeViewPanel, CustomTreeView } from 'vs/workbench/browser/parts/views/customView';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { coalesce, } from 'vs/base/common/arrays';
import { viewsContainersExtensionPoint } from 'vs/workbench/api/browser/viewsContainersExtensionPoint';
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';
@@ -19,6 +19,61 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/parts/files/common/files';
import { VIEWLET_ID as SCM } from 'vs/workbench/parts/scm/common/scm';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/parts/debug/common/debug';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor, ShowViewletAction } from 'vs/workbench/browser/viewlet';
import { IExtensionDescription, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { createCSSRule } from 'vs/base/browser/dom';
export interface IUserFriendlyViewsContainerDescriptor {
id: string;
title: string;
icon: string;
}
const viewsContainerSchema: IJSONSchema = {
type: 'object',
properties: {
id: {
description: localize({ key: 'vscode.extension.contributes.views.containers.id', comment: ['Contribution refers to those that an extension contributes to VS Code through an extension/contribution point. '] }, "Unique id used to identify the container in which views can be contributed using 'views' contribution point"),
type: 'string',
pattern: '^[a-zA-Z0-9_-]+$'
},
title: {
description: localize('vscode.extension.contributes.views.containers.title', 'Human readable string used to render the container'),
type: 'string'
},
icon: {
description: localize('vscode.extension.contributes.views.containers.icon', "Path to the container icon. Icons are 24x24 centered on a 50x40 block and have a fill color of 'rgb(215, 218, 224)' or '#d7dae0'. It is recommended that icons be in SVG, though any image file type is accepted."),
type: 'string'
}
}
};
export const viewsContainersContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.viewsContainers', 'Contributes views containers to the editor'),
type: 'object',
properties: {
'activitybar': {
description: localize('views.container.activitybar', "Contribute views containers to Activity Bar"),
type: 'array',
items: viewsContainerSchema
}
}
};
interface IUserFriendlyViewDescriptor {
id: string;
@@ -81,69 +136,282 @@ const viewsContribution: IJSONSchema = {
}
};
export interface ICustomViewDescriptor extends ITreeViewDescriptor {
readonly extensionId: ExtensionIdentifier;
readonly originalContainerId: string;
}
const viewsExtensionPoint: IExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }> = ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: IUserFriendlyViewDescriptor[] }>('views', [viewsContainersExtensionPoint], viewsContribution);
type ViewContainerExtensionPointType = { [loc: string]: IUserFriendlyViewsContainerDescriptor[] };
// {{SQL CARBON EDIT}} - Export viewsContainersExtensionPoint
export const viewsContainersExtensionPoint: IExtensionPoint<ViewContainerExtensionPointType> = ExtensionsRegistry.registerExtensionPoint<ViewContainerExtensionPointType>({
extensionPoint: 'viewsContainers',
jsonSchema: viewsContainersContribution,
isDynamic: true
});
class ViewsContainersExtensionHandler implements IWorkbenchContribution {
type ViewExtensionPointType = { [loc: string]: IUserFriendlyViewDescriptor[] };
const viewsExtensionPoint: IExtensionPoint<ViewExtensionPointType> = ExtensionsRegistry.registerExtensionPoint<ViewExtensionPointType>({
extensionPoint: 'views',
deps: [viewsContainersExtensionPoint],
jsonSchema: viewsContribution,
isDynamic: true
});
const TEST_VIEW_CONTAINER_ORDER = 6;
class ViewsExtensionHandler implements IWorkbenchContribution {
private viewContainersRegistry: IViewContainersRegistry;
constructor(
@IInstantiationService private instantiationService: IInstantiationService
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
this.viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
this.handleAndRegisterCustomViewContainers();
this.handleAndRegisterCustomViews();
}
private handleAndRegisterCustomViews() {
viewsExtensionPoint.setHandler(extensions => {
for (let extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!this.isValidViewDescriptors(entry.value, collector)) {
return;
}
let container = this.getViewContainer(entry.key);
if (!container) {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Data Explorer'.", entry.key));
container = this.viewContainersRegistry.get(EXPLORER);
}
const registeredViews = ViewsRegistry.getViews(container);
const viewIds: string[] = [];
const viewDescriptors = coalesce(entry.value.map((item, index) => {
// validate
if (viewIds.indexOf(item.id) !== -1) {
collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the view container `{1}`", item.id, container.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 view container `{1}`", item.id, container.id));
return null;
}
const viewDescriptor = <ICustomViewDescriptor>{
id: item.id,
name: item.name,
ctor: CustomTreeViewPanel,
container,
when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true,
collapsed: this.showCollapsed(container),
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, container),
order: extension.description.id === container.extensionId ? index + 1 : void 0
};
viewIds.push(viewDescriptor.id);
return viewDescriptor;
}));
ViewsRegistry.registerViews(viewDescriptors);
});
private handleAndRegisterCustomViewContainers() {
this.registerTestViewContainer();
viewsContainersExtensionPoint.setHandler((extensions, { added, removed }) => {
if (removed.length) {
this.removeCustomViewContainers(removed);
}
if (added.length) {
this.addCustomViewContainers(added, this.viewContainersRegistry.all);
}
});
}
private addCustomViewContainers(extensionPoints: IExtensionPointUser<ViewContainerExtensionPointType>[], existingViewContainers: ViewContainer[]): void {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
let order = TEST_VIEW_CONTAINER_ORDER + viewContainersRegistry.all.filter(v => !!v.extensionId).length + 1;
for (let { value, collector, description } of extensionPoints) {
forEach(value, entry => {
if (!this.isValidViewsContainer(entry.value, collector)) {
return;
}
switch (entry.key) {
case 'activitybar':
order = this.registerCustomViewContainers(entry.value, description, order, existingViewContainers);
break;
}
});
}
}
private removeCustomViewContainers(extensionPoints: IExtensionPointUser<ViewContainerExtensionPointType>[]): void {
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
const removedExtensions: Set<string> = extensionPoints.reduce((result, e) => { result.add(ExtensionIdentifier.toKey(e.description.identifier)); return result; }, new Set<string>());
for (const viewContainer of viewContainersRegistry.all) {
if (viewContainer.extensionId && removedExtensions.has(ExtensionIdentifier.toKey(viewContainer.extensionId))) {
// move only those views that do not belong to the removed extension
const views = ViewsRegistry.getViews(viewContainer).filter((view: ICustomViewDescriptor) => !removedExtensions.has(ExtensionIdentifier.toKey(view.extensionId)));
if (views.length) {
ViewsRegistry.moveViews(views, this.getDefaultViewContainer());
}
this.deregisterCustomViewContainer(viewContainer);
}
}
}
private registerTestViewContainer(): void {
const title = localize('test', "Test");
const cssClass = `extensionViewlet-test`;
const icon = URI.parse(require.toUrl('./media/test.svg'));
this.registerCustomViewContainer(TEST_VIEW_CONTAINER_ID, title, icon, TEST_VIEW_CONTAINER_ORDER, cssClass, undefined);
}
private isValidViewsContainer(viewsContainersDescriptors: IUserFriendlyViewsContainerDescriptor[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(viewsContainersDescriptors)) {
collector.error(localize('viewcontainer requirearray', "views containers must be an array"));
return false;
}
for (let descriptor of viewsContainersDescriptors) {
if (typeof descriptor.id !== 'string') {
collector.error(localize('requireidstring', "property `{0}` is mandatory and must be of type `string`. Only alphanumeric characters, '_', and '-' are allowed.", 'id'));
return false;
}
if (!(/^[a-z0-9_-]+$/i.test(descriptor.id))) {
collector.error(localize('requireidstring', "property `{0}` is mandatory and must be of type `string`. Only alphanumeric characters, '_', and '-' are allowed.", 'id'));
return false;
}
if (typeof descriptor.title !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'title'));
return false;
}
if (typeof descriptor.icon !== 'string') {
collector.error(localize('requirestring', "property `{0}` is mandatory and must be of type `string`", 'icon'));
return false;
}
}
return true;
}
private registerCustomViewContainers(containers: IUserFriendlyViewsContainerDescriptor[], extension: IExtensionDescription, order: number, existingViewContainers: ViewContainer[]): number {
containers.forEach(descriptor => {
const cssClass = `extensionViewlet-${descriptor.id}`;
const icon = resources.joinPath(extension.extensionLocation, descriptor.icon);
const id = `workbench.view.extension.${descriptor.id}`;
const viewContainer = this.registerCustomViewContainer(id, descriptor.title, icon, order++, cssClass, extension.identifier);
// Move those views that belongs to this container
if (existingViewContainers.length) {
const viewsToMove: IViewDescriptor[] = [];
for (const existingViewContainer of existingViewContainers) {
if (viewContainer !== existingViewContainer) {
viewsToMove.push(...ViewsRegistry.getViews(existingViewContainer).filter((view: ICustomViewDescriptor) => view.originalContainerId === descriptor.id));
}
}
if (viewsToMove.length) {
ViewsRegistry.moveViews(viewsToMove, viewContainer);
}
}
});
return order;
}
private registerCustomViewContainer(id: string, title: string, icon: URI, order: number, cssClass: string, extensionId: ExtensionIdentifier | undefined): ViewContainer {
let viewContainer = this.viewContainersRegistry.get(id);
if (!viewContainer) {
viewContainer = this.viewContainersRegistry.registerViewContainer(id, extensionId);
// Register as viewlet
class CustomViewlet extends ViewContainerViewlet {
constructor(
@IConfigurationService configurationService: IConfigurationService,
@IPartService partService: IPartService,
@ITelemetryService telemetryService: ITelemetryService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService,
@IEditorService editorService: IEditorService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextMenuService contextMenuService: IContextMenuService,
@IExtensionService extensionService: IExtensionService
) {
super(id, `${id}.state`, true, configurationService, partService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
}
}
const viewletDescriptor = new ViewletDescriptor(
CustomViewlet,
id,
title,
cssClass,
order,
icon
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
// Register Action to Open Viewlet
class OpenCustomViewletAction extends ShowViewletAction {
constructor(
id: string, label: string,
@IViewletService viewletService: IViewletService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPartService partService: IPartService
) {
super(id, label, id, viewletService, editorGroupService, partService);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(
new SyncActionDescriptor(OpenCustomViewletAction, id, localize('showViewlet', "Show {0}", title)),
'View: Show {0}',
localize('view', "View")
);
// Generate CSS to show the icon in the activity bar
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${cssClass}`;
createCSSRule(iconClass, `-webkit-mask: url('${icon}') no-repeat 50% 50%`);
}
return viewContainer;
}
private deregisterCustomViewContainer(viewContainer: ViewContainer): void {
this.viewContainersRegistry.deregisterViewContainer(viewContainer);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).deregisterViewlet(viewContainer.id);
}
private handleAndRegisterCustomViews() {
viewsExtensionPoint.setHandler((extensions, { added, removed }) => {
if (removed.length) {
this.removeViews(removed);
}
if (added.length) {
this.addViews(added);
}
});
}
private addViews(extensions: IExtensionPointUser<ViewExtensionPointType>[]): void {
for (const extension of extensions) {
const { value, collector } = extension;
forEach(value, entry => {
if (!this.isValidViewDescriptors(entry.value, collector)) {
return;
}
let container = this.getViewContainer(entry.key);
if (!container) {
collector.warn(localize('ViewContainerDoesnotExist', "View container '{0}' does not exist and all views registered to it will be added to 'Explorer'.", entry.key));
container = this.getDefaultViewContainer();
}
const registeredViews = ViewsRegistry.getViews(container);
const viewIds: string[] = [];
const viewDescriptors = coalesce(entry.value.map((item, index) => {
// validate
if (viewIds.indexOf(item.id) !== -1) {
collector.error(localize('duplicateView1', "Cannot register multiple views with same id `{0}` in the view container `{1}`", item.id, container.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 view container `{1}`", item.id, container.id));
return null;
}
const viewDescriptor = <ICustomViewDescriptor>{
id: item.id,
name: item.name,
ctor: CustomTreeViewPanel,
when: ContextKeyExpr.deserialize(item.when),
canToggleVisibility: true,
collapsed: this.showCollapsed(container),
treeView: this.instantiationService.createInstance(CustomTreeView, item.id, container),
order: ExtensionIdentifier.equals(extension.description.identifier, container.extensionId) ? index + 1 : undefined,
extensionId: extension.description.identifier,
originalContainerId: entry.key
};
viewIds.push(viewDescriptor.id);
return viewDescriptor;
}));
ViewsRegistry.registerViews(viewDescriptors, container);
});
}
}
private getDefaultViewContainer(): ViewContainer {
return this.viewContainersRegistry.get(EXPLORER);
}
private removeViews(extensions: IExtensionPointUser<ViewExtensionPointType>[]): void {
const removedExtensions: Set<string> = extensions.reduce((result, e) => { result.add(ExtensionIdentifier.toKey(e.description.identifier)); return result; }, new Set<string>());
for (const viewContainer of this.viewContainersRegistry.all) {
const removedViews = ViewsRegistry.getViews(viewContainer).filter((v: ICustomViewDescriptor) => v.extensionId && removedExtensions.has(ExtensionIdentifier.toKey(v.extensionId)));
if (removedViews.length) {
ViewsRegistry.deregisterViews(removedViews, viewContainer);
}
}
}
private isValidViewDescriptors(viewDescriptors: IUserFriendlyViewDescriptor[], collector: ExtensionMessageCollector): boolean {
if (!Array.isArray(viewDescriptors)) {
collector.error(localize('requirearray', "views must be an array"));
@@ -168,7 +436,6 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
return true;
}
private getViewContainer(value: string): ViewContainer {
switch (value) {
case 'explorer': return this.viewContainersRegistry.get(EXPLORER);
@@ -190,4 +457,4 @@ class ViewsContainersExtensionHandler implements IWorkbenchContribution {
}
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(ViewsContainersExtensionHandler, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(ViewsExtensionHandler, LifecyclePhase.Starting);