@@ -228,52 +228,7 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
228228 const { isLive, sendTransforms, onCodeReceived } = this . props ;
229229
230230 if ( isLive && sendTransforms && ! this . receivingCode ) {
231- let code = this . currentModule . code || '' ;
232- const t = changes
233- . map ( change => {
234- const startPos = change . range . getStartPosition ( ) ;
235- const lines = code . split ( '\n' ) ;
236- let index = 0 ;
237- const totalLength = code . length ;
238- let currentLine = 0 ;
239-
240- while ( currentLine + 1 < startPos . lineNumber ) {
241- index += lines [ currentLine ] . length ;
242- index += 1 ; // Linebreak character
243- currentLine += 1 ;
244- }
245-
246- index += startPos . column - 1 ;
247-
248- const operation = new TextOperation ( ) ;
249- if ( index ) {
250- operation . retain ( index ) ;
251- }
252-
253- if ( change . rangeLength > 0 ) {
254- // Deletion
255- operation . delete ( change . rangeLength ) ;
256-
257- index += change . rangeLength ;
258- }
259- if ( change . text ) {
260- // Insertion
261- operation . insert ( change . text ) ;
262- }
263-
264- operation . retain ( Math . max ( 0 , totalLength - index ) ) ;
265-
266- if ( changes . length > 1 ) {
267- code = operation . apply ( code ) ;
268- }
269-
270- return operation ;
271- } )
272- . reduce ( ( prev , next ) => prev . compose ( next ) ) ;
273-
274- sendTransforms ( t ) ;
275- } else if ( onCodeReceived ) {
276- onCodeReceived ( ) ;
231+ this . addChangesOperation ( changes ) ;
277232 }
278233 } ) ;
279234
@@ -364,6 +319,82 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
364319 } ) ;
365320 } ;
366321
322+ changes = { code : '' , changes : [ ] } ;
323+ changeTimeout : ?TimeoutID ;
324+ /**
325+ * Throttle the changes and handle them after a desired amount of time as one array of changes
326+ */
327+ addChangesOperation = ( changes : Array < any > ) => {
328+ if ( ! this . changes . code ) {
329+ this . changes . code = this . currentModule . code || '' ;
330+ }
331+
332+ changes . forEach ( change => {
333+ this . changes . changes . push ( change ) ;
334+ } ) ;
335+
336+ if ( this . changeTimeout ) {
337+ clearTimeout ( this . changeTimeout ) ;
338+ }
339+ this . changeTimeout = setTimeout ( ( ) => {
340+ this . sendChangeOperations ( ) ;
341+ } , 10 ) ;
342+ } ;
343+
344+ sendChangeOperations = ( ) => {
345+ const { sendTransforms, isLive, onCodeReceived } = this . props ;
346+
347+ if ( sendTransforms && this . changes . changes ) {
348+ let code = this . changes . code ;
349+ const t = this . changes . changes
350+ . map ( change => {
351+ const startPos = change . range . getStartPosition ( ) ;
352+ const lines = code . split ( '\n' ) ;
353+ let index = 0 ;
354+ const totalLength = code . length ;
355+ let currentLine = 0 ;
356+
357+ while ( currentLine + 1 < startPos . lineNumber ) {
358+ index += lines [ currentLine ] . length ;
359+ index += 1 ; // Linebreak character
360+ currentLine += 1 ;
361+ }
362+
363+ index += startPos . column - 1 ;
364+
365+ const operation = new TextOperation ( ) ;
366+ if ( index ) {
367+ operation . retain ( index ) ;
368+ }
369+
370+ if ( change . rangeLength > 0 ) {
371+ // Deletion
372+ operation . delete ( change . rangeLength ) ;
373+
374+ index += change . rangeLength ;
375+ }
376+ if ( change . text ) {
377+ // Insertion
378+ operation . insert ( change . text ) ;
379+ }
380+
381+ operation . retain ( Math . max ( 0 , totalLength - index ) ) ;
382+
383+ if ( this . changes . changes . length > 1 ) {
384+ code = operation . apply ( code ) ;
385+ }
386+
387+ return operation ;
388+ } )
389+ . reduce ( ( prev , next ) => prev . compose ( next ) ) ;
390+
391+ sendTransforms ( t ) ;
392+ } else if ( ! isLive && onCodeReceived ) {
393+ onCodeReceived ( ) ;
394+ }
395+ this . changes = { code : '' , changes : [ ] } ;
396+ } ;
397+
367398 changeSandbox = (
368399 newSandbox : Sandbox ,
369400 newCurrentModule : Module ,
@@ -407,46 +438,46 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
407438 }
408439 } ;
409440
410- applyOperations = ops => {
411- const monacoEditOperations = [ ] ;
412-
413- ops . forEach ( operation => {
414- const lines = this . editor . getModel ( ) . getLinesContent ( ) ;
415-
416- let index = 0 ;
417- for ( let i = 0 ; i < operation . ops . length ; i ++ ) {
418- let op = operation . ops [ i ] ;
419- if ( TextOperation . isRetain ( op ) ) {
420- index += op ;
421- } else if ( TextOperation . isInsert ( op ) ) {
422- const { lineNumber, column } = indexToLineAndColumn ( lines , index ) ;
423- monacoEditOperations . push ( {
441+ applyOperation = ( operation : any ) => {
442+ let index = 0 ;
443+ for ( let i = 0 ; i < operation . ops . length ; i ++ ) {
444+ const op = operation . ops [ i ] ;
445+ if ( TextOperation . isRetain ( op ) ) {
446+ index += op ;
447+ } else if ( TextOperation . isInsert ( op ) ) {
448+ const { lineNumber, column } = indexToLineAndColumn (
449+ this . editor . getModel ( ) . getLinesContent ( ) ,
450+ index
451+ ) ;
452+ this . editor . getModel ( ) . applyEdits ( [
453+ {
424454 range : new this . monaco . Range (
425455 lineNumber ,
426456 column ,
427457 lineNumber ,
428458 column
429459 ) ,
430460 text : op ,
431- } ) ;
432- index += op . length ;
433- } else if ( TextOperation . isDelete ( op ) ) {
434- const from = indexToLineAndColumn ( lines , index ) ;
435- const to = indexToLineAndColumn ( lines , index - op ) ;
436- monacoEditOperations . push ( {
461+ } ,
462+ ] ) ;
463+ index += op . length ;
464+ } else if ( TextOperation . isDelete ( op ) ) {
465+ const lines = this . editor . getModel ( ) . getLinesContent ( ) ;
466+ const from = indexToLineAndColumn ( lines , index ) ;
467+ const to = indexToLineAndColumn ( lines , index - op ) ;
468+ this . editor . getModel ( ) . applyEdits ( [
469+ {
437470 range : new this . monaco . Range (
438471 from . lineNumber ,
439472 from . column ,
440473 to . lineNumber ,
441474 to . column
442475 ) ,
443476 text : '' ,
444- } ) ;
445- }
477+ } ,
478+ ] ) ;
446479 }
447- } ) ;
448-
449- this . editor . getModel ( ) . applyEdits ( monacoEditOperations ) ;
480+ }
450481 } ;
451482
452483 changeDependencies = (
@@ -770,6 +801,9 @@ class MonacoEditor extends React.Component<Props, State> implements Editor {
770801 // the old extraLib definition and defining a new one.
771802 modelCache [ currentId ] . lib . dispose ( ) ;
772803 modelCache [ currentId ] . lib = this . addLib ( currentModule . code || '' , path ) ;
804+
805+ // Reset changes
806+ this . changes = { code : '' , changes : [ ] } ;
773807 }
774808 }
775809
0 commit comments