diff options
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(); }  | 
