Skip to content

Commit

Permalink
Merge pull request #196609 from microsoft/benibenj/hideTabsActionBar
Browse files Browse the repository at this point in the history
Add option to show editor actions in title bar
  • Loading branch information
benibenj authored Nov 4, 2023
2 parents b41d864 + aad951e commit c2d75ed
Show file tree
Hide file tree
Showing 15 changed files with 357 additions and 194 deletions.
1 change: 0 additions & 1 deletion src/vs/platform/actions/common/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ export class MenuId {
static readonly ExplorerContextShare = new MenuId('ExplorerContextShare');
static readonly ExtensionContext = new MenuId('ExtensionContext');
static readonly GlobalActivity = new MenuId('GlobalActivity');
static readonly TitleBarGlobalControlMenu = new MenuId('TitleBarGlobalControlMenu');
static readonly CommandCenter = new MenuId('CommandCenter');
static readonly CommandCenterCenter = new MenuId('CommandCenterCenter');
static readonly LayoutControlMenuSubmenu = new MenuId('LayoutControlMenuSubmenu');
Expand Down
2 changes: 2 additions & 0 deletions src/vs/workbench/browser/parts/editor/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
splitOnDragAndDrop: true,
centeredLayoutFixedWidth: false,
doubleClickTabToToggleEditorGroupSizes: 'expand',
showEditorActionsInTitleBar: 'noTabs',
wrapTabs: false,
enablePreviewFromQuickOpen: false,
scrollToSwitchTabs: false,
Expand Down Expand Up @@ -149,6 +150,7 @@ function validateEditorPartOptions(options: IEditorPartOptions): IEditorPartOpti
'splitInGroupLayout': new EnumVerifier(DEFAULT_EDITOR_PART_OPTIONS['splitInGroupLayout'], ['vertical', 'horizontal']),
'splitSizing': new EnumVerifier(DEFAULT_EDITOR_PART_OPTIONS['splitSizing'], ['distribute', 'split', 'auto']),
'doubleClickTabToToggleEditorGroupSizes': new EnumVerifier(DEFAULT_EDITOR_PART_OPTIONS['doubleClickTabToToggleEditorGroupSizes'], ['maximize', 'expand', 'off']),
'showEditorActionsInTitleBar': new EnumVerifier(DEFAULT_EDITOR_PART_OPTIONS['showEditorActionsInTitleBar'], ['noTabs', 'never']),
'autoLockGroups': new SetVerifier<string>(DEFAULT_EDITOR_PART_OPTIONS['autoLockGroups']),

'limit': new ObjectVerifier<IEditorPartLimitOptions>(DEFAULT_EDITOR_PART_OPTIONS['limit'], {
Expand Down
83 changes: 67 additions & 16 deletions src/vs/workbench/browser/parts/editor/editorGroupView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@

import 'vs/css!./media/editorgroupview';
import { EditorGroupModel, IEditorOpenOptions, IGroupModelChangeEvent, ISerializedEditorGroupModel, isGroupEditorCloseEvent, isGroupEditorOpenEvent, isSerializedEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, IEditorPane, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent, IMatchEditorOptions, GroupModelChangeKind, IActiveEditorChangeEvent, IFindEditorOptions } from 'vs/workbench/common/editor';
import { ActiveEditorGroupLockedContext, ActiveEditorDirtyContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorPinnedContext, ActiveEditorLastInGroupContext, ActiveEditorFirstInGroupContext, EditorPinnedAndUnpinnedTabsContext } from 'vs/workbench/common/contextkeys';
import { GroupIdentifier, CloseDirection, IEditorCloseEvent, IEditorPane, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, EditorResourceAccessor, EditorInputCapabilities, IUntypedEditorInput, DEFAULT_EDITOR_ASSOCIATION, SideBySideEditor, EditorCloseContext, IEditorWillMoveEvent, IEditorWillOpenEvent, IMatchEditorOptions, GroupModelChangeKind, IActiveEditorChangeEvent, IFindEditorOptions, IToolbarActions } from 'vs/workbench/common/editor';
import { ActiveEditorGroupLockedContext, ActiveEditorDirtyContext, EditorGroupEditorsCountContext, ActiveEditorStickyContext, ActiveEditorPinnedContext, ActiveEditorLastInGroupContext, ActiveEditorFirstInGroupContext, EditorPinnedAndUnpinnedTabsContext, ResourceContextKey, applyAvailableEditorIds, ActiveEditorAvailableEditorIdsContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext } from 'vs/workbench/common/contextkeys';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { Emitter, Relay } from 'vs/base/common/event';
import { Emitter, Relay, Event } from 'vs/base/common/event';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Dimension, trackFocus, addDisposableListener, EventType, EventHelper, findParentWithClass, isAncestor, IDomNodePagePosition, isMouseEvent, isActiveElement, focusWindow } from 'vs/base/browser/dom';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
Expand All @@ -18,20 +18,20 @@ import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme';
import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ICloseEditorsFilter, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, IEditorReplacement, IActiveEditorActions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { EditorPanes } from 'vs/workbench/browser/parts/editor/editorPanes';
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
import { EditorProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator';
import { localize } from 'vs/nls';
import { coalesce, firstOrDefault } from 'vs/base/common/arrays';
import { MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { DeferredPromise, Promises, RunOnceWorker } from 'vs/base/common/async';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { IEditorGroupsView, IEditorGroupView, fillActiveEditorViewState, EditorServiceImpl, IEditorGroupTitleHeight, IInternalEditorOpenOptions, IInternalMoveCopyOptions, IInternalEditorCloseOptions, IInternalEditorTitleControlOptions, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IAction } from 'vs/base/common/actions';
import { IAction, SubmenuAction } from 'vs/base/common/actions';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
Expand All @@ -53,6 +53,8 @@ import { defaultProgressBarStyles } from 'vs/platform/theme/browser/defaultStyle
import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
import { EditorGroupWatermark } from 'vs/workbench/browser/parts/editor/editorGroupWatermark';
import { EditorTitleControl } from 'vs/workbench/browser/parts/editor/editorTitleControl';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService';

export class EditorGroupView extends Themable implements IEditorGroupView {

Expand Down Expand Up @@ -115,6 +117,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {

private readonly scopedInstantiationService: IInstantiationService;

private readonly resourceContext: ResourceContextKey;

private readonly titleContainer: HTMLElement;
private readonly titleControl: EditorTitleControl;

Expand Down Expand Up @@ -149,7 +153,8 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
@IEditorService private readonly editorService: EditorServiceImpl,
@IFilesConfigurationService private readonly filesConfigurationService: IFilesConfigurationService,
@IUriIdentityService private readonly uriIdentityService: IUriIdentityService,
@ILogService private readonly logService: ILogService
@ILogService private readonly logService: ILogService,
@IEditorResolverService private readonly editorResolverService: IEditorResolverService
) {
super(themeService);

Expand Down Expand Up @@ -192,6 +197,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
));

// Context keys
this.resourceContext = this._register(this.scopedInstantiationService.createInstance(ResourceContextKey));
this.handleGroupContextKeys();

// Title container
Expand Down Expand Up @@ -245,20 +251,34 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
const groupLockedContext = ActiveEditorGroupLockedContext.bindTo(this.scopedContextKeyService);
const groupHasPinnedAndUnpinnedContext = EditorPinnedAndUnpinnedTabsContext.bindTo(this.scopedContextKeyService);

const groupActiveEditorAvailableEditorIds = ActiveEditorAvailableEditorIdsContext.bindTo(this.scopedContextKeyService);
const groupActiveEditorCanSplitInGroupContext = ActiveEditorCanSplitInGroupContext.bindTo(this.scopedContextKeyService);
const sideBySideEditorContext = SideBySideEditorActiveContext.bindTo(this.scopedContextKeyService);

const activeEditorListener = this._register(new MutableDisposable());

const observeActiveEditor = () => {
activeEditorListener.clear();

const activeEditor = this.model.activeEditor;
if (activeEditor) {
groupActiveEditorDirtyContext.set(activeEditor.isDirty() && !activeEditor.isSaving());
activeEditorListener.value = activeEditor.onDidChangeDirty(() => {
this.scopedContextKeyService.bufferChangeEvents(() => {
const activeEditor = this.activeEditor;

this.resourceContext.set(EditorResourceAccessor.getOriginalUri(activeEditor, { supportSideBySide: SideBySideEditor.PRIMARY } ?? null));

applyAvailableEditorIds(groupActiveEditorAvailableEditorIds, activeEditor, this.editorResolverService);

groupActiveEditorCanSplitInGroupContext.set(activeEditor ? activeEditor.hasCapability(EditorInputCapabilities.CanSplitInGroup) : false);
sideBySideEditorContext.set(activeEditor?.typeId === SideBySideEditorInput.ID);

if (activeEditor) {
groupActiveEditorDirtyContext.set(activeEditor.isDirty() && !activeEditor.isSaving());
});
} else {
groupActiveEditorDirtyContext.set(false);
}
activeEditorListener.value = activeEditor.onDidChangeDirty(() => {
groupActiveEditorDirtyContext.set(activeEditor.isDirty() && !activeEditor.isSaving());
});
} else {
groupActiveEditorDirtyContext.set(false);
}
});
};

// Update group contexts based on group changes
Expand Down Expand Up @@ -350,7 +370,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Toolbar actions
const containerToolbarMenu = this._register(this.menuService.createMenu(MenuId.EmptyEditorGroup, this.scopedContextKeyService));
const updateContainerToolbar = () => {
const actions: { primary: IAction[]; secondary: IAction[] } = { primary: [], secondary: [] };
const actions: IToolbarActions = { primary: [], secondary: [] };

// Clear old actions
this.containerToolBarMenuDisposable.value = toDisposable(() => containerToolbar.clear());
Expand Down Expand Up @@ -1889,6 +1909,37 @@ export class EditorGroupView extends Themable implements IEditorGroupView {

//#endregion

//#region Editor Actions

createEditorActions(disposables: DisposableStore): IActiveEditorActions {
const primary: IAction[] = [];
const secondary: IAction[] = [];

let onDidChange = Event.None;

// Editor actions require the editor control to be there, so we retrieve it via service
const activeEditorPane = this.activeEditorPane;
if (activeEditorPane instanceof EditorPane) {
const editorScopedContextKeyService = activeEditorPane.scopedContextKeyService ?? this.scopedContextKeyService;
const editorTitleMenu = disposables.add(this.menuService.createMenu(MenuId.EditorTitle, editorScopedContextKeyService, { emitEventsForSubmenuChanges: true, eventDebounceDelay: 0 }));
onDidChange = editorTitleMenu.onDidChange;

const shouldInlineGroup = (action: SubmenuAction, group: string) => group === 'navigation' && action.actions.length <= 1;

createAndFillInActionBarActions(
editorTitleMenu,
{ arg: this.resourceContext.get(), shouldForwardArgs: true },
{ primary, secondary },
'navigation',
shouldInlineGroup
);
}

return { actions: { primary, secondary }, onDidChange };
}

//#endregion

//#region Themable

override updateStyles(): void {
Expand Down
Loading

0 comments on commit c2d75ed

Please sign in to comment.