1- import { Dispatcher } from './Dispatcher' ;
1+ import { Dispatcher , CommitParams } from './Dispatcher' ;
22import { JWPlugin , JWPluginConfig } from './JWPlugin' ;
33import { Core } from './Core' ;
44import { ContextManager } from './ContextManager' ;
@@ -10,6 +10,9 @@ import { ContainerNode } from './VNodes/ContainerNode';
1010import { AtomicNode } from './VNodes/AtomicNode' ;
1111import { SeparatorNode } from './VNodes/SeparatorNode' ;
1212import { ModeIdentifier , ModeDefinition , Mode } from './Mode' ;
13+ import { Memory } from './Memory/Memory' ;
14+ import { makeVersionable } from './Memory/Versionable' ;
15+ import { VersionableArray } from './Memory/VersionableArray' ;
1316
1417export enum EditorStage {
1518 CONFIGURATION = 'configuration' ,
@@ -68,7 +71,10 @@ export class JWEditor {
6871 plugins : [ ] ,
6972 loadables : { } ,
7073 } ;
71- selection = new VSelection ( this ) ;
74+ memory : Memory ;
75+ memoryID = 0 ;
76+ memoryInfo : { commandNames : string [ ] } ;
77+ selection : VSelection ;
7278 loaders : Record < string , Loader > = { } ;
7379 private mutex = Promise . resolve ( ) ;
7480 // Use a set so that when asynchronous functions are called we ensure that
@@ -86,6 +92,7 @@ export class JWEditor {
8692 constructor ( ) {
8793 this . dispatcher = new Dispatcher ( this ) ;
8894 this . plugins = new Map ( ) ;
95+ this . selection = new VSelection ( this ) ;
8996 this . contextManager = new ContextManager ( this ) ;
9097
9198 this . nextEventMutex = this . nextEventMutex . bind ( this ) ;
@@ -130,9 +137,18 @@ export class JWEditor {
130137 this . setMode ( this . configuration . mode ) ;
131138 }
132139
133- for ( const plugin of this . plugins . values ( ) ) {
134- await plugin . start ( ) ;
135- }
140+ // create memory
141+ this . memoryInfo = makeVersionable ( { commandNames : [ ] } ) ;
142+ this . memory = new Memory ( ) ;
143+ this . memory . linkToMemory ( this . memoryInfo ) ;
144+ this . memory . create ( this . memoryID . toString ( ) ) ;
145+
146+ // Start all plugins in the first memory slice.
147+ return this . execBatch ( async ( ) => {
148+ for ( const plugin of this . plugins . values ( ) ) {
149+ await plugin . start ( ) ;
150+ }
151+ } ) ;
136152 }
137153
138154 //--------------------------------------------------------------------------
@@ -303,11 +319,16 @@ export class JWEditor {
303319 }
304320 }
305321
306- async execBatch ( callback : ( ) => Promise < void > ) : Promise < void > {
307- this . preventRenders . add ( callback ) ;
308- await callback ( ) ;
309- this . preventRenders . delete ( callback ) ;
310- await this . dispatcher . dispatchHooks ( '@batch' ) ;
322+ /**
323+ * Execute arbitrary code in `callback`, then dispatch the commit event.
324+ *
325+ * @param callback
326+ */
327+ async execBatch ( callback : ( ) => Promise < void > | void ) : Promise < void > {
328+ return this . _execBatchInMemory ( ( ) => {
329+ this . memoryInfo . commandNames . push ( '@batch' ) ;
330+ return callback ( ) ;
331+ } ) ;
311332 }
312333
313334 /**
@@ -320,26 +341,61 @@ export class JWEditor {
320341 commandName : C ,
321342 params ?: CommandParams < P , C > ,
322343 ) : Promise < void > {
323- return await this . dispatcher . dispatch ( commandName , params ) ;
344+ await this . _execBatchInMemory ( ( ) => {
345+ this . memoryInfo . commandNames . push ( commandName ) ;
346+ return this . dispatcher . dispatch ( commandName , params ) ;
347+ } ) ;
324348 }
325349
326350 /**
327- * Execute arbitrary code in `callback`, then dispatch the event.
351+ * Execute arbitrary code in `callback` in a free memory slice.
352+ * Return true if we open a memory slice.
353+ *
354+ * TODO: create memory for each plugin who use the command then use
355+ * squashInto(winnerSliceKey, winnerSliceKey, newMasterSliceKey)
356+ *
357+ * @param callback
328358 */
329- async execCustomCommand < P extends JWPlugin , C extends Commands < P > = Commands < P > > (
330- callback : ( ) => Promise < void > ,
331- ) : Promise < void > {
359+ private async _execBatchInMemory ( callback : ( ) => Promise < void > | void ) : Promise < void > {
360+ const isFrozen = this . memory . isFrozen ( ) ;
361+ const previousSlice = ( this . memoryID - 1 ) . toString ( ) ;
362+ const memorySlice = this . memoryID . toString ( ) ;
363+ if ( isFrozen ) {
364+ // Switch to the next memory slice (unfreeze the memory).
365+ this . memory . switchTo ( memorySlice ) ;
366+ this . memoryInfo . commandNames = new VersionableArray ( ) ;
367+ }
332368 await callback ( ) ;
333- await this . dispatcher . dispatchHooks ( '@custom' ) ;
369+ if ( isFrozen ) {
370+ // Check if it's frozen for calling execCommand inside a call of
371+ // execCommand Create the next memory slice (and freeze the
372+ // current memory).
373+ this . memoryID ++ ;
374+ this . memory . create ( this . memoryID . toString ( ) ) ;
375+
376+ // Send the commit message with a froozen memory.
377+ const diff : CommitParams = this . memory . getChanges ( previousSlice , memorySlice ) ;
378+ await this . dispatcher . dispatchHooks ( '@commit' , diff ) ;
379+ }
334380 }
335381
336382 /**
337383 * Stop this editor instance.
338384 */
339385 async stop ( ) : Promise < void > {
386+ if ( this . memory ) {
387+ // Unfreeze the memory.
388+ this . memory . create ( 'stop' ) ;
389+ this . memory . switchTo ( 'stop' ) ;
390+ this . memory = null ;
391+ }
340392 for ( const plugin of this . plugins . values ( ) ) {
341393 await plugin . stop ( ) ;
342394 }
395+ this . plugins . clear ( ) ;
396+ this . dispatcher = new Dispatcher ( this ) ;
397+ this . selection = new VSelection ( this ) ;
398+ this . contextManager = new ContextManager ( this ) ;
343399 // Clear loaders.
344400 this . loaders = { } ;
345401 this . _stage = EditorStage . CONFIGURATION ;
0 commit comments