aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx4
-rw-r--r--src/CellBuffer.h2
-rw-r--r--src/Document.cxx2
-rw-r--r--src/Document.h2
-rw-r--r--src/UndoHistory.cxx54
-rw-r--r--src/UndoHistory.h5
6 files changed, 57 insertions, 12 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index b3111914e..691a811dd 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -1160,8 +1160,8 @@ int CellBuffer::UndoSavePoint() const noexcept {
return uh->SavePoint();
}
-void CellBuffer::SetUndoCurrent(int action) noexcept {
- uh->SetCurrent(action);
+void CellBuffer::SetUndoCurrent(int action) {
+ uh->SetCurrent(action, Length());
}
int CellBuffer::UndoCurrent() const noexcept {
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index 5422e92aa..916937845 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -183,7 +183,7 @@ public:
int UndoActions() const noexcept;
void SetUndoSavePoint(int action) noexcept;
int UndoSavePoint() const noexcept;
- void SetUndoCurrent(int action) noexcept;
+ void SetUndoCurrent(int action);
int UndoCurrent() const noexcept;
void SetUndoTentative(int action) noexcept;
int UndoTentative() const noexcept;
diff --git a/src/Document.cxx b/src/Document.cxx
index 52081e1cd..8ab837daa 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -363,7 +363,7 @@ int Document::UndoSavePoint() const noexcept {
return cb.UndoSavePoint();
}
-void Document::SetUndoCurrent(int action) noexcept {
+void Document::SetUndoCurrent(int action) {
cb.SetUndoCurrent(action);
}
diff --git a/src/Document.h b/src/Document.h
index 185066a6c..81cb299c0 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -409,7 +409,7 @@ public:
int UndoActions() const noexcept;
void SetUndoSavePoint(int action) noexcept;
int UndoSavePoint() const noexcept;
- void SetUndoCurrent(int action) noexcept;
+ void SetUndoCurrent(int action);
int UndoCurrent() const noexcept;
void SetUndoTentative(int action) noexcept;
int UndoTentative() const noexcept;
diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx
index 1a956b998..62f871a60 100644
--- a/src/UndoHistory.cxx
+++ b/src/UndoHistory.cxx
@@ -173,6 +173,14 @@ bool UndoActions::AtStart(size_t index) const noexcept {
return !types[index-1].mayCoalesce;
}
+size_t UndoActions::LengthTo(size_t index) const noexcept {
+ size_t sum = 0;
+ for (size_t act = 0; act < index; act++) {
+ sum += lengths.ValueAt(act);
+ }
+ return sum;
+}
+
void ScrapStack::Clear() noexcept {
stack.clear();
current = 0;
@@ -395,15 +403,49 @@ bool UndoHistory::AfterOrAtDetachPoint() const noexcept {
return detach && (*detach <= currentAction);
}
-void UndoHistory::SetCurrent(int action) noexcept {
- // Find position in scraps for action
- memory = {};
- size_t position = 0;
+intptr_t UndoHistory::Delta(int action) noexcept {
+ intptr_t sizeChange = 0;
for (int act = 0; act < action; act++) {
- position += actions.lengths.ValueAt(act);
+ const intptr_t lengthChange = actions.lengths.SignedValueAt(act);
+ sizeChange += (actions.types[act].at == ActionType::insert) ? lengthChange : -lengthChange;
+ }
+ return sizeChange;
+}
+
+bool UndoHistory::Validate(intptr_t lengthDocument) noexcept {
+ // Check history for validity
+ const intptr_t sizeChange = Delta(currentAction);
+ if (sizeChange > lengthDocument) {
+ // Current document size too small for changes made in undo history.
+ return false;
}
- scraps->SetCurrent(position);
+ const intptr_t lengthOriginal = lengthDocument - sizeChange;
+ intptr_t lengthCurrent = lengthOriginal;
+ for (int act = 0; act < actions.SSize(); act++) {
+ const intptr_t lengthChange = actions.lengths.SignedValueAt(act);
+ if (actions.positions.SignedValueAt(act) > lengthCurrent) {
+ // Change outside document.
+ return false;
+ }
+ lengthCurrent += (actions.types[act].at == ActionType::insert) ? lengthChange : -lengthChange;
+ if (lengthCurrent < 0) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void UndoHistory::SetCurrent(int action, intptr_t lengthDocument) {
+ // Find position in scraps for action
+ memory = {};
+ const size_t lengthSum = actions.LengthTo(action);
+ scraps->SetCurrent(lengthSum);
currentAction = action;
+ if (!Validate(lengthDocument)) {
+ currentAction = 0;
+ DeleteUndoHistory();
+ throw std::runtime_error("UndoHistory::SetCurrent: invalid undo history.");
+ }
}
int UndoHistory::Current() const noexcept {
diff --git a/src/UndoHistory.h b/src/UndoHistory.h
index 1186a1e0e..13aaca98c 100644
--- a/src/UndoHistory.h
+++ b/src/UndoHistory.h
@@ -53,6 +53,7 @@ struct UndoActions {
[[nodiscard]] intptr_t SSize() const noexcept;
void Create(size_t index, ActionType at_, Sci::Position position_, Sci::Position lenData_, bool mayCoalesce_);
[[nodiscard]] bool AtStart(size_t index) const noexcept;
+ [[nodiscard]] size_t LengthTo(size_t index) const noexcept;
};
class ScrapStack {
@@ -112,7 +113,9 @@ public:
bool AfterDetachPoint() const noexcept;
bool AfterOrAtDetachPoint() const noexcept;
- void SetCurrent(int action) noexcept;
+ [[nodiscard]] intptr_t Delta(int action) noexcept;
+ [[nodiscard]] bool Validate(intptr_t lengthDocument) noexcept;
+ void SetCurrent(int action, intptr_t lengthDocument);
[[nodiscard]] int Current() const noexcept;
[[nodiscard]] int Type(int action) const noexcept;
[[nodiscard]] Sci::Position Position(int action) const noexcept;