Merge pull request #130983 from microsoft/hediet/fix-stack-overflow

Early return CursorController.setState when there are no changes
This commit is contained in:
Alexandru Dima 2021-08-19 10:49:13 +02:00 committed by GitHub
commit 24caafb06d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -332,7 +332,15 @@ export class CursorsController extends Disposable {
if (e instanceof ModelInjectedTextChangedEvent) {
// If injected texts change, the view positions of all cursors need to be updated.
const selectionsFromMarkers = this._cursors.readSelectionFromMarkers();
this.setStates(eventsCollector, 'modelChange', CursorChangeReason.RecoverFromMarkers, CursorState.fromModelSelections(selectionsFromMarkers));
const newState = CursorState.fromModelSelections(selectionsFromMarkers);
if (didStateChange(this.getCursorStates(), newState || [])) {
// setStates might remove markers, which could trigger a decoration change.
// If there are injected text decorations for that line, `onModelContentChanged` is emitted again
// and an endless recursion happens.
// This is why we only call setStates if we really need to (this fixes recursion).
this.setStates(eventsCollector, 'modelChange', CursorChangeReason.RecoverFromMarkers, newState);
}
} else {
this._knownModelVersionId = e.versionId;
if (this._isHandling) {
@ -719,6 +727,28 @@ export class CursorsController extends Disposable {
}
}
function didStateChange(currentStates: CursorState[], newStates: PartialCursorState[]): boolean {
if (currentStates.length !== newStates.length) {
return true;
}
for (let i = 0; i < currentStates.length; i++) {
const curState = currentStates[i];
const newState = newStates[i];
if (newState.modelState) {
if (!newState.modelState.equals(curState.modelState)) {
return true;
}
}
if (newState.viewState) {
if (!newState.viewState.equals(curState.viewState)) {
return true;
}
}
}
return false;
}
interface IExecContext {
readonly model: ITextModel;
readonly selectionsBefore: Selection[];