Custom hover for editor tabs (#204742)

This commit is contained in:
Benjamin Christopher Simmonds 2024-02-08 18:16:28 +01:00 committed by GitHub
parent 31a7befa31
commit f618bf3bef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 54 additions and 16 deletions

View file

@ -25,7 +25,7 @@ import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillEditorsDragData, isWindowDraggedOver } from 'vs/workbench/browser/dnd';
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
import { IEditorGroupsView, IEditorGroupView, IEditorPartsView, IInternalEditorOpenOptions } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorCommandsContext, EditorResourceAccessor, IEditorPartOptions, SideBySideEditor, EditorsOrder, EditorInputCapabilities, IToolbarActions, GroupIdentifier } from 'vs/workbench/common/editor';
import { IEditorCommandsContext, EditorResourceAccessor, IEditorPartOptions, SideBySideEditor, EditorsOrder, EditorInputCapabilities, IToolbarActions, GroupIdentifier, Verbosity } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { ResourceContextKey, ActiveEditorPinnedContext, ActiveEditorStickyContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, ActiveEditorFirstInGroupContext, ActiveEditorAvailableEditorIdsContext, applyAvailableEditorIds, ActiveEditorLastInGroupContext } from 'vs/workbench/common/contextkeys';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
@ -44,6 +44,11 @@ import { IAuxiliaryEditorPart, MergeGroupMode } from 'vs/workbench/services/edit
import { isMacintosh } from 'vs/base/common/platform';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { MarkdownString, MarkdownStringTextNewlineStyle } from 'vs/base/common/htmlContent';
import { ITooltipMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabelHover';
import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations';
import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate';
import { IHoverService } from 'vs/platform/hover/browser/hover';
export class EditorCommandsContextActionRunner extends ActionRunner {
@ -135,7 +140,9 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
@IQuickInputService protected quickInputService: IQuickInputService,
@IThemeService themeService: IThemeService,
@IEditorResolverService private readonly editorResolverService: IEditorResolverService,
@IHostService private readonly hostService: IHostService
@IHostService private readonly hostService: IHostService,
@IDecorationsService private readonly decorationsService: IDecorationsService,
@IHoverService private readonly hoverService: IHoverService
) {
super(themeService);
@ -444,6 +451,41 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC
return this.groupsView.partOptions.tabHeight !== 'compact' ? EditorTabsControl.EDITOR_TAB_HEIGHT.normal : EditorTabsControl.EDITOR_TAB_HEIGHT.compact;
}
protected getHoverTitle(editor: EditorInput): ITooltipMarkdownString {
const title = editor.getTitle(Verbosity.LONG);
const markdown = new MarkdownString(title);
if (editor.resource) {
const decoration = this.decorationsService.getDecoration(editor.resource, false);
if (decoration) {
const decorations = decoration.tooltip.split('• ');
const decorationString = `${decorations.join('\n• ')}`;
markdown.appendText('\n', MarkdownStringTextNewlineStyle.Paragraph);
markdown.appendText(decorationString, MarkdownStringTextNewlineStyle.Break);
}
}
return {
markdown,
markdownNotSupportedFallback: title
};
}
protected getHoverDelegate(): IHoverDelegate {
return {
delay: 500,
showHover: options => {
return this.hoverService.showHover({
...options,
persistence: {
hideOnHover: true
}
});
}
};
}
protected updateTabHeight(): void {
this.parent.style.setProperty('--editor-group-tab-height', `${this.tabHeight}px`);
}

View file

@ -56,6 +56,8 @@ import { IEditorTitleControlDimensions } from 'vs/workbench/browser/parts/editor
import { StickyEditorGroupModel, UnstickyEditorGroupModel } from 'vs/workbench/common/editor/filteredEditorGroupModel';
import { IReadonlyEditorGroupModel } from 'vs/workbench/common/editor/editorGroupModel';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IHoverService } from 'vs/platform/hover/browser/hover';
import { IDecorationsService } from 'vs/workbench/services/decorations/common/decorations';
interface IEditorInputLabel {
readonly editor: EditorInput;
@ -149,9 +151,11 @@ export class MultiEditorTabsControl extends EditorTabsControl {
@IPathService private readonly pathService: IPathService,
@ITreeViewsDnDService private readonly treeViewsDragAndDropService: ITreeViewsDnDService,
@IEditorResolverService editorResolverService: IEditorResolverService,
@IHostService hostService: IHostService
@IHostService hostService: IHostService,
@IDecorationsService decorationsService: IDecorationsService,
@IHoverService hoverService: IHoverService,
) {
super(parent, editorPartsView, groupsView, groupView, tabsModel, contextMenuService, instantiationService, contextKeyService, keybindingService, notificationService, quickInputService, themeService, editorResolverService, hostService);
super(parent, editorPartsView, groupsView, groupView, tabsModel, contextMenuService, instantiationService, contextKeyService, keybindingService, notificationService, quickInputService, themeService, editorResolverService, hostService, decorationsService, hoverService);
// Resolve the correct path library for the OS we are on
// If we are connected to remote, this accounts for the
@ -793,7 +797,7 @@ export class MultiEditorTabsControl extends EditorTabsControl {
tabContainer.appendChild(tabBorderTopContainer);
// Tab Editor Label
const editorLabel = this.tabResourceLabels.create(tabContainer);
const editorLabel = this.tabResourceLabels.create(tabContainer, { hoverDelegate: this.getHoverDelegate() });
// Tab Actions
const tabActionsContainer = document.createElement('div');
@ -1469,14 +1473,11 @@ export class MultiEditorTabsControl extends EditorTabsControl {
tabContainer.setAttribute('aria-description', '');
}
const title = tabLabel.title || '';
tabContainer.title = title;
// Label
tabLabelWidget.setResource(
{ name, description, resource: EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.BOTH }) },
{
title,
title: this.getHoverTitle(editor),
extraClasses: coalesce(['tab-label', fileDecorationBadges ? 'tab-label-has-badge' : undefined].concat(editor.getLabelExtraClasses())),
italic: !this.tabsModel.isPinned(editor),
forceLabel,

View file

@ -51,7 +51,7 @@ export class SingleEditorTabsControl extends EditorTabsControl {
titleContainer.appendChild(labelContainer);
// Editor Label
this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, undefined)).element;
this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, { hoverDelegate: this.getHoverDelegate() })).element;
this._register(addDisposableListener(this.editorLabel.element, EventType.CLICK, e => this.onTitleLabelClick(e)));
// Breadcrumbs
@ -304,11 +304,6 @@ export class SingleEditorTabsControl extends EditorTabsControl {
description = editor.getDescription(this.getVerbosity(labelFormat)) || '';
}
let title = editor.getTitle(Verbosity.LONG);
if (description === title) {
title = ''; // dont repeat what is already shown
}
editorLabel.setResource(
{
resource: EditorResourceAccessor.getOriginalUri(editor, { supportSideBySide: SideBySideEditor.BOTH }),
@ -316,7 +311,7 @@ export class SingleEditorTabsControl extends EditorTabsControl {
description
},
{
title,
title: this.getHoverTitle(editor),
italic: !isEditorPinned,
extraClasses: ['single-tab', 'title-label'].concat(editor.getLabelExtraClasses()),
fileDecorations: {