From e4e853fecf4e83033bade6bad9ea74c6f58dd1ef Mon Sep 17 00:00:00 2001 From: Benjamin Christopher Simmonds <44439583+benibenj@users.noreply.github.com> Date: Thu, 15 Feb 2024 20:25:45 +0100 Subject: [PATCH] Workbench hover to align and correctly apply delay setting (#204871) * Workbench hover * :lipstick: * placement element for tabs and breadcrumbs * enableInstantHoverAfterRecentlyShown * :lipstick: * adobt custom hover in all toolbars and labels * dropdown hover * widgets * dispose hover delegate uf own instance * testing hover delegate (might be a better way of doing this?) * nullHoverDelegateFactory * registering the disposables and handing down options * Hygiene * fix quickinput --- .../browser/ui/actionbar/actionViewItems.ts | 17 +++--- src/vs/base/browser/ui/actionbar/actionbar.ts | 6 +- src/vs/base/browser/ui/button/button.ts | 15 ++++- src/vs/base/browser/ui/dropdown/dropdown.ts | 10 +++- .../ui/dropdown/dropdownActionViewItem.ts | 8 ++- src/vs/base/browser/ui/hover/hoverDelegate.ts | 35 +++++++++++ .../browser/ui/iconLabel/iconHoverDelegate.ts | 2 + src/vs/base/browser/ui/iconLabel/iconLabel.ts | 17 +++--- src/vs/base/browser/ui/inputbox/inputBox.ts | 9 ++- .../browser/ui/selectBox/selectBoxCustom.ts | 13 +++-- src/vs/base/browser/ui/table/tableWidget.ts | 13 +++-- src/vs/base/browser/ui/toggle/toggle.ts | 7 ++- src/vs/base/browser/ui/toolbar/toolbar.ts | 11 +++- .../diffEditorItemTemplate.ts | 2 +- .../quickInput/standaloneQuickInputService.ts | 3 - .../browser/standaloneCodeEditor.ts | 4 ++ .../dropdownWithPrimaryActionViewItem.ts | 12 ++-- .../browser/menuEntryActionViewItem.ts | 2 +- src/vs/platform/hover/browser/hover.ts | 58 ++++++++++++++++++- .../platform/quickinput/browser/quickInput.ts | 36 ++++-------- .../quickinput/browser/quickInputService.ts | 4 +- src/vs/workbench/browser/composite.ts | 3 +- src/vs/workbench/browser/panecomposite.ts | 5 +- .../workbench/browser/parts/compositePart.ts | 16 +++-- .../parts/editor/breadcrumbsControl.ts | 16 +---- .../browser/parts/editor/editorTabsControl.ts | 28 ++++----- .../parts/editor/multiEditorTabsControl.ts | 6 +- .../browser/parts/globalCompositeBar.ts | 5 ++ .../browser/parts/paneCompositePart.ts | 7 ++- .../browser/parts/statusbar/statusbarPart.ts | 56 +++++------------- .../browser/parts/titlebar/titlebarPart.ts | 50 +++++----------- .../workbench/browser/parts/views/treeView.ts | 9 +-- .../workbench/browser/parts/views/viewPane.ts | 2 +- .../browser/parts/views/viewPaneContainer.ts | 7 ++- src/vs/workbench/browser/workbench.ts | 6 ++ .../browser/outline/documentSymbolsOutline.ts | 2 +- .../browser/outline/documentSymbolsTree.ts | 18 ++---- .../contrib/debug/browser/callStackView.ts | 4 +- .../debug/browser/debugActionViewItems.ts | 5 +- .../contrib/debug/browser/debugToolBar.ts | 13 +++-- .../contrib/debug/browser/debugViewlet.ts | 9 +-- .../extensions/browser/extensionsViewlet.ts | 2 +- .../interactive/browser/interactiveEditor.ts | 4 +- .../browser/view/cellParts/cellToolbars.ts | 8 +-- .../contrib/remote/browser/tunnelView.ts | 23 ++++---- .../contrib/scm/browser/scmViewPane.ts | 6 +- src/vs/workbench/contrib/scm/browser/util.ts | 12 ++-- .../terminal/browser/terminalEditor.ts | 7 ++- .../contrib/terminal/browser/terminalView.ts | 10 ++-- .../testing/browser/testingExplorerView.ts | 2 +- .../contrib/timeline/browser/timelinePane.ts | 11 +--- .../parts/titlebar/titlebarPart.ts | 10 +--- .../quickinput/browser/quickInputService.ts | 4 +- .../test/browser/workbenchTestServices.ts | 24 +------- 54 files changed, 356 insertions(+), 318 deletions(-) create mode 100644 src/vs/base/browser/ui/hover/hoverDelegate.ts diff --git a/src/vs/base/browser/ui/actionbar/actionViewItems.ts b/src/vs/base/browser/ui/actionbar/actionViewItems.ts index 906c437b325..804b0c386ac 100644 --- a/src/vs/base/browser/ui/actionbar/actionViewItems.ts +++ b/src/vs/base/browser/ui/actionbar/actionViewItems.ts @@ -9,6 +9,7 @@ import { addDisposableListener, EventHelper, EventLike, EventType } from 'vs/bas import { EventType as TouchEventType, Gesture } from 'vs/base/browser/touch'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { ISelectBoxOptions, ISelectBoxStyles, ISelectOptionItem, SelectBox } from 'vs/base/browser/ui/selectBox/selectBox'; @@ -224,16 +225,14 @@ export class BaseActionViewItem extends Disposable implements IActionViewItem { } const title = this.getTooltip() ?? ''; this.updateAriaLabel(); - if (!this.options.hoverDelegate) { - this.element.title = title; + + this.element.title = ''; + if (!this.customHover) { + const hoverDelegate = this.options.hoverDelegate ?? getDefaultHoverDelegate('element'); + this.customHover = setupCustomHover(hoverDelegate, this.element, title); + this._store.add(this.customHover); } else { - this.element.title = ''; - if (!this.customHover) { - this.customHover = setupCustomHover(this.options.hoverDelegate, this.element, title); - this._store.add(this.customHover); - } else { - this.customHover.update(title); - } + this.customHover.update(title); } } diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index fafc3417f8b..9ba16500c8f 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -6,6 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionViewItem, BaseActionViewItem, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { ActionRunner, IAction, IActionRunner, IRunEvent, Separator } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; @@ -67,6 +68,7 @@ export interface IActionOptions extends IActionViewItemOptions { export class ActionBar extends Disposable implements IActionRunner { private readonly options: IActionBarOptions; + private readonly _hoverDelegate: IHoverDelegate; private _actionRunner: IActionRunner; private readonly _actionRunnerDisposables = this._register(new DisposableStore()); @@ -117,6 +119,8 @@ export class ActionBar extends Disposable implements IActionRunner { keys: this.options.triggerKeys?.keys ?? [KeyCode.Enter, KeyCode.Space] }; + this._hoverDelegate = options.hoverDelegate ?? this._register(getDefaultHoverDelegate('element', true)); + if (this.options.actionRunner) { this._actionRunner = this.options.actionRunner; } else { @@ -358,7 +362,7 @@ export class ActionBar extends Disposable implements IActionRunner { let item: IActionViewItem | undefined; - const viewItemOptions = { hoverDelegate: this.options.hoverDelegate, ...options }; + const viewItemOptions = { hoverDelegate: this._hoverDelegate, ...options }; if (this.options.actionViewItemProvider) { item = this.options.actionViewItemProvider(action, viewItemOptions); } diff --git a/src/vs/base/browser/ui/button/button.ts b/src/vs/base/browser/ui/button/button.ts index 3b1ad7915bb..4675ee8c5ee 100644 --- a/src/vs/base/browser/ui/button/button.ts +++ b/src/vs/base/browser/ui/button/button.ts @@ -9,6 +9,8 @@ import { sanitize } from 'vs/base/browser/dompurify/dompurify'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { renderMarkdown, renderStringAsPlaintext } from 'vs/base/browser/markdownRenderer'; import { Gesture, EventType as TouchEventType } from 'vs/base/browser/touch'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { Action, IAction, IActionRunner } from 'vs/base/common/actions'; import { Codicon } from 'vs/base/common/codicons'; @@ -74,6 +76,7 @@ export class Button extends Disposable implements IButton { protected _label: string | IMarkdownString = ''; protected _labelElement: HTMLElement | undefined; protected _labelShortElement: HTMLElement | undefined; + private _hover: ICustomHover | undefined; private _onDidClick = this._register(new Emitter()); get onDidClick(): BaseEvent { return this._onDidClick.event; } @@ -240,10 +243,16 @@ export class Button extends Disposable implements IButton { } } + let title: string = ''; if (typeof this.options.title === 'string') { - this._element.title = this.options.title; + title = this.options.title; } else if (this.options.title) { - this._element.title = renderStringAsPlaintext(value); + title = renderStringAsPlaintext(value); + } + if (!this._hover) { + this._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this._element, title)); + } else { + this._hover.update(title); } if (typeof this.options.ariaLabel === 'string') { @@ -348,7 +357,7 @@ export class ButtonWithDropdown extends Disposable implements IButton { this.separator.style.backgroundColor = options.buttonSeparator ?? ''; this.dropdownButton = this._register(new Button(this.element, { ...options, title: false, supportIcons: true })); - this.dropdownButton.element.title = localize("button dropdown more actions", 'More Actions...'); + this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.dropdownButton.element, localize("button dropdown more actions", 'More Actions...'))); this.dropdownButton.element.setAttribute('aria-haspopup', 'true'); this.dropdownButton.element.setAttribute('aria-expanded', 'false'); this.dropdownButton.element.classList.add('monaco-dropdown-button'); diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index 8fd8867058a..88dfaf2c5b1 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -8,6 +8,8 @@ import { $, addDisposableListener, append, EventHelper, EventType, isMouseEvent import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { EventType as GestureEventType, Gesture } from 'vs/base/browser/touch'; import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { IMenuOptions } from 'vs/base/browser/ui/menu/menu'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { Emitter } from 'vs/base/common/event'; @@ -34,6 +36,8 @@ class BaseDropdown extends ActionRunner { private _onDidChangeVisibility = this._register(new Emitter()); readonly onDidChangeVisibility = this._onDidChangeVisibility.event; + private hover: ICustomHover | undefined; + constructor(container: HTMLElement, options: IBaseDropdownOptions) { super(); @@ -101,7 +105,11 @@ class BaseDropdown extends ActionRunner { set tooltip(tooltip: string) { if (this._label) { - this._label.title = tooltip; + if (!this.hover) { + this.hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this._label, tooltip)); + } else { + this.hover.update(tooltip); + } } } diff --git a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts index a5fee4835b3..419658a21bb 100644 --- a/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts +++ b/src/vs/base/browser/ui/dropdown/dropdownActionViewItem.ts @@ -19,6 +19,8 @@ import { KeyCode } from 'vs/base/common/keyCodes'; import { ResolvedKeybinding } from 'vs/base/common/keybindings'; import { IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./dropdown'; +import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export interface IKeybindingProvider { (action: IAction): ResolvedKeybinding | undefined; @@ -90,7 +92,9 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { this.element.setAttribute('role', 'button'); this.element.setAttribute('aria-haspopup', 'true'); this.element.setAttribute('aria-expanded', 'false'); - this.element.title = this._action.label || ''; + if (this._action.label) { + this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.element, this._action.label)); + } this.element.ariaLabel = this._action.label || ''; return null; @@ -203,7 +207,7 @@ export class ActionWithDropdownActionViewItem extends ActionViewItem { separator.classList.toggle('prominent', menuActionClassNames.includes('prominent')); append(this.element, separator); - this.dropdownMenuActionViewItem = this._register(new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', nls.localize('moreActions', "More Actions..."))), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...ThemeIcon.asClassNameArray(Codicon.dropDownButton), ...menuActionClassNames] })); + this.dropdownMenuActionViewItem = this._register(new DropdownMenuActionViewItem(this._register(new Action('dropdownAction', nls.localize('moreActions', "More Actions..."))), menuActionsProvider, this.contextMenuProvider, { classNames: ['dropdown', ...ThemeIcon.asClassNameArray(Codicon.dropDownButton), ...menuActionClassNames], hoverDelegate: this.options.hoverDelegate })); this.dropdownMenuActionViewItem.render(this.element); this._register(addDisposableListener(this.element, EventType.KEY_DOWN, e => { diff --git a/src/vs/base/browser/ui/hover/hoverDelegate.ts b/src/vs/base/browser/ui/hover/hoverDelegate.ts new file mode 100644 index 00000000000..6682d739c26 --- /dev/null +++ b/src/vs/base/browser/ui/hover/hoverDelegate.ts @@ -0,0 +1,35 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IHoverDelegate, IScopedHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { Lazy } from 'vs/base/common/lazy'; + +const nullHoverDelegateFactory = () => ({ + get delay(): number { return -1; }, + dispose: () => { }, + showHover: () => { return undefined; }, +}); + +let hoverDelegateFactory: (placement: 'mouse' | 'element', enableInstantHover: boolean) => IScopedHoverDelegate = nullHoverDelegateFactory; +const defaultHoverDelegateMouse = new Lazy(() => hoverDelegateFactory('mouse', false)); +const defaultHoverDelegateElement = new Lazy(() => hoverDelegateFactory('element', false)); + +export function setHoverDelegateFactory(hoverDelegateProvider: ((placement: 'mouse' | 'element', enableInstantHover: boolean) => IScopedHoverDelegate)): void { + hoverDelegateFactory = hoverDelegateProvider; +} + +export function getDefaultHoverDelegate(placement: 'mouse' | 'element'): IHoverDelegate; +export function getDefaultHoverDelegate(placement: 'mouse' | 'element', enableInstantHover: true): IScopedHoverDelegate; +export function getDefaultHoverDelegate(placement: 'mouse' | 'element', enableInstantHover?: boolean): IHoverDelegate | IScopedHoverDelegate { + if (enableInstantHover) { + // If instant hover is enabled, the consumer is responsible for disposing the hover delegate + return hoverDelegateFactory(placement, true); + } + + if (placement === 'element') { + return defaultHoverDelegateElement.value; + } + return defaultHoverDelegateMouse.value; +} diff --git a/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts b/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts index 74fcd97d4a9..d6d9096b5f1 100644 --- a/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts +++ b/src/vs/base/browser/ui/iconLabel/iconHoverDelegate.ts @@ -64,6 +64,8 @@ export interface IHoverDelegate { placement?: 'mouse' | 'element'; } +export interface IScopedHoverDelegate extends IHoverDelegate, IDisposable { } + export interface IHoverWidget extends IDisposable { readonly isDisposed: boolean; } diff --git a/src/vs/base/browser/ui/iconLabel/iconLabel.ts b/src/vs/base/browser/ui/iconLabel/iconLabel.ts index f95a11c9c44..6a7edc12dcf 100644 --- a/src/vs/base/browser/ui/iconLabel/iconLabel.ts +++ b/src/vs/base/browser/ui/iconLabel/iconLabel.ts @@ -7,11 +7,12 @@ import 'vs/css!./iconlabel'; import * as dom from 'vs/base/browser/dom'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { ITooltipMarkdownString, setupCustomHover, setupNativeHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; +import { ITooltipMarkdownString, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { IMatch } from 'vs/base/common/filters'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { equals } from 'vs/base/common/objects'; import { Range } from 'vs/base/common/range'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export interface IIconLabelCreationOptions { readonly supportHighlights?: boolean; @@ -94,7 +95,7 @@ export class IconLabel extends Disposable { private readonly labelContainer: HTMLElement; - private readonly hoverDelegate: IHoverDelegate | undefined; + private readonly hoverDelegate: IHoverDelegate; private readonly customHovers: Map = new Map(); constructor(container: HTMLElement, options?: IIconLabelCreationOptions) { @@ -113,7 +114,7 @@ export class IconLabel extends Disposable { this.nameNode = new Label(this.nameContainer); } - this.hoverDelegate = options?.hoverDelegate; + this.hoverDelegate = options?.hoverDelegate ?? getDefaultHoverDelegate('mouse'); } get element(): HTMLElement { @@ -186,13 +187,9 @@ export class IconLabel extends Disposable { return; } - if (!this.hoverDelegate) { - setupNativeHover(htmlElement, tooltip); - } else { - const hoverDisposable = setupCustomHover(this.hoverDelegate, htmlElement, tooltip); - if (hoverDisposable) { - this.customHovers.set(htmlElement, hoverDisposable); - } + const hoverDisposable = setupCustomHover(this.hoverDelegate, htmlElement, tooltip); + if (hoverDisposable) { + this.customHovers.set(htmlElement, hoverDisposable); } } diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index e4c89dd3aff..a23848dd914 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -11,6 +11,8 @@ import { MarkdownRenderOptions } from 'vs/base/browser/markdownRenderer'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { AnchorAlignment, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Widget } from 'vs/base/browser/ui/widget'; import { IAction } from 'vs/base/common/actions'; @@ -111,6 +113,7 @@ export class InputBox extends Widget { private cachedContentHeight: number | undefined; private maxHeight: number = Number.POSITIVE_INFINITY; private scrollableElement: ScrollableElement | undefined; + private hover: ICustomHover | undefined; private _onDidChange = this._register(new Emitter()); public readonly onDidChange: Event = this._onDidChange.event; @@ -230,7 +233,11 @@ export class InputBox extends Widget { public setTooltip(tooltip: string): void { this.tooltip = tooltip; - this.input.title = tooltip; + if (!this.hover) { + this.hover = this._register(setupCustomHover(getDefaultHoverDelegate('element'), this.input, tooltip)); + } else { + this.hover.update(tooltip); + } } public setAriaLabel(label: string): void { diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 83073ee2666..ca6aaa33505 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -9,6 +9,8 @@ import { IContentActionHandler } from 'vs/base/browser/formattedTextRenderer'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { renderMarkdown } from 'vs/base/browser/markdownRenderer'; import { AnchorPosition, IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { IListEvent, IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { ISelectBoxDelegate, ISelectBoxOptions, ISelectBoxStyles, ISelectData, ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; @@ -101,6 +103,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi private selectionDetailsPane!: HTMLElement; private _skipLayout: boolean = false; private _cachedMaxDetailsHeight?: number; + private _hover: ICustomHover; private _sticky: boolean = false; // for dev purposes only @@ -131,6 +134,8 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi this.selectElement.setAttribute('aria-description', this.selectBoxOptions.ariaDescription); } + this._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.selectElement, '')); + this._onDidSelect = new Emitter(); this._register(this._onDidSelect); @@ -199,7 +204,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi selected: e.target.value }); if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; + this._hover.update(this.options[this.selected].text); } })); @@ -309,7 +314,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi this.selectElement.selectedIndex = this.selected; if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; + this._hover.update(this.options[this.selected].text); } } @@ -837,7 +842,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi }); if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; + this._hover.update(this.options[this.selected].text); } } @@ -936,7 +941,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi selected: this.options[this.selected].text }); if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; + this._hover.update(this.options[this.selected].text); } } diff --git a/src/vs/base/browser/ui/table/tableWidget.ts b/src/vs/base/browser/ui/table/tableWidget.ts index 6e20fd6e34a..536fb25608e 100644 --- a/src/vs/base/browser/ui/table/tableWidget.ts +++ b/src/vs/base/browser/ui/table/tableWidget.ts @@ -4,12 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { $, append, clearNode, createStyleSheet, getContentHeight, getContentWidth } from 'vs/base/browser/dom'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { IListOptions, IListOptionsUpdate, IListStyles, List, unthemedListStyles } from 'vs/base/browser/ui/list/listWidget'; import { ISplitViewDescriptor, IView, Orientation, SplitView } from 'vs/base/browser/ui/splitview/splitview'; import { ITableColumn, ITableContextMenuEvent, ITableEvent, ITableGestureEvent, ITableMouseEvent, ITableRenderer, ITableTouchEvent, ITableVirtualDelegate } from 'vs/base/browser/ui/table/table'; import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; import { ISpliceable } from 'vs/base/common/sequence'; import 'vs/css!./table'; @@ -115,7 +117,7 @@ function asListVirtualDelegate(delegate: ITableVirtualDelegate): ILi }; } -class ColumnHeader implements IView { +class ColumnHeader extends Disposable implements IView { readonly element: HTMLElement; @@ -127,7 +129,10 @@ class ColumnHeader implements IView { readonly onDidLayout = this._onDidLayout.event; constructor(readonly column: ITableColumn, private index: number) { - this.element = $('.monaco-table-th', { 'data-col-index': index, title: column.tooltip }, column.label); + super(); + + this.element = $('.monaco-table-th', { 'data-col-index': index }, column.label); + this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.element, column.tooltip)); } layout(size: number): void { @@ -191,7 +196,7 @@ export class Table implements ISpliceable, IDisposable { ) { this.domNode = append(container, $(`.monaco-table.${this.domId}`)); - const headers = columns.map((c, i) => new ColumnHeader(c, i)); + const headers = columns.map((c, i) => this.disposables.add(new ColumnHeader(c, i))); const descriptor: ISplitViewDescriptor = { size: headers.reduce((a, b) => a + b.column.weight, 0), views: headers.map(view => ({ size: view.column.weight, view })) diff --git a/src/vs/base/browser/ui/toggle/toggle.ts b/src/vs/base/browser/ui/toggle/toggle.ts index 4146f24d141..54b9130d9e4 100644 --- a/src/vs/base/browser/ui/toggle/toggle.ts +++ b/src/vs/base/browser/ui/toggle/toggle.ts @@ -13,6 +13,8 @@ import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import 'vs/css!./toggle'; import { isActiveElement, $, addDisposableListener, EventType } from 'vs/base/browser/dom'; +import { ICustomHover, setupCustomHover } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export interface IToggleOpts extends IToggleStyles { readonly actionClassName?: string; @@ -107,6 +109,7 @@ export class Toggle extends Widget { readonly domNode: HTMLElement; private _checked: boolean; + private _hover: ICustomHover; constructor(opts: IToggleOpts) { super(); @@ -127,7 +130,7 @@ export class Toggle extends Widget { } this.domNode = document.createElement('div'); - this.domNode.title = this._opts.title; + this._hover = this._register(setupCustomHover(getDefaultHoverDelegate('mouse'), this.domNode, this._opts.title)); this.domNode.classList.add(...classes); if (!this._opts.notFocusable) { this.domNode.tabIndex = 0; @@ -213,7 +216,7 @@ export class Toggle extends Widget { } setTitle(newTitle: string): void { - this.domNode.title = newTitle; + this._hover.update(newTitle); this.domNode.setAttribute('aria-label', newTitle); } } diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 2f46a692357..f92369cddfb 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -15,6 +15,8 @@ import { ResolvedKeybinding } from 'vs/base/common/keybindings'; import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import 'vs/css!./toolbar'; import * as nls from 'vs/nls'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; @@ -30,6 +32,7 @@ export interface IToolBarOptions { moreIcon?: ThemeIcon; allowContextMenu?: boolean; skipTelemetry?: boolean; + hoverDelegate?: IHoverDelegate; /** * If true, toggled primary items are highlighted with a background color. @@ -57,6 +60,7 @@ export class ToolBar extends Disposable { constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) { super(); + options.hoverDelegate = options.hoverDelegate ?? this._register(getDefaultHoverDelegate('element', true)); this.options = options; this.lookupKeybindings = typeof this.options.getKeyBinding === 'function'; @@ -72,6 +76,7 @@ export class ToolBar extends Disposable { actionRunner: options.actionRunner, allowContextMenu: options.allowContextMenu, highlightToggledItems: options.highlightToggledItems, + hoverDelegate: options.hoverDelegate, actionViewItemProvider: (action, viewItemOptions) => { if (action.id === ToggleMenuAction.ID) { this.toggleMenuActionViewItem = new DropdownMenuActionViewItem( @@ -86,7 +91,8 @@ export class ToolBar extends Disposable { anchorAlignmentProvider: this.options.anchorAlignmentProvider, menuAsChild: !!this.options.renderDropdownAsChildElement, skipTelemetry: this.options.skipTelemetry, - isMenu: true + isMenu: true, + hoverDelegate: this.options.hoverDelegate } ); this.toggleMenuActionViewItem.setActionContext(this.actionBar.context); @@ -115,7 +121,8 @@ export class ToolBar extends Disposable { classNames: action.class, anchorAlignmentProvider: this.options.anchorAlignmentProvider, menuAsChild: !!this.options.renderDropdownAsChildElement, - skipTelemetry: this.options.skipTelemetry + skipTelemetry: this.options.skipTelemetry, + hoverDelegate: this.options.hoverDelegate } ); result.setActionContext(this.actionBar.context); diff --git a/src/vs/editor/browser/widget/multiDiffEditorWidget/diffEditorItemTemplate.ts b/src/vs/editor/browser/widget/multiDiffEditorWidget/diffEditorItemTemplate.ts index da71ca719f7..8c44f6e4181 100644 --- a/src/vs/editor/browser/widget/multiDiffEditorWidget/diffEditorItemTemplate.ts +++ b/src/vs/editor/browser/widget/multiDiffEditorWidget/diffEditorItemTemplate.ts @@ -148,7 +148,7 @@ export class DiffEditorItemTemplate extends Disposable implements IPooledObject< shouldForwardArgs: true, }, toolbarOptions: { primaryGroup: g => g.startsWith('navigation') }, - actionViewItemProvider: action => createActionViewItem(_instantiationService, action), + actionViewItemProvider: (action, options) => createActionViewItem(_instantiationService, action, options), })); } diff --git a/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts index 75a3520379b..0c94d2824e9 100644 --- a/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts +++ b/src/vs/editor/standalone/browser/quickInput/standaloneQuickInputService.ts @@ -20,7 +20,6 @@ import { QuickInputService } from 'vs/platform/quickinput/browser/quickInputServ import { createSingleCallFunction } from 'vs/base/common/functional'; import { IQuickAccessController } from 'vs/platform/quickinput/common/quickAccess'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; class EditorScopedQuickInputService extends QuickInputService { @@ -33,7 +32,6 @@ class EditorScopedQuickInputService extends QuickInputService { @IThemeService themeService: IThemeService, @ICodeEditorService codeEditorService: ICodeEditorService, @IConfigurationService configurationService: IConfigurationService, - @IHoverService hoverService: IHoverService, ) { super( instantiationService, @@ -41,7 +39,6 @@ class EditorScopedQuickInputService extends QuickInputService { themeService, new EditorScopedLayoutService(editor.getContainerDomNode(), codeEditorService), configurationService, - hoverService ); // Use the passed in code editor as host for the quick input widget diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 739e76f97c2..479bb75745c 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -39,6 +39,8 @@ import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeat import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditor/diffEditorWidget'; import { IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService'; import { mainWindow } from 'vs/base/browser/window'; +import { setHoverDelegateFactory } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover'; /** * Description of an action contribution @@ -289,6 +291,8 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon } createAriaDomNode(options.ariaContainerElement); + + setHoverDelegateFactory((placement, enableInstantHover) => instantiationService.createInstance(WorkbenchHoverDelegate, placement, enableInstantHover, {})); } public addCommand(keybinding: number, handler: ICommandHandler, context?: string): string | null { diff --git a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts index 99e25133cd8..cfcc0e2c73b 100644 --- a/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts +++ b/src/vs/platform/actions/browser/dropdownWithPrimaryActionViewItem.ts @@ -19,10 +19,12 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; export interface IDropdownWithPrimaryActionViewItemOptions { actionRunner?: IActionRunner; getKeyBinding?: (action: IAction) => ResolvedKeybinding | undefined; + hoverDelegate?: IHoverDelegate; } export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { @@ -48,8 +50,8 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { @IThemeService _themeService: IThemeService, @IAccessibilityService _accessibilityService: IAccessibilityService ) { - super(null, primaryAction); - this._primaryAction = new MenuEntryActionViewItem(primaryAction, undefined, _keybindingService, _notificationService, _contextKeyService, _themeService, _contextMenuProvider, _accessibilityService); + super(null, primaryAction, { hoverDelegate: _options?.hoverDelegate }); + this._primaryAction = new MenuEntryActionViewItem(primaryAction, { hoverDelegate: _options?.hoverDelegate }, _keybindingService, _notificationService, _contextKeyService, _themeService, _contextMenuProvider, _accessibilityService); if (_options?.actionRunner) { this._primaryAction.actionRunner = _options.actionRunner; } @@ -58,7 +60,8 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { menuAsChild: true, classNames: className ? ['codicon', 'codicon-chevron-down', className] : ['codicon', 'codicon-chevron-down'], actionRunner: this._options?.actionRunner, - keybindingProvider: this._options?.getKeyBinding + keybindingProvider: this._options?.getKeyBinding, + hoverDelegate: _options?.hoverDelegate }); } @@ -130,7 +133,8 @@ export class DropdownWithPrimaryActionViewItem extends BaseActionViewItem { this._dropdown.dispose(); this._dropdown = new DropdownMenuActionViewItem(dropdownAction, dropdownMenuActions, this._contextMenuProvider, { menuAsChild: true, - classNames: ['codicon', dropdownIcon || 'codicon-chevron-down'] + classNames: ['codicon', dropdownIcon || 'codicon-chevron-down'], + hoverDelegate: this._options?.hoverDelegate }); if (this._dropdownContainer) { this._dropdown.render(this._dropdownContainer); diff --git a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts index 8374e100d3c..c1edd287bea 100644 --- a/src/vs/platform/actions/browser/menuEntryActionViewItem.ts +++ b/src/vs/platform/actions/browser/menuEntryActionViewItem.ts @@ -515,7 +515,7 @@ class SubmenuEntrySelectActionViewItem extends SelectActionViewItem { /** * Creates action view items for menu actions or submenu actions. */ -export function createActionViewItem(instaService: IInstantiationService, action: IAction, options?: IDropdownMenuActionViewItemOptions | IMenuEntryActionViewItemOptions): undefined | MenuEntryActionViewItem | SubmenuEntryActionViewItem | BaseActionViewItem { +export function createActionViewItem(instaService: IInstantiationService, action: IAction, options: IDropdownMenuActionViewItemOptions | IMenuEntryActionViewItemOptions | undefined): undefined | MenuEntryActionViewItem | SubmenuEntryActionViewItem | BaseActionViewItem { if (action instanceof MenuItemAction) { return instaService.createInstance(MenuEntryActionViewItem, action, options); } else if (action instanceof SubmenuItemAction) { diff --git a/src/vs/platform/hover/browser/hover.ts b/src/vs/platform/hover/browser/hover.ts index 5f3bb1e3317..5bbd3ff00b9 100644 --- a/src/vs/platform/hover/browser/hover.ts +++ b/src/vs/platform/hover/browser/hover.ts @@ -4,10 +4,11 @@ *--------------------------------------------------------------------------------------------*/ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { HoverPosition } from 'vs/base/browser/ui/hover/hoverWidget'; -import { IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IHoverDelegate, IHoverDelegateOptions, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export const IHoverService = createDecorator('hoverService'); @@ -229,3 +230,56 @@ export interface IHoverTarget extends IDisposable { */ y?: number; } + +export class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate { + + private lastHoverHideTime = Number.MAX_VALUE; + private timeLimit = 200; + + + private _delay: number; + get delay(): number { + if (this.instantHover && Date.now() - this.lastHoverHideTime < this.timeLimit) { + return 0; // show instantly when a hover was recently shown + } + return this._delay; + } + + constructor( + public readonly placement: 'mouse' | 'element', + private readonly instantHover: boolean, + private overrideOptions: Partial | ((options: IHoverDelegateOptions, focus?: boolean) => Partial) = {}, + @IConfigurationService private readonly configurationService: IConfigurationService, + @IHoverService private readonly hoverService: IHoverService, + ) { + super(); + + this._delay = this.configurationService.getValue('workbench.hover.delay'); + this._register(this.configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('workbench.hover.delay')) { + this._delay = this.configurationService.getValue('workbench.hover.delay'); + } + })); + } + + showHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined { + const overrideOptions = typeof this.overrideOptions === 'function' ? this.overrideOptions(options, focus) : this.overrideOptions; + return this.hoverService.showHover({ + ...options, + persistence: { + hideOnHover: true + }, + ...overrideOptions + }, focus); + } + + setOptions(options: Partial | ((options: IHoverDelegateOptions, focus?: boolean) => Partial)): void { + this.overrideOptions = options; + } + + onDidHideHover(): void { + if (this.instantHover) { + this.lastHoverHideTime = Date.now(); + } + } +} diff --git a/src/vs/platform/quickinput/browser/quickInput.ts b/src/vs/platform/quickinput/browser/quickInput.ts index 79e8b3d6aa1..f23f8447a02 100644 --- a/src/vs/platform/quickinput/browser/quickInput.ts +++ b/src/vs/platform/quickinput/browser/quickInput.ts @@ -8,7 +8,7 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { Button, IButtonStyles } from 'vs/base/browser/ui/button/button'; import { CountBadge, ICountBadgeStyles } from 'vs/base/browser/ui/countBadge/countBadge'; -import { IHoverDelegate, IHoverDelegateOptions, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IInputBoxStyles } from 'vs/base/browser/ui/inputbox/inputBox'; import { IKeybindingLabelStyles } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; @@ -31,7 +31,7 @@ import { QuickInputBox } from './quickInputBox'; import { QuickInputList, QuickInputListFocus } from './quickInputList'; import { quickInputButtonToAction, renderQuickInputDescription } from './quickInputUtils'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; +import { IHoverOptions, IHoverService, WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover'; export interface IQuickInputOptions { idPrefix: string; @@ -1258,24 +1258,16 @@ export class QuickWidget extends QuickInput implements IQuickWidget { } } -export class QuickInputHoverDelegate implements IHoverDelegate { - private lastHoverHideTime = 0; - readonly placement = 'element'; - - get delay() { - if (Date.now() - this.lastHoverHideTime < 200) { - return 0; // show instantly when a hover was recently shown - } - - return this.configurationService.getValue('workbench.hover.delay'); - } +export class QuickInputHoverDelegate extends WorkbenchHoverDelegate { constructor( - private readonly configurationService: IConfigurationService, - private readonly hoverService: IHoverService - ) { } + @IConfigurationService configurationService: IConfigurationService, + @IHoverService hoverService: IHoverService + ) { + super('mouse', true, (options) => this.getOverrideOptions(options), configurationService, hoverService); + } - showHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined { + private getOverrideOptions(options: IHoverDelegateOptions): Partial { // Only show the hover hint if the content is of a decent size const showHoverHint = ( options.content instanceof HTMLElement @@ -1284,8 +1276,8 @@ export class QuickInputHoverDelegate implements IHoverDelegate { ? options.content : options.content.value ).includes('\n'); - return this.hoverService.showHover({ - ...options, + + return { persistence: { hideOnKeyDown: false, }, @@ -1293,10 +1285,6 @@ export class QuickInputHoverDelegate implements IHoverDelegate { showHoverHint, skipFadeInAnimation: true, }, - }, focus); - } - - onDidHideHover(): void { - this.lastHoverHideTime = Date.now(); + }; } } diff --git a/src/vs/platform/quickinput/browser/quickInputService.ts b/src/vs/platform/quickinput/browser/quickInputService.ts index c36470d2a95..c2d178c4c46 100644 --- a/src/vs/platform/quickinput/browser/quickInputService.ts +++ b/src/vs/platform/quickinput/browser/quickInputService.ts @@ -21,7 +21,6 @@ import { IThemeService, Themable } from 'vs/platform/theme/common/themeService'; import { IQuickInputOptions, IQuickInputStyles, QuickInputHoverDelegate } from './quickInput'; import { QuickInputController, IQuickInputControllerHost } from 'vs/platform/quickinput/browser/quickInputController'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; import { getWindow } from 'vs/base/browser/dom'; export class QuickInputService extends Themable implements IQuickInputService { @@ -64,7 +63,6 @@ export class QuickInputService extends Themable implements IQuickInputService { @IThemeService themeService: IThemeService, @ILayoutService protected readonly layoutService: ILayoutService, @IConfigurationService protected readonly configurationService: IConfigurationService, - @IHoverService private readonly hoverService: IHoverService ) { super(themeService); } @@ -92,7 +90,7 @@ export class QuickInputService extends Themable implements IQuickInputService { options: IWorkbenchListOptions ) => this.instantiationService.createInstance(WorkbenchList, user, container, delegate, renderers, options) as List, styles: this.computeStyles(), - hoverDelegate: new QuickInputHoverDelegate(this.configurationService, this.hoverService) + hoverDelegate: this.instantiationService.createInstance(QuickInputHoverDelegate) }; const controller = this._register(new QuickInputController({ diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index ab28dbb003b..59eba8e11ff 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -17,6 +17,7 @@ import { assertIsDefined } from 'vs/base/common/types'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; import { MenuId } from 'vs/platform/actions/common/actions'; import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; /** * Composites are layed out in the sidebar and panel part of the workbench. At a time only one composite @@ -204,7 +205,7 @@ export abstract class Composite extends Component implements IComposite { * of an action. Returns undefined to indicate that the action is not rendered through * an action item. */ - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionViewItem(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { return undefined; } diff --git a/src/vs/workbench/browser/panecomposite.ts b/src/vs/workbench/browser/panecomposite.ts index b829c9f3d77..89e701e2d0b 100644 --- a/src/vs/workbench/browser/panecomposite.ts +++ b/src/vs/workbench/browser/panecomposite.ts @@ -22,6 +22,7 @@ import { IView } from 'vs/workbench/common/views'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { VIEWPANE_FILTER_ACTION } from 'vs/workbench/browser/parts/views/viewPane'; import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export abstract class PaneComposite extends Composite implements IPaneComposite { @@ -140,8 +141,8 @@ export abstract class PaneComposite extends Composite implements IPaneComposite return menuActions.length ? menuActions : viewPaneActions; } - override getActionViewItem(action: IAction): IActionViewItem | undefined { - return this.viewPaneContainer?.getActionViewItem(action); + override getActionViewItem(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { + return this.viewPaneContainer?.getActionViewItem(action, options); } override getTitle(): string { diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index de055f7b032..b4d406a6364 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -32,6 +32,9 @@ import { AbstractProgressScope, ScopedProgressIndicator } from 'vs/workbench/ser import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; import { defaultProgressBarStyles } from 'vs/platform/theme/browser/defaultStyles'; import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export interface ICompositeTitleLabel { @@ -59,6 +62,7 @@ export abstract class CompositePart extends Part { protected toolBar: WorkbenchToolBar | undefined; protected titleLabelElement: HTMLElement | undefined; + protected readonly hoverDelegate: IHoverDelegate; private readonly mapCompositeToCompositeContainer = new Map(); private readonly mapActionsBindingToComposite = new Map void>(); @@ -92,6 +96,7 @@ export abstract class CompositePart extends Part { super(id, options, themeService, storageService, layoutService); this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId); + this.hoverDelegate = this._register(getDefaultHoverDelegate('element', true)); } protected openComposite(id: string, focus?: boolean): Composite | undefined { @@ -396,12 +401,13 @@ export abstract class CompositePart extends Part { // Toolbar this.toolBar = this._register(this.instantiationService.createInstance(WorkbenchToolBar, titleActionsContainer, { - actionViewItemProvider: action => this.actionViewItemProvider(action), + actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options), orientation: ActionsOrientation.HORIZONTAL, getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), toggleMenuTitle: localize('viewsAndMoreActions', "Views and More Actions..."), - telemetrySource: this.nameForTelemetry + telemetrySource: this.nameForTelemetry, + hoverDelegate: this.hoverDelegate })); this.collectCompositeActions()(); @@ -438,14 +444,14 @@ export abstract class CompositePart extends Part { titleLabel.updateStyles(); } - protected actionViewItemProvider(action: IAction): IActionViewItem | undefined { + protected actionViewItemProvider(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { // Check Active Composite if (this.activeComposite) { - return this.activeComposite.getActionViewItem(action); + return this.activeComposite.getActionViewItem(action, options); } - return createActionViewItem(this.instantiationService, action); + return createActionViewItem(this.instantiationService, action, options); } protected actionsContextProvider(): unknown { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index b8b74e5aec1..2c88a644bd5 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -41,7 +41,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { defaultBreadcrumbsWidgetStyles } from 'vs/platform/theme/browser/defaultStyles'; import { Emitter } from 'vs/base/common/event'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { IHoverOptions, IHoverService } from 'vs/platform/hover/browser/hover'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; class OutlineItem extends BreadcrumbsItem { @@ -207,7 +207,7 @@ export class BreadcrumbsControl { @ILabelService private readonly _labelService: ILabelService, @IConfigurationService configurationService: IConfigurationService, @IBreadcrumbsService breadcrumbsService: IBreadcrumbsService, - @IHoverService private readonly hoverService: IHoverService + @IInstantiationService instantiationService: IInstantiationService, ) { this.domNode = document.createElement('div'); this.domNode.classList.add('breadcrumbs-control'); @@ -230,17 +230,7 @@ export class BreadcrumbsControl { this._ckBreadcrumbsVisible = BreadcrumbsControl.CK_BreadcrumbsVisible.bindTo(this._contextKeyService); this._ckBreadcrumbsActive = BreadcrumbsControl.CK_BreadcrumbsActive.bindTo(this._contextKeyService); - this._hoverDelegate = { - delay: 500, - showHover: (options: IHoverOptions) => { - return this.hoverService.showHover({ - ...options, - persistence: { - hideOnHover: true - } - }); - } - }; + this._hoverDelegate = getDefaultHoverDelegate('element'); this._disposables.add(breadcrumbsService.register(this._editorGroup.id, this._widget)); this.hide(); diff --git a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts index 651a9b3ff16..782ad9b007d 100644 --- a/src/vs/workbench/browser/parts/editor/editorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorTabsControl.ts @@ -45,7 +45,8 @@ 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 { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export class EditorCommandsContextActionRunner extends ActionRunner { @@ -123,6 +124,8 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC private renderDropdownAsChildElement: boolean; + private readonly tabsHoverDelegate: IHoverDelegate; + constructor( protected readonly parent: HTMLElement, protected readonly editorPartsView: IEditorPartsView, @@ -138,7 +141,6 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC @IThemeService themeService: IThemeService, @IEditorResolverService private readonly editorResolverService: IEditorResolverService, @IHostService private readonly hostService: IHostService, - @IHoverService private readonly hoverService: IHoverService ) { super(themeService); @@ -162,6 +164,8 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC this.renderDropdownAsChildElement = false; + this.tabsHoverDelegate = getDefaultHoverDelegate('element'); + this.create(parent); } @@ -205,7 +209,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC // Toolbar Widget this.editorActionsToolbar = this.editorActionsToolbarDisposables.add(this.instantiationService.createInstance(WorkbenchToolBar, container, { - actionViewItemProvider: action => this.actionViewItemProvider(action), + actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options), orientation: ActionsOrientation.HORIZONTAL, ariaLabel: localize('ariaLabelEditorActions', "Editor actions"), getKeyBinding: action => this.getKeybinding(action), @@ -231,12 +235,12 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC })); } - private actionViewItemProvider(action: IAction): IActionViewItem | undefined { + private actionViewItemProvider(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { const activeEditorPane = this.groupView.activeEditorPane; // Check Active Editor if (activeEditorPane instanceof EditorPane) { - const result = activeEditorPane.getActionViewItem(action); + const result = activeEditorPane.getActionViewItem(action, options); if (result) { return result; @@ -244,7 +248,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC } // Check extensions - return createActionViewItem(this.instantiationService, action, { menuAsChild: this.renderDropdownAsChildElement }); + return createActionViewItem(this.instantiationService, action, { ...options, menuAsChild: this.renderDropdownAsChildElement }); } protected updateEditorActionsToolbar(): void { @@ -452,17 +456,7 @@ export abstract class EditorTabsControl extends Themable implements IEditorTabsC } protected getHoverDelegate(): IHoverDelegate { - return { - delay: 500, - showHover: options => { - return this.hoverService.showHover({ - ...options, - persistence: { - hideOnHover: true - } - }); - } - }; + return this.tabsHoverDelegate; } protected updateTabHeight(): void { diff --git a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts index 2f613acd93f..0043df4e615 100644 --- a/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts +++ b/src/vs/workbench/browser/parts/editor/multiEditorTabsControl.ts @@ -56,8 +56,6 @@ 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; @@ -152,10 +150,8 @@ export class MultiEditorTabsControl extends EditorTabsControl { @ITreeViewsDnDService private readonly treeViewsDragAndDropService: ITreeViewsDnDService, @IEditorResolverService editorResolverService: IEditorResolverService, @IHostService hostService: IHostService, - @IDecorationsService decorationsService: IDecorationsService, - @IHoverService hoverService: IHoverService, ) { - super(parent, editorPartsView, groupsView, groupView, tabsModel, contextMenuService, instantiationService, contextKeyService, keybindingService, notificationService, quickInputService, themeService, editorResolverService, hostService, hoverService); + super(parent, editorPartsView, groupsView, groupView, tabsModel, contextMenuService, instantiationService, contextKeyService, keybindingService, notificationService, quickInputService, themeService, editorResolverService, hostService); // Resolve the correct path library for the OS we are on // If we are connected to remote, this accounts for the diff --git a/src/vs/workbench/browser/parts/globalCompositeBar.ts b/src/vs/workbench/browser/parts/globalCompositeBar.ts index 263ef8d9616..550866d685b 100644 --- a/src/vs/workbench/browser/parts/globalCompositeBar.ts +++ b/src/vs/workbench/browser/parts/globalCompositeBar.ts @@ -42,6 +42,7 @@ import { DEFAULT_ICON } from 'vs/workbench/services/userDataProfile/common/userD import { isString } from 'vs/base/common/types'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND } from 'vs/workbench/common/theme'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export class GlobalCompositeBar extends Disposable { @@ -612,6 +613,7 @@ export class SimpleAccountActivityActionViewItem extends AccountsActivityActionV constructor( hoverOptions: IActivityHoverOptions, + options: IBaseActionViewItemOptions, @IThemeService themeService: IThemeService, @ILifecycleService lifecycleService: ILifecycleService, @IHoverService hoverService: IHoverService, @@ -629,6 +631,7 @@ export class SimpleAccountActivityActionViewItem extends AccountsActivityActionV @IInstantiationService instantiationService: IInstantiationService ) { super(() => [], { + ...options, colors: theme => ({ badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), @@ -643,6 +646,7 @@ export class SimpleGlobalActivityActionViewItem extends GlobalActivityActionView constructor( hoverOptions: IActivityHoverOptions, + options: IBaseActionViewItemOptions, @IUserDataProfileService userDataProfileService: IUserDataProfileService, @IThemeService themeService: IThemeService, @IHoverService hoverService: IHoverService, @@ -656,6 +660,7 @@ export class SimpleGlobalActivityActionViewItem extends GlobalActivityActionView @IActivityService activityService: IActivityService, ) { super(() => [], { + ...options, colors: theme => ({ badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND), badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND), diff --git a/src/vs/workbench/browser/parts/paneCompositePart.ts b/src/vs/workbench/browser/parts/paneCompositePart.ts index ebee8aa4b42..82d20fd9666 100644 --- a/src/vs/workbench/browser/parts/paneCompositePart.ts +++ b/src/vs/workbench/browser/parts/paneCompositePart.ts @@ -302,11 +302,12 @@ export abstract class AbstractPaneCompositePart extends CompositePart this.actionViewItemProvider(action), + actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options), orientation: ActionsOrientation.HORIZONTAL, getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment(), - toggleMenuTitle: localize('moreActions', "More Actions...") + toggleMenuTitle: localize('moreActions', "More Actions..."), + hoverDelegate: this.hoverDelegate })); this.updateGlobalToolbarActions(); @@ -503,7 +504,7 @@ export abstract class AbstractPaneCompositePart extends CompositePart event, getActions: () => activePaneCompositeActions, - getActionViewItem: action => this.actionViewItemProvider(action), + getActionViewItem: (action, options) => this.actionViewItemProvider(action, options), actionRunner: activePaneComposite.getActionRunner(), skipTelemetry: true }); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 940b074561a..e8a133fd4b4 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -27,9 +27,7 @@ import { assertIsDefined } from 'vs/base/common/types'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { isHighContrast } from 'vs/platform/theme/common/theme'; import { hash } from 'vs/base/common/hash'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IHoverDelegate, IHoverDelegateOptions, IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover'; import { HideStatusbarEntryAction, ToggleStatusbarEntryVisibilityAction } from 'vs/workbench/browser/parts/statusbar/statusbarActions'; import { IStatusbarViewModelEntry, StatusbarViewModel } from 'vs/workbench/browser/parts/statusbar/statusbarModel'; import { StatusbarEntryItem } from 'vs/workbench/browser/parts/statusbar/statusbarItem'; @@ -138,39 +136,8 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { private leftItemsContainer: HTMLElement | undefined; private rightItemsContainer: HTMLElement | undefined; - private readonly hoverDelegate = new class implements IHoverDelegate { - private lastHoverHideTime = 0; - - readonly placement = 'element'; - - get delay() { - if (Date.now() - this.lastHoverHideTime < 200) { - return 0; // show instantly when a hover was recently shown - } - - return this.configurationService.getValue('workbench.hover.delay'); - } - - constructor( - private readonly configurationService: IConfigurationService, - private readonly hoverService: IHoverService - ) { } - - showHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined { - return this.hoverService.showHover({ - ...options, - persistence: { - hideOnKeyDown: true, - sticky: focus - } - }, focus); - } - - onDidHideHover(): void { - this.lastHoverHideTime = Date.now(); - } - }(this.configurationService, this.hoverService); + private readonly hoverDelegate: WorkbenchHoverDelegate; private readonly compactEntriesDisposable = this._register(new MutableDisposable()); private readonly styleOverrides = new Set(); @@ -184,11 +151,18 @@ class StatusbarPart extends Part implements IStatusbarEntryContainer { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextMenuService private contextMenuService: IContextMenuService, @IContextKeyService private readonly contextKeyService: IContextKeyService, - @IHoverService private readonly hoverService: IHoverService, - @IConfigurationService private readonly configurationService: IConfigurationService ) { super(id, { hasTitle: false }, themeService, storageService, layoutService); + this.hoverDelegate = this._register(instantiationService.createInstance(WorkbenchHoverDelegate, 'element', true, (_, focus?: boolean) => ( + { + persistence: { + hideOnKeyDown: true, + sticky: focus + } + } + ))); + this.registerListeners(); } @@ -667,10 +641,8 @@ export class MainStatusbarPart extends StatusbarPart { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextMenuService contextMenuService: IContextMenuService, @IContextKeyService contextKeyService: IContextKeyService, - @IHoverService hoverService: IHoverService, - @IConfigurationService configurationService: IConfigurationService ) { - super(Parts.STATUSBAR_PART, instantiationService, themeService, contextService, storageService, layoutService, contextMenuService, contextKeyService, hoverService, configurationService); + super(Parts.STATUSBAR_PART, instantiationService, themeService, contextService, storageService, layoutService, contextMenuService, contextKeyService); } } @@ -694,11 +666,9 @@ export class AuxiliaryStatusbarPart extends StatusbarPart implements IAuxiliaryS @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextMenuService contextMenuService: IContextMenuService, @IContextKeyService contextKeyService: IContextKeyService, - @IHoverService hoverService: IHoverService, - @IConfigurationService configurationService: IConfigurationService ) { const id = AuxiliaryStatusbarPart.COUNTER++; - super(`workbench.parts.auxiliaryStatus.${id}`, instantiationService, themeService, contextService, storageService, layoutService, contextMenuService, contextKeyService, hoverService, configurationService); + super(`workbench.parts.auxiliaryStatus.${id}`, instantiationService, themeService, contextService, storageService, layoutService, contextMenuService, contextKeyService); } } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index cbe98d2e852..05ad43933f8 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -33,8 +33,6 @@ import { Codicon } from 'vs/base/common/codicons'; import { getIconRegistry } from 'vs/platform/theme/common/iconRegistry'; import { WindowTitle } from 'vs/workbench/browser/parts/titlebar/windowTitle'; import { CommandCenterControl } from 'vs/workbench/browser/parts/titlebar/commandCenterControl'; -import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; import { Categories } from 'vs/platform/action/common/actionCommonCategories'; import { WorkbenchToolBar } from 'vs/platform/actions/browser/toolbar'; import { ACCOUNTS_ACTIVITY_ID, GLOBAL_ACTIVITY_ID } from 'vs/workbench/common/activity'; @@ -54,6 +52,9 @@ import { IEditorCommandsContext, IEditorPartOptionsChangeEvent, IToolbarActions import { mainWindow } from 'vs/base/browser/window'; import { ACCOUNTS_ACTIVITY_TILE_ACTION, GLOBAL_ACTIVITY_TITLE_ACTION } from 'vs/workbench/browser/parts/titlebar/titlebarActions'; import { IView } from 'vs/base/browser/ui/grid/grid'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; export interface ITitleVariable { readonly name: string; @@ -191,28 +192,6 @@ export class BrowserTitleService extends MultiWindowParts i //#endregion } -class TitlebarPartHoverDelegate implements IHoverDelegate { - - readonly showHover = this.hoverService.showHover.bind(this.hoverService); - readonly placement = 'element'; - - private lastHoverHideTime: number = 0; - get delay(): number { - return Date.now() - this.lastHoverHideTime < 200 - ? 0 // show instantly when a hover was recently shown - : this.configurationService.getValue('workbench.hover.delay'); - } - - constructor( - @IHoverService private readonly hoverService: IHoverService, - @IConfigurationService private readonly configurationService: IConfigurationService - ) { } - - onDidHideHover() { - this.lastHoverHideTime = Date.now(); - } -} - export class BrowserTitlebarPart extends Part implements ITitlebarPart { //#region IView @@ -264,7 +243,7 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { private readonly editorToolbarMenuDisposables = this._register(new DisposableStore()); private readonly layoutToolbarMenuDisposables = this._register(new DisposableStore()); - private readonly hoverDelegate = new TitlebarPartHoverDelegate(this.hoverService, this.configurationService); + private readonly hoverDelegate: IHoverDelegate; private readonly titleDisposables = this._register(new DisposableStore()); private titleBarStyle: TitlebarStyle = getTitleBarStyle(this.configurationService); @@ -290,7 +269,6 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextKeyService private readonly contextKeyService: IContextKeyService, @IHostService private readonly hostService: IHostService, - @IHoverService private readonly hoverService: IHoverService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService private readonly menuService: IMenuService, @@ -304,6 +282,8 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { this.windowTitle = this._register(instantiationService.createInstance(WindowTitle, targetWindow, editorGroupsContainer)); + this.hoverDelegate = this._register(getDefaultHoverDelegate('element', true)); + this.registerListeners(getWindowId(targetWindow)); } @@ -537,22 +517,22 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { } } - private actionViewItemProvider(action: IAction): IActionViewItem | undefined { + private actionViewItemProvider(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { // --- Activity Actions if (!this.isAuxiliary) { if (action.id === GLOBAL_ACTIVITY_ID) { - return this.instantiationService.createInstance(SimpleGlobalActivityActionViewItem, { position: () => HoverPosition.BELOW }); + return this.instantiationService.createInstance(SimpleGlobalActivityActionViewItem, { position: () => HoverPosition.BELOW }, options); } if (action.id === ACCOUNTS_ACTIVITY_ID) { - return this.instantiationService.createInstance(SimpleAccountActivityActionViewItem, { position: () => HoverPosition.BELOW }); + return this.instantiationService.createInstance(SimpleAccountActivityActionViewItem, { position: () => HoverPosition.BELOW }, options); } } // --- Editor Actions const activeEditorPane = this.editorGroupsContainer.activeGroup?.activeEditorPane; if (activeEditorPane && activeEditorPane instanceof EditorPane) { - const result = activeEditorPane.getActionViewItem(action); + const result = activeEditorPane.getActionViewItem(action, { hoverDelegate: this.hoverDelegate }); if (result) { return result; @@ -560,7 +540,7 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { } // Check extensions - return createActionViewItem(this.instantiationService, action, { hoverDelegate: this.hoverDelegate, menuAsChild: false }); + return createActionViewItem(this.instantiationService, action, { ...options, hoverDelegate: this.hoverDelegate, menuAsChild: false }); } private getKeybinding(action: IAction): ResolvedKeybinding | undefined { @@ -585,7 +565,7 @@ export class BrowserTitlebarPart extends Part implements ITitlebarPart { anchorAlignmentProvider: () => AnchorAlignment.RIGHT, telemetrySource: 'titlePart', highlightToggledItems: this.editorActionsEnabled, // Only show toggled state for editor actions (Layout actions are not shown as toggled) - actionViewItemProvider: action => this.actionViewItemProvider(action) + actionViewItemProvider: (action, options) => this.actionViewItemProvider(action, options) })); if (this.editorActionsEnabled) { @@ -820,13 +800,12 @@ export class MainBrowserTitlebarPart extends BrowserTitlebarPart { @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, - @IHoverService hoverService: IHoverService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService menuService: IMenuService, @IKeybindingService keybindingService: IKeybindingService, ) { - super(Parts.TITLEBAR_PART, mainWindow, 'main', contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, hoverService, editorGroupService, editorService, menuService, keybindingService); + super(Parts.TITLEBAR_PART, mainWindow, 'main', contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, editorGroupService, editorService, menuService, keybindingService); } } @@ -854,14 +833,13 @@ export class AuxiliaryBrowserTitlebarPart extends BrowserTitlebarPart implements @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, - @IHoverService hoverService: IHoverService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService menuService: IMenuService, @IKeybindingService keybindingService: IKeybindingService, ) { const id = AuxiliaryBrowserTitlebarPart.COUNTER++; - super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, hoverService, editorGroupService, editorService, menuService, keybindingService); + super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, editorGroupService, editorService, menuService, keybindingService); } override get preventZoom(): boolean { diff --git a/src/vs/workbench/browser/parts/views/treeView.ts b/src/vs/workbench/browser/parts/views/treeView.ts index 19bfe50a6e2..d142226edb7 100644 --- a/src/vs/workbench/browser/parts/views/treeView.ts +++ b/src/vs/workbench/browser/parts/views/treeView.ts @@ -8,7 +8,7 @@ import * as DOM from 'vs/base/browser/dom'; import { renderMarkdownAsPlaintext } from 'vs/base/browser/markdownRenderer'; import { ActionBar, IActionViewItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; -import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { ITooltipMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabelHover'; import { IIdentityProvider, IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { ElementsDragAndDropData, ListViewTargetSector } from 'vs/base/browser/ui/list/listView'; @@ -73,6 +73,7 @@ import { TelemetryTrustedValue } from 'vs/platform/telemetry/common/telemetryUti import { ITreeViewsDnDService } from 'vs/editor/common/services/treeViewsDndService'; import { DraggedTreeItemsIdentifier } from 'vs/editor/common/services/treeViewsDnd'; import { IMarkdownRenderResult, MarkdownRenderer } from 'vs/editor/browser/widget/markdownRenderer/browser/markdownRenderer'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export class TreeViewPane extends ViewPane { @@ -1106,15 +1107,11 @@ class TreeRenderer extends Disposable implements ITreeRenderer this.hoverService.showHover(options), - delay: this.configurationService.getValue('workbench.hover.delay') - }; + this._hoverDelegate = getDefaultHoverDelegate('mouse'); this._register(this.themeService.onDidFileIconThemeChange(() => this.rerender())); this._register(this.themeService.onDidColorThemeChange(() => this.rerender())); this._register(checkboxStateHandler.onDidChangeCheckboxState(items => { diff --git a/src/vs/workbench/browser/parts/views/viewPane.ts b/src/vs/workbench/browser/parts/views/viewPane.ts index aa66323770b..978baf437cd 100644 --- a/src/vs/workbench/browser/parts/views/viewPane.ts +++ b/src/vs/workbench/browser/parts/views/viewPane.ts @@ -432,7 +432,7 @@ export abstract class ViewPane extends Pane implements IView { actions.classList.toggle('show-expanded', this.showActions === ViewPaneShowActions.WhenExpanded); this.toolbar = this.instantiationService.createInstance(WorkbenchToolBar, actions, { orientation: ActionsOrientation.HORIZONTAL, - actionViewItemProvider: action => this.getActionViewItem(action), + actionViewItemProvider: (action, options) => this.getActionViewItem(action, options), ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title), getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id), renderDropdownAsChildElement: true, diff --git a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts index 1c7201e246b..f575fa95242 100644 --- a/src/vs/workbench/browser/parts/views/viewPaneContainer.ts +++ b/src/vs/workbench/browser/parts/views/viewPaneContainer.ts @@ -40,6 +40,7 @@ import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; import { FocusedViewContext } from 'vs/workbench/common/contextkeys'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { ActivityBarPosition, IWorkbenchLayoutService, LayoutSettings, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export const ViewsSubMenu = new MenuId('Views'); MenuRegistry.appendMenuItem(MenuId.ViewContainerTitle, { @@ -590,11 +591,11 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer { return undefined; } - getActionViewItem(action: IAction): IActionViewItem | undefined { + getActionViewItem(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { if (this.isViewMergedWithContainer()) { - return this.paneItems[0].pane.getActionViewItem(action); + return this.paneItems[0].pane.getActionViewItem(action, options); } - return createActionViewItem(this.instantiationService, action); + return createActionViewItem(this.instantiationService, action, options); } focus(): void { diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 9ac40779c6e..8a311d4bb0e 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -43,6 +43,8 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { mainWindow } from 'vs/base/browser/window'; import { PixelRatio } from 'vs/base/browser/pixelRatio'; +import { WorkbenchHoverDelegate } from 'vs/platform/hover/browser/hover'; +import { setHoverDelegateFactory } from 'vs/base/browser/ui/hover/hoverDelegate'; export interface IWorkbenchOptions { @@ -152,6 +154,10 @@ export class Workbench extends Layout { const dialogService = accessor.get(IDialogService); const notificationService = accessor.get(INotificationService) as NotificationService; + // Default Hover Delegate must be registered before creating any workbench/layout components + // as these possibly will use the default hover delegate + setHoverDelegateFactory((placement, enableInstantHover) => instantiationService.createInstance(WorkbenchHoverDelegate, placement, enableInstantHover, {})); + // Layout this.initLayout(accessor); diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts index 10c5c92bd46..557d9a025ec 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsOutline.ts @@ -144,7 +144,7 @@ class DocumentSymbolsOutline implements IOutline { this._breadcrumbsDataSource = new DocumentSymbolBreadcrumbsSource(_editor, textResourceConfigurationService); const delegate = new DocumentSymbolVirtualDelegate(); - const renderers = [new DocumentSymbolGroupRenderer(), instantiationService.createInstance(DocumentSymbolRenderer, true)]; + const renderers = [new DocumentSymbolGroupRenderer(), instantiationService.createInstance(DocumentSymbolRenderer, true, target)]; const treeDataSource: IDataSource = { getChildren: (parent) => { if (parent instanceof OutlineElement || parent instanceof OutlineGroup) { diff --git a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts index 8434fa5acf3..450c690d6a8 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/outline/documentSymbolsTree.ts @@ -21,11 +21,11 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { listErrorForeground, listWarningForeground } from 'vs/platform/theme/common/colorRegistry'; import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfiguration'; import { IListAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; -import { IOutlineComparator, OutlineConfigKeys } from 'vs/workbench/services/outline/browser/outline'; +import { IOutlineComparator, OutlineConfigKeys, OutlineTarget } from 'vs/workbench/services/outline/browser/outline'; import { ThemeIcon } from 'vs/base/common/themables'; import { mainWindow } from 'vs/base/browser/window'; import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { IHoverOptions, IHoverService } from 'vs/platform/hover/browser/hover'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export type DocumentSymbolItem = OutlineGroup | OutlineElement; @@ -121,21 +121,11 @@ export class DocumentSymbolRenderer implements ITreeRenderer { - return hoverService.showHover({ - ...options, - persistence: { - hideOnHover: true - } - }); - } - }; + this._hoverDelegate = getDefaultHoverDelegate(target === OutlineTarget.Breadcrumbs ? 'element' : 'mouse'); } renderTemplate(container: HTMLElement): DocumentSymbolTemplate { diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index c930fbdf0e2..4145d4ae91a 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -541,10 +541,10 @@ class SessionsRenderer implements ICompressibleTreeRenderer { + actionViewItemProvider: (action, options) => { if ((action.id === STOP_ID || action.id === DISCONNECT_ID) && action instanceof MenuItemAction) { stopActionViewItemDisposables.clear(); - const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, stopActionViewItemDisposables, accessor)); + const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, stopActionViewItemDisposables, accessor, options)); if (item) { return item; } diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index db14887850c..433a562e4bf 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -18,7 +18,7 @@ import { IContextViewService } from 'vs/platform/contextview/browser/contextView import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ADD_CONFIGURATION_ID } from 'vs/workbench/contrib/debug/browser/debugCommands'; -import { BaseActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { BaseActionViewItem, IBaseActionViewItemOptions, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { debugStart } from 'vs/workbench/contrib/debug/browser/debugIcons'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { defaultSelectBoxStyles } from 'vs/platform/theme/browser/defaultStyles'; @@ -40,6 +40,7 @@ export class StartDebugActionViewItem extends BaseActionViewItem { constructor( private context: unknown, action: IAction, + options: IBaseActionViewItemOptions, @IDebugService private readonly debugService: IDebugService, @IConfigurationService private readonly configurationService: IConfigurationService, @ICommandService private readonly commandService: ICommandService, @@ -47,7 +48,7 @@ export class StartDebugActionViewItem extends BaseActionViewItem { @IContextViewService contextViewService: IContextViewService, @IKeybindingService private readonly keybindingService: IKeybindingService ) { - super(context, action); + super(context, action, options); this.toDispose = []; this.selectBox = new SelectBox([], -1, contextViewService, defaultSelectBoxStyles, { ariaLabel: nls.localize('debugLaunchConfigurations', 'Debug Launch Configurations') }); this.selectBox.setFocusable(false); diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index c46cd2d9a6f..0b9fb05501d 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -16,7 +16,7 @@ import 'vs/css!./media/debugToolBar'; import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { localize } from 'vs/nls'; import { ICommandAction, ICommandActionTitle } from 'vs/platform/action/common/action'; -import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; +import { DropdownWithPrimaryActionViewItem, IDropdownWithPrimaryActionViewItemOptions } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem'; import { createActionViewItem, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IMenu, IMenuService, MenuId, MenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -40,6 +40,7 @@ import { Codicon } from 'vs/base/common/codicons'; import { CodeWindow, mainWindow } from 'vs/base/browser/window'; import { clamp } from 'vs/base/common/numbers'; import { PixelRatio } from 'vs/base/browser/pixelRatio'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; const DEBUG_TOOLBAR_POSITION_KEY = 'debug.actionswidgetposition'; const DEBUG_TOOLBAR_Y_KEY = 'debug.actionswidgety'; @@ -89,18 +90,18 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { this.activeActions = []; this.actionBar = this._register(new ActionBar(actionBarContainer, { orientation: ActionsOrientation.HORIZONTAL, - actionViewItemProvider: (action: IAction) => { + actionViewItemProvider: (action: IAction, options: IBaseActionViewItemOptions) => { if (action.id === FOCUS_SESSION_ID) { return this.instantiationService.createInstance(FocusSessionActionViewItem, action, undefined); } else if (action.id === STOP_ID || action.id === DISCONNECT_ID) { this.stopActionViewItemDisposables.clear(); - const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, this.stopActionViewItemDisposables, accessor)); + const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, this.stopActionViewItemDisposables, accessor, { hoverDelegate: options.hoverDelegate })); if (item) { return item; } } - return createActionViewItem(this.instantiationService, action); + return createActionViewItem(this.instantiationService, action, options); } })); @@ -337,7 +338,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { } } -export function createDisconnectMenuItemAction(action: MenuItemAction, disposables: DisposableStore, accessor: ServicesAccessor): IActionViewItem | undefined { +export function createDisconnectMenuItemAction(action: MenuItemAction, disposables: DisposableStore, accessor: ServicesAccessor, options: IDropdownWithPrimaryActionViewItemOptions): IActionViewItem | undefined { const menuService = accessor.get(IMenuService); const contextKeyService = accessor.get(IContextKeyService); const instantiationService = accessor.get(IInstantiationService); @@ -358,7 +359,7 @@ export function createDisconnectMenuItemAction(action: MenuItemAction, disposabl secondary, 'debug-stop-actions', contextMenuService, - {}); + options); return item; } diff --git a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts index 24c202b7c34..6a51b8f273a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts @@ -33,6 +33,7 @@ import { WelcomeView } from 'vs/workbench/contrib/debug/browser/welcomeView'; import { BREAKPOINTS_VIEW_ID, CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE, CONTEXT_DEBUG_UX, CONTEXT_DEBUG_UX_KEY, getStateLabel, IDebugService, ILaunch, REPL_VIEW_ID, State, VIEWLET_ID } from 'vs/workbench/contrib/debug/common/debug'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export class DebugViewPaneContainer extends ViewPaneContainer { @@ -93,9 +94,9 @@ export class DebugViewPaneContainer extends ViewPaneContainer { } } - override getActionViewItem(action: IAction): IActionViewItem | undefined { + override getActionViewItem(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { if (action.id === DEBUG_START_COMMAND_ID) { - this.startDebugActionViewItem = this.instantiationService.createInstance(StartDebugActionViewItem, null, action); + this.startDebugActionViewItem = this.instantiationService.createInstance(StartDebugActionViewItem, null, action, options); return this.startDebugActionViewItem; } if (action.id === FOCUS_SESSION_ID) { @@ -104,13 +105,13 @@ export class DebugViewPaneContainer extends ViewPaneContainer { if (action.id === STOP_ID || action.id === DISCONNECT_ID) { this.stopActionViewItemDisposables.clear(); - const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, this.stopActionViewItemDisposables, accessor)); + const item = this.instantiationService.invokeFunction(accessor => createDisconnectMenuItemAction(action as MenuItemAction, this.stopActionViewItemDisposables, accessor, { hoverDelegate: options.hoverDelegate })); if (item) { return item; } } - return createActionViewItem(this.instantiationService, action); + return createActionViewItem(this.instantiationService, action, options); } focusView(id: string): void { diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 53819a2eb53..38c0e666af1 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -590,7 +590,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE toolbarOptions: { primaryGroup: () => true, }, - actionViewItemProvider: action => createActionViewItem(this.instantiationService, action) + actionViewItemProvider: (action, options) => createActionViewItem(this.instantiationService, action, options) })); // Register DragAndDrop support diff --git a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts index ffd76aca945..f9c766ca849 100644 --- a/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts +++ b/src/vs/workbench/contrib/interactive/browser/interactiveEditor.ts @@ -201,8 +201,8 @@ export class InteractiveEditor extends EditorPane { const menu = this._register(this._menuService.createMenu(MenuId.InteractiveInputExecute, this._contextKeyService)); this._runbuttonToolbar = this._register(new ToolBar(runButtonContainer, this._contextMenuService, { getKeyBinding: action => this._keybindingService.lookupKeybinding(action.id), - actionViewItemProvider: action => { - return createActionViewItem(this._instantiationService, action); + actionViewItemProvider: (action, options) => { + return createActionViewItem(this._instantiationService, action, options); }, renderDropdownAsChildElement: true })); diff --git a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts index 3a38688600a..a7b79d85684 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/cellParts/cellToolbars.ts @@ -167,8 +167,8 @@ export class CellTitleToolbarPart extends CellOverlayPart { } const toolbar = this._register(this.instantiationService.createInstance(WorkbenchToolBar, this.toolbarContainer, { - actionViewItemProvider: action => { - return createActionViewItem(this.instantiationService, action); + actionViewItemProvider: (action, options) => { + return createActionViewItem(this.instantiationService, action, options); }, renderDropdownAsChildElement: true })); @@ -275,8 +275,8 @@ function createDeleteToolbar(accessor: ServicesAccessor, container: HTMLElement, const instantiationService = accessor.get(IInstantiationService); const toolbar = new ToolBar(container, contextMenuService, { getKeyBinding: action => keybindingService.lookupKeybinding(action.id), - actionViewItemProvider: action => { - return createActionViewItem(instantiationService, action); + actionViewItemProvider: (action, options) => { + return createActionViewItem(instantiationService, action, options); }, renderDropdownAsChildElement: true }); diff --git a/src/vs/workbench/contrib/remote/browser/tunnelView.ts b/src/vs/workbench/contrib/remote/browser/tunnelView.ts index 0753f9429c5..3559f22390e 100644 --- a/src/vs/workbench/contrib/remote/browser/tunnelView.ts +++ b/src/vs/workbench/contrib/remote/browser/tunnelView.ts @@ -51,12 +51,12 @@ import { WorkbenchTable } from 'vs/platform/list/browser/listService'; import { Button } from 'vs/base/browser/ui/button/button'; import { registerColor } from 'vs/platform/theme/common/colorRegistry'; import { IMarkdownString, MarkdownString } from 'vs/base/common/htmlContent'; -import { IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { STATUS_BAR_REMOTE_ITEM_BACKGROUND } from 'vs/workbench/common/theme'; import { Codicon } from 'vs/base/common/codicons'; import { defaultButtonStyles, defaultInputBoxStyles } from 'vs/platform/theme/browser/defaultStyles'; import { Attributes, CandidatePort, Tunnel, TunnelCloseReason, TunnelModel, TunnelSource, forwardedPortsViewEnabled, makeAddress, mapHasAddressLocalhostOrAllInterfaces, parseAddress } from 'vs/workbench/services/remote/common/tunnelModel'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; export const openPreviewEnabledContext = new RawContextKey('openPreviewEnabled', false); @@ -342,6 +342,7 @@ class ActionBarRenderer extends Disposable implements ITableRenderer void; private _actionRunner: ActionRunner | undefined; + private readonly _hoverDelegate: IHoverDelegate; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -351,8 +352,11 @@ class ActionBarRenderer extends Disposable implements ITableRenderer this.hoverService.showHover(options), - delay: this.configurationService.getValue('workbench.hover.delay') - } + hoverDelegate: this._hoverDelegate }); const actionsContainer = dom.append(cell, dom.$('.actions')); const actionBar = new ActionBar(actionsContainer, { - actionViewItemProvider: createActionViewItem.bind(undefined, this.instantiationService) + actionViewItemProvider: createActionViewItem.bind(undefined, this.instantiationService), + hoverDelegate: this._hoverDelegate }); return { label, icon, actionBar, container: cell, elementDisposable: Disposable.None }; } @@ -781,7 +783,6 @@ export class TunnelPanel extends ViewPane { @ITelemetryService telemetryService: ITelemetryService, @ITunnelService private readonly tunnelService: ITunnelService, @IContextViewService private readonly contextViewService: IContextViewService, - @IHoverService private readonly hoverService: IHoverService ) { super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService); this.tunnelTypeContext = TunnelTypeContextKey.bindTo(contextKeyService); @@ -865,7 +866,7 @@ export class TunnelPanel extends ViewPane { const actionBarRenderer = new ActionBarRenderer(this.instantiationService, this.contextKeyService, this.menuService, this.contextViewService, this.remoteExplorerService, this.commandService, - this.configurationService, this.hoverService); + this.configurationService); const columns = [new IconColumn(), new PortColumn(), new LocalAddressColumn(), new RunningProcessColumn()]; if (this.tunnelService.canChangePrivacy) { columns.push(new PrivacyColumn()); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts index a42ecfd8374..ca7a033fdcd 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewPane.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewPane.ts @@ -2492,12 +2492,12 @@ class SCMInputWidget { // Toolbar this.toolbar = instantiationService2.createInstance(SCMInputWidgetToolbar, this.toolbarContainer, { - actionViewItemProvider: action => { + actionViewItemProvider: (action, options) => { if (action instanceof MenuItemAction && this.toolbar.dropdownActions.length > 1) { - return instantiationService.createInstance(DropdownWithPrimaryActionViewItem, action, this.toolbar.dropdownAction, this.toolbar.dropdownActions, '', this.contextMenuService, { actionRunner: this.toolbar.actionRunner }); + return instantiationService.createInstance(DropdownWithPrimaryActionViewItem, action, this.toolbar.dropdownAction, this.toolbar.dropdownActions, '', this.contextMenuService, { actionRunner: this.toolbar.actionRunner, hoverDelegate: options.hoverDelegate }); } - return createActionViewItem(instantiationService, action); + return createActionViewItem(instantiationService, action, options); }, menuOptions: { shouldForwardArgs: true diff --git a/src/vs/workbench/contrib/scm/browser/util.ts b/src/vs/workbench/contrib/scm/browser/util.ts index be5afbb292f..d44c36c332b 100644 --- a/src/vs/workbench/contrib/scm/browser/util.ts +++ b/src/vs/workbench/contrib/scm/browser/util.ts @@ -12,7 +12,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; import { Action, IAction } from 'vs/base/common/actions'; import { createActionViewItem, createAndFillInActionBarActions, createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { equals } from 'vs/base/common/arrays'; -import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { ActionViewItem, IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { Command } from 'vs/editor/common/languages'; @@ -149,8 +149,8 @@ export class StatusBarAction extends Action { class StatusBarActionViewItem extends ActionViewItem { - constructor(action: StatusBarAction) { - super(null, action, {}); + constructor(action: StatusBarAction, options: IBaseActionViewItemOptions) { + super(null, action, options); } protected override updateLabel(): void { @@ -161,11 +161,11 @@ class StatusBarActionViewItem extends ActionViewItem { } export function getActionViewItemProvider(instaService: IInstantiationService): IActionViewItemProvider { - return action => { + return (action, options) => { if (action instanceof StatusBarAction) { - return new StatusBarActionViewItem(action); + return new StatusBarActionViewItem(action, options); } - return createActionViewItem(instaService, action); + return createActionViewItem(instaService, action, options); }; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts index 63ae90748b4..6835b5e9c35 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalEditor.ts @@ -29,6 +29,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { openContextMenu } from 'vs/workbench/contrib/terminal/browser/terminalContextMenu'; import { ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; +import { IBaseActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionViewItems'; export class TerminalEditor extends EditorPane { @@ -203,18 +204,18 @@ export class TerminalEditor extends EditorPane { this._editorInput?.terminalInstance?.setVisible(visible && this._workbenchLayoutService.isVisible(Parts.EDITOR_PART, dom.getWindow(this._editorInstanceElement))); } - override getActionViewItem(action: IAction): IActionViewItem | undefined { + override getActionViewItem(action: IAction, options: IBaseActionViewItemOptions): IActionViewItem | undefined { switch (action.id) { case TerminalCommandId.CreateTerminalEditor: { if (action instanceof MenuItemAction) { const location = { viewColumn: ACTIVE_GROUP }; const actions = getTerminalActionBarArgs(location, this._terminalProfileService.availableProfiles, this._getDefaultProfileName(), this._terminalProfileService.contributedProfiles, this._terminalService, this._dropdownMenu); - const button = this._instantiationService.createInstance(DropdownWithPrimaryActionViewItem, action, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService, {}); + const button = this._instantiationService.createInstance(DropdownWithPrimaryActionViewItem, action, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService, { hoverDelegate: options.hoverDelegate }); return button; } } } - return super.getActionViewItem(action); + return super.getActionViewItem(action, options); } private _getDefaultProfileName(): string { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalView.ts b/src/vs/workbench/contrib/terminal/browser/terminalView.ts index c5d7591819e..31ed968488e 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalView.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalView.ts @@ -23,7 +23,7 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IMenu, IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions'; import { ITerminalProfileResolverService, ITerminalProfileService, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalSettingId, ITerminalProfile, TerminalLocation } from 'vs/platform/terminal/common/terminal'; -import { ActionViewItem, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; +import { ActionViewItem, IBaseActionViewItemOptions, SelectActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems'; import { asCssVariable, selectBorder } from 'vs/platform/theme/common/colorRegistry'; import { ISelectOptionItem } from 'vs/base/browser/ui/selectBox/selectBox'; import { IActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; @@ -236,7 +236,7 @@ export class TerminalViewPane extends ViewPane { this._terminalTabbedView?.layout(width, height); } - override getActionViewItem(action: Action): IActionViewItem | undefined { + override getActionViewItem(action: Action, options: IBaseActionViewItemOptions): IActionViewItem | undefined { switch (action.id) { case TerminalCommandId.Split: { // Split needs to be special cased to force splitting within the panel, not the editor @@ -257,7 +257,7 @@ export class TerminalViewPane extends ViewPane { return; } }; - return new ActionViewItem(action, panelOnlySplitAction, { icon: true, label: false, keybinding: this._getKeybindingLabel(action) }); + return new ActionViewItem(action, panelOnlySplitAction, { ...options, icon: true, label: false, keybinding: this._getKeybindingLabel(action) }); } case TerminalCommandId.SwitchTerminal: { return this._instantiationService.createInstance(SwitchTerminalActionViewItem, action); @@ -273,13 +273,13 @@ export class TerminalViewPane extends ViewPane { if (action instanceof MenuItemAction) { const actions = getTerminalActionBarArgs(TerminalLocation.Panel, this._terminalProfileService.availableProfiles, this._getDefaultProfileName(), this._terminalProfileService.contributedProfiles, this._terminalService, this._dropdownMenu); this._newDropdown?.dispose(); - this._newDropdown = new DropdownWithPrimaryActionViewItem(action, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService, {}, this._keybindingService, this._notificationService, this._contextKeyService, this._themeService, this._accessibilityService); + this._newDropdown = new DropdownWithPrimaryActionViewItem(action, actions.dropdownAction, actions.dropdownMenuActions, actions.className, this._contextMenuService, { hoverDelegate: options.hoverDelegate }, this._keybindingService, this._notificationService, this._contextKeyService, this._themeService, this._accessibilityService); this._updateTabActionBar(this._terminalProfileService.availableProfiles); return this._newDropdown; } } } - return super.getActionViewItem(action); + return super.getActionViewItem(action, options); } private _getDefaultProfileName(): string { diff --git a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts index 4110388332e..ba7f2800830 100644 --- a/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts +++ b/src/vs/workbench/contrib/testing/browser/testingExplorerView.ts @@ -473,7 +473,7 @@ class ResultSummaryView extends Disposable { })); const ab = this._register(new ActionBar(this.elements.rerun, { - actionViewItemProvider: action => createActionViewItem(instantiationService, action), + actionViewItemProvider: (action, options) => createActionViewItem(instantiationService, action, options), })); ab.push(instantiationService.createInstance(MenuItemAction, { ...new ReRunLastRun().desc, icon: icons.testingRerunIcon }, diff --git a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts index d919f15af47..70afef1e015 100644 --- a/src/vs/workbench/contrib/timeline/browser/timelinePane.ts +++ b/src/vs/workbench/contrib/timeline/browser/timelinePane.ts @@ -49,13 +49,13 @@ import { API_OPEN_DIFF_EDITOR_COMMAND_ID, API_OPEN_EDITOR_COMMAND_ID } from 'vs/ import { MarshalledId } from 'vs/base/common/marshallingIds'; import { isString } from 'vs/base/common/types'; import { renderMarkdownAsPlaintext } from 'vs/base/browser/markdownRenderer'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; -import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; +import { IHoverDelegate } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IUriIdentityService } from 'vs/platform/uriIdentity/common/uriIdentity'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; import { AriaRole } from 'vs/base/browser/ui/aria/aria'; import { ILocalizedString } from 'vs/platform/action/common/action'; +import { getDefaultHoverDelegate } from 'vs/base/browser/ui/hover/hoverDelegate'; const ItemHeight = 22; @@ -1147,14 +1147,9 @@ class TimelineTreeRenderer implements ITreeRenderer this.hoverService.showHover(options), - delay: this.configurationService.getValue('workbench.hover.delay') - }; + this._hoverDelegate = getDefaultHoverDelegate('element'); } private uri: URI | undefined; diff --git a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts index fbf85313f6c..5d989fc5e1b 100644 --- a/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/electron-sandbox/parts/titlebar/titlebarPart.ts @@ -23,7 +23,6 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { Codicon } from 'vs/base/common/codicons'; import { ThemeIcon } from 'vs/base/common/themables'; import { NativeMenubarControl } from 'vs/workbench/electron-sandbox/parts/titlebar/menubarControl'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; import { IEditorGroupsContainer, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -72,13 +71,12 @@ export class NativeTitlebarPart extends BrowserTitlebarPart { @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, @INativeHostService private readonly nativeHostService: INativeHostService, - @IHoverService hoverService: IHoverService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService menuService: IMenuService, @IKeybindingService keybindingService: IKeybindingService ) { - super(id, targetWindow, editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, hoverService, editorGroupService, editorService, menuService, keybindingService); + super(id, targetWindow, editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, editorGroupService, editorService, menuService, keybindingService); this.bigSurOrNewer = isBigSurOrNewer(environmentService.os.release); } @@ -286,13 +284,12 @@ export class MainNativeTitlebarPart extends NativeTitlebarPart { @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, @INativeHostService nativeHostService: INativeHostService, - @IHoverService hoverService: IHoverService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService menuService: IMenuService, @IKeybindingService keybindingService: IKeybindingService ) { - super(Parts.TITLEBAR_PART, mainWindow, 'main', contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, nativeHostService, hoverService, editorGroupService, editorService, menuService, keybindingService); + super(Parts.TITLEBAR_PART, mainWindow, 'main', contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, nativeHostService, editorGroupService, editorService, menuService, keybindingService); } } @@ -316,14 +313,13 @@ export class AuxiliaryNativeTitlebarPart extends NativeTitlebarPart implements I @IContextKeyService contextKeyService: IContextKeyService, @IHostService hostService: IHostService, @INativeHostService nativeHostService: INativeHostService, - @IHoverService hoverService: IHoverService, @IEditorGroupsService editorGroupService: IEditorGroupsService, @IEditorService editorService: IEditorService, @IMenuService menuService: IMenuService, @IKeybindingService keybindingService: IKeybindingService ) { const id = AuxiliaryNativeTitlebarPart.COUNTER++; - super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, nativeHostService, hoverService, editorGroupService, editorService, menuService, keybindingService); + super(`workbench.parts.auxiliaryTitle.${id}`, getWindow(container), editorGroupsContainer, contextMenuService, configurationService, environmentService, instantiationService, themeService, storageService, layoutService, contextKeyService, hostService, nativeHostService, editorGroupService, editorService, menuService, keybindingService); } override get preventZoom(): boolean { diff --git a/src/vs/workbench/services/quickinput/browser/quickInputService.ts b/src/vs/workbench/services/quickinput/browser/quickInputService.ts index 463bea822b2..8e09c681660 100644 --- a/src/vs/workbench/services/quickinput/browser/quickInputService.ts +++ b/src/vs/workbench/services/quickinput/browser/quickInputService.ts @@ -14,7 +14,6 @@ import { QuickInputService as BaseQuickInputService } from 'vs/platform/quickinp import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { InQuickPickContextKey } from 'vs/workbench/browser/quickaccess'; -import { IHoverService } from 'vs/platform/hover/browser/hover'; export class QuickInputService extends BaseQuickInputService { @@ -27,9 +26,8 @@ export class QuickInputService extends BaseQuickInputService { @IContextKeyService contextKeyService: IContextKeyService, @IThemeService themeService: IThemeService, @ILayoutService layoutService: ILayoutService, - @IHoverService hoverService: IHoverService ) { - super(instantiationService, contextKeyService, themeService, layoutService, configurationService, hoverService); + super(instantiationService, contextKeyService, themeService, layoutService, configurationService); this.registerListeners(); } diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 10461c8e293..23355faf76d 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -163,13 +163,11 @@ import { IUserDataProfileService } from 'vs/workbench/services/userDataProfile/c import { EnablementState, IScannedExtension, IWebExtensionsScannerService, IWorkbenchExtensionEnablementService, IWorkbenchExtensionManagementService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; import { InstallVSIXOptions, ILocalExtension, IGalleryExtension, InstallOptions, IExtensionIdentifier, UninstallOptions, IExtensionsControlManifest, IGalleryMetadata, IExtensionManagementParticipant, Metadata, InstallExtensionResult, InstallExtensionInfo } from 'vs/platform/extensionManagement/common/extensionManagement'; import { Codicon } from 'vs/base/common/codicons'; -import { IHoverOptions, IHoverService } from 'vs/platform/hover/browser/hover'; import { IRemoteExtensionsScannerService } from 'vs/platform/remote/common/remoteExtensionsScanner'; import { IRemoteSocketFactoryService, RemoteSocketFactoryService } from 'vs/platform/remote/common/remoteSocketFactoryService'; import { EditorParts } from 'vs/workbench/browser/parts/editor/editorParts'; import { mainWindow } from 'vs/base/browser/window'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { IHoverWidget } from 'vs/base/browser/ui/iconLabel/iconHoverDelegate'; import { IAccessibilitySignalService } from 'vs/platform/accessibilitySignal/browser/accessibilitySignalService'; import { IEditorPaneService } from 'vs/workbench/services/editor/common/editorPaneService'; import { EditorPaneService } from 'vs/workbench/services/editor/browser/editorPaneService'; @@ -334,8 +332,7 @@ export function workbenchInstantiationService( instantiationService.stub(ICodeEditorService, disposables.add(new CodeEditorService(editorService, themeService, configService))); instantiationService.stub(IPaneCompositePartService, disposables.add(new TestPaneCompositeService())); instantiationService.stub(IListService, new TestListService()); - const hoverService = instantiationService.stub(IHoverService, instantiationService.createInstance(TestHoverService)); - instantiationService.stub(IQuickInputService, disposables.add(new QuickInputService(configService, instantiationService, keybindingService, contextKeyService, themeService, layoutService, hoverService))); + instantiationService.stub(IQuickInputService, disposables.add(new QuickInputService(configService, instantiationService, keybindingService, contextKeyService, themeService, layoutService))); instantiationService.stub(IWorkspacesService, new TestWorkspacesService()); instantiationService.stub(IWorkspaceTrustManagementService, disposables.add(new TestWorkspaceTrustManagementService())); instantiationService.stub(IWorkspaceTrustRequestService, disposables.add(new TestWorkspaceTrustRequestService(false))); @@ -758,25 +755,6 @@ export class TestSideBarPart implements IPaneCompositePart { layout(width: number, height: number, top: number, left: number): void { } } -class TestHoverService implements IHoverService { - private currentHover: IHoverWidget | undefined; - _serviceBrand: undefined; - showHover(options: IHoverOptions, focus?: boolean | undefined): IHoverWidget | undefined { - this.currentHover = new class implements IHoverWidget { - private _isDisposed = false; - get isDisposed(): boolean { return this._isDisposed; } - dispose(): void { - this._isDisposed = true; - } - }; - return this.currentHover; - } - showAndFocusLastHover(): void { } - hideHover(): void { - this.currentHover?.dispose(); - } -} - export class TestPanelPart implements IPaneCompositePart { declare readonly _serviceBrand: undefined;