Skip to content

Commit 5ff3c23

Browse files
authored
Fixing hover disappearance in chat pannel (microsoft#219099)
* adding code * adding code to send the event at the lowest level * adding code * adding some code * polish * fixing hover disappearing too quickly, not looking at delay * polishing the code * cleaning * adding cleaning code * settign timeout to 0
1 parent b97d0a2 commit 5ff3c23

File tree

4 files changed

+97
-27
lines changed

4 files changed

+97
-27
lines changed

src/vs/editor/browser/controller/mouseHandler.ts

Lines changed: 72 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { MouseWheelClassifier } from 'vs/base/browser/ui/scrollbar/scrollableEle
2424

2525
export interface IPointerHandlerHelper {
2626
viewDomNode: HTMLElement;
27+
overflowWidgetsDomNode: HTMLElement | null;
2728
linesContentDomNode: HTMLElement;
2829
viewLinesDomNode: HTMLElement;
2930

@@ -62,6 +63,8 @@ export class MouseHandler extends ViewEventHandler {
6263
private lastMouseLeaveTime: number;
6364
private _height: number;
6465
private _mouseLeaveMonitor: IDisposable | null = null;
66+
private _mouseOnOverflowWidgetsDomNode: boolean = false;
67+
private _mouseOnViewDomNode: boolean = false;
6568

6669
constructor(context: ViewContext, viewController: ViewController, viewHelper: IPointerHandlerHelper) {
6770
super();
@@ -76,7 +79,7 @@ export class MouseHandler extends ViewEventHandler {
7679
this.viewController,
7780
this.viewHelper,
7881
this.mouseTargetFactory,
79-
(e, testEventTarget) => this._createMouseTarget(e, testEventTarget),
82+
(e, testEventTarget) => this._createMouseTargetForView(e, testEventTarget),
8083
(e) => this._getMouseColumn(e)
8184
));
8285

@@ -88,7 +91,8 @@ export class MouseHandler extends ViewEventHandler {
8891
this._register(mouseEvents.onContextMenu(this.viewHelper.viewDomNode, (e) => this._onContextMenu(e, true)));
8992

9093
this._register(mouseEvents.onMouseMove(this.viewHelper.viewDomNode, (e) => {
91-
this._onMouseMove(e);
94+
this._mouseOnViewDomNode = true;
95+
this._onMouseMoveOverView(e);
9296

9397
// See https://github.com/microsoft/vscode/issues/138789
9498
// When moving the mouse really quickly, the browser sometimes forgets to
@@ -101,15 +105,45 @@ export class MouseHandler extends ViewEventHandler {
101105
this._mouseLeaveMonitor = dom.addDisposableListener(this.viewHelper.viewDomNode.ownerDocument, 'mousemove', (e) => {
102106
if (!this.viewHelper.viewDomNode.contains(e.target as Node | null)) {
103107
// went outside the editor!
104-
this._onMouseLeave(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode));
108+
this._mouseOnViewDomNode = false;
109+
setTimeout(() => {
110+
if (!this._mouseOnOverflowWidgetsDomNode) {
111+
this._onMouseLeave(new EditorMouseEvent(e, false, this.viewHelper.viewDomNode));
112+
}
113+
}, 0);
105114
}
106115
});
107116
}
108117
}));
109118

110119
this._register(mouseEvents.onMouseUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));
111120

112-
this._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));
121+
this._register(mouseEvents.onMouseLeave(this.viewHelper.viewDomNode, (e) => {
122+
this._mouseOnViewDomNode = false;
123+
setTimeout(() => {
124+
if (!this._mouseOnOverflowWidgetsDomNode) {
125+
this._onMouseLeave(e);
126+
}
127+
}, 0);
128+
}));
129+
130+
const overflowWidgetsDomNode = this.viewHelper.overflowWidgetsDomNode;
131+
if (overflowWidgetsDomNode) {
132+
this._register(mouseEvents.onMouseMove(overflowWidgetsDomNode, (e) => {
133+
this._mouseOnOverflowWidgetsDomNode = true;
134+
this._mouseLeaveMonitor?.dispose();
135+
this._mouseLeaveMonitor = null;
136+
this._onMouseMoveOverOverflowWidgetsDomNode(e);
137+
}));
138+
this._register(mouseEvents.onMouseLeave(overflowWidgetsDomNode, (e) => {
139+
this._mouseOnOverflowWidgetsDomNode = false;
140+
setTimeout(() => {
141+
if (!this._mouseOnViewDomNode) {
142+
this._onMouseLeave(e);
143+
}
144+
}, 0);
145+
}));
146+
}
113147

114148
// `pointerdown` events can't be used to determine if there's a double click, or triple click
115149
// because their `e.detail` is always 0.
@@ -234,10 +268,10 @@ export class MouseHandler extends ViewEventHandler {
234268
}
235269

236270
const relativePos = createCoordinatesRelativeToEditor(this.viewHelper.viewDomNode, editorPos, pos);
237-
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);
271+
return this.mouseTargetFactory.createMouseTargetForView(this.viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);
238272
}
239273

240-
protected _createMouseTarget(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget {
274+
protected _createMouseTargetForView(e: EditorMouseEvent, testEventTarget: boolean): IMouseTarget {
241275
let target = e.target;
242276
if (!this.viewHelper.viewDomNode.contains(target)) {
243277
const shadowRoot = dom.getShadowRoot(this.viewHelper.viewDomNode);
@@ -247,7 +281,11 @@ export class MouseHandler extends ViewEventHandler {
247281
);
248282
}
249283
}
250-
return this.mouseTargetFactory.createMouseTarget(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null);
284+
return this.mouseTargetFactory.createMouseTargetForView(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, testEventTarget ? target : null);
285+
}
286+
287+
private _createMouseTargetForOverflowWidgetsDomNode(e: EditorMouseEvent): IMouseTarget {
288+
return this.mouseTargetFactory.createMouseTargetForOverflowWidgetsDomNode(this.viewHelper.getLastRenderData(), e.editorPos, e.pos, e.relativePos, e.target);
251289
}
252290

253291
private _getMouseColumn(e: EditorMouseEvent): number {
@@ -257,30 +295,45 @@ export class MouseHandler extends ViewEventHandler {
257295
protected _onContextMenu(e: EditorMouseEvent, testEventTarget: boolean): void {
258296
this.viewController.emitContextMenu({
259297
event: e,
260-
target: this._createMouseTarget(e, testEventTarget)
298+
target: this._createMouseTargetForView(e, testEventTarget)
299+
});
300+
}
301+
302+
protected _onMouseMoveOverView(e: EditorMouseEvent): void {
303+
this._onMouseMove(e, this._createMouseTargetForView(e, true));
304+
}
305+
306+
private _onMouseMoveOverOverflowWidgetsDomNode(e: EditorMouseEvent): void {
307+
this._onMouseMove(e, this._createMouseTargetForOverflowWidgetsDomNode(e));
308+
}
309+
310+
private _onMouseMove(e: EditorMouseEvent, target: IMouseTarget): void {
311+
const shouldIgnoreMouseMoveEvent = this._shouldIgnoreMouseMoveEvent(e);
312+
if (shouldIgnoreMouseMoveEvent) {
313+
return undefined;
314+
}
315+
this.viewController.emitMouseMove({
316+
event: e,
317+
target
261318
});
262319
}
263320

264-
protected _onMouseMove(e: EditorMouseEvent): void {
321+
private _shouldIgnoreMouseMoveEvent(e: EditorMouseEvent): boolean {
265322
const targetIsWidget = this.mouseTargetFactory.mouseTargetIsWidget(e);
266323
if (!targetIsWidget) {
267324
e.preventDefault();
268325
}
269326

270327
if (this._mouseDownOperation.isActive()) {
271328
// In selection/drag operation
272-
return;
329+
return true;
273330
}
274331
const actualMouseMoveTime = e.timestamp;
275332
if (actualMouseMoveTime < this.lastMouseLeaveTime) {
276333
// Due to throttling, this event occurred before the mouse left the editor, therefore ignore it.
277-
return;
334+
return true;
278335
}
279-
280-
this.viewController.emitMouseMove({
281-
event: e,
282-
target: this._createMouseTarget(e, true)
283-
});
336+
return false;
284337
}
285338

286339
protected _onMouseLeave(e: EditorMouseEvent): void {
@@ -298,12 +351,12 @@ export class MouseHandler extends ViewEventHandler {
298351
protected _onMouseUp(e: EditorMouseEvent): void {
299352
this.viewController.emitMouseUp({
300353
event: e,
301-
target: this._createMouseTarget(e, true)
354+
target: this._createMouseTargetForView(e, true)
302355
});
303356
}
304357

305358
protected _onMouseDown(e: EditorMouseEvent, pointerId: number): void {
306-
const t = this._createMouseTarget(e, true);
359+
const t = this._createMouseTargetForView(e, true);
307360

308361
const targetIsContent = (t.type === MouseTargetType.CONTENT_TEXT || t.type === MouseTargetType.CONTENT_EMPTY);
309362
const targetIsGutter = (t.type === MouseTargetType.GUTTER_GLYPH_MARGIN || t.type === MouseTargetType.GUTTER_LINE_NUMBERS || t.type === MouseTargetType.GUTTER_LINE_DECORATIONS);
@@ -742,7 +795,7 @@ class TopBottomDragScrollingOperation extends Disposable {
742795
const horizontalScrollbarHeight = this._context.configuration.options.get(EditorOption.layoutInfo).horizontalScrollbarHeight;
743796
const pos = new PageCoordinates(this._mouseEvent.pos.x, editorPos.y + editorPos.height - horizontalScrollbarHeight - 0.1);
744797
const relativePos = createCoordinatesRelativeToEditor(this._viewHelper.viewDomNode, editorPos, pos);
745-
mouseTarget = this._mouseTargetFactory.createMouseTarget(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);
798+
mouseTarget = this._mouseTargetFactory.createMouseTargetForView(this._viewHelper.getLastRenderData(), editorPos, pos, relativePos, null);
746799
}
747800
if (!mouseTarget.position || mouseTarget.position.lineNumber !== edgeLineNumber) {
748801
if (this._position.outsidePosition === 'above') {

src/vs/editor/browser/controller/mouseTarget.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,7 @@ export class HitTestContext {
238238
public readonly viewModel: IViewModel;
239239
public readonly layoutInfo: EditorLayoutInfo;
240240
public readonly viewDomNode: HTMLElement;
241+
public readonly overflowWidgetsDomNode: HTMLElement | null;
241242
public readonly lineHeight: number;
242243
public readonly stickyTabStops: boolean;
243244
public readonly typicalHalfwidthCharacterWidth: number;
@@ -251,6 +252,7 @@ export class HitTestContext {
251252
const options = context.configuration.options;
252253
this.layoutInfo = options.get(EditorOption.layoutInfo);
253254
this.viewDomNode = viewHelper.viewDomNode;
255+
this.overflowWidgetsDomNode = viewHelper.overflowWidgetsDomNode ?? null;
254256
this.lineHeight = options.get(EditorOption.lineHeight);
255257
this.stickyTabStops = options.get(EditorOption.stickyTabStops);
256258
this.typicalHalfwidthCharacterWidth = options.get(EditorOption.fontInfo).typicalHalfwidthCharacterWidth;
@@ -413,6 +415,7 @@ class HitTestRequest extends BareHitTestRequest {
413415
private _useHitTestTarget: boolean;
414416
private _targetPathCacheElement: HTMLElement | null = null;
415417
private _targetPathCacheValue: Uint8Array = new Uint8Array(0);
418+
private _targetElement: HTMLElement | null = null;
416419

417420
public get target(): HTMLElement | null {
418421
if (this._useHitTestTarget) {
@@ -422,17 +425,18 @@ class HitTestRequest extends BareHitTestRequest {
422425
}
423426

424427
public get targetPath(): Uint8Array {
425-
if (this._targetPathCacheElement !== this.target) {
428+
if (this._targetPathCacheElement !== this.target && this._targetElement) {
426429
this._targetPathCacheElement = this.target;
427-
this._targetPathCacheValue = PartFingerprints.collect(this.target, this._ctx.viewDomNode);
430+
this._targetPathCacheValue = PartFingerprints.collect(this.target, this._targetElement);
428431
}
429432
return this._targetPathCacheValue;
430433
}
431434

432-
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, eventTarget: HTMLElement | null) {
435+
constructor(ctx: HitTestContext, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, eventTarget: HTMLElement | null, targetElement: HTMLElement | null = null) {
433436
super(ctx, editorPos, pos, relativePos);
434437
this._ctx = ctx;
435438
this._eventTarget = eventTarget;
439+
this._targetElement = targetElement;
436440

437441
// If no event target is passed in, we will use the hit test target
438442
const hasEventTarget = Boolean(this._eventTarget);
@@ -532,9 +536,9 @@ export class MouseTargetFactory {
532536
return false;
533537
}
534538

535-
public createMouseTarget(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget {
539+
public createMouseTargetForView(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null): IMouseTarget {
536540
const ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData);
537-
const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target);
541+
const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target, ctx.viewDomNode);
538542
try {
539543
const r = MouseTargetFactory._createMouseTarget(ctx, request);
540544

@@ -555,6 +559,16 @@ export class MouseTargetFactory {
555559
}
556560
}
557561

562+
public createMouseTargetForOverflowWidgetsDomNode(lastRenderData: PointerHandlerLastRenderData, editorPos: EditorPagePosition, pos: PageCoordinates, relativePos: CoordinatesRelativeToEditor, target: HTMLElement | null) {
563+
const ctx = new HitTestContext(this._context, this._viewHelper, lastRenderData);
564+
const request = new HitTestRequest(ctx, editorPos, pos, relativePos, target, ctx.overflowWidgetsDomNode);
565+
try {
566+
return MouseTargetFactory._createMouseTarget(ctx, request);
567+
} catch (err) {
568+
return request.fulfillUnknown();
569+
}
570+
}
571+
558572
private static _createMouseTarget(ctx: HitTestContext, request: HitTestRequest): IMouseTarget {
559573

560574
// console.log(`${domHitTestExecuted ? '=>' : ''}CAME IN REQUEST: ${request}`);

src/vs/editor/browser/controller/pointerHandler.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class PointerEventHandler extends MouseHandler {
4747
// PonterEvents
4848
const pointerEvents = new EditorPointerEventFactory(this.viewHelper.viewDomNode);
4949

50-
this._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMove(e)));
50+
this._register(pointerEvents.onPointerMove(this.viewHelper.viewDomNode, (e) => this._onMouseMoveOverView(e)));
5151
this._register(pointerEvents.onPointerUp(this.viewHelper.viewDomNode, (e) => this._onMouseUp(e)));
5252
this._register(pointerEvents.onPointerLeave(this.viewHelper.viewDomNode, (e) => this._onMouseLeave(e)));
5353
this._register(pointerEvents.onPointerDown(this.viewHelper.viewDomNode, (e, pointerId) => this._onMouseDown(e, pointerId)));
@@ -73,7 +73,7 @@ export class PointerEventHandler extends MouseHandler {
7373
}
7474

7575
private _dispatchGesture(event: GestureEvent, inSelectionMode: boolean): void {
76-
const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);
76+
const target = this._createMouseTargetForView(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);
7777
if (target.position) {
7878
this.viewController.dispatchMouse({
7979
position: target.position,
@@ -119,7 +119,7 @@ class TouchHandler extends MouseHandler {
119119

120120
this.viewHelper.focusTextArea();
121121

122-
const target = this._createMouseTarget(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);
122+
const target = this._createMouseTargetForView(new EditorMouseEvent(event, false, this.viewHelper.viewDomNode), false);
123123

124124
if (target.position) {
125125
// Send the tap event also to the <textarea> (for input purposes)

src/vs/editor/browser/view.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ export class View extends ViewEventHandler {
9797
private readonly _linesContent: FastDomNode<HTMLElement>;
9898
public readonly domNode: FastDomNode<HTMLElement>;
9999
private readonly _overflowGuardContainer: FastDomNode<HTMLElement>;
100+
private readonly _overflowWidgetsDomNode: HTMLElement | null;
100101

101102
// Actual mutable state
102103
private _shouldRecomputeGlyphMarginLanes: boolean = false;
@@ -114,6 +115,7 @@ export class View extends ViewEventHandler {
114115
super();
115116
this._selections = [new Selection(1, 1, 1, 1)];
116117
this._renderAnimationFrame = null;
118+
this._overflowWidgetsDomNode = overflowWidgetsDomNode ?? null;
117119

118120
const viewController = new ViewController(configuration, model, userInputEvents, commandDelegate);
119121

@@ -278,6 +280,7 @@ export class View extends ViewEventHandler {
278280
private _createPointerHandlerHelper(): IPointerHandlerHelper {
279281
return {
280282
viewDomNode: this.domNode.domNode,
283+
overflowWidgetsDomNode: this._overflowWidgetsDomNode,
281284
linesContentDomNode: this._linesContent.domNode,
282285
viewLinesDomNode: this._viewLines.getDomNode().domNode,
283286

0 commit comments

Comments
 (0)