Skip to content

Commit 40a85c5

Browse files
author
aiday-mar
committed
Resolving comments from review
1 parent 31a056e commit 40a85c5

File tree

1 file changed

+66
-53
lines changed

1 file changed

+66
-53
lines changed

src/vs/editor/contrib/stickyScroll/browser/stickyScrollWidget.ts

Lines changed: 66 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,29 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
6-
import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, MouseTargetType } from 'vs/editor/browser/editorBrowser';
5+
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
6+
import { IActiveCodeEditor, ICodeEditor, IOverlayWidget, IOverlayWidgetPosition } from 'vs/editor/browser/editorBrowser';
77
import * as dom from 'vs/base/browser/dom';
88
import { EditorLayoutInfo, EditorOption, RenderLineNumbersType } from 'vs/editor/common/config/editorOptions';
99
import { createStringBuilder } from 'vs/editor/common/core/stringBuilder';
1010
import { RenderLineInput, renderViewLine } from 'vs/editor/common/viewLayout/viewLineRenderer';
1111
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
1212
import { Position } from 'vs/editor/common/core/position';
13-
import 'vs/css!./stickyScroll';
1413
import { ClickLinkGesture } from 'vs/editor/contrib/gotoSymbol/browser/link/clickLinkGesture';
1514
import { getDefinitionsAtPosition } from 'vs/editor/contrib/gotoSymbol/browser/goToSymbol';
1615
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
1716
import { Location } from 'vs/editor/common/languages';
1817
import { goToDefinitionWithLocation } from 'vs/editor/contrib/inlayHints/browser/inlayHintsLocations';
1918
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
20-
import { CancellationTokenSource, } from 'vs/base/common/cancellation';
19+
import { CancellationTokenSource } from 'vs/base/common/cancellation';
2120
import { IRange } from 'vs/editor/common/core/range';
21+
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
22+
import 'vs/css!./stickyScroll';
23+
24+
interface CustomMouseEvent {
25+
detail: string;
26+
element: HTMLElement;
27+
}
2228

