@@ -23,6 +23,17 @@ import { IHashCalculateService } from '@opensumi/ide-core-common/lib/hash-calcul
2323import { monaco , URI as MonacoURI } from '@opensumi/ide-monaco/lib/browser/monaco-api' ;
2424import { EOL , EndOfLineSequence , ITextModel } from '@opensumi/ide-monaco/lib/browser/monaco-api/types' ;
2525import { 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
2738import {
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