diff options
author | Neil <nyamatongwe@gmail.com> | 2014-07-18 23:37:23 +1000 |
---|---|---|
committer | Neil <nyamatongwe@gmail.com> | 2014-07-18 23:37:23 +1000 |
commit | 286895b1a01a6fd57b9fd5044efad711e9c2216b (patch) | |
tree | f8fbc009263db18ff89876e4600ac5910c3e227d /src | |
parent | 2fc9c2d3742b5b09a6e1ec40d32e4d93f83df5ca (diff) | |
download | scintilla-mirror-286895b1a01a6fd57b9fd5044efad711e9c2216b.tar.gz |
Added the tentative undo feature. This is useful for IMEs that want to display
and manipulate a character being composed, but may then commit or remove it
leaving no history in undo of the intermediate forms.
Diffstat (limited to 'src')
-rw-r--r-- | src/CellBuffer.cxx | 40 | ||||
-rw-r--r-- | src/CellBuffer.h | 12 | ||||
-rw-r--r-- | src/Document.cxx | 59 | ||||
-rw-r--r-- | src/Document.h | 6 |
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(); } |