diff options
Diffstat (limited to 'src/CellBuffer.cxx')
-rw-r--r-- | src/CellBuffer.cxx | 133 |
1 files changed, 74 insertions, 59 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(); |