Improve history serialization and persistence #135
Description
@as-cii I wanted to some up some of my thoughts on history serialization in case you're interested. Here's a potential set of steps that I think could put is in a better spot both design-wise and in terms of performance.
Compact Binary Patch Format
- Switch the undo/redo stack to store patches rather than the current list of temporally-ordered changes.
- Implement
Patch.prototype.compact
that converts the internal representation of the patch from a tree to a flat buffer. This format would only supportgetChanges
by directly iterating the serialized data, which is easy with that library. Call this method at the end of each transaction to keep the history in a memory-efficient way. - Implement
Patch.prototype.serialize
in terms of the same buffer format.
It might make more sense to just serialize patches to buffers before storing them in the history and deserializing them on an as-needed basis. The compact
approach where you actually store Patch
instances with a different backing store just seemed cool in that it maintains a nice programmatic interface, but it may be more trouble than it's worth in other ways.
Incremental Persistence
I'm still concerned about repeatedly serializing the same history over and over again. It might not be a big deal once it's smaller, but if it is, I have this idea for incrementally persisting the state.
- Create a global buffer pool in IndexedDB... We'd store opened buffers in a single pool, regardless of window or project with a key scheme like
atom::buffers::/path/to/buffer.txt
(there may be precedent for the key delimiter so we should research). - Associated with each buffer could be its modified text in a record at
atom::buffers::/path/to/buffer.txt::modifiedContents
- Also associated with each buffer could be an undo and redo stack, stored via lexicographically-sorted keys as follows:
atom::buffers::/path/to/buffer.txt::undo::1
,atom::buffers::/path/to/buffer.txt::undo::2
,atom::buffers::/path/to/buffer.txt::undo::3
, etc. If you pop an undo entry, delete its record. If you build a new undo entry, increment the integer in the key. (You might actually want to decouple the undo and redo entry keys from the buffer's path and just synthesize an id that you reference from the path once to simplify rename.)
It may be that the history never gets big enough to require this, but it would be a cool scheme for basically associate an infinite history with any file on disk in a persistent way. I think it might be pretty cool.