Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix all x-model highlight flickering #224415

Merged
merged 1 commit into from
Jul 31, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions src/vs/editor/contrib/wordHighlighter/browser/wordHighlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import * as nls from 'vs/nls';
import * as arrays from 'vs/base/common/arrays';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { CancelablePromise, createCancelablePromise, first, timeout } from 'vs/base/common/async';
import { CancelablePromise, createCancelablePromise, Delayer, first, timeout } from 'vs/base/common/async';
import { CancellationToken } from 'vs/base/common/cancellation';
import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
Expand Down Expand Up @@ -267,11 +267,11 @@ class WordHighlighter {
private readonly editor: IActiveCodeEditor;
private readonly providers: LanguageFeatureRegistry<DocumentHighlightProvider>;
private readonly multiDocumentProviders: LanguageFeatureRegistry<MultiDocumentHighlightProvider>;
private occurrencesHighlight: string;
private readonly model: ITextModel;
private readonly decorations: IEditorDecorationsCollection;
private readonly toUnhook = new DisposableStore();
private readonly codeEditorService: ICodeEditorService;
private occurrencesHighlight: string;

private workerRequestTokenId: number = 0;
private workerRequest: IOccurenceAtPositionRequest | null;
Expand All @@ -284,7 +284,9 @@ class WordHighlighter {
private readonly _hasWordHighlights: IContextKey<boolean>;
private _ignorePositionChangeEvent: boolean;

private static storedDecorations: ResourceMap<string[]> = new ResourceMap();
private readonly runDelayer: Delayer<void> = this.toUnhook.add(new Delayer<void>(50));

private static storedDecorationIDs: ResourceMap<string[]> = new ResourceMap();
private static query: IWordHighlighterQuery | null = null;

constructor(editor: IActiveCodeEditor, providers: LanguageFeatureRegistry<DocumentHighlightProvider>, multiProviders: LanguageFeatureRegistry<MultiDocumentHighlightProvider>, contextKeyService: IContextKeyService, @ICodeEditorService codeEditorService: ICodeEditorService) {
Expand All @@ -308,7 +310,7 @@ class WordHighlighter {
return;
}

this._onPositionChanged(e);
this.runDelayer.trigger(() => { this._onPositionChanged(e); });
}));
this.toUnhook.add(editor.onDidFocusEditorText((e) => {
if (this.occurrencesHighlight === 'off') {
Expand All @@ -317,7 +319,7 @@ class WordHighlighter {
}

if (!this.workerRequest) {
this._run();
this.runDelayer.trigger(() => { this._run(); });
}
}));
this.toUnhook.add(editor.onDidChangeModelContent((e) => {
Expand Down Expand Up @@ -345,7 +347,7 @@ class WordHighlighter {
break;
case 'multiFile':
if (WordHighlighter.query) {
this._run();
this._run(true);
}
break;
default:
Expand Down Expand Up @@ -439,13 +441,13 @@ class WordHighlighter {
return;
}

const currentDecorationIDs = WordHighlighter.storedDecorations.get(this.editor.getModel().uri);
const currentDecorationIDs = WordHighlighter.storedDecorationIDs.get(this.editor.getModel().uri);
if (!currentDecorationIDs) {
return;
}

this.editor.removeDecorations(currentDecorationIDs);
WordHighlighter.storedDecorations.delete(this.editor.getModel().uri);
WordHighlighter.storedDecorationIDs.delete(this.editor.getModel().uri);

if (this.decorations.length > 0) {
this.decorations.clear();
Expand All @@ -462,7 +464,7 @@ class WordHighlighter {
continue;
}

const currentDecorationIDs = WordHighlighter.storedDecorations.get(editor.getModel().uri);
const currentDecorationIDs = WordHighlighter.storedDecorationIDs.get(editor.getModel().uri);
if (!currentDecorationIDs) {
continue;
}
Expand All @@ -483,7 +485,7 @@ class WordHighlighter {
}

for (const uri of deleteURI) {
WordHighlighter.storedDecorations.delete(uri);
WordHighlighter.storedDecorationIDs.delete(uri);
}
}

Expand Down Expand Up @@ -639,13 +641,14 @@ class WordHighlighter {
return currentModels;
}

private _run(): void {
private _run(multiFileConfigChange?: boolean): void {

let workerRequestIsValid;
const hasTextFocus = this.editor.hasTextFocus();

if (!hasTextFocus) { // new nb cell scrolled in, didChangeModel fires
if (!WordHighlighter.query) { // no previous query, nothing to highlight off of
this._stopAll();
return;
}
} else { // has text focus
Expand Down Expand Up @@ -705,10 +708,22 @@ class WordHighlighter {
this.renderDecorationsTimer = -1;
this._beginRenderDecorations();
}
} else {
} else if (isEqual(this.editor.getModel().uri, WordHighlighter.query.modelInfo?.model.uri)) { // only trigger new worker requests from the primary model that initiated the query
// case d)
// Stop all previous actions and start fresh
this._stopAll();

// check if the new queried word is contained in the range of a stored decoration for this model
if (!multiFileConfigChange) {
const currentModelDecorationRanges = this.decorations.getRanges();
for (const storedRange of currentModelDecorationRanges) {
if (storedRange.containsPosition(this.editor.getPosition())) {
return;
}
}
}

// stop all previous actions if new word is highlighted
// if we trigger the run off a setting change -> multifile highlighting, we do not want to remove decorations from this model
this._stopAll(multiFileConfigChange ? this.model : undefined);

const myRequestId = ++this.workerRequestTokenId;
this.workerRequestCompleted = false;
Expand Down Expand Up @@ -773,7 +788,7 @@ class WordHighlighter {
const newDecorations: IModelDeltaDecoration[] = [];
const uri = editor.getModel()?.uri;
if (uri && this.workerRequestValue.has(uri)) {
const oldDecorationIDs: string[] | undefined = WordHighlighter.storedDecorations.get(uri);
const oldDecorationIDs: string[] | undefined = WordHighlighter.storedDecorationIDs.get(uri);
const newDocumentHighlights = this.workerRequestValue.get(uri);
if (newDocumentHighlights) {
for (const highlight of newDocumentHighlights) {
Expand All @@ -791,7 +806,7 @@ class WordHighlighter {
editor.changeDecorations((changeAccessor) => {
newDecorationIDs = changeAccessor.deltaDecorations(oldDecorationIDs ?? [], newDecorations);
});
WordHighlighter.storedDecorations = WordHighlighter.storedDecorations.set(uri, newDecorationIDs);
WordHighlighter.storedDecorationIDs = WordHighlighter.storedDecorationIDs.set(uri, newDecorationIDs);

if (newDecorations.length > 0) {
editorHighlighterContrib.wordHighlighter?.decorations.set(newDecorations);
Expand Down
Loading