3 ms·
I came up with a "almost too clever" way to reduce the tedium of writing command objects. Most command APIs expect you to write a separate redo and undo method,
by nyanpasu64 5y ago
I came up with a "almost too clever" way to reduce the tedium of writing command objects. Most command APIs expect you to write a separate redo and undo method, and possibly even a separate "apply" method. Instead I created a `BaseEditCommand` interface where each command object subclass precomputes the new state of the altered portions of the document. When the command is applied, the undo system calls `apply_swap(self: &mut dyn BaseEditCommand, &mut Document)` which swaps the Document's old state with the BaseEditCommand's new state. To undo the change, you merely call `apply_swap` a second time, which swaps the old state from the edit command back into the document (saving the document's new state in the edit command). To redo the change, you merely call `apply_swap` a third time.
It has the same tradeoffs as the usual command/action pattern (richer information about what was changed, but you have to implement a new type for each operation, and might end up copying a lot of memory anyway). However it's a lot easier to implement each command (less boilerplate, somewhat lower risk of implementing undo/redo incorrectly and altering state). As a bonus, apply/undo/redo perform zero memory allocations, because they only swap data, not copy or destroy it.
One arguable downside is that you can't transplant the same command from one point in the history to another (but most undo commands in traditional applications, as opposed to VCS systems or nonlinear editors, aren't built to do that either). And I'm not sure my "can_merge" system (which merely drops commands rather than bundling or intelligently combining their contents) was a good idea, since all mergable commands must alter the same state.
API: https://gitlab.com/exotracker/exotracker-cpp/-/blob/dev/src/edit_common.h#L29 https://gitlab.com/exotracker/exotracker-cpp/-/blob/dev/src/...