Change:
Currently the hover disappear as soon as the mouse leaves the content hover. Sometimes the user leaves briefly the content hover. The ask is to wait until some times (ex. 500 ms) has passed before measuring whether the mouse is within the hover or not, then make the hover disappear or not.
This would be quite helpful in resizing the hover (because it's easy to go out of the hover when aiming for the angle to hover with a mouse). But I would think 500 ms is too much for that use case

Discussion:
const defaults: EditorHoverOptions = { enabled: true, delay: 300, <ins> hidingDelay: 500, </ins> sticky: true, above: true, };

default: defaults.sticky, description: nls.localize('hover.sticky', "Controls whether the hover should remain visible when mouse is moved over it.") }, <ins> 'editor.hover.hidingDelay': { type: 'integer', minimum: 0, default: defaults.hidingDelay, description: nls.localize('hover.hidingDelay', "Controls the delay in milliseconds after thich the hover is hidden. Requires `editor.hover.sticky` to be enabled.") }, </ins> 'editor.hover.above': { type: 'boolean', default: defaults.above,

enabled: boolean(input.enabled, this.defaultValue.enabled), delay: EditorIntOption.clampedInt(input.delay, this.defaultValue.delay, 0, 10000), sticky: boolean(input.sticky, this.defaultValue.sticky), <ins> hidingDelay: EditorIntOption.clampedInt(input.hidingDelay, this.defaultValue.hidingDelay, 0, 600000), </ins> above: boolean(input.above, this.defaultValue.above), }; }

private _hoverClicked: boolean; private _isHoverEnabled!: boolean; private _isHoverSticky!: boolean; <ins> private _hidingDelay!: number; </ins> private _hoverActivatedByColorDecoratorClick: boolean = false; <ins> private _mouseWasOverWidget: boolean = false; private _hideWidgetsTimeout: NodeJS.Timeout | undefined; </ins> static get(editor: ICodeEditor): ModesHoverController | null { return editor.getContribution<ModesHoverController>(ModesHoverController.ID);

const hoverOpts = this._editor.getOption(EditorOption.hover); this._isHoverEnabled = hoverOpts.enabled; this._isHoverSticky = hoverOpts.sticky; <ins> this._hidingDelay = hoverOpts.hidingDelay; </ins> if (this._isHoverEnabled) { this._toUnhook.add(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); this._toUnhook.add(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e)));

} } <del> private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { </del> <ins> private _isMouseOverWidget(mouseEvent: IEditorMouseEvent): boolean { </ins> const target = mouseEvent.target; <del> if (this._contentWidget?.isFocused || this._contentWidget?.isResizing) { return; } if (this._isMouseDown && this._hoverClicked) { return; } if (this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID) { </del> <ins> if ( this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID ) { </ins> // mouse moved on top of content hover widget <del> return; </del> <ins> return true; </ins> } <del> if (this._isHoverSticky && this._contentWidget?.containsNode(mouseEvent.event.browserEvent.view?.document.activeElement) && !mouseEvent.event.browserEvent.view?.getSelection()?.isCollapsed) { </del> <ins> if ( this._isHoverSticky && this._contentWidget?.containsNode(mouseEvent.event.browserEvent.view?.document.activeElement) && !mouseEvent.event.browserEvent.view?.getSelection()?.isCollapsed ) { </ins> // selected text within content hover widget <del> return; </del> <ins> return true; </ins> } if ( <del> !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID </del> <ins> !this._isHoverSticky && target.type === MouseTargetType.CONTENT_WIDGET && target.detail === ContentHoverWidget.ID </ins> && this._contentWidget?.isColorPickerVisible ) { // though the hover is not sticky, the color picker needs to. <del> return; </del> <ins> return true; </ins> } <del> if (this._isHoverSticky && target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID) { </del> <ins> if (this._isHoverSticky && target.type === MouseTargetType.OVERLAY_WIDGET && target.detail === MarginHoverWidget.ID ) { </ins> // mouse moved on top of overlay hover widget <del> return; </del> <ins> return true; </ins> } <ins> return false; } private _onEditorMouseMove(mouseEvent: IEditorMouseEvent): void { const target = mouseEvent.target; if (this._contentWidget?.isFocused || this._contentWidget?.isResizing) { return; } if (this._isMouseDown && this._hoverClicked) { return; } </ins> if (this._isHoverSticky && this._contentWidget?.isVisibleFromKeyboard) { // Sticky mode is on and the hover has been shown via keyboard // so moving the mouse has no effect return; } <ins> const mouseIsOverWidget = this._isMouseOverWidget(mouseEvent); if (mouseIsOverWidget) { if (this._hideWidgetsTimeout) { clearTimeout(this._hideWidgetsTimeout); this._hideWidgetsTimeout = undefined; } this._mouseWasOverWidget = mouseIsOverWidget; return; } if (this._hideWidgetsTimeout) { return; } </ins> const mouseOnDecorator = target.element?.classList.contains('colorpicker-color-decoration'); const decoratorActivatedOn = this._editor.getOption(EditorOption.colorDecoratorsActivatedOn);

if (_sticky) { return; } <del> this._hideWidgets(); </del> <ins> if (this._mouseWasOverWidget) { // The mouse just left the content widget and a timeout is trigerred to hide the widget // This timeout will be cancelled if the mouse re-enters the content widget this._hideWidgetsTimeout = setTimeout(() => { this._hideWidgets(); this._hideWidgetsTimeout = undefined; }, this._hidingDelay); this._mouseWasOverWidget = false; } else { this._hideWidgets(); } </ins> } private _onKeyDown(e: IKeyboardEvent): void {

*/ sticky?: boolean; /** <ins> * Controls how long the hover is visible after you hovered out of it. * Require sticky setting to be true. */ hidingDelay?: number; /** </ins> * Should the hover be shown above the line if possible? * Defaults to false. */