@@ -7,6 +7,7 @@ import * as math from 'lib0/math.js'
77import * as Y from 'yjs'
88import * as func from 'lib0/function.js'
99import * as eventloop from 'lib0/eventloop.js'
10+ import * as diff from 'lib0/diff.js'
1011import CodeMirror from 'codemirror'
1112
1213export const cmOrigin = 'prosemirror-binding'
@@ -77,16 +78,25 @@ const typeObserver = (binding, event) => {
7778 } )
7879}
7980
80- const targetObserver = ( binding , change ) => {
81+ const targetObserver = ( binding , changes ) => {
8182 binding . _mux ( ( ) => {
8283 binding . doc . transact ( ( ) => {
83- const start = binding . cmDoc . indexFromPos ( change . from )
84- const delLen = change . removed . map ( s => s . length ) . reduce ( math . add ) + change . removed . length - 1
85- if ( delLen > 0 ) {
86- binding . type . delete ( start , delLen )
87- }
88- if ( change . text . length > 0 ) {
89- binding . type . insert ( start , change . text . join ( '\n' ) )
84+ if ( changes . length > 1 ) {
85+ // If there are several consecutive changes, we can't reliably compute the positions anymore. See y-codemirror#11
86+ // Instead, we will compute the diff and apply the changes
87+ const d = diff . simpleDiffString ( binding . type . toString ( ) , binding . cmDoc . getValue ( ) )
88+ binding . type . delete ( d . index , d . remove )
89+ binding . type . insert ( d . index , d . insert )
90+ } else {
91+ const change = changes [ 0 ]
92+ const start = binding . cmDoc . indexFromPos ( change . from )
93+ const delLen = change . removed . map ( s => s . length ) . reduce ( math . add ) + change . removed . length - 1
94+ if ( delLen > 0 ) {
95+ binding . type . delete ( start , delLen )
96+ }
97+ if ( change . text . length > 0 ) {
98+ binding . type . insert ( start , change . text . join ( '\n' ) )
99+ }
90100 }
91101 } , binding )
92102 } )
@@ -231,7 +241,11 @@ export class CodemirrorBinding {
231241 cmDoc . setValue ( textType . toString ( ) )
232242 // observe type and target
233243 this . _typeObserver = event => typeObserver ( this , event )
234- this . _targetObserver = ( _ , change ) => targetObserver ( this , change )
244+ this . _targetObserver = ( instance , changes ) => {
245+ if ( instance . getDoc ( ) === cmDoc ) {
246+ targetObserver ( this , changes )
247+ }
248+ }
235249 this . _cursors = new Map ( )
236250 this . _changedCursors = new Set ( )
237251 this . _debounceCursorEvent = eventloop . createDebouncer ( 10 )
@@ -258,19 +272,21 @@ export class CodemirrorBinding {
258272 }
259273 this . _cursorListener = ( ) => {
260274 if ( codeMirror . getDoc ( ) === cmDoc ) {
261- codemirrorCursorActivity ( doc , codeMirror , textType , awareness )
275+ setTimeout ( ( ) => {
276+ codemirrorCursorActivity ( doc , codeMirror , textType , awareness )
277+ } , 0 )
262278 }
263279 }
264280 this . _blurListeer = ( ) => awareness . setLocalStateField ( 'cursor' , null )
265281
266282 textType . observe ( this . _typeObserver )
267283 // @ts -ignore
268- cmDoc . on ( 'change ' , this . _targetObserver )
284+ codeMirror . on ( 'changes ' , this . _targetObserver )
269285 if ( awareness ) {
270286 codeMirror . on ( 'swapDoc' , this . _blurListeer )
271287 awareness . on ( 'change' , this . _awarenessListener )
272288 // @ts -ignore
273- cmDoc . on ( 'cursorActivity' , this . _cursorListener )
289+ codeMirror . on ( 'cursorActivity' , this . _cursorListener )
274290 codeMirror . on ( 'blur' , this . _blurListeer )
275291 codeMirror . on ( 'focus' , this . _cursorListener )
276292 }
@@ -280,9 +296,9 @@ export class CodemirrorBinding {
280296 this . type . unobserve ( this . _typeObserver )
281297 this . cm . off ( 'swapDoc' , this . _blurListeer )
282298 // @ts -ignore
283- this . cmDoc . off ( 'change ' , this . _targetObserver )
299+ this . cm . off ( 'changes ' , this . _targetObserver )
284300 // @ts -ignore
285- this . cmDoc . off ( 'cursorActivity' , this . _cursorListener )
301+ this . cm . off ( 'cursorActivity' , this . _cursorListener )
286302 this . cm . off ( 'focus' , this . _cursorListener )
287303 this . cm . off ( 'blur' , this . _blurListeer )
288304 if ( this . awareness ) {
0 commit comments