aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CellBuffer.cxx40
-rw-r--r--src/CellBuffer.h12
-rw-r--r--src/Document.cxx59
-rw-r--r--src/Document.h6
4 files changed, 116 insertions, 1 deletions
diff --git a/src/CellBuffer.cxx b/src/CellBuffer.cxx
index 0c56c9e92..710e32403 100644
--- a/src/CellBuffer.cxx
+++ b/src/CellBuffer.cxx
@@ -144,6 +144,7 @@ UndoHistory::UndoHistory() {
currentAction = 0;
undoSequenceDepth = 0;
savePoint = 0;
+ tentativePoint = -1;
actions[currentAction].Create(startAction);
}
@@ -194,7 +195,7 @@ const char *UndoHistory::AppendAction(actionType at, int position, const char *d
// Visual Studio 2013 Code Analysis wrongly believes actions can be NULL at its next reference
__analysis_assume(actions);
#endif
- if (currentAction == savePoint) {
+ if ((currentAction == savePoint) || (currentAction == tentativePoint)) {
currentAction++;
} else if (!actions[currentAction].mayCoalesce) {
// Not allowed to coalesce if this set
@@ -282,6 +283,7 @@ void UndoHistory::DeleteUndoHistory() {
currentAction = 0;
actions[currentAction].Create(startAction);
savePoint = 0;
+ tentativePoint = -1;
}
void UndoHistory::SetSavePoint() {
@@ -292,6 +294,26 @@ bool UndoHistory::IsSavePoint() const {
return savePoint == currentAction;
}
+void UndoHistory::TentativeStart() {
+ tentativePoint = currentAction;
+}
+
+void UndoHistory::TentativeCommit() {
+ tentativePoint = -1;
+ // Truncate undo history
+ maxAction = currentAction;
+}
+
+int UndoHistory::TentativeSteps() {
+ // Drop any trailing startAction
+ if (actions[currentAction].at == startAction && currentAction > 0)
+ currentAction--;
+ if (tentativePoint >= 0)
+ return currentAction - tentativePoint;
+ else
+ return -1;
+}
+
bool UndoHistory::CanUndo() const {
return (currentAction > 0) && (maxAction > 0);
}
@@ -505,6 +527,22 @@ bool CellBuffer::IsSavePoint() const {
return uh.IsSavePoint();
}
+void CellBuffer::TentativeStart() {
+ uh.TentativeStart();
+}
+
+void CellBuffer::TentativeCommit() {
+ uh.TentativeCommit();
+}
+
+int CellBuffer::TentativeSteps() {
+ return uh.TentativeSteps();
+}
+
+bool CellBuffer::TentativeActive() const {
+ return uh.TentativeActive();
+}
+
// Without undo
void CellBuffer::InsertLine(int line, int position, bool lineStart) {
diff --git a/src/CellBuffer.h b/src/CellBuffer.h
index f07b45983..5e4fc7c8c 100644
--- a/src/CellBuffer.h
+++ b/src/CellBuffer.h
@@ -95,6 +95,7 @@ class UndoHistory {
int currentAction;
int undoSequenceDepth;
int savePoint;
+ int tentativePoint;
void EnsureUndoRoom();
@@ -117,6 +118,12 @@ public:
void SetSavePoint();
bool IsSavePoint() const;
+ // Tentative actions are used for input composition so that it can be undone cleanly
+ void TentativeStart();
+ void TentativeCommit();
+ bool TentativeActive() const { return tentativePoint >= 0; }
+ int TentativeSteps();
+
/// 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;
@@ -193,6 +200,11 @@ public:
void SetSavePoint();
bool IsSavePoint() const;
+ void TentativeStart();
+ void TentativeCommit();
+ bool TentativeActive() const;
+ int TentativeSteps();
+
bool SetUndoCollection(bool collectUndo);
bool IsCollectingUndo() const;
void BeginUndoAction();
diff --git a/src/Document.cxx b/src/Document.cxx
index 32d5f1896..4c1901679 100644
--- a/src/Document.cxx
+++ b/src/Document.cxx
@@ -209,6 +209,65 @@ void Document::SetSavePoint() {
NotifySavePoint(true);
}
+void Document::TentativeUndo() {
+ CheckReadOnly();
+ if (enteredModification == 0) {
+ enteredModification++;
+ if (!cb.IsReadOnly()) {
+ bool startSavePoint = cb.IsSavePoint();
+ bool multiLine = false;
+ int steps = cb.TentativeSteps();
+ //Platform::DebugPrintf("Steps=%d\n", steps);
+ for (int step = 0; step < steps; step++) {
+ const int prevLinesTotal = LinesTotal();
+ const Action &action = cb.GetUndoStep();
+ if (action.at == removeAction) {
+ NotifyModified(DocModification(
+ SC_MOD_BEFOREINSERT | SC_PERFORMED_UNDO, action));
+ } else if (action.at == containerAction) {
+ DocModification dm(SC_MOD_CONTAINER | SC_PERFORMED_UNDO);
+ dm.token = action.position;
+ NotifyModified(dm);
+ } else {
+ NotifyModified(DocModification(
+ SC_MOD_BEFOREDELETE | SC_PERFORMED_UNDO, action));
+ }
+ cb.PerformUndoStep();
+ if (action.at != containerAction) {
+ ModifiedAt(action.position);
+ }
+
+ int modFlags = SC_PERFORMED_UNDO;
+ // With undo, an insertion action becomes a deletion notification
+ if (action.at == removeAction) {
+ modFlags |= SC_MOD_INSERTTEXT;
+ } else if (action.at == insertAction) {
+ modFlags |= SC_MOD_DELETETEXT;
+ }
+ if (steps > 1)
+ modFlags |= SC_MULTISTEPUNDOREDO;
+ const int linesAdded = LinesTotal() - prevLinesTotal;
+ if (linesAdded != 0)
+ multiLine = true;
+ if (step == steps - 1) {
+ modFlags |= SC_LASTSTEPINUNDOREDO;
+ if (multiLine)
+ modFlags |= SC_MULTILINEUNDOREDO;
+ }
+ NotifyModified(DocModification(modFlags, action.position, action.lenData,
+ linesAdded, action.data));
+ }
+
+ bool endSavePoint = cb.IsSavePoint();
+ if (startSavePoint != endSavePoint)
+ NotifySavePoint(endSavePoint);
+
+ cb.TentativeCommit();
+ }
+ enteredModification--;
+ }
+}
+
int Document::GetMark(int line) {
return static_cast<LineMarkers *>(perLineData[ldMarkers])->MarkValue(line);
}
diff --git a/src/Document.h b/src/Document.h
index a59f192a9..0f2985f89 100644
--- a/src/Document.h
+++ b/src/Document.h
@@ -303,6 +303,12 @@ public:
void AddUndoAction(int token, bool mayCoalesce) { cb.AddUndoAction(token, mayCoalesce); }
void SetSavePoint();
bool IsSavePoint() const { return cb.IsSavePoint(); }
+
+ void TentativeStart() { cb.TentativeStart(); }
+ void TentativeCommit() { cb.TentativeCommit(); }
+ void TentativeUndo();
+ bool TentativeActive() { return cb.TentativeActive(); }
+
const char * SCI_METHOD BufferPointer() { return cb.BufferPointer(); }
const char *RangePointer(int position, int rangeLength) { return cb.RangePointer(position, rangeLength); }
int GapPosition() const { return cb.GapPosition(); }