add undo docs
This commit is contained in:
64
undo.md
Normal file
64
undo.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Towards an Undo System
|
||||
|
||||
date
|
||||
2025-11-27 20:14
|
||||
|
||||
tags
|
||||
ked, hacks, text-editors
|
||||
|
||||
I've been thinking about building an undo system for
|
||||
[ke](https://git.wntrmute.dev/kyle/ke). The first pass is going to be a
|
||||
linear system. Let's start with the basic definitions for an undo
|
||||
system:
|
||||
|
||||
``` c
|
||||
typedef enum undo_kind {
|
||||
UNDO_INSERT = 1 << 0,
|
||||
UNDO_UNKNOWN = 1 << 1,
|
||||
/* more types to follow */
|
||||
} undo_kind;
|
||||
|
||||
|
||||
typedef struct undo_node {
|
||||
undo_kind op;
|
||||
size_t row, col;
|
||||
abuf text;
|
||||
struct undo_node *next;
|
||||
struct undo_node *parent;
|
||||
} undo_node;
|
||||
|
||||
|
||||
typedef struct undo_tree {
|
||||
/* the start of the undo sequence */
|
||||
undo_node *root;
|
||||
/* where we are currently at */
|
||||
undo_node *current;
|
||||
/* the current undo operations being built */
|
||||
undo_node *pending;
|
||||
} undo_tree;
|
||||
```
|
||||
|
||||
The root is anchored at the last time the file was saved; when saving,
|
||||
the tree is freed. Current points to the end of the history, and pending
|
||||
is the sequence being built.
|
||||
|
||||
The lifecycle looks something like:
|
||||
|
||||
- `undo_tree_new` and `undo_tree_free` --- called in `init_editor` and
|
||||
`deathknell`, respectively. The tree is initialized with all nodes set
|
||||
to `NULL`.
|
||||
- Once the user starts doing undoable things, `undo_begin(undo_kind)`
|
||||
gets called, calling `undo_node_new(undo_kind)` if needed to set up
|
||||
`tree->pending`. It may need to call `undo_commit` (below) if needed.
|
||||
- Until an `undo_commit` is called, some form of `undo_append` or
|
||||
`undo_prepend` is called.
|
||||
- Finally, at some point `undo_commit` is called. This needs to do a few
|
||||
things:
|
||||
1. If `tree->current->next` is not `NULL`, it must be freed.
|
||||
2. Set `tree->current->next` as pending, set `tree->current` to
|
||||
`tree->current->next`.
|
||||
3. Set `tree->pending` to `NULL`.
|
||||
|
||||
Once the e
|
||||
|
||||
- `undo_node_new(undo_kind)` and `undo_node_free`
|
||||
Reference in New Issue
Block a user