diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CellBuffer.cxx | 133 | ||||
-rw-r--r-- | src/UndoHistory.cxx | 8 | ||||
-rw-r--r-- | src/UndoHistory.h | 8 |
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; }; |