Merge from vscode d06f0e877ceaf3a35a283f1bfdc50927ec8dfd1e (#8767)

This commit is contained in:
Anthony Dresser
2019-12-22 08:53:45 -08:00
committed by GitHub
parent ce10c3ac3f
commit 4293d53e79
64 changed files with 1142 additions and 791 deletions

View File

@@ -156,9 +156,4 @@ export interface EditorServiceImpl extends IEditorService {
* Emitted when the list of most recently active editors change.
*/
readonly onDidMostRecentlyActiveEditorsChange: Event<void>;
/**
* Access to the list of most recently active editors.
*/
readonly mostRecentlyActiveEditors: ReadonlyArray<IEditorIdentifier>;
}

View File

@@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { mixin } from 'vs/base/common/objects';
import { IEditorInput, EditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason } from 'vs/workbench/common/editor';
import { IEditorInput, EditorInput, IEditorIdentifier, IEditorCommandsContext, CloseDirection, SaveReason, EditorsOrder } from 'vs/workbench/common/editor';
import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
@@ -16,7 +16,7 @@ import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { CLOSE_EDITOR_COMMAND_ID, NAVIGATE_ALL_EDITORS_BY_APPEARANCE_PREFIX, MOVE_ACTIVE_EDITOR_COMMAND_ID, NAVIGATE_IN_ACTIVE_GROUP_BY_MOST_RECENTLY_USED_PREFIX, ActiveEditorMoveArguments, SPLIT_EDITOR_LEFT, SPLIT_EDITOR_RIGHT, SPLIT_EDITOR_UP, SPLIT_EDITOR_DOWN, splitEditor, LAYOUT_EDITOR_GROUPS_COMMAND_ID, mergeAllGroups, NAVIGATE_ALL_EDITORS_BY_MOST_RECENTLY_USED_PREFIX } from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, EditorsOrder, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorGroupsService, IEditorGroup, GroupsArrangement, GroupLocation, GroupDirection, preferredSideBySideGroupDirection, IFindGroupScope, GroupOrientation, EditorGroupLayout, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { DisposableStore } from 'vs/base/common/lifecycle';

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/editorgroupview';
import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, toResource, SideBySideEditor, SaveReason, SaveContext, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext, toResource, SideBySideEditor, SaveReason, SaveContext, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom';
@@ -17,7 +17,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_FOCUSED_EMPTY_BORDER } from 'vs/workbench/common/theme';
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, GroupsOrder, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl';
import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
@@ -725,7 +725,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
get editors(): EditorInput[] {
return this._group.getEditors();
return this._group.getEditors(EditorsOrder.SEQUENTIAL);
}
get count(): number {
@@ -752,12 +752,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._group.isActive(editor);
}
getEditors(order?: EditorsOrder): EditorInput[] {
if (order === EditorsOrder.MOST_RECENTLY_ACTIVE) {
return this._group.getEditors(true);
}
return this.editors;
getEditors(order: EditorsOrder): EditorInput[] {
return this._group.getEditors(order);
}
getEditorByIndex(index: number): EditorInput | undefined {
@@ -1021,7 +1017,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Use the first editor as active editor
const { editor, options } = editors.shift()!;
let firstOpenedEditor = await this.openEditor(editor, options);
await this.openEditor(editor, options);
// Open the other ones inactive
const startingIndex = this.getIndexOfEditor(editor) + 1;
@@ -1031,13 +1027,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
adjustedEditorOptions.pinned = true;
adjustedEditorOptions.index = startingIndex + index;
const openedEditor = await this.openEditor(editor, adjustedEditorOptions);
if (!firstOpenedEditor) {
firstOpenedEditor = openedEditor; // only take if the first editor opening failed
}
await this.openEditor(editor, adjustedEditorOptions);
}));
return firstOpenedEditor;
// Opening many editors at once can put any editor to be
// the active one depending on options. As such, we simply
// return the active control after this operation.
return this.editorControl.activeControl;
}
//#endregion
@@ -1373,7 +1369,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
const filter = editors;
const hasDirection = typeof filter.direction === 'number';
let editorsToClose = this._group.getEditors(!hasDirection /* in MRU order only if direction is not specified */);
let editorsToClose = this._group.getEditors(hasDirection ? EditorsOrder.SEQUENTIAL : EditorsOrder.MOST_RECENTLY_ACTIVE); // in MRU order only if direction is not specified
// Filter: saved only
if (filter.savedOnly) {
@@ -1434,7 +1430,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
// Check for dirty and veto
const editors = this._group.getEditors(true);
const editors = this._group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE);
const veto = await this.handleDirtyClosing(editors.slice(0));
if (veto) {
return;
@@ -1528,8 +1524,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#endregion
//#endregion
//#region Themable
protected updateStyles(): void {

View File

@@ -13,12 +13,11 @@ import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { QuickOpenHandler } from 'vs/workbench/browser/quickopen';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService, IEditorGroup, EditorsOrder, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorGroupsService, IEditorGroup, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { toResource, SideBySideEditor, IEditorInput } from 'vs/workbench/common/editor';
import { toResource, SideBySideEditor, IEditorInput, EditorsOrder } from 'vs/workbench/common/editor';
import { compareItemsByScore, scoreItem, ScorerCache, prepareQuery } from 'vs/base/parts/quickopen/common/quickOpenScorer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
export class EditorPickerEntry extends QuickOpenEntryGroup {
@@ -209,14 +208,13 @@ export abstract class BaseAllEditorsPicker extends BaseEditorPicker {
constructor(
@IInstantiationService instantiationService: IInstantiationService,
@IEditorService editorService: IEditorService,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IHistoryService protected historyService: IHistoryService
@IEditorGroupsService editorGroupService: IEditorGroupsService
) {
super(instantiationService, editorService, editorGroupService);
}
protected count(): number {
return this.historyService.getMostRecentlyUsedOpenEditors().length;
return this.editorService.count;
}
getEmptyLabel(searchString: string): string {
@@ -262,7 +260,7 @@ export class AllEditorsByMostRecentlyUsedPicker extends BaseAllEditorsPicker {
protected getEditorEntries(): EditorPickerEntry[] {
const entries: EditorPickerEntry[] = [];
for (const { editor, groupId } of this.historyService.getMostRecentlyUsedOpenEditors()) {
for (const { editor, groupId } of this.editorService.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE)) {
entries.push(this.instantiationService.createInstance(EditorPickerEntry, editor, this.editorGroupService.getGroup(groupId)!));
}

View File

@@ -3,12 +3,12 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent, EditorsOrder } from 'vs/workbench/common/editor';
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { Registry } from 'vs/platform/registry/common/platform';
import { Event, Emitter } from 'vs/base/common/event';
import { IEditorGroupsService, IEditorGroup, EditorsOrder, GroupChangeKind, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorGroupsService, IEditorGroup, GroupChangeKind, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { coalesce } from 'vs/base/common/arrays';
import { LinkedMap, Touch } from 'vs/base/common/map';
import { equals } from 'vs/base/common/objects';
@@ -41,6 +41,10 @@ export class EditorsObserver extends Disposable {
private readonly _onDidChange = this._register(new Emitter<void>());
readonly onDidChange = this._onDidChange.event;
get count(): number {
return this.mostRecentEditorsMap.size;
}
get editors(): IEditorIdentifier[] {
return this.mostRecentEditorsMap.values();
}
@@ -231,7 +235,7 @@ export class EditorsObserver extends Disposable {
if (typeof groupId === 'number') {
const group = this.editorGroupsService.getGroup(groupId);
if (group) {
this.doEnsureOpenedEditorsLimit(limit, group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).map(editor => ({ editor, groupId })), exclude);
await this.doEnsureOpenedEditorsLimit(limit, group.getEditors(EditorsOrder.MOST_RECENTLY_ACTIVE).map(editor => ({ editor, groupId })), exclude);
}
}
@@ -245,7 +249,7 @@ export class EditorsObserver extends Disposable {
// Across all editor groups
else {
this.doEnsureOpenedEditorsLimit(limit, this.mostRecentEditorsMap.values(), exclude);
await this.doEnsureOpenedEditorsLimit(limit, this.mostRecentEditorsMap.values(), exclude);
}
}

View File

@@ -13,7 +13,7 @@ import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/
import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/actions';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService, Parts, Position, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { ActivityAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { ActivityAction, ToggleCompositePinnedAction, ICompositeBar } from 'vs/workbench/browser/parts/compositeBarActions';
import { IActivity } from 'vs/workbench/common/activity';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel';
@@ -149,7 +149,7 @@ function createPositionPanelActionConfig(id: string, alias: string, label: strin
};
}
export const PositionPanelActionConfigs = [
export const PositionPanelActionConfigs: PanelActionConfig<Position>[] = [
createPositionPanelActionConfig(PositionPanelActionId.LEFT, 'View: Panel Position Left', nls.localize('positionPanelLeft', 'Move Panel Left'), Position.LEFT),
createPositionPanelActionConfig(PositionPanelActionId.RIGHT, 'View: Panel Position Right', nls.localize('positionPanelRight', 'Move Panel Right'), Position.RIGHT),
createPositionPanelActionConfig(PositionPanelActionId.BOTTOM, 'View: Panel Position Bottom', nls.localize('positionPanelBottom', 'Move Panel To Bottom'), Position.BOTTOM),
@@ -187,8 +187,34 @@ export class PanelActivityAction extends ActivityAction {
this.activate();
return Promise.resolve();
}
setActivity(activity: IActivity): void {
this.activity = activity;
}
}
export class PlaceHolderPanelActivityAction extends PanelActivityAction {
constructor(
id: string,
@IPanelService panelService: IPanelService
) {
super({ id, name: id }, panelService);
}
}
export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinnedAction {
constructor(id: string, compositeBar: ICompositeBar) {
super({ id, name: id, cssClass: undefined }, compositeBar);
}
setActivity(activity: IActivity): void {
this.label = activity.name;
}
}
export class SwitchPanelViewAction extends Action {
constructor(

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/panelpart';
import { IAction } from 'vs/base/common/actions';
import { IAction, Action } from 'vs/base/common/actions';
import { Event } from 'vs/base/common/event';
import { Registry } from 'vs/platform/registry/common/platform';
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -18,7 +18,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ClosePanelAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction, PositionPanelActionConfigs, SetPanelPositionAction } from 'vs/workbench/browser/parts/panel/panelActions';
import { ClosePanelAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction, PlaceHolderPanelActivityAction, PlaceHolderToggleCompositePinnedAction, PositionPanelActionConfigs, SetPanelPositionAction } from 'vs/workbench/browser/parts/panel/panelActions';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER } from 'vs/workbench/common/theme';
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
@@ -28,17 +28,19 @@ import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { Dimension, trackFocus } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IContextKey, IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { isUndefinedOrNull, assertIsDefined } from 'vs/base/common/types';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, IViewsService, IViewDescriptorCollection } from 'vs/workbench/common/views';
interface ICachedPanel {
id: string;
pinned: boolean;
order?: number;
visible: boolean;
views?: { when?: string }[];
}
export class PanelPart extends CompositePart<Panel> implements IPanelService {
@@ -80,9 +82,13 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
private compositeBar: CompositeBar;
private compositeActions: Map<string, { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction; }> = new Map();
private readonly panelDisposables: Map<string, IDisposable> = new Map<string, IDisposable>();
private blockOpeningPanel = false;
private _contentDimension: Dimension | undefined;
private panelRegistry: PanelRegistry;
constructor(
@INotificationService notificationService: INotificationService,
@IStorageService storageService: IStorageService,
@@ -92,8 +98,9 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
@IKeybindingService keybindingService: IKeybindingService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@ILifecycleService private readonly lifecycleService: ILifecycleService
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IExtensionService private readonly extensionService: IExtensionService,
@IViewsService private readonly viewsService: IViewsService,
) {
super(
notificationService,
@@ -114,6 +121,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
{ hasTitle: true }
);
this.panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.getCachedPanels(), {
icon: false,
orientation: ActionsOrientation.HORIZONTAL,
@@ -127,8 +136,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
.filter(({ when }) => contextKeyService.contextMatchesRules(when))
.map(({ id, label }) => this.instantiationService.createInstance(SetPanelPositionAction, id, label)),
this.instantiationService.createInstance(TogglePanelAction, TogglePanelAction.ID, localize('hidePanel', "Hide Panel"))
],
getDefaultCompositeId: () => Registry.as<PanelRegistry>(PanelExtensions.Panels).getDefaultPanelId(),
] as Action[],
getDefaultCompositeId: () => this.panelRegistry.getDefaultPanelId(),
hidePart: () => this.layoutService.setPanelHidden(true),
compositeSize: 0,
overflowActionSize: 44,
@@ -144,47 +153,156 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
})
}));
for (const panel of this.getPanels()) {
this.compositeBar.addComposite(panel);
}
this.activePanelContextKey = ActivePanelContext.bindTo(contextKeyService);
this.panelFocusContextKey = PanelFocusContext.bindTo(contextKeyService);
this.registerListeners();
this.onDidRegisterPanels([...this.getPanels()]);
}
private onDidRegisterPanels(panels: PanelDescriptor[]): void {
for (const panel of panels) {
const cachedPanel = this.getCachedPanels().filter(({ id }) => id === panel.id)[0];
const activePanel = this.getActivePanel();
const isActive = activePanel?.getId() === panel.id;
if (isActive || !this.shouldBeHidden(panel.id, cachedPanel)) {
this.compositeBar.addComposite(panel);
// Pin it by default if it is new
if (!cachedPanel) {
this.compositeBar.pin(panel.id);
}
if (isActive) {
this.compositeBar.activateComposite(panel.id);
}
}
}
for (const panel of panels) {
this.enableCompositeActions(panel);
const viewContainer = this.getViewContainer(panel.id);
if (viewContainer?.hideIfEmpty) {
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
if (viewDescriptors) {
this.onDidChangeActiveViews(panel, viewDescriptors);
this.panelDisposables.set(panel.id, viewDescriptors.onDidChangeActiveViews(() => this.onDidChangeActiveViews(panel, viewDescriptors)));
}
}
}
}
private onDidDeregisterPanel(panelId: string): void {
const disposable = this.panelDisposables.get(panelId);
if (disposable) {
disposable.dispose();
}
this.panelDisposables.delete(panelId);
this.hideComposite(panelId);
}
private enableCompositeActions(panel: PanelDescriptor): void {
const { activityAction, pinnedAction } = this.getCompositeActions(panel.id);
if (activityAction instanceof PlaceHolderPanelActivityAction) {
activityAction.setActivity(panel);
}
if (pinnedAction instanceof PlaceHolderToggleCompositePinnedAction) {
pinnedAction.setActivity(panel);
}
}
private onDidChangeActiveViews(panel: PanelDescriptor, viewDescriptors: IViewDescriptorCollection): void {
if (viewDescriptors.activeViewDescriptors.length) {
this.compositeBar.addComposite(panel);
} else {
this.hideComposite(panel.id);
}
}
private shouldBeHidden(panelId: string, cachedPanel?: ICachedPanel): boolean {
const viewContainer = this.getViewContainer(panelId);
if (!viewContainer || !viewContainer.hideIfEmpty) {
return false;
}
return cachedPanel?.views && cachedPanel.views.length
? cachedPanel.views.every(({ when }) => !!when && !this.contextKeyService.contextMatchesRules(ContextKeyExpr.deserialize(when)))
: false;
}
private registerListeners(): void {
// Panel registration
this._register(this.registry.onDidRegister(panel => this.onDidRegisterPanels([panel])));
this._register(this.registry.onDidDeregister(panel => this.onDidDeregisterPanel(panel.id)));
// Panel open/close
// Activate on panel open
this._register(this.onDidPanelOpen(({ panel }) => this.onPanelOpen(panel)));
// Deactivate on panel close
this._register(this.onDidPanelClose(this.onPanelClose, this));
// Panel register/deregister
this._register(this.registry.onDidRegister(panelDescriptor => this.compositeBar.addComposite(panelDescriptor)));
this._register(this.registry.onDidDeregister(panelDescriptor => {
this.compositeBar.hideComposite(panelDescriptor.id);
this.removeComposite(panelDescriptor.id);
// Extension registration
let disposables = this._register(new DisposableStore());
this._register(this.extensionService.onDidRegisterExtensions(() => {
disposables.clear();
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedPanels(), this, disposables);
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
}));
}
// Activate panel action on opening of a panel
this._register(this.onDidPanelOpen(({ panel }) => {
this.compositeBar.activateComposite(panel.getId());
this.layoutCompositeBar(); // Need to relayout composite bar since different panels have different action bar width
}));
private onDidRegisterExtensions(): void {
this.removeNotExistingComposites();
// Deactivate panel action on close
this._register(this.onDidPanelClose(panel => this.compositeBar.deactivateComposite(panel.getId())));
this.saveCachedPanels();
}
// State
this.lifecycleService.when(LifecyclePhase.Eventually).then(() => {
this._register(this.compositeBar.onDidChange(() => this.saveCachedPanels()));
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
});
private removeNotExistingComposites(): void {
const panels = this.getPanels();
for (const { id } of this.getCachedPanels()) { // should this value match viewlet (load on ctor)
if (panels.every(panel => panel.id !== id)) {
this.hideComposite(id);
}
}
}
private hideComposite(compositeId: string): void {
this.compositeBar.hideComposite(compositeId);
const compositeActions = this.compositeActions.get(compositeId);
if (compositeActions) {
compositeActions.activityAction.dispose();
compositeActions.pinnedAction.dispose();
this.compositeActions.delete(compositeId);
}
}
private onPanelOpen(panel: IPanel): void {
this.activePanelContextKey.set(panel.getId());
const foundPanel = this.panelRegistry.getPanel(panel.getId());
if (foundPanel) {
this.compositeBar.addComposite(foundPanel);
}
// Activate composite when opened
this.compositeBar.activateComposite(panel.getId());
const panelDescriptor = this.panelRegistry.getPanel(panel.getId());
if (panelDescriptor) {
const viewContainer = this.getViewContainer(panelDescriptor.id);
if (viewContainer?.hideIfEmpty) {
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
if (viewDescriptors?.activeViewDescriptors.length === 0) {
this.hideComposite(panelDescriptor.id); // Update the composite bar by hiding
}
}
}
this.layoutCompositeBar(); // Need to relayout composite bar since different panels have different action bar width
}
private onPanelClose(panel: IPanel): void {
@@ -193,6 +311,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
if (this.activePanelContextKey.get() === id) {
this.activePanelContextKey.reset();
}
this.compositeBar.deactivateComposite(panel.getId());
}
create(parent: HTMLElement): void {
@@ -243,11 +363,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
getPanel(panelId: string): IPanelIdentifier | undefined {
return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanel(panelId);
return this.panelRegistry.getPanel(panelId);
}
getPanels(): readonly PanelDescriptor[] {
return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels()
return this.panelRegistry.getPanels()
.sort((v1, v2) => typeof v1.order === 'number' && typeof v2.order === 'number' ? v1.order - v2.order : NaN);
}
@@ -331,10 +451,18 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
private getCompositeActions(compositeId: string): { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction; } {
let compositeActions = this.compositeActions.get(compositeId);
if (!compositeActions) {
compositeActions = {
activityAction: this.instantiationService.createInstance(PanelActivityAction, assertIsDefined(this.getPanel(compositeId))),
pinnedAction: new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar)
};
const panel = this.getPanel(compositeId);
if (panel) {
compositeActions = {
activityAction: new PanelActivityAction(assertIsDefined(this.getPanel(compositeId)), this),
pinnedAction: new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar)
};
} else {
compositeActions = {
activityAction: new PlaceHolderPanelActivityAction(compositeId, this),
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar)
};
}
this.compositeActions.set(compositeId, compositeActions);
}
@@ -448,6 +576,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL);
}
private getViewContainer(panelId: string): ViewContainer | undefined {
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
return viewContainerRegistry.get(panelId);
}
toJSON(): object {
return {
type: Parts.PANEL_PART

View File

@@ -495,14 +495,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
private showMessage(message: string): void {
DOM.removeClass(this.messageElement, 'hide');
if (this._messageValue !== message) {
this.resetMessageElement();
this._messageValue = message;
if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue;
}
this.layout(this._height, this._width);
this.resetMessageElement();
this._messageValue = message;
if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue;
}
this.layout(this._height, this._width);
}
private hideMessage(): void {

View File

@@ -243,7 +243,7 @@ interface IViewPaneItem {
export class ViewPaneContainer extends Component implements IViewPaneContainer {
private readonly viewContainer: ViewContainer;
readonly viewContainer: ViewContainer;
private lastFocusedPane: ViewPane | undefined;
private paneItems: IViewPaneItem[] = [];
private paneview?: PaneView;

View File

@@ -8,6 +8,21 @@ import * as nls from 'vs/nls';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { isMacintosh, isWindows, isLinux, isWeb, isNative } from 'vs/base/common/platform';
import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuration';
import { PanelRegistry, Extensions as PanelExtensions, PanelDescriptor, PaneCompositePanel } from 'vs/workbench/browser/panel';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ViewContainer, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainerLocation } from 'vs/workbench/common/views';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { Viewlet, ViewletDescriptor, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isString } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
// Configuration
(function registerConfiguration(): void {
@@ -373,3 +388,74 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
}
});
})();
// Viewlets & Panels
(function registerViewletsAndPanels(): void {
const registerPanel = (viewContainer: ViewContainer): void => {
class PaneContainerPanel extends PaneCompositePanel {
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService storageService: IStorageService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextMenuService contextMenuService: IContextMenuService,
@IExtensionService extensionService: IExtensionService,
@IWorkspaceContextService contextService: IWorkspaceContextService
) {
super(viewContainer.id, (instantiationService as any).createInstance(viewContainer.ctorDescriptor!.ctor, ...(viewContainer.ctorDescriptor!.arguments || [])), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService);
}
}
Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(PanelDescriptor.create(
PaneContainerPanel,
viewContainer.id,
viewContainer.name,
isString(viewContainer.icon) ? viewContainer.icon : undefined,
viewContainer.order,
viewContainer.focusCommand?.id,
));
};
const registerViewlet = (viewContainer: ViewContainer): void => {
class PaneContainerViewlet extends Viewlet {
constructor(
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@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(viewContainer.id, (instantiationService as any).createInstance(viewContainer.ctorDescriptor!.ctor, ...(viewContainer.ctorDescriptor!.arguments || [])), telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService, layoutService, configurationService);
}
}
const viewletDescriptor = ViewletDescriptor.create(
PaneContainerViewlet,
viewContainer.id,
viewContainer.name,
isString(viewContainer.icon) ? viewContainer.icon : undefined,
viewContainer.order,
viewContainer.icon instanceof URI ? viewContainer.icon : undefined
);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).registerViewlet(viewletDescriptor);
};
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
viewContainerRegistry.getViewContainers(ViewContainerLocation.Panel).forEach(viewContainer => registerPanel(viewContainer));
viewContainerRegistry.onDidRegister(({ viewContainer, viewContainerLocation }) => {
switch (viewContainerLocation) {
case ViewContainerLocation.Panel:
registerPanel(viewContainer);
return;
case ViewContainerLocation.Sidebar:
if (viewContainer.ctorDescriptor) {
registerViewlet(viewContainer);
}
return;
}
});
})();