diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CellBuffer.cxx | 48 | ||||
-rw-r--r-- | src/CellBuffer.h | 13 | ||||
-rw-r--r-- | src/Document.cxx | 48 | ||||
-rw-r--r-- | src/Document.h | 13 | ||||
-rw-r--r-- | src/Editor.cxx | 43 | ||||
-rw-r--r-- | src/UndoHistory.cxx | 95 | ||||
-rw-r--r-- | src/UndoHistory.h | 18 |
7 files changed, 276 insertions, 2 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx index bfef83da5..b3111914e 100644 --- a/src/CellBuffer.cxx +++ b/src/CellBuffer.cxx @@ -1148,6 +1148,54 @@ void CellBuffer::PerformRedoStep() { uh->CompletedRedoStep(); } +int CellBuffer::UndoActions() const noexcept { + return uh->Actions(); +} + +void CellBuffer::SetUndoSavePoint(int action) noexcept { + uh->SetSavePoint(action); +} + +int CellBuffer::UndoSavePoint() const noexcept { + return uh->SavePoint(); +} + +void CellBuffer::SetUndoCurrent(int action) noexcept { + uh->SetCurrent(action); +} + +int CellBuffer::UndoCurrent() const noexcept { + return uh->Current(); +} + +void CellBuffer::SetUndoTentative(int action) noexcept { + uh->SetTentative(action); +} + +int CellBuffer::UndoTentative() const noexcept { + return uh->TentativePoint(); +} + +int CellBuffer::UndoActionType(int action) const noexcept { + return uh->Type(action); +} + +Sci::Position CellBuffer::UndoActionPosition(int action) const noexcept { + return uh->Position(action); +} + +std::string_view CellBuffer::UndoActionText(int action) const noexcept { + return uh->Text(action); +} + +void CellBuffer::PushUndoActionType(int type, Sci::Position position) { + uh->PushUndoActionType(type, position); +} + +void CellBuffer::ChangeLastUndoActionText(size_t length, const char *text) { + uh->ChangeLastUndoActionText(length, text); +} + void CellBuffer::ChangeHistorySet(bool set) { if (set) { if (!changeHistory && !uh->CanUndo()) { diff --git a/src/CellBuffer.h b/src/CellBuffer.h index 16ed14d6c..5422e92aa 100644 --- a/src/CellBuffer.h +++ b/src/CellBuffer.h @@ -180,6 +180,19 @@ public: Action GetRedoStep() const noexcept; void PerformRedoStep(); + int UndoActions() const noexcept; + void SetUndoSavePoint(int action) noexcept; + int UndoSavePoint() const noexcept; + void SetUndoCurrent(int action) noexcept; + int UndoCurrent() const noexcept; + void SetUndoTentative(int action) noexcept; + int UndoTentative() const noexcept; + int UndoActionType(int action) const noexcept; + Sci::Position UndoActionPosition(int action) const noexcept; + std::string_view UndoActionText(int action) const noexcept; + void PushUndoActionType(int type, Sci::Position position); + void ChangeLastUndoActionText(size_t length, const char *text); + void ChangeHistorySet(bool set); [[nodiscard]] int EditionAt(Sci::Position pos) const noexcept; [[nodiscard]] Sci::Position EditionEndRun(Sci::Position pos) const noexcept; diff --git a/src/Document.cxx b/src/Document.cxx index 306cdb725..52081e1cd 100644 --- a/src/Document.cxx +++ b/src/Document.cxx @@ -351,6 +351,54 @@ void Document::TentativeUndo() { } } +int Document::UndoActions() const noexcept { + return cb.UndoActions(); +} + +void Document::SetUndoSavePoint(int action) noexcept { + cb.SetUndoSavePoint(action); +} + +int Document::UndoSavePoint() const noexcept { + return cb.UndoSavePoint(); +} + +void Document::SetUndoCurrent(int action) noexcept { + cb.SetUndoCurrent(action); +} + +int Document::UndoCurrent() const noexcept { + return cb.UndoCurrent(); +} + +void Document::SetUndoTentative(int action) noexcept { + cb.SetUndoTentative(action); +} + +int Document::UndoTentative() const noexcept { + return cb.UndoTentative(); +} + +int Document::UndoActionType(int action) const noexcept { + return cb.UndoActionType(action); +} + +Sci::Position Document::UndoActionPosition(int action) const noexcept { + return cb.UndoActionPosition(action); +} + +std::string_view Document::UndoActionText(int action) const noexcept { + return cb.UndoActionText(action); +} + +void Document::PushUndoActionType(int type, Sci::Position position) { + cb.PushUndoActionType(type, position); +} + +void Document::ChangeLastUndoActionText(size_t length, const char *text) { + cb.ChangeLastUndoActionText(length, text); +} + int Document::GetMark(Sci::Line line, bool includeChangeHistory) const { int marksHistory = 0; if (includeChangeHistory && (line < LinesTotal())) { diff --git a/src/Document.h b/src/Document.h index af6bb98fd..185066a6c 100644 --- a/src/Document.h +++ b/src/Document.h @@ -406,6 +406,19 @@ public: void TentativeUndo(); bool TentativeActive() const noexcept { return cb.TentativeActive(); } + int UndoActions() const noexcept; + void SetUndoSavePoint(int action) noexcept; + int UndoSavePoint() const noexcept; + void SetUndoCurrent(int action) noexcept; + int UndoCurrent() const noexcept; + void SetUndoTentative(int action) noexcept; + int UndoTentative() const noexcept; + int UndoActionType(int action) const noexcept; + Sci::Position UndoActionPosition(int action) const noexcept; + std::string_view UndoActionText(int action) const noexcept; + void PushUndoActionType(int type, Sci::Position position); + void ChangeLastUndoActionText(size_t length, const char *text); + void ChangeHistorySet(bool set) { cb.ChangeHistorySet(set); } [[nodiscard]] int EditionAt(Sci::Position pos) const noexcept { return cb.EditionAt(pos); } [[nodiscard]] Sci::Position EditionEndRun(Sci::Position pos) const noexcept { return cb.EditionEndRun(pos); } diff --git a/src/Editor.cxx b/src/Editor.cxx index 2d7d07e22..b8ed636d3 100644 --- a/src/Editor.cxx +++ b/src/Editor.cxx @@ -6586,6 +6586,49 @@ sptr_t Editor::WndProc(Message iMessage, uptr_t wParam, sptr_t lParam) { pdoc->EndUndoAction(); return 0; + case Message::GetUndoActions: + return pdoc->UndoActions(); + + case Message::SetUndoSavePoint: + pdoc->SetUndoSavePoint(static_cast<int>(wParam)); + break; + + case Message::GetUndoSavePoint: + return pdoc->UndoSavePoint(); + + case Message::SetUndoCurrent: + pdoc->SetUndoCurrent(static_cast<int>(wParam)); + break; + + case Message::GetUndoCurrent: + return pdoc->UndoCurrent(); + + case Message::SetUndoTentative: + pdoc->SetUndoTentative(static_cast<int>(wParam)); + break; + + case Message::GetUndoTentative: + return pdoc->UndoTentative(); + + case Message::GetUndoActionType: + return pdoc->UndoActionType(static_cast<int>(wParam)); + + case Message::GetUndoActionPosition: + return pdoc->UndoActionPosition(static_cast<int>(wParam)); + + case Message::GetUndoActionText: { + std::string_view text = pdoc->UndoActionText(static_cast<int>(wParam)); + return BytesResult(lParam, reinterpret_cast<const unsigned char *>(text.data()), text.length()); + } + + case Message::PushUndoActionType: + pdoc->PushUndoActionType(static_cast<int>(wParam), lParam); + break; + + case Message::ChangeLastUndoActionText: + pdoc->ChangeLastUndoActionText(wParam, CharPtrFromSPtr(lParam)); + break; + case Message::GetCaretPeriod: return caret.period; diff --git a/src/UndoHistory.cxx b/src/UndoHistory.cxx index d6bda27f1..9c1b89c94 100644 --- a/src/UndoHistory.cxx +++ b/src/UndoHistory.cxx @@ -341,6 +341,20 @@ void UndoHistory::DeleteUndoHistory() noexcept { currentAction = 0; savePoint = 0; tentativePoint = -1; + scraps = std::make_unique<ScrapStack>(); + memory = {}; +} + +int UndoHistory::Actions() const noexcept { + return static_cast<int>(actions.SSize()); +} + +void UndoHistory::SetSavePoint(int action) noexcept { + savePoint = action; +} + +int UndoHistory::SavePoint() const noexcept { + return savePoint; } void UndoHistory::SetSavePoint() noexcept { @@ -376,6 +390,72 @@ 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; + for (int act = 0; act < action; act++) { + position += actions.lengths.ValueAt(act); + } + scraps->SetCurrent(position); + currentAction = action; +} + +int UndoHistory::Current() const noexcept { + return currentAction; +} + +int UndoHistory::Type(int action) const noexcept { + const int baseType = static_cast<int>(actions.types[action].at); + const int open = actions.types[action].mayCoalesce ? coalesceFlag : 0; + return baseType | open; +} + +Sci::Position UndoHistory::Position(int action) const noexcept { + return actions.positions.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 + if (action == 0) { + memory = {}; + } + int act = 0; + size_t position = 0; + if (memory && memory->act <= action) { + act = memory->act; + position = memory->position; + } + for (; act < action; act++) { + position += actions.lengths.ValueAt(act); + } + const size_t length = actions.lengths.ValueAt(action); + const char *scrap = scraps->TextAt(position); + memory = {action, position}; + return {scrap, length}; +} + +void UndoHistory::PushUndoActionType(int type, Sci::Position position) { + actions.PushBack(); + actions.Create(actions.SSize()-1, static_cast<ActionType>(type & byteMask), + position, 0, type & coalesceFlag); +} + +void UndoHistory::ChangeLastUndoActionText(size_t length, const char *text) { + assert(actions.lengths.ValueAt(actions.SSize()-1) == 0); + actions.lengths.SetValueAt(actions.SSize()-1, length); + scraps->Push(text, length); +} + +void UndoHistory::SetTentative(int action) noexcept { + tentativePoint = action; +} + +int UndoHistory::TentativePoint() const noexcept { + return tentativePoint; +} + void UndoHistory::TentativeStart() noexcept { tentativePoint = currentAction; } @@ -402,11 +482,15 @@ bool UndoHistory::CanUndo() const noexcept { } int UndoHistory::StartUndo() noexcept { + assert(currentAction >= 0); + // Count the steps in this action - if (currentAction <= 0) { + if (currentAction == 0) { return 0; } + int act = currentAction - 1; + while (act > 0 && !actions.AtStart(act)) { act--; } @@ -439,14 +523,21 @@ bool UndoHistory::CanRedo() const noexcept { int UndoHistory::StartRedo() noexcept { // Count the steps in this action + if (currentAction >= actions.SSize()) { // Already at end so can't redo return 0; } + + // Slightly unusual logic handles case where last action still has mayCoalesce. + // Could set mayCoalesce of last action to false in StartUndo but this state is + // visible to applications so should not be changed. + const int maxAction = Actions() - 1; int act = currentAction; - while ((act + 1) < actions.SSize() && !actions.AtStart(act + 1)) { + while (act <= maxAction && actions.types[act].mayCoalesce) { act++; } + act = std::min(act, maxAction); return act - currentAction + 1; } diff --git a/src/UndoHistory.h b/src/UndoHistory.h index 03bea3de3..ab8c24250 100644 --- a/src/UndoHistory.h +++ b/src/UndoHistory.h @@ -67,6 +67,8 @@ public: [[nodiscard]] const char *TextAt(size_t position) const noexcept; }; +constexpr int coalesceFlag = 0x100; + /** * */ @@ -78,6 +80,8 @@ class UndoHistory { int tentativePoint = -1; std::optional<int> detach; std::unique_ptr<ScrapStack> scraps; + struct actPos { int act; size_t position; }; + std::optional<actPos> memory; int PreviousAction() const noexcept; @@ -92,8 +96,12 @@ public: void DropUndoSequence() noexcept; void DeleteUndoHistory() noexcept; + [[nodiscard]] int Actions() const noexcept; + /// The save point is a marker in the undo stack where the container has stated that /// the buffer was saved. Undo and redo can move over the save point. + void SetSavePoint(int action) noexcept; + [[nodiscard]] int SavePoint() const noexcept; void SetSavePoint() noexcept; bool IsSavePoint() const noexcept; bool BeforeSavePoint() const noexcept; @@ -103,7 +111,17 @@ public: bool AfterDetachPoint() const noexcept; bool AfterOrAtDetachPoint() const noexcept; + void SetCurrent(int action) noexcept; + [[nodiscard]] int Current() const noexcept; + [[nodiscard]] int Type(int action) const noexcept; + [[nodiscard]] Sci::Position Position(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); + // Tentative actions are used for input composition so that it can be undone cleanly + void SetTentative(int action) noexcept; + [[nodiscard]] int TentativePoint() const noexcept; void TentativeStart() noexcept; void TentativeCommit() noexcept; bool TentativeActive() const noexcept; |