Add non-linear undo/redo design documentation and improve UndoSystem with backspace batching and GUI integration fixes.

This commit is contained in:
2025-11-30 01:49:07 -08:00
parent 35ffe6d11c
commit b77ebdfd07
17 changed files with 891 additions and 147 deletions

View File

@@ -13,20 +13,40 @@ UndoSystem::Begin(UndoType type)
const int row = static_cast<int>(buf_.Cury());
const int col = static_cast<int>(buf_.Curx());
if (tree_.pending && tree_.pending->type == type && tree_.pending->row == row) {
std::size_t expected = static_cast<std::size_t>(tree_.pending->col) + tree_.pending->text.size();
if (expected == static_cast<std::size_t>(col)) {
return; // keep batching
if (type == UndoType::Delete) {
// Support batching both forward deletes (DeleteChar) and backspace (prepend case)
// Forward delete: cursor stays at anchor col; expected == col
std::size_t anchor = static_cast<std::size_t>(tree_.pending->col);
if (anchor + tree_.pending->text.size() == static_cast<std::size_t>(col)) {
pending_prepend_ = false;
return; // keep batching forward delete
}
// Backspace: cursor moved left by 1; allow extend if col + text.size() == anchor
if (static_cast<std::size_t>(col) + tree_.pending->text.size() == anchor) {
// Move anchor one left to new cursor column; next Append should prepend
tree_.pending->col = col;
pending_prepend_ = true;
return;
}
} else {
std::size_t expected = static_cast<std::size_t>(tree_.pending->col) + tree_.pending->text.
size();
if (expected == static_cast<std::size_t>(col)) {
pending_prepend_ = false;
return; // keep batching
}
}
}
// Otherwise commit any existing batch and start a new node
commit();
auto *node = new UndoNode();
node->type = type;
node->row = row;
node->col = col;
node->child = nullptr;
node->next = nullptr;
tree_.pending = node;
auto *node = new UndoNode();
node->type = type;
node->row = row;
node->col = col;
node->child = nullptr;
node->next = nullptr;
tree_.pending = node;
pending_prepend_ = false;
}
@@ -35,7 +55,12 @@ UndoSystem::Append(char ch)
{
if (!tree_.pending)
return;
tree_.pending->text.push_back(ch);
if (pending_prepend_ && tree_.pending->type == UndoType::Delete) {
// Prepend for backspace so that text is in increasing column order
tree_.pending->text.insert(tree_.pending->text.begin(), ch);
} else {
tree_.pending->text.push_back(ch);
}
}