Skip to content

Commit b27162e

Browse files
authored
feat: optimize editor updateContent logic (#2097)
1 parent 695ae3d commit b27162e

1 file changed

Lines changed: 101 additions & 10 deletions

File tree

packages/editor/src/browser/doc-model/editor-document-model.ts

Lines changed: 101 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calcul
2323
import { monaco, URI as MonacoURI } from '@opensumi/ide-monaco/lib/browser/monaco-api';
2424
import { EOL, EndOfLineSequence, ITextModel } from '@opensumi/ide-monaco/lib/browser/monaco-api/types';
2525
import { IMessageService } from '@opensumi/ide-overlay';
26+
import {
27+
EditOperation,
28+
ISingleEditOperation,
29+
} from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/editOperation';
30+
import { Range } from '@opensumi/monaco-editor-core/esm/vs/editor/common/core/range';
31+
import {
32+
ITextBuffer,
33+
EndOfLinePreference,
34+
DefaultEndOfLine,
35+
} from '@opensumi/monaco-editor-core/esm/vs/editor/common/model';
36+
import { createTextBuffer } from '@opensumi/monaco-editor-core/esm/vs/editor/common/model/textModel';
2637

2738
import {
2839
IDocCache,
@@ -468,24 +479,104 @@ export class EditorDocumentModel extends Disposable implements IEditorDocumentMo
468479
}
469480

470481
updateContent(content: string, eol?: EOL, setPersist = false) {
471-
this.monacoModel.pushEditOperations(
472-
[],
473-
[
474-
{
475-
range: this.monacoModel.getFullModelRange(),
476-
text: content,
477-
},
478-
],
479-
() => [],
480-
);
481482
if (eol) {
482483
this.eol = eol;
483484
}
485+
486+
const defaultEOL = this.eol === EOL.CRLF ? DefaultEndOfLine.CRLF : DefaultEndOfLine.LF;
487+
const { textBuffer, disposable } = createTextBuffer(content, defaultEOL);
488+
// 计算新旧 Monaco 文档的差异,避免全量更新导致的高亮闪烁问题
489+
const singleEditOperation = EditorDocumentModel._computeEdits(this.monacoModel, textBuffer);
490+
this.monacoModel.pushEditOperations([], singleEditOperation, () => []);
491+
484492
if (setPersist) {
485493
this.setPersist(this.monacoModel.getAlternativeVersionId());
486494
this.baseContent = content;
487495
this.dirtyChanges = [];
488496
}
497+
disposable.dispose();
498+
}
499+
500+
/**
501+
* Compute edits to bring `model` to the state of `textSource`.
502+
*/
503+
public static _computeEdits(model: ITextModel, textBuffer: ITextBuffer): ISingleEditOperation[] {
504+
const modelLineCount = model.getLineCount();
505+
const textBufferLineCount = textBuffer.getLineCount();
506+
const commonPrefix = this._commonPrefix(model, modelLineCount, 1, textBuffer, textBufferLineCount, 1);
507+
508+
if (modelLineCount === textBufferLineCount && commonPrefix === modelLineCount) {
509+
// equality case
510+
return [];
511+
}
512+
513+
const commonSuffix = this._commonSuffix(
514+
model,
515+
modelLineCount - commonPrefix,
516+
commonPrefix,
517+
textBuffer,
518+
textBufferLineCount - commonPrefix,
519+
commonPrefix,
520+
);
521+
522+
let oldRange: Range;
523+
let newRange: Range;
524+
if (commonSuffix > 0) {
525+
oldRange = new Range(commonPrefix + 1, 1, modelLineCount - commonSuffix + 1, 1);
526+
newRange = new Range(commonPrefix + 1, 1, textBufferLineCount - commonSuffix + 1, 1);
527+
} else if (commonPrefix > 0) {
528+
oldRange = new Range(
529+
commonPrefix,
530+
model.getLineMaxColumn(commonPrefix),
531+
modelLineCount,
532+
model.getLineMaxColumn(modelLineCount),
533+
);
534+
newRange = new Range(
535+
commonPrefix,
536+
1 + textBuffer.getLineLength(commonPrefix),
537+
textBufferLineCount,
538+
1 + textBuffer.getLineLength(textBufferLineCount),
539+
);
540+
} else {
541+
oldRange = new Range(1, 1, modelLineCount, model.getLineMaxColumn(modelLineCount));
542+
newRange = new Range(1, 1, textBufferLineCount, 1 + textBuffer.getLineLength(textBufferLineCount));
543+
}
544+
545+
return [EditOperation.replaceMove(oldRange, textBuffer.getValueInRange(newRange, EndOfLinePreference.TextDefined))];
546+
}
547+
548+
private static _commonPrefix(
549+
a: ITextModel,
550+
aLen: number,
551+
aDelta: number,
552+
b: ITextBuffer,
553+
bLen: number,
554+
bDelta: number,
555+
): number {
556+
const maxResult = Math.min(aLen, bLen);
557+
558+
let result = 0;
559+
for (let i = 0; i < maxResult && a.getLineContent(aDelta + i) === b.getLineContent(bDelta + i); i++) {
560+
result++;
561+
}
562+
return result;
563+
}
564+
565+
private static _commonSuffix(
566+
a: ITextModel,
567+
aLen: number,
568+
aDelta: number,
569+
b: ITextBuffer,
570+
bLen: number,
571+
bDelta: number,
572+
): number {
573+
const maxResult = Math.min(aLen, bLen);
574+
575+
let result = 0;
576+
for (let i = 0; i < maxResult && a.getLineContent(aDelta + aLen - i) === b.getLineContent(bDelta + bLen - i); i++) {
577+
result++;
578+
}
579+
return result;
489580
}
490581

491582
set baseContent(content: string) {

0 commit comments

Comments
 (0)