aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorNeil <nyamatongwe@gmail.com>2024-02-09 21:45:35 +1100
committerNeil <nyamatongwe@gmail.com>2024-02-09 21:45:35 +1100
commitbd53ffcbefe4e7a22fc493b1916939bae5f9dc1d (patch)
treebfe435d75b222d464a9cbb21e25583d33c591936 /src
parent07a7683902feb4b9944394b9378f0a1a51972497 (diff)
downloadscintilla-mirror-bd53ffcbefe4e7a22fc493b1916939bae5f9dc1d.tar.gz
Implement API to read and write undo history from applications.
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx48
-rw-r--r--src/CellBuffer.h13
-rw-r--r--src/Document.cxx48
-rw-r--r--src/Document.h13
-rw-r--r--src/Editor.cxx43
-rw-r--r--src/UndoHistory.cxx95
-rw-r--r--src/UndoHistory.h18
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;