Reduce usages of editor.deltaDecorations (#149718)

This commit is contained in:
Alexandru Dima
2022-05-17 16:06:59 +02:00
committed by GitHub
parent caa463191f
commit 8463cd27b3
10 changed files with 79 additions and 78 deletions
@@ -2179,6 +2179,10 @@ class EditorDecorationsCollection implements editorCommon.IEditorDecorationsColl
return result;
}
public has(decoration: IModelDecoration): boolean {
return this._decorationIds.includes(decoration.id);
}
public clear(): void {
if (this._decorationIds.length === 0) {
// nothing to do
+5 -1
View File
@@ -11,7 +11,7 @@ import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ISelection, Selection } from 'vs/editor/common/core/selection';
import { IModelDecorationsChangeAccessor, ITextModel, OverviewRulerLane, TrackedRangeStickiness, IValidEditOperation, IModelDeltaDecoration } from 'vs/editor/common/model';
import { IModelDecorationsChangeAccessor, ITextModel, OverviewRulerLane, TrackedRangeStickiness, IValidEditOperation, IModelDeltaDecoration, IModelDecoration } from 'vs/editor/common/model';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { IDimension } from 'vs/editor/common/core/dimension';
import { IModelDecorationsChangedEvent } from 'vs/editor/common/textModelEvents';
@@ -538,6 +538,10 @@ export interface IEditorDecorationsCollection {
* Get all ranges for decorations.
*/
getRanges(): Range[];
/**
* Determine if a decoration is in this collection.
*/
has(decoration: IModelDecoration): boolean;
/**
* Replace all previous decorations with `newDecorations`.
*/
@@ -13,7 +13,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { Selection } from 'vs/editor/common/core/selection';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IEditorContribution, IEditorDecorationsCollection } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { IModelDeltaDecoration, OverviewRulerLane, TrackedRangeStickiness } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
@@ -105,7 +105,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont
private _lastBracketsData: BracketsData[];
private _lastVersionId: number;
private _decorations: string[];
private readonly _decorations: IEditorDecorationsCollection;
private readonly _updateBracketsSoon: RunOnceScheduler;
private _matchBrackets: 'never' | 'near' | 'always';
@@ -116,7 +116,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont
this._editor = editor;
this._lastBracketsData = [];
this._lastVersionId = 0;
this._decorations = [];
this._decorations = this._editor.createDecorationsCollection();
this._updateBracketsSoon = this._register(new RunOnceScheduler(() => this._updateBrackets(), 50));
this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);
@@ -136,7 +136,6 @@ export class BracketMatchingController extends Disposable implements IEditorCont
}));
this._register(editor.onDidChangeModel((e) => {
this._lastBracketsData = [];
this._decorations = [];
this._updateBracketsSoon.schedule();
}));
this._register(editor.onDidChangeModelLanguageConfiguration((e) => {
@@ -146,7 +145,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont
this._register(editor.onDidChangeConfiguration((e) => {
if (e.hasChanged(EditorOption.matchBrackets)) {
this._matchBrackets = this._editor.getOption(EditorOption.matchBrackets);
this._decorations = this._editor.deltaDecorations(this._decorations, []);
this._decorations.clear();
this._lastBracketsData = [];
this._lastVersionId = 0;
this._updateBracketsSoon.schedule();
@@ -285,7 +284,7 @@ export class BracketMatchingController extends Disposable implements IEditorCont
}
}
this._decorations = this._editor.deltaDecorations(this._decorations, newDecorations);
this._decorations.set(newDecorations);
}
private _recomputeBrackets(): void {
@@ -16,7 +16,7 @@ import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { Position } from 'vs/editor/common/core/position';
import { Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IModelDeltaDecoration } from 'vs/editor/common/model';
import { IModelDecoration, IModelDeltaDecoration } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { IFeatureDebounceInformation, ILanguageFeatureDebounceService } from 'vs/editor/common/services/languageFeatureDebounce';
import { ILanguageFeaturesService } from 'vs/editor/common/services/languageFeatures';
@@ -41,7 +41,7 @@ export class ColorDetector extends Disposable implements IEditorContribution {
private _decorationsIds: string[] = [];
private _colorDatas = new Map<string, IColorData>();
private _colorDecoratorIds: ReadonlySet<string> = new Set<string>();
private readonly _colorDecoratorIds = this._editor.createDecorationsCollection();
private _isEnabled: boolean;
@@ -215,12 +215,12 @@ export class ColorDetector extends Disposable implements IEditorContribution {
});
}
this._colorDecoratorIds = new Set(this._editor.deltaDecorations([...this._colorDecoratorIds], decorations));
this._colorDecoratorIds.set(decorations);
}
private removeAllDecorations(): void {
this._decorationsIds = this._editor.deltaDecorations(this._decorationsIds, []);
this._colorDecoratorIds = new Set(this._editor.deltaDecorations([...this._colorDecoratorIds], []));
this._colorDecoratorIds.clear();
this._colorDecorationClassRefs.clear();
}
@@ -241,8 +241,8 @@ export class ColorDetector extends Disposable implements IEditorContribution {
return this._colorDatas.get(decorations[0].id)!;
}
isColorDecorationId(decorationId: string): boolean {
return this._colorDecoratorIds.has(decorationId);
isColorDecoration(decoration: IModelDecoration): boolean {
return this._colorDecoratorIds.has(decoration);
}
}
@@ -70,7 +70,7 @@ export class ColorHoverParticipant implements IEditorHoverParticipant<ColorHover
return [];
}
for (const d of lineDecorations) {
if (!colorDetector.isColorDecorationId(d.id)) {
if (!colorDetector.isColorDecoration(d)) {
continue;
}
@@ -19,7 +19,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService
import { EditorOption } from 'vs/editor/common/config/editorOptions';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IEditorContribution, IEditorDecorationsCollection } from 'vs/editor/common/editorCommon';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { IModelDeltaDecoration, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
@@ -70,7 +70,9 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
private _currentRequestPosition: Position | null;
private _currentRequestModelVersion: number | null;
private _currentDecorations: string[]; // The one at index 0 is the reference one
private _currentDecorations: IEditorDecorationsCollection; // The one at index 0 is the reference one
private _syncRangesToken: number = 0;
private _languageWordPattern: RegExp | null;
private _currentWordPattern: RegExp | null;
private _ignoreChangeEvent: boolean;
@@ -91,7 +93,7 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
this._visibleContextKey = CONTEXT_ONTYPE_RENAME_INPUT_VISIBLE.bindTo(contextKeyService);
this._debounceInformation = languageFeatureDebounceService.for(this._providers, 'Linked Editing', { min: 200 });
this._currentDecorations = [];
this._currentDecorations = this._editor.createDecorationsCollection();
this._languageWordPattern = null;
this._currentWordPattern = null;
this._ignoreChangeEvent = false;
@@ -147,8 +149,8 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
this._rangeUpdateTriggerPromise = rangeUpdateScheduler.trigger(() => this.updateRanges(), this._debounceDuration ?? this._debounceInformation.get(model));
};
const rangeSyncScheduler = new Delayer(0);
const triggerRangeSync = (decorations: string[]) => {
this._rangeSyncTriggerPromise = rangeSyncScheduler.trigger(() => this._syncRanges(decorations));
const triggerRangeSync = (token: number) => {
this._rangeSyncTriggerPromise = rangeSyncScheduler.trigger(() => this._syncRanges(token));
};
this._localToDispose.add(this._editor.onDidChangeCursorPosition(() => {
triggerRangeUpdate();
@@ -156,9 +158,9 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
this._localToDispose.add(this._editor.onDidChangeModelContent((e) => {
if (!this._ignoreChangeEvent) {
if (this._currentDecorations.length > 0) {
const referenceRange = model.getDecorationRange(this._currentDecorations[0]);
const referenceRange = this._currentDecorations.getRange(0);
if (referenceRange && e.changes.every(c => referenceRange.intersectRanges(c.range))) {
triggerRangeSync(this._currentDecorations);
triggerRangeSync(this._syncRangesToken);
return;
}
}
@@ -174,15 +176,15 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
this.updateRanges();
}
private _syncRanges(decorations: string[]): void {
private _syncRanges(token: number): void {
// dalayed invocation, make sure we're still on
if (!this._editor.hasModel() || decorations !== this._currentDecorations || decorations.length === 0) {
if (!this._editor.hasModel() || token !== this._syncRangesToken || this._currentDecorations.length === 0) {
// nothing to do
return;
}
const model = this._editor.getModel();
const referenceRange = model.getDecorationRange(decorations[0]);
const referenceRange = this._currentDecorations.getRange(0);
if (!referenceRange || referenceRange.startLineNumber !== referenceRange.endLineNumber) {
return this.clearRanges();
@@ -198,8 +200,8 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
}
let edits: ISingleEditOperation[] = [];
for (let i = 1, len = decorations.length; i < len; i++) {
const mirrorRange = model.getDecorationRange(decorations[i]);
for (let i = 1, len = this._currentDecorations.length; i < len; i++) {
const mirrorRange = this._currentDecorations.getRange(i);
if (!mirrorRange) {
continue;
}
@@ -255,7 +257,7 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
public clearRanges(): void {
this._visibleContextKey.set(false);
this._currentDecorations = this._editor.deltaDecorations(this._currentDecorations, []);
this._currentDecorations.clear();
if (this._currentRequest) {
this._currentRequest.cancel();
this._currentRequest = null;
@@ -290,8 +292,8 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
if (position.equals(this._currentRequestPosition)) {
return; // same position
}
if (this._currentDecorations && this._currentDecorations.length > 0) {
const range = model.getDecorationRange(this._currentDecorations[0]);
if (this._currentDecorations.length > 0) {
const range = this._currentDecorations.getRange(0);
if (range && range.containsPosition(position)) {
return; // just moving inside the existing primary range
}
@@ -341,7 +343,8 @@ export class LinkedEditingContribution extends Disposable implements IEditorCont
const decorations: IModelDeltaDecoration[] = ranges.map(range => ({ range: range, options: LinkedEditingContribution.DECORATION }));
this._visibleContextKey.set(true);
this._currentDecorations = this._editor.deltaDecorations(this._currentDecorations, decorations);
this._currentDecorations.set(decorations);
this._syncRangesToken++; // cancel any pending syncRanges call
} catch (err) {
if (!isCancellationError(err)) {
onUnexpectedError(err);
@@ -179,9 +179,9 @@ export class UnicodeHighlighter extends Disposable implements IEditorContributio
}
}
public getDecorationInfo(decorationId: string): UnicodeHighlighterDecorationInfo | null {
public getDecorationInfo(decoration: IModelDecoration): UnicodeHighlighterDecorationInfo | null {
if (this._highlighter) {
return this._highlighter.getDecorationInfo(decorationId);
return this._highlighter.getDecorationInfo(decoration);
}
return null;
}
@@ -214,7 +214,7 @@ function resolveOptions(trusted: boolean, options: InternalUnicodeHighlightOptio
class DocumentUnicodeHighlighter extends Disposable {
private readonly _model: ITextModel = this._editor.getModel();
private readonly _updateSoon: RunOnceScheduler;
private _decorationIds = new Set<string>();
private _decorations = this._editor.createDecorationsCollection();
constructor(
private readonly _editor: IActiveCodeEditor,
@@ -233,7 +233,7 @@ class DocumentUnicodeHighlighter extends Disposable {
}
public override dispose() {
this._decorationIds = new Set(this._model.deltaDecorations(Array.from(this._decorationIds), []));
this._decorations.clear();
super.dispose();
}
@@ -243,7 +243,7 @@ class DocumentUnicodeHighlighter extends Disposable {
}
if (!this._model.mightContainNonBasicASCII()) {
this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), []));
this._decorations.clear();
return;
}
@@ -271,31 +271,21 @@ class DocumentUnicodeHighlighter extends Disposable {
});
}
}
this._decorationIds = new Set(this._editor.deltaDecorations(
Array.from(this._decorationIds),
decorations
));
this._decorations.set(decorations);
});
}
public getDecorationInfo(decorationId: string): UnicodeHighlighterDecorationInfo | null {
if (!this._decorationIds.has(decorationId)) {
public getDecorationInfo(decoration: IModelDecoration): UnicodeHighlighterDecorationInfo | null {
if (!this._decorations.has(decoration)) {
return null;
}
const model = this._editor.getModel();
const range = model.getDecorationRange(decorationId)!;
const decoration = {
range: range,
options: Decorations.instance.getDecorationFromOptions(this._options),
id: decorationId,
ownerId: 0,
};
if (
!isModelDecorationVisible(model, decoration)
) {
return null;
}
const text = model.getValueInRange(range);
const text = model.getValueInRange(decoration.range);
return {
reason: computeReason(text, this._options)!,
inComment: isModelDecorationInComment(model, decoration),
@@ -308,7 +298,7 @@ class ViewportUnicodeHighlighter extends Disposable {
private readonly _model: ITextModel = this._editor.getModel();
private readonly _updateSoon: RunOnceScheduler;
private _decorationIds = new Set<string>();
private readonly _decorations = this._editor.createDecorationsCollection();
constructor(
private readonly _editor: IActiveCodeEditor,
@@ -336,7 +326,7 @@ class ViewportUnicodeHighlighter extends Disposable {
}
public override dispose() {
this._decorationIds = new Set(this._model.deltaDecorations(Array.from(this._decorationIds), []));
this._decorations.clear();
super.dispose();
}
@@ -346,7 +336,7 @@ class ViewportUnicodeHighlighter extends Disposable {
}
if (!this._model.mightContainNonBasicASCII()) {
this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), []));
this._decorations.clear();
return;
}
@@ -379,22 +369,15 @@ class ViewportUnicodeHighlighter extends Disposable {
}
this._updateState(totalResult);
this._decorationIds = new Set(this._editor.deltaDecorations(Array.from(this._decorationIds), decorations));
this._decorations.set(decorations);
}
public getDecorationInfo(decorationId: string): UnicodeHighlighterDecorationInfo | null {
if (!this._decorationIds.has(decorationId)) {
public getDecorationInfo(decoration: IModelDecoration): UnicodeHighlighterDecorationInfo | null {
if (!this._decorations.has(decoration)) {
return null;
}
const model = this._editor.getModel();
const range = model.getDecorationRange(decorationId)!;
const text = model.getValueInRange(range);
const decoration = {
range: range,
options: Decorations.instance.getDecorationFromOptions(this._options),
id: decorationId,
ownerId: 0,
};
const text = model.getValueInRange(decoration.range);
if (!isModelDecorationVisible(model, decoration)) {
return null;
}
@@ -449,7 +432,7 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa
let index = 300;
for (const d of lineDecorations) {
const highlightInfo = unicodeHighlighter.getDecorationInfo(d.id);
const highlightInfo = unicodeHighlighter.getDecorationInfo(d);
if (!highlightInfo) {
continue;
}
+4
View File
@@ -2553,6 +2553,10 @@ declare namespace monaco.editor {
* Get all ranges for decorations.
*/
getRanges(): Range[];
/**
* Determine if a decoration is in this collection.
*/
has(decoration: IModelDecoration): boolean;
/**
* Replace all previous decorations with `newDecorations`.
*/
+5 -2
View File
@@ -47,8 +47,11 @@ export class RangeHighlightDecorations extends Disposable {
}
removeHighlightRange() {
if (this.editor?.getModel() && this.rangeHighlightDecorationId) {
this.editor.deltaDecorations([this.rangeHighlightDecorationId], []);
if (this.editor && this.rangeHighlightDecorationId) {
const decorationId = this.rangeHighlightDecorationId;
this.editor.changeDecorations((accessor) => {
accessor.removeDecoration(decorationId);
});
this._onHighlightRemoved.fire();
}
@@ -11,7 +11,7 @@ import severity from 'vs/base/common/severity';
import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions';
import { Range } from 'vs/editor/common/core/range';
import { ICodeEditor, IEditorMouseEvent, MouseTargetType, IContentWidget, IActiveCodeEditor, IContentWidgetPosition, ContentWidgetPositionPreference } from 'vs/editor/browser/editorBrowser';
import { IModelDecorationOptions, IModelDeltaDecoration, TrackedRangeStickiness, ITextModel, OverviewRulerLane, IModelDecorationOverviewRulerOptions } from 'vs/editor/common/model';
import { IModelDecorationOptions, TrackedRangeStickiness, ITextModel, OverviewRulerLane, IModelDecorationOverviewRulerOptions } from 'vs/editor/common/model';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -158,7 +158,7 @@ async function createCandidateDecorations(model: ITextModel, breakpointDecoratio
export class BreakpointEditorContribution implements IBreakpointEditorContribution {
private breakpointHintDecoration: string[] = [];
private breakpointHintDecoration: string | null = null;
private breakpointWidget: BreakpointWidget | undefined;
private breakpointWidgetVisible: IContextKey<boolean>;
private toDispose: IDisposable[] = [];
@@ -443,20 +443,21 @@ export class BreakpointEditorContribution implements IBreakpointEditorContributi
}
private ensureBreakpointHintDecoration(showBreakpointHintAtLineNumber: number): void {
const newDecoration: IModelDeltaDecoration[] = [];
if (showBreakpointHintAtLineNumber !== -1) {
newDecoration.push({
options: breakpointHelperDecoration,
range: {
this.editor.changeDecorations((accessor) => {
if (this.breakpointHintDecoration) {
accessor.removeDecoration(this.breakpointHintDecoration);
this.breakpointHintDecoration = null;
}
if (showBreakpointHintAtLineNumber !== -1) {
this.breakpointHintDecoration = accessor.addDecoration({
startLineNumber: showBreakpointHintAtLineNumber,
startColumn: 1,
endLineNumber: showBreakpointHintAtLineNumber,
endColumn: 1
}
});
}
this.breakpointHintDecoration = this.editor.deltaDecorations(this.breakpointHintDecoration, newDecoration);
}, breakpointHelperDecoration
);
}
});
}
private async setDecorations(): Promise<void> {