aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx133
-rw-r--r--src/UndoHistory.cxx8
-rw-r--r--src/UndoHistory.h8
3 files changed, 82 insertions, 67 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 320a61639..1ffc749bf 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -483,7 +483,7 @@ const char *CellBuffer::DeleteChars(Sci::Position position, Sci::Position delete
if (changeHistory) {
changeHistory->DeleteRangeSavingHistory(position, deleteLength,
- uh->BeforeReachableSavePoint(), uh->AfterDetachPoint());
+ uh->BeforeReachableSavePoint(), uh->AfterOrAtDetachPoint());
}
BasicDeleteChars(position, deleteLength);
@@ -1092,24 +1092,26 @@ Action CellBuffer::GetUndoStep() const noexcept {
}
void CellBuffer::PerformUndoStep() {
- const Action actionStep = uh->GetUndoStep();
- if (changeHistory && uh->BeforeOrAtSavePoint()) {
+ const Action previousStep = uh->GetUndoStep();
+ // PreviousBeforeSavePoint and AfterDetachPoint are called since acting on the previous action,
+ // that is currentAction-1
+ if (changeHistory && uh->PreviousBeforeSavePoint()) {
changeHistory->StartReversion();
}
- if (actionStep.at == ActionType::insert) {
- if (substance.Length() < actionStep.lenData) {
+ if (previousStep.at == ActionType::insert) {
+ if (substance.Length() < previousStep.lenData) {
throw std::runtime_error(
"CellBuffer::PerformUndoStep: deletion must be less than document length.");
}
if (changeHistory) {
- changeHistory->DeleteRange(actionStep.position, actionStep.lenData,
- uh->BeforeOrAtSavePoint() && !uh->AfterDetachPoint());
+ changeHistory->DeleteRange(previousStep.position, previousStep.lenData,
+ uh->PreviousBeforeSavePoint() && !uh->AfterDetachPoint());
}
- BasicDeleteChars(actionStep.position, actionStep.lenData);
- } else if (actionStep.at == ActionType::remove) {
- BasicInsertString(actionStep.position, actionStep.data, actionStep.lenData);
+ BasicDeleteChars(previousStep.position, previousStep.lenData);
+ } else if (previousStep.at == ActionType::remove) {
+ BasicInsertString(previousStep.position, previousStep.data, previousStep.lenData);
if (changeHistory) {
- changeHistory->UndoDeleteStep(actionStep.position, actionStep.lenData, uh->AfterDetachPoint());
+ changeHistory->UndoDeleteStep(previousStep.position, previousStep.lenData, uh->AfterDetachPoint());
}
}
uh->CompletedUndoStep();
@@ -1138,7 +1140,7 @@ void CellBuffer::PerformRedoStep() {
} else if (actionStep.at == ActionType::remove) {
if (changeHistory) {
changeHistory->DeleteRangeSavingHistory(actionStep.position, actionStep.lenData,
- uh->BeforeReachableSavePoint(), uh->AfterDetachPoint());
+ uh->BeforeReachableSavePoint(), uh->AfterOrAtDetachPoint());
}
BasicDeleteChars(actionStep.position, actionStep.lenData);
}
@@ -1176,60 +1178,73 @@ int CellBuffer::UndoTentative() const noexcept {
return uh->TentativePoint();
}
+namespace {
+
+void RestoreChangeHistory(const UndoHistory *uh, ChangeHistory *changeHistory) {
+ // Replay all 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 || ((detachPoint >= 0) && (detachPoint > act));
+ 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 beforeSave = act < savePoint;
+ const bool afterDetach = (detachPoint >= 0) && (detachPoint < act);
+ if (beforeSave) {
+ changeHistory->StartReversion();
+ }
+ switch (type) {
+ case ActionType::insert:
+ changeHistory->DeleteRange(position, length, beforeSave && !afterDetach);
+ break;
+ case ActionType::remove:
+ changeHistory->UndoDeleteStep(position, length, afterDetach);
+ break;
+ default:
+ // Only insertions and deletions go into change history
+ break;
+ }
+ changeHistory->Check();
+ }
+}
+
+}
+
void CellBuffer::SetUndoCurrent(int action) {
uh->SetCurrent(action, Length());
if (changeHistory) {
+ if ((uh->DetachPoint() >= 0) && (uh->SavePoint() >= 0)) {
+ // Can't have a valid save point and a valid detach point at same time
+ uh->DeleteUndoHistory();
+ changeHistory.reset();
+ throw std::runtime_error("UndoHistory::SetCurrent: invalid undo history.");
+ }
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();
- }
+ RestoreChangeHistory(uh.get(), changeHistory.get());
if (Length() != changeHistory->Length()) {
uh->DeleteUndoHistory();
changeHistory.reset();
diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx
index aac802dfd..c71551e60 100644
--- a/src/UndoHistory.cxx
+++ b/src/UndoHistory.cxx
@@ -383,12 +383,12 @@ bool UndoHistory::BeforeSavePoint() const noexcept {
return (savePoint < 0) || (savePoint > currentAction);
}
-bool UndoHistory::BeforeOrAtSavePoint() const noexcept {
+bool UndoHistory::PreviousBeforeSavePoint() const noexcept {
return (savePoint < 0) || (savePoint >= currentAction);
}
bool UndoHistory::BeforeReachableSavePoint() const noexcept {
- return (savePoint > 0) && !detach && (savePoint > currentAction);
+ return (savePoint > 0) && (savePoint > currentAction);
}
bool UndoHistory::AfterSavePoint() const noexcept {
@@ -544,7 +544,7 @@ bool UndoHistory::CanUndo() const noexcept {
return (currentAction > 0) && (actions.SSize() != 0);
}
-int UndoHistory::StartUndo() noexcept {
+int UndoHistory::StartUndo() const noexcept {
assert(currentAction >= 0);
// Count the steps in this action
@@ -584,7 +584,7 @@ bool UndoHistory::CanRedo() const noexcept {
return actions.SSize() > currentAction;
}
-int UndoHistory::StartRedo() noexcept {
+int UndoHistory::StartRedo() const noexcept {
// Count the steps in this action
if (currentAction >= actions.SSize()) {
diff --git a/src/UndoHistory.h b/src/UndoHistory.h
index 5ddc03593..90b2860a7 100644
--- a/src/UndoHistory.h
+++ b/src/UndoHistory.h
@@ -80,7 +80,7 @@ class UndoHistory {
int undoSequenceDepth = 0;
int savePoint = 0;
int tentativePoint = -1;
- std::optional<int> detach;
+ std::optional<int> detach; // Never set if savePoint set (>= 0)
std::unique_ptr<ScrapStack> scraps;
struct actPos { int act; size_t position; };
std::optional<actPos> memory;
@@ -107,7 +107,7 @@ public:
void SetSavePoint() noexcept;
bool IsSavePoint() const noexcept;
bool BeforeSavePoint() const noexcept;
- bool BeforeOrAtSavePoint() const noexcept;
+ bool PreviousBeforeSavePoint() const noexcept;
bool BeforeReachableSavePoint() const noexcept;
bool AfterSavePoint() const noexcept;
@@ -139,11 +139,11 @@ public:
/// To perform an undo, StartUndo is called to retrieve the number of steps, then UndoStep is
/// called that many times. Similarly for redo.
bool CanUndo() const noexcept;
- int StartUndo() noexcept;
+ int StartUndo() const noexcept;
Action GetUndoStep() const noexcept;
void CompletedUndoStep() noexcept;
bool CanRedo() const noexcept;
- int StartRedo() noexcept;
+ int StartRedo() const noexcept;
Action GetRedoStep() const noexcept;
void CompletedRedoStep() noexcept;
};