Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/hover/browser/hover.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { createDecorator } from '../../instantiation/common/instantiation.js';
7
import { Disposable, DisposableStore } from '../../../base/common/lifecycle.js';
8
import { IHoverDelegate, IHoverDelegateOptions } from '../../../base/browser/ui/hover/hoverDelegate.js';
9
import { IConfigurationService } from '../../configuration/common/configuration.js';
10
import { addStandardDisposableListener, isHTMLElement } from '../../../base/browser/dom.js';
11
import { KeyCode } from '../../../base/common/keyCodes.js';
12
import type { IHoverDelegate2, IHoverOptions, IHoverWidget, IManagedHoverContentOrFactory } from '../../../base/browser/ui/hover/hover.js';
13
14
export const IHoverService = createDecorator<IHoverService>('hoverService');
15
16
export interface IHoverService extends IHoverDelegate2 {
17
readonly _serviceBrand: undefined;
18
}
19
20
export interface IHoverDelayOptions {
21
readonly instantHover?: boolean;
22
readonly dynamicDelay?: (content?: IManagedHoverContentOrFactory) => number | undefined;
23
}
24
25
export class WorkbenchHoverDelegate extends Disposable implements IHoverDelegate {
26
27
private lastHoverHideTime = 0;
28
private timeLimit = 200;
29
30
private _delay: number;
31
get delay(): number | ((content: IManagedHoverContentOrFactory) => number) {
32
if (this.isInstantlyHovering()) {
33
return 0; // show instantly when a hover was recently shown
34
}
35
36
if (this.hoverOptions?.dynamicDelay) {
37
return content => this.hoverOptions?.dynamicDelay?.(content) ?? this._delay;
38
}
39
40
return this._delay;
41
}
42
43
private readonly hoverDisposables = this._register(new DisposableStore());
44
45
constructor(
46
public readonly placement: 'mouse' | 'element',
47
private readonly hoverOptions: IHoverDelayOptions | undefined,
48
private overrideOptions: Partial<IHoverOptions> | ((options: IHoverDelegateOptions, focus?: boolean) => Partial<IHoverOptions>) = {},
49
@IConfigurationService private readonly configurationService: IConfigurationService,
50
@IHoverService private readonly hoverService: IHoverService,
51
) {
52
super();
53
54
this._delay = this.configurationService.getValue<number>('workbench.hover.delay');
55
this._register(this.configurationService.onDidChangeConfiguration(e => {
56
if (e.affectsConfiguration('workbench.hover.delay')) {
57
this._delay = this.configurationService.getValue<number>('workbench.hover.delay');
58
}
59
}));
60
}
61
62
showHover(options: IHoverDelegateOptions, focus?: boolean): IHoverWidget | undefined {
63
const overrideOptions = typeof this.overrideOptions === 'function' ? this.overrideOptions(options, focus) : this.overrideOptions;
64
65
// close hover on escape
66
this.hoverDisposables.clear();
67
const targets = isHTMLElement(options.target) ? [options.target] : options.target.targetElements;
68
for (const target of targets) {
69
this.hoverDisposables.add(addStandardDisposableListener(target, 'keydown', (e) => {
70
if (e.equals(KeyCode.Escape)) {
71
this.hoverService.hideHover();
72
}
73
}));
74
}
75
76
const id = isHTMLElement(options.content)
77
? undefined
78
: typeof options.content === 'string'
79
? options.content.toString()
80
: options.content.value;
81
82
return this.hoverService.showInstantHover({
83
...options,
84
...overrideOptions,
85
persistence: {
86
hideOnKeyDown: true,
87
...overrideOptions.persistence
88
},
89
id,
90
appearance: {
91
...options.appearance,
92
compact: true,
93
skipFadeInAnimation: this.isInstantlyHovering(),
94
...overrideOptions.appearance
95
}
96
}, focus);
97
}
98
99
private isInstantlyHovering(): boolean {
100
return !!this.hoverOptions?.instantHover && Date.now() - this.lastHoverHideTime < this.timeLimit;
101
}
102
103
setInstantHoverTimeLimit(timeLimit: number): void {
104
if (!this.hoverOptions?.instantHover) {
105
throw new Error('Instant hover is not enabled');
106
}
107
this.timeLimit = timeLimit;
108
}
109
110
onDidHideHover(): void {
111
this.hoverDisposables.clear();
112
if (this.hoverOptions?.instantHover) {
113
this.lastHoverHideTime = Date.now();
114
}
115
}
116
}
117
118
// TODO@benibenj remove this, only temp fix for contextviews
119
export const nativeHoverDelegate: IHoverDelegate = {
120
showHover: function (): IHoverWidget | undefined {
121
throw new Error('Native hover function not implemented.');
122
},
123
delay: 0,
124
showNativeHover: true
125
};
126
127