Search code examples
javascriptace-editor

Persist the ACE editor UndoManager across sessions


I would like to persist the Ace Editor's UndoManager instance across browser sessions, the way the Cloud9 IDE seems to.

I have tried to stringify the UndoManager object so that I may store it somewhere to later retrieve it like so:

 let undoManager    = editorHTML.getSession().getUndoManager();
 let undoManagerStr = JSON.stringify(undoManager);

But the stringify call throws the exception Uncaught TypeError: Converting circular structure to JSON

I've also tried extracting pieces of the object for storage:

 let redoStackStr       = JSON.stringify(undoManager.$redoStack, null, 2);
 let undoStackStr       = JSON.stringify(undoManager.$undoStack, null, 2);
 let dirtyCounter       = undoManager.dirtyCounter;

.

 let manager = new ace.UndoManager();
 if(redoStackStr && undoStackStr && dirtyCounter) {
      manager.$redoStack = JSON.parse(redoStackStr);
      manager.$undoStack = JSON.parse(undoStackStr);
      manager.dirtyCounter = dirtyCounter;
 }
 editorHTML.getSession().setUndoManager(manager)

But Ace doesn't like this at all and bombs out on CTRL-Z

I would prefer not to have to write my own file history manager when one already exists.

Edit

I was able to solve this using the answer selected below, but only after upgrading to Ace editor version 1.4.2. The above code was my attempt after analyzing the UndoManager in version 1.2.8, which is why it's so different.


Solution

  • With ace 1.4 the second method you mention works, the only problem in your example is that dirtyCounter is undefined

    UndoManager = require("ace/undomanager").UndoManager
    undoManager = editor.session.$undoManager
    var str  = JSON.stringify({ 
        $redoStack: undoManager.$redoStack,
        $undoStack: undoManager.$undoStack,
        mark: undoManager.mark,
        $rev: undoManager.$rev,
     })
     var manager = new UndoManager();
     if (str) {
         var json = JSON.parse(str)
          manager.$redoStack = json.$redoStack;
          manager.$undoStack = json.$undoStack
          manager.mark = json.mark
          manager.$rev = json.$rev
     }
     editor.getSession().setUndoManager(manager)
    

    But note that this will fail if you do this for sessions with different values.