Skip to content

Commit

Permalink
Merge pull request microsoft#195222 from microsoft/benibenj/noTabBar
Browse files Browse the repository at this point in the history
Allow to hide editor title section entirely (tabs, breadcrumbs) (microsoft#33607)
  • Loading branch information
benibenj authored and Alex0007 committed Oct 26, 2023
2 parents 90acbc8 + 77660f3 commit b8df51b
Show file tree
Hide file tree
Showing 17 changed files with 220 additions and 67 deletions.
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';

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 @@ -1238,8 +1238,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 @@ -2311,7 +2311,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 @@ -64,7 +64,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';
import { ICommandAction } from 'vs/platform/action/common/action';

Expand Down Expand Up @@ -354,7 +354,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 Tabs"), toggled: ContextKeyExpr.equals('config.workbench.editor.showTabs', 'multiple') }, group: '1_config', order: 10 });
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 @@ -465,7 +465,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 @@ -701,7 +701,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 @@ -1901,7 +1901,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') {
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

0 comments on commit b8df51b

Please sign in to comment.