Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -5,19 +5,20 @@
import 'vs/css!./media/views';
import { Disposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TPromise } from 'vs/base/common/winjs.base';
import { IViewsService, ViewsRegistry, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, TEST_VIEW_CONTAINER_ID, IView } from 'vs/workbench/common/views';
import { IViewsService, ViewsRegistry, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, IView, IViewDescriptorCollection } from 'vs/workbench/common/views';
import { Registry } from 'vs/platform/registry/common/platform';
import { ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IContextKeyService, IContextKeyChangeEvent, IReadableSet } from 'vs/platform/contextkey/common/contextkey';
import { IContextKeyService, IContextKeyChangeEvent, IReadableSet, IContextKey, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { Event, chain, filterEvent, Emitter } from 'vs/base/common/event';
import { sortedDiff, firstIndex, move } from 'vs/base/common/arrays';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { MenuId, MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { localize } from 'vs/nls';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { values } from 'vs/base/common/map';
function filterViewEvent(container: ViewContainer, event: Event<IViewDescriptor[]>): Event<IViewDescriptor[]> {
return chain(event)
@@ -63,20 +64,24 @@ interface IViewItem {
active: boolean;
}
class ViewDescriptorCollection extends Disposable {
class ViewDescriptorCollection extends Disposable implements IViewDescriptorCollection {
private contextKeys = new CounterSet<string>();
private items: IViewItem[] = [];
private _onDidChange = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
private _onDidChange: Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._register(new Emitter<{ added: IViewDescriptor[], removed: IViewDescriptor[] }>());
readonly onDidChangeActiveViews: Event<{ added: IViewDescriptor[], removed: IViewDescriptor[] }> = this._onDidChange.event;
get viewDescriptors(): IViewDescriptor[] {
get activeViewDescriptors(): IViewDescriptor[] {
return this.items
.filter(i => i.active)
.map(i => i.viewDescriptor);
}
get allViewDescriptors(): IViewDescriptor[] {
return this.items.map(i => i.viewDescriptor);
}
constructor(
container: ViewContainer,
@IContextKeyService private contextKeyService: IContextKeyService
@@ -95,7 +100,7 @@ class ViewDescriptorCollection extends Disposable {
}
private onViewsRegistered(viewDescriptors: IViewDescriptor[]): any {
let fireChangeEvent = false;
const added: IViewDescriptor[] = [];
for (const viewDescriptor of viewDescriptors) {
const item = {
@@ -112,17 +117,17 @@ class ViewDescriptorCollection extends Disposable {
}
if (item.active) {
fireChangeEvent = true;
added.push(viewDescriptor);
}
}
if (fireChangeEvent) {
this._onDidChange.fire();
if (added.length) {
this._onDidChange.fire({ added, removed: [] });
}
}
private onViewsDeregistered(viewDescriptors: IViewDescriptor[]): any {
let fireChangeEvent = false;
const removed: IViewDescriptor[] = [];
for (const viewDescriptor of viewDescriptors) {
const index = firstIndex(this.items, i => i.viewDescriptor.id === viewDescriptor.id);
@@ -141,30 +146,35 @@ class ViewDescriptorCollection extends Disposable {
}
if (item.active) {
fireChangeEvent = true;
removed.push(viewDescriptor);
}
}
if (fireChangeEvent) {
this._onDidChange.fire();
if (removed.length) {
this._onDidChange.fire({ added: [], removed });
}
}
private onContextChanged(event: IContextKeyChangeEvent): any {
let fireChangeEvent = false;
const removed: IViewDescriptor[] = [];
const added: IViewDescriptor[] = [];
for (const item of this.items) {
const active = this.isViewDescriptorActive(item.viewDescriptor);
if (item.active !== active) {
fireChangeEvent = true;
if (active) {
added.push(item.viewDescriptor);
} else {
removed.push(item.viewDescriptor);
}
}
item.active = active;
}
if (fireChangeEvent) {
this._onDidChange.fire();
if (added.length || removed.length) {
this._onDidChange.fire({ added, removed });
}
}
@@ -208,14 +218,14 @@ export class ContributableViewsModel extends Disposable {
constructor(
container: ViewContainer,
contextKeyService: IContextKeyService,
viewsService: IViewsService,
protected viewStates = new Map<string, IViewState>(),
) {
super();
const viewDescriptorCollection = this._register(new ViewDescriptorCollection(container, contextKeyService));
const viewDescriptorCollection = viewsService.getViewDescriptors(container);
this._register(viewDescriptorCollection.onDidChange(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.viewDescriptors)));
this.onDidChangeViewDescriptors(viewDescriptorCollection.viewDescriptors);
this._register(viewDescriptorCollection.onDidChangeActiveViews(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors)));
this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors);
}
isVisible(id: string): boolean {
@@ -407,14 +417,14 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
constructor(
container: ViewContainer,
viewletStateStorageId: string,
@IContextKeyService contextKeyService: IContextKeyService,
@IViewsService viewsService: IViewsService,
@IStorageService storageService: IStorageService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
const hiddenViewsStorageId = `${viewletStateStorageId}.hidden`;
const viewStates = PersistentContributableViewsModel.loadViewsStates(viewletStateStorageId, hiddenViewsStorageId, storageService, contextService);
super(container, contextKeyService, viewStates);
super(container, viewsService, viewStates);
this.viewletStateStorageId = viewletStateStorageId;
this.hiddenViewsStorageId = hiddenViewsStorageId;
@@ -423,17 +433,26 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
this._register(this.onDidAdd(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor))));
this._register(this.onDidRemove(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor))));
this._register(this.storageService.onWillSaveState(() => this.saveViewsStates()));
}
saveViewsStates(): void {
private saveViewsStates(): void {
const storedViewsStates: { [id: string]: { collapsed: boolean, size: number, order: number } } = {};
let hasState = false;
for (const viewDescriptor of this.viewDescriptors) {
const viewState = this.viewStates.get(viewDescriptor.id);
if (viewState) {
storedViewsStates[viewDescriptor.id] = { collapsed: viewState.collapsed, size: viewState.size, order: viewState.order };
hasState = true;
}
}
this.storageService.store(this.viewletStateStorageId, JSON.stringify(storedViewsStates), this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL);
if (hasState) {
this.storageService.store(this.viewletStateStorageId, JSON.stringify(storedViewsStates), StorageScope.WORKSPACE);
} else {
this.storageService.remove(this.viewletStateStorageId, StorageScope.WORKSPACE);
}
}
private saveVisibilityStates(viewDescriptors: IViewDescriptor[]): void {
@@ -441,17 +460,17 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
for (const viewDescriptor of viewDescriptors) {
if (viewDescriptor.canToggleVisibility) {
const viewState = this.viewStates.get(viewDescriptor.id);
storedViewsVisibilityStates.push({ id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : void 0 });
storedViewsVisibilityStates.set(viewDescriptor.id, { id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : void 0 });
}
}
this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(storedViewsVisibilityStates), StorageScope.GLOBAL);
this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL);
}
private static loadViewsStates(viewletStateStorageId: string, hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): Map<string, IViewState> {
const viewStates = new Map<string, IViewState>();
const storedViewsStates = JSON.parse(storageService.get(viewletStateStorageId, contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? StorageScope.WORKSPACE : StorageScope.GLOBAL, '{}'));
const storedViewsStates = JSON.parse(storageService.get(viewletStateStorageId, StorageScope.WORKSPACE, '{}'));
const viewsVisibilityStates = PersistentContributableViewsModel.loadViewsVisibilityState(hiddenViewsStorageId, storageService, contextService);
for (const { id, isHidden } of viewsVisibilityStates) {
for (const { id, isHidden } of values(viewsVisibilityStates)) {
const viewState = storedViewsStates[id];
if (viewState) {
viewStates.set(id, <IViewState>{ ...viewState, ...{ visible: !isHidden } });
@@ -468,43 +487,62 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
return viewStates;
}
private static loadViewsVisibilityState(hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): { id: string, isHidden: boolean }[] {
private static loadViewsVisibilityState(hiddenViewsStorageId: string, storageService: IStorageService, contextService: IWorkspaceContextService): Map<string, { id: string, isHidden: boolean }> {
const storedVisibilityStates = <Array<string | { id: string, isHidden: boolean }>>JSON.parse(storageService.get(hiddenViewsStorageId, StorageScope.GLOBAL, '[]'));
return <{ id: string, isHidden: boolean }[]>storedVisibilityStates.map(c => typeof c === 'string' /* migration */ ? { id: c, isHidden: true } : c);
}
let hasDuplicates = false;
const storedViewsVisibilityStates = storedVisibilityStates.reduce((result, storedState) => {
if (typeof storedState === 'string' /* migration */) {
hasDuplicates = hasDuplicates || result.has(storedState);
result.set(storedState, { id: storedState, isHidden: true });
} else {
hasDuplicates = hasDuplicates || result.has(storedState.id);
result.set(storedState.id, storedState);
}
return result;
}, new Map<string, { id: string, isHidden: boolean }>());
dispose(): void {
this.saveViewsStates();
super.dispose();
if (hasDuplicates) {
storageService.store(hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL);
}
return storedViewsVisibilityStates;
}
}
const SCM_VIEWLET_ID = 'workbench.view.scm';
export class ViewsService extends Disposable implements IViewsService {
_serviceBrand: any;
private readonly viewDescriptorCollections: Map<ViewContainer, IViewDescriptorCollection>;
private readonly activeViewContextKeys: Map<string, IContextKey<boolean>>;
constructor(
@IInstantiationService private instantiationService: IInstantiationService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IViewletService private viewletService: IViewletService,
@IStorageService private storageService: IStorageService
@IContextKeyService private contextKeyService: IContextKeyService
) {
super();
this.viewDescriptorCollections = new Map<ViewContainer, IViewDescriptorCollection>();
this.activeViewContextKeys = new Map<string, IContextKey<boolean>>();
this.onDidRegisterViews(ViewsRegistry.getAllViews());
this._register(ViewsRegistry.onViewsRegistered(views => this.onDidRegisterViews(views)));
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
this._register(viewContainersRegistry.onDidRegister(viewContainer => this.onDidRegisterViewContainer(viewContainer)));
this._register(Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).onDidRegister(viewlet => this.viewletService.setViewletEnablement(viewlet.id, this.storageService.getBoolean(`viewservice.${viewlet.id}.enablement`, StorageScope.GLOBAL, viewlet.id !== TEST_VIEW_CONTAINER_ID))));
}
openView(id: string, focus: boolean): TPromise<IView> {
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection {
return this.viewDescriptorCollections.get(container);
}
openView(id: string, focus: boolean): Thenable<IView> {
const viewDescriptor = ViewsRegistry.getView(id);
if (viewDescriptor) {
const viewletDescriptor = this.viewletService.getViewlet(viewDescriptor.container.id);
if (viewletDescriptor) {
return this.viewletService.openViewlet(viewletDescriptor.id)
return this.viewletService.openViewlet(viewletDescriptor.id, focus)
.then((viewlet: IViewsViewlet) => {
if (viewlet && viewlet.openView) {
return viewlet.openView(id, focus);
@@ -513,21 +551,62 @@ export class ViewsService extends Disposable implements IViewsService {
});
}
}
return TPromise.as(null);
return Promise.resolve(null);
}
private onDidRegisterViewContainer(viewContainer: ViewContainer): void {
// TODO: @Joao Remove this after moving SCM Viewlet to ViewContainerViewlet - https://github.com/Microsoft/vscode/issues/49054
if (viewContainer.id !== SCM_VIEWLET_ID) {
const viewDescriptorCollection = this._register(this.instantiationService.createInstance(ViewDescriptorCollection, viewContainer));
this._register(viewDescriptorCollection.onDidChange(() => this.updateViewletEnablement(viewContainer, viewDescriptorCollection)));
this.lifecycleService.when(LifecyclePhase.Eventually).then(() => this.updateViewletEnablement(viewContainer, viewDescriptorCollection));
const viewDescriptorCollection = this._register(new ViewDescriptorCollection(viewContainer, this.contextKeyService));
this.onDidChangeActiveViews({ added: viewDescriptorCollection.activeViewDescriptors, removed: [] });
this._register(viewDescriptorCollection.onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed)));
this.viewDescriptorCollections.set(viewContainer, viewDescriptorCollection);
}
private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[] }): void {
added.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(true));
removed.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(false));
}
private onDidRegisterViews(viewDescriptors: IViewDescriptor[]): void {
for (const viewDescriptor of viewDescriptors) {
const viewlet = this.viewletService.getViewlet(viewDescriptor.container.id);
const command: ICommandAction = {
id: viewDescriptor.focusCommand ? viewDescriptor.focusCommand.id : `${viewDescriptor.id}.focus`,
title: { original: `Focus on ${viewDescriptor.name} View`, value: localize('focus view', "Focus on {0} View", viewDescriptor.name) },
category: viewlet ? viewlet.name : localize('view category', "View"),
};
const when = ContextKeyExpr.has(`${viewDescriptor.id}.active`);
CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true).then(() => null));
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command,
when
});
if (viewDescriptor.focusCommand && viewDescriptor.focusCommand.keybindings) {
KeybindingsRegistry.registerKeybindingRule({
id: command.id,
when,
weight: KeybindingWeight.WorkbenchContrib,
primary: viewDescriptor.focusCommand.keybindings.primary,
secondary: viewDescriptor.focusCommand.keybindings.secondary,
linux: viewDescriptor.focusCommand.keybindings.linux,
mac: viewDescriptor.focusCommand.keybindings.mac,
win: viewDescriptor.focusCommand.keybindings.win
});
}
}
}
private updateViewletEnablement(viewContainer: ViewContainer, viewDescriptorCollection: ViewDescriptorCollection): void {
const enabled = viewDescriptorCollection.viewDescriptors.length > 0;
this.viewletService.setViewletEnablement(viewContainer.id, enabled);
this.storageService.store(`viewservice.${viewContainer.id}.enablement`, enabled, StorageScope.GLOBAL);
private getOrCreateActiveViewContextKey(viewDescriptor: IViewDescriptor): IContextKey<boolean> {
const activeContextKeyId = `${viewDescriptor.id}.active`;
let contextKey = this.activeViewContextKeys.get(activeContextKeyId);
if (!contextKey) {
contextKey = new RawContextKey(activeContextKeyId, false).bindTo(this.contextKeyService);
this.activeViewContextKeys.set(activeContextKeyId, contextKey);
}
return contextKey;
}
}
}