aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/CellBuffer.cxx58
-rw-r--r--src/UndoHistory.cxx4
-rw-r--r--src/UndoHistory.h1
3 files changed, 63 insertions, 0 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 6dde7eb84..320a61639 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -1178,6 +1178,64 @@ int CellBuffer::UndoTentative() const noexcept {
void CellBuffer::SetUndoCurrent(int action) {
uh->SetCurrent(action, Length());
+ if (changeHistory) {
+ const intptr_t sizeChange = uh->Delta(action);
+ const intptr_t lengthOriginal = Length() - sizeChange;
+ // Recreate empty change history
+ changeHistory = std::make_unique<ChangeHistory>(lengthOriginal);
+
+ // Replay all undo undo actions into changeHistory
+ const int savePoint = uh->SavePoint();
+ const int detachPoint = uh->DetachPoint();
+ const int currentPoint = uh->Current();
+ for (int act = 0; act < uh->Actions(); act++) {
+ const ActionType type = static_cast<ActionType>(uh->Type(act) & ~coalesceFlag);
+ const Sci::Position position = uh->Position(act);
+ const Sci::Position length = uh->Length(act);
+ const bool beforeSave = act < savePoint;
+ const bool afterDetach = (detachPoint >= 0) && (detachPoint < act);
+ switch (type) {
+ case ActionType::insert:
+ changeHistory->Insert(position, length, true, beforeSave);
+ break;
+ case ActionType::remove:
+ changeHistory->DeleteRangeSavingHistory(position, length, beforeSave, afterDetach);
+ break;
+ default:
+ // Only insertions and deletions go into change history
+ break;
+ }
+ changeHistory->Check();
+ }
+ // Undo back to currentPoint, updating change history
+ for (int act = uh->Actions()-1; act >= currentPoint; act--) {
+ const ActionType type = static_cast<ActionType>(uh->Type(act) & ~coalesceFlag);
+ const Sci::Position position = uh->Position(act);
+ const Sci::Position length = uh->Length(act);
+ const bool beforeOrAtSavePoint = (savePoint < 0) || (savePoint >= act);
+ const bool afterDetach = (detachPoint >= 0) && (detachPoint < act);
+ if (beforeOrAtSavePoint) {
+ changeHistory->StartReversion();
+ }
+ switch (type) {
+ case ActionType::insert:
+ changeHistory->DeleteRange(position, length, beforeOrAtSavePoint && !afterDetach);
+ break;
+ case ActionType::remove:
+ changeHistory->UndoDeleteStep(position, length, afterDetach);
+ break;
+ default:
+ // Only insertions and deletions go into change history
+ break;
+ }
+ changeHistory->Check();
+ }
+ if (Length() != changeHistory->Length()) {
+ uh->DeleteUndoHistory();
+ changeHistory.reset();
+ throw std::runtime_error("UndoHistory::SetCurrent: invalid undo history.");
+ }
+ }
}
int CellBuffer::UndoCurrent() const noexcept {
diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx
index 810cd9a14..aac802dfd 100644
--- a/src/UndoHistory.cxx
+++ b/src/UndoHistory.cxx
@@ -474,6 +474,10 @@ Sci::Position UndoHistory::Position(int action) const noexcept {
return actions.positions.SignedValueAt(action);
}
+Sci::Position UndoHistory::Length(int action) const noexcept {
+ return actions.lengths.SignedValueAt(action);
+}
+
std::string_view UndoHistory::Text(int action) noexcept {
// Assumes first call after any changes is for action 0.
// TODO: may need to invalidate memory in other circumstances
diff --git a/src/UndoHistory.h b/src/UndoHistory.h
index 10660a195..5ddc03593 100644
--- a/src/UndoHistory.h
+++ b/src/UndoHistory.h
@@ -123,6 +123,7 @@ public:
[[nodiscard]] int Current() const noexcept;
[[nodiscard]] int Type(int action) const noexcept;
[[nodiscard]] Sci::Position Position(int action) const noexcept;
+ [[nodiscard]] Sci::Position Length(int action) const noexcept;
[[nodiscard]] std::string_view Text(int action) noexcept;
void PushUndoActionType(int type, Sci::Position position);
void ChangeLastUndoActionText(size_t length, const char *text);