Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to hide editor title section entirely (tabs, breadcrumbs) (#33607) #195222

Merged
merged 12 commits into from
Oct 18, 2023
1 change: 1 addition & 0 deletions src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class MenuId {
static readonly EmptyEditorGroup = new MenuId('EmptyEditorGroup');
static readonly EmptyEditorGroupContext = new MenuId('EmptyEditorGroupContext');
static readonly EditorTabsBarContext = new MenuId('EditorTabsBarContext');
static readonly EditorTabsBarShowTabsSubmenu = new MenuId('EditorTabsBarShowTabsSubmenu');
static readonly ExplorerContext = new MenuId('ExplorerContext');
static readonly ExplorerContextShare = new MenuId('ExplorerContextShare');
static readonly ExtensionContext = new MenuId('ExtensionContext');
Expand Down
81 changes: 62 additions & 19 deletions src/vs/workbench/browser/actions/layoutActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -470,49 +470,87 @@ export class ToggleStatusbarVisibilityAction extends Action2 {

registerAction2(ToggleStatusbarVisibilityAction);

// --- Bse Class Toggle Boolean Setting Action
// --- Hide Editor Tabs

abstract class BaseToggleBooleanSettingAction extends Action2 {
export class HideEditorTabsAction extends Action2 {

protected abstract get settingId(): string;
static readonly ID = 'workbench.action.hideEditorTabs';

constructor() {
super({
id: HideEditorTabsAction.ID,
title: {
value: localize('hideEditorTabs', "Hide Editor Tabs"),
original: 'Hide Editor Tabs'
},
category: Categories.View,
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none').negate(),
f1: true
});
}

override run(accessor: ServicesAccessor): Promise<void> {
const configurationService = accessor.get(IConfigurationService);
return configurationService.updateValue('workbench.editor.showTabs', 'none');
}
}
registerAction2(HideEditorTabsAction);

const oldettingValue = configurationService.getValue<string>(this.settingId);
const newSettingValue = !oldettingValue;
// --- Show Multiple Editor Tabs

export class ShowMultipleEditorTabsAction extends Action2 {

static readonly ID = 'workbench.action.showMultipleEditorTabs';

constructor() {
super({
id: ShowMultipleEditorTabsAction.ID,
title: {
value: localize('showMultipleEditorTabs', "Show Multiple Editor Tabs"),
original: 'Show Multiple Editor Tabs'
},
category: Categories.View,
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple').negate(),
f1: true
});
}

return configurationService.updateValue(this.settingId, newSettingValue);
override run(accessor: ServicesAccessor): Promise<void> {
const configurationService = accessor.get(IConfigurationService);
return configurationService.updateValue('workbench.editor.showTabs', 'multiple');
}
}
registerAction2(ShowMultipleEditorTabsAction);

// --- Toggle Tabs Visibility
// --- Show Single Editor Tab

export class ToggleTabsVisibilityAction extends BaseToggleBooleanSettingAction {
export class ShowSingleEditorTabAction extends Action2 {

static readonly ID = 'workbench.action.toggleTabsVisibility';
static readonly ID = 'workbench.action.showEditorTab';
bpasero marked this conversation as resolved.
Show resolved Hide resolved

constructor() {
super({
id: ToggleTabsVisibilityAction.ID,
id: ShowSingleEditorTabAction.ID,
title: {
value: localize('toggleTabs', "Toggle Editor Tab Visibility"),
original: 'Toggle Editor Tab Visibility'
value: localize('showSingleEditorTab', "Show Single Editor Tab"),
original: 'Show Single Editor Tab'
},
category: Categories.View,
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single').negate(),
f1: true
});
}

protected override get settingId(): string {
return 'workbench.editor.showTabs';
override run(accessor: ServicesAccessor): Promise<void> {
const configurationService = accessor.get(IConfigurationService);
return configurationService.updateValue('workbench.editor.showTabs', 'single');
}
}
registerAction2(ToggleTabsVisibilityAction);
registerAction2(ShowSingleEditorTabAction);

// --- Toggle Pinned Tabs On Separate Row

export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingAction {
export class ToggleSeparatePinnedTabsAction extends Action2 {

static readonly ID = 'workbench.action.toggleSeparatePinnedEditorTabs';

Expand All @@ -524,13 +562,18 @@ export class ToggleSeparatePinnedTabsAction extends BaseToggleBooleanSettingActi
original: 'Separate Pinned Editor Tabs'
},
category: Categories.View,
precondition: ContextKeyExpr.has('config.workbench.editor.showTabs'),
precondition: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple'),
f1: true
});
}

protected override get settingId(): string {
return 'workbench.editor.pinnedTabsOnSeparateRow';
override run(accessor: ServicesAccessor): Promise<void> {
const configurationService = accessor.get(IConfigurationService);

const oldettingValue = configurationService.getValue<string>('workbench.editor.pinnedTabsOnSeparateRow');
const newSettingValue = !oldettingValue;

return configurationService.updateValue('workbench.editor.pinnedTabsOnSeparateRow', newSettingValue);
}
}
registerAction2(ToggleSeparatePinnedTabsAction);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/contextkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
}

private updateEditorAreaContextKeys(): void {
this.editorTabsVisibleContext.set(!!this.editorGroupService.partOptions.showTabs);
this.editorTabsVisibleContext.set(this.editorGroupService.partOptions.showTabs === 'multiple');
}

private updateEditorContextKeys(): void {
Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/browser/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1232,8 +1232,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.runtime.zenMode.transitionDisposables.add(this.editorService.onDidVisibleEditorsChange(() => setLineNumbers('off')));
}

if (config.hideTabs && this.editorGroupService.partOptions.showTabs) {
this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: false }));
if (config.showTabs !== this.editorGroupService.partOptions.showTabs) {
this.state.runtime.zenMode.transitionDisposables.add(this.editorGroupService.enforcePartOptions({ showTabs: config.showTabs }));
}

if (config.silentNotifications && zenModeExitInfo.handleNotificationsDoNotDisturbMode) {
Expand Down Expand Up @@ -2305,7 +2305,7 @@ type ZenModeConfiguration = {
hideActivityBar: boolean;
hideLineNumbers: boolean;
hideStatusBar: boolean;
hideTabs: boolean;
showTabs: 'multiple' | 'single' | 'none';
restore: boolean;
silentNotifications: boolean;
};
Expand Down
7 changes: 5 additions & 2 deletions src/vs/workbench/browser/parts/editor/editor.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { UntitledTextEditorInputSerializer, UntitledTextEditorWorkingCopyEditorHandler } from 'vs/workbench/services/untitled/common/untitledTextEditorHandler';
import { DynamicEditorConfigurations } from 'vs/workbench/browser/parts/editor/editorConfiguration';
import { ToggleSeparatePinnedTabsAction, ToggleTabsVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
import { HideEditorTabsAction, ShowMultipleEditorTabsAction, ShowSingleEditorTabAction, ToggleSeparatePinnedTabsAction } from 'vs/workbench/browser/actions/layoutActions';
import product from 'vs/platform/product/common/product';

//#region Editor Registrations
Expand Down Expand Up @@ -355,7 +355,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_DOWN, title: localize('splitDown', "Split Down") }, group: '2_split', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_LEFT, title: localize('splitLeft', "Split Left") }, group: '2_split', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: SPLIT_EDITOR_RIGHT, title: localize('splitRight', "Split Right") }, group: '2_split', order: 40 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleTabsVisibilityAction.ID, title: localize('toggleTabs', "Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.showTabs') }, group: '3_config', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { submenu: MenuId.EditorTabsBarShowTabsSubmenu, title: localize('showTabs', "Show Tabs"), group: '3_config', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowMultipleEditorTabsAction.ID, title: localize('multipleTabs', "Multiple Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 });
benibenj marked this conversation as resolved.
Show resolved Hide resolved
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: ShowSingleEditorTabAction.ID, title: localize('singleTab', "Single Tab"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'single') }, group: '1_config', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarShowTabsSubmenu, { command: { id: HideEditorTabsAction.ID, title: localize('hideTabBar', "Hide Tab Bar"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'none') }, group: '1_config', order: 30 });
MenuRegistry.appendMenuItem(MenuId.EditorTabsBarContext, { command: { id: ToggleSeparatePinnedTabsAction.ID, title: localize('toggleSeparatePinnedEditorTabs', "Separate Pinned Editor Tabs"), toggled: ContextKeyExpr.has('config.workbench.editor.pinnedTabsOnSeparateRow') }, when: EditorPinnedAndUnpinnedTabsContext, group: '3_config', order: 20 });

// Editor Title Context Menu
Expand Down
14 changes: 13 additions & 1 deletion src/vs/workbench/browser/parts/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const DEFAULT_EDITOR_MIN_DIMENSIONS = new Dimension(220, 70);
export const DEFAULT_EDITOR_MAX_DIMENSIONS = new Dimension(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);

export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
showTabs: true,
showTabs: 'multiple',
highlightModifiedTabs: false,
tabCloseButton: 'right',
tabSizing: 'fit',
Expand Down Expand Up @@ -85,9 +85,21 @@ export function getEditorPartOptions(configurationService: IConfigurationService
options.tabHeight = windowConfig.window.density.editorTabHeight;
}

validateEditorPartOptions(options);

return options;
}

function validateEditorPartOptions(options: IEditorPartOptions) {
// showTabs ensure correct enum value
if (typeof options.showTabs === 'boolean') {
// Migration service kicks in very late and can cause a flicker otherwise
options.showTabs = options.showTabs ? 'multiple' : 'single';
} else if (options.showTabs !== 'multiple' && options.showTabs !== 'single' && options.showTabs !== 'none') {
options.showTabs = 'multiple';
}
}

/**
* A helper to access editor groups across all opened editor parts.
*/
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/parts/editor/editorDropTarget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ class DropOverlay extends Themable {
private getOverlayOffsetHeight(): number {

// With tabs and opened editors: use the area below tabs as drop target
if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs) {
if (!this.groupView.isEmpty && this.editorGroupService.partOptions.showTabs === 'multiple') {
return this.groupView.titleHeight.offset;
}

Expand Down
6 changes: 3 additions & 3 deletions src/vs/workbench/browser/parts/editor/editorGroupView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}

private updateTitleContainer(): void {
this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs);
this.titleContainer.classList.toggle('tabs', this.groupsView.partOptions.showTabs === 'multiple');
this.titleContainer.classList.toggle('show-file-icons', this.groupsView.partOptions.showIcons);
}

Expand Down Expand Up @@ -699,7 +699,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Title control switch between singleEditorTabs, multiEditorTabs and multiRowEditorTabs
if (
event.oldPartOptions.showTabs !== event.newPartOptions.showTabs ||
(event.oldPartOptions.showTabs && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow)
(event.oldPartOptions.showTabs === 'multiple' && event.oldPartOptions.pinnedTabsOnSeparateRow !== event.newPartOptions.pinnedTabsOnSeparateRow)
) {

// Re-layout
Expand Down Expand Up @@ -1885,7 +1885,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}

const { showTabs } = this.groupsView.partOptions;
this.titleContainer.style.backgroundColor = this.getColor(showTabs ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || '';
this.titleContainer.style.backgroundColor = this.getColor(showTabs === 'multiple' ? EDITOR_GROUP_HEADER_TABS_BACKGROUND : EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND) || '';

// Editor container
this.editorContainer.style.backgroundColor = this.getColor(editorBackground) || '';
Expand Down
4 changes: 2 additions & 2 deletions src/vs/workbench/browser/parts/editor/editorTabsControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC

// Drag all tabs of the group if tabs are enabled
let hasDataTransfer = false;
if (this.groupsView.partOptions.showTabs) {
if (this.groupsView.partOptions.showTabs === 'multiple') {
hasDataTransfer = this.doFillResourceDataTransfers(this.groupView.getEditors(EditorsOrder.SEQUENTIAL), e);
}

Expand All @@ -309,7 +309,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
// Drag Image
if (this.groupView.activeEditor) {
let label = this.groupView.activeEditor.getName();
if (this.groupsView.partOptions.showTabs && this.groupView.count > 1) {
if (this.groupsView.partOptions.showTabs === 'multiple' && this.groupView.count > 1) {
label = localize('draggedEditorGroup', "{0} (+{1})", label, this.groupView.count - 1);
}

Expand Down
29 changes: 17 additions & 12 deletions src/vs/workbench/browser/parts/editor/editorTitleControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { MultiRowEditorControl } from 'vs/workbench/browser/parts/editor/multiRowEditorTabsControl';
import { IReadonlyEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
import { NoEditorTabsControl } from 'vs/workbench/browser/parts/editor/noEditorTabsControl';

export interface IEditorTitleControlDimensions {

Expand Down Expand Up @@ -57,23 +58,27 @@ export class EditorTitleControl extends Themable {
}

private createEditorTabsControl(): IEditorTabsControl {
let control: IEditorTabsControl;
if (this.groupsView.partOptions.showTabs) {
if (this.groupsView.partOptions.pinnedTabsOnSeparateRow) {
control = this.instantiationService.createInstance(MultiRowEditorControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
} else {
control = this.instantiationService.createInstance(MultiEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
}
} else {
control = this.instantiationService.createInstance(SingleEditorTabsControl, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
let tabsControlType;
switch (this.groupsView.partOptions.showTabs) {
case 'none':
tabsControlType = NoEditorTabsControl;
break;
case 'single':
tabsControlType = SingleEditorTabsControl;
break;
case 'multiple':
default:
tabsControlType = this.groupsView.partOptions.pinnedTabsOnSeparateRow ? MultiRowEditorControl : MultiEditorTabsControl;
break;
}

const control = this.instantiationService.createInstance(tabsControlType, this.parent, this.editorPartsView, this.groupsView, this.groupView, this.model);
return this.editorTabsControlDisposable.add(control);
}

private createBreadcrumbsControl(): BreadcrumbsControlFactory | undefined {
if (!this.groupsView.partOptions.showTabs) {
return undefined; // single tabs have breadcrumbs inlined
if (this.groupsView.partOptions.showTabs !== 'multiple') {
benibenj marked this conversation as resolved.
Show resolved Hide resolved
return undefined; // Single tabs have breadcrumbs inlined. No tabs have no breadcrumbs.
}

// Breadcrumbs container
Expand Down Expand Up @@ -170,7 +175,7 @@ export class EditorTitleControl extends Themable {
// Update editor tabs control if options changed
if (
oldOptions.showTabs !== newOptions.showTabs ||
(newOptions.showTabs && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow)
(newOptions.showTabs === 'multiple' && oldOptions.pinnedTabsOnSeparateRow !== newOptions.pinnedTabsOnSeparateRow)
) {
// Clear old
this.editorTabsControlDisposable.clear();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

/* Breadcrumbs (inline next to single editor tab) */

.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .no-tabs.title-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .single-tab.title-label {
flex: none;
}

Expand Down
56 changes: 56 additions & 0 deletions src/vs/workbench/browser/parts/editor/noEditorTabsControl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import 'vs/css!./media/singleeditortabscontrol';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { EditorTabsControl, IToolbarActions } from 'vs/workbench/browser/parts/editor/editorTabsControl';
import { Dimension } from 'vs/base/browser/dom';
import { IEditorTitleControlDimensions } from 'vs/workbench/browser/parts/editor/editorTitleControl';

export class NoEditorTabsControl extends EditorTabsControl {

protected prepareEditorActions(editorActions: IToolbarActions): IToolbarActions {
return {
primary: [],
secondary: []
};
}

openEditor(editor: EditorInput): boolean {
return false;
}

openEditors(editors: EditorInput[]): boolean {
return false;
}

beforeCloseEditor(editor: EditorInput): void { }

closeEditor(editor: EditorInput): void { }

closeEditors(editors: EditorInput[]): void { }

moveEditor(editor: EditorInput, fromIndex: number, targetIndex: number): void { }

pinEditor(editor: EditorInput): void { }

stickEditor(editor: EditorInput): void { }

unstickEditor(editor: EditorInput): void { }

setActive(isActive: boolean): void { }

updateEditorLabel(editor: EditorInput): void { }

updateEditorDirty(editor: EditorInput): void { }

getHeight(): number {
return 0;
}

layout(dimensions: IEditorTitleControlDimensions): Dimension {
return new Dimension(dimensions.container.width, this.getHeight());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ export class SingleEditorTabsControl extends EditorTabsControl {
{
title,
italic: !isEditorPinned,
extraClasses: ['no-tabs', 'title-label'].concat(editor.getLabelExtraClasses()),
extraClasses: ['single-tab', 'title-label'].concat(editor.getLabelExtraClasses()),
fileDecorations: {
colors: Boolean(options.decorations?.colors),
badges: Boolean(options.decorations?.badges)
Expand Down
Loading
Loading