2329
export class StickyScrollWidgetState {
2430
constructor(
@@ -37,10 +43,10 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
3743
private lineHeight: number;
3844
private lineNumbers: number[];
3945
private lastLineRelativePosition: number;
46+
4047
private hoverOnLine: number;
41-
private positionOfDefinitionToJumpTo: Location;
42-
private lastChildDecorated: HTMLElement | undefined;
43-
private stickyPositionProjectedOnEditor: Position;
48+
private hoverOnColumn: number;
49+
private stickyRangeProjectedOnEditor: IRange;
4450

4551
constructor(
4652
private readonly _editor: ICodeEditor,
@@ -57,9 +63,8 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
5763
this.lastLineRelativePosition = 0;
5864

5965
this.hoverOnLine = -1;
60-
this.positionOfDefinitionToJumpTo = { uri: {}, range: {} } as Location;
61-
this.lastChildDecorated = undefined;
62-
this.stickyPositionProjectedOnEditor = new Position(-1, -1);
66+
this.hoverOnColumn = -1;
67+
this.stickyRangeProjectedOnEditor = {} as IRange;
6368

6469
this.lineHeight = this._editor.getOption(EditorOption.lineHeight);
6570
this._register(this._editor.onDidChangeConfiguration(e => {
@@ -71,69 +76,76 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
7176
}
7277

7378
private updateLinkGesture(): IDisposable {
79+
80+
7481
const linkGestureStore = new DisposableStore();
75-
const gesture = linkGestureStore.add(new ClickLinkGesture(this._editor, true));
76-
const cancellationToken = new CancellationTokenSource();
7782
const sessionStore = new DisposableStore();
78-
sessionStore.add(cancellationToken);
7983
linkGestureStore.add(sessionStore);
84+
const gesture = new ClickLinkGesture(this._editor, true);
85+
linkGestureStore.add(gesture);
86+
8087
linkGestureStore.add(gesture.onMouseMoveOrRelevantKeyDown(([mouseEvent, _keyboardEvent]) => {
8188
if (!this._editor.hasModel() || !mouseEvent.hasTriggerModifier) {
8289
sessionStore.clear();
8390
return;
8491
}
85-
const targetMouseEvent = mouseEvent.target as any;
86-
if (targetMouseEvent.detail === 'editor.contrib.stickyScrollWidget' && this.hoverOnLine !== -1 && targetMouseEvent.element.innerText === targetMouseEvent.element.innerHTML) {
92+
const targetMouseEvent = mouseEvent.target as unknown as CustomMouseEvent;
93+
if (targetMouseEvent.detail === 'editor.contrib.stickyScrollWidget' && targetMouseEvent.element.innerText === targetMouseEvent.element.innerHTML) {
8794
const text = targetMouseEvent.element.innerText;
88-
const lineNumber = this.hoverOnLine;
89-
// TODO: workaround to find the column index, perhaps need more solid solution
90-
const column = this._editor.getModel().getLineContent(lineNumber).indexOf(text);
91-
if (column === -1) {
95+
if (this.hoverOnColumn === -1) {
9296
return;
9397
}
94-
const stickyPositionProjectedOnEditor = new Position(lineNumber, column + 1);
95-
if (this.stickyPositionProjectedOnEditor !== stickyPositionProjectedOnEditor) {
96-
this.stickyPositionProjectedOnEditor = stickyPositionProjectedOnEditor;
97-
cancellationToken.cancel();
98+
const lineNumber = this.hoverOnLine;
99+
const column = this.hoverOnColumn;
100+
101+
const stickyPositionProjectedOnEditor = { startLineNumber: lineNumber, endLineNumber: lineNumber, startColumn: column, endColumn: column + text.length } as IRange;
102+
if (JSON.stringify(this.stickyRangeProjectedOnEditor) !== JSON.stringify(stickyPositionProjectedOnEditor)) {
103+
this.stickyRangeProjectedOnEditor = stickyPositionProjectedOnEditor;
104+
sessionStore.clear();
98105
}
99-
getDefinitionsAtPosition(this._languageFeatureService.definitionProvider, this._editor.getModel(), stickyPositionProjectedOnEditor, cancellationToken.token).then((candidateDefinitions => {
106+
107+
const cancellationToken = new CancellationTokenSource();
108+
sessionStore.add(toDisposable(() => cancellationToken.dispose(true)));
109+
110+
let currentHTMLChild: HTMLElement;
111+
112+
getDefinitionsAtPosition(this._languageFeatureService.definitionProvider, this._editor.getModel(), new Position(lineNumber, column + 1), cancellationToken.token).then((candidateDefinitions => {
100113
if (cancellationToken.token.isCancellationRequested) {
101114
return;
102115
}
103116
if (candidateDefinitions.length !== 0) {
104-
// TODO: Currently only taking the first definition but there could be other ones of interest
105-
this.positionOfDefinitionToJumpTo.uri = candidateDefinitions[0]?.uri;
106-
this.positionOfDefinitionToJumpTo.range = candidateDefinitions[0]?.targetSelectionRange as IRange;
107-
108117
const lineToDecorate = this.getDomNode().getElementsByClassName(`stickyLine${lineNumber}`)[0].children[0] as HTMLElement;
109-
let currentHTMLChild: HTMLElement | undefined = undefined;
110-
118+
let childHTML: HTMLElement | undefined = undefined;
111119
for (const childElement of lineToDecorate.children) {
112120
const childAsHTMLElement = childElement as HTMLElement;
113121
if (childAsHTMLElement.innerText === text) {
114-
currentHTMLChild = childAsHTMLElement;
122+
childHTML = childAsHTMLElement;
115123
break;
116124
}
117125
}
118-
if (!currentHTMLChild) {
126+
if (!childHTML) {
119127
return;
120128
}
121-
if (this.lastChildDecorated && this.lastChildDecorated !== currentHTMLChild) {
122-
this.lastChildDecorated.style.textDecoration = 'none';
123-
this.lastChildDecorated = currentHTMLChild;
124-
this.lastChildDecorated.style.textDecoration = 'underline';
125-
} else if (!this.lastChildDecorated) {
126-
this.lastChildDecorated = currentHTMLChild;
127-
this.lastChildDecorated.style.textDecoration = 'underline';
129+
if (currentHTMLChild !== childHTML) {
130+
sessionStore.clear();
131+
currentHTMLChild = childHTML;
132+
currentHTMLChild.style.textDecoration = 'underline';
133+
sessionStore.add(toDisposable(() => {
134+
currentHTMLChild.style.textDecoration = 'none';
135+
}));
136+
} else if (!currentHTMLChild) {
137+
currentHTMLChild = childHTML;
138+
currentHTMLChild.style.textDecoration = 'underline';
139+
sessionStore.add(toDisposable(() => {
140+
currentHTMLChild.style.textDecoration = 'none';
141+
}));
128142
}
129-
} else if (this.lastChildDecorated) {
130-
this.lastChildDecorated.style.textDecoration = 'none';
131-
this.lastChildDecorated = undefined;
143+
} else {
144+
sessionStore.clear();
132145
}
133146
}));
134-
} else if (this.lastChildDecorated) {
135-
this.lastChildDecorated.style.textDecoration = 'none';
136-
this.lastChildDecorated = undefined;
147+
} else {
148+
sessionStore.clear();
137149
}
138150
}));
139151
linkGestureStore.add(gesture.onCancel(() => {
@@ -143,7 +155,7 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
143155
if (this.hoverOnLine !== -1) {
144156
if (e.hasTriggerModifier) {
145157
// Control click
146-
this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, this.positionOfDefinitionToJumpTo);
158+
this._instaService.invokeFunction(goToDefinitionWithLocation, e, this._editor as IActiveCodeEditor, { uri: this._editor.getModel()!.uri, range: this.stickyRangeProjectedOnEditor } as Location);
147159
} else {
148160
// Normal click
149161
this._editor.revealPosition({ lineNumber: this.hoverOnLine, column: 1 });
@@ -259,15 +271,20 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
259271
child.style.top = this.lastLineRelativePosition + 'px';
260272
}
261273

262-
this.disposableStore.add(dom.addDisposableListener(child, 'mouseover', () => {
263-
this.hoverOnLine = line;
274+
this.disposableStore.add(dom.addDisposableListener(child, 'mouseover', (e) => {
275+
if (this._editor.hasModel()) {
276+
const mouseOverEvent = new StandardMouseEvent(e);
277+
const text = mouseOverEvent.target.innerText;
278+
this.hoverOnLine = line;
279+
// TODO: workaround to find the column index, perhaps need more solid solution
280+
this.hoverOnColumn = this._editor.getModel().getLineContent(line).indexOf(text) + 1 || -1;
281+
}
264282
}));
265283

266284
return child;
267285
}
268286

269287
private renderRootNode(): void {
270-
271288
if (!this._editor._getViewModel()) {
272289
return;
273290
}
@@ -283,10 +300,6 @@ export class StickyScrollWidget extends Disposable implements IOverlayWidget {
283300
} else if (minimapSide === 'right') {
284301
this.rootDomNode.style.marginLeft = '0px';
285302
}
286-
287-
this.disposableStore.add(dom.addDisposableListener(this.rootDomNode, 'mouseout', () => {
288-
this.hoverOnLine = -1;
289-
}));
290303
}
291304

292305
public getId(): string {

0 commit comments

Comments
 (0)