Subject: Implementation of TIP #446 - Introspect Undo/Redo Stack Depths

From: fvogel <[email-masked]>
Date: Tue, 5 Apr 2016 20:28:54 +0000

---
 generic/tkText.c | 30 ++++++++++++++++++++++---
 generic/tkUndo.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 generic/tkUndo.h |  3 ++-
 3 files changed, 93 insertions(+), 7 deletions(-)

diff --git a/generic/tkText.c b/generic/tkText.c
index 506075d..c293557 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -2093,7 +2093,7 @@ ConfigureText(
     textPtr->sharedTextPtr->maxUndo = textPtr->maxUndo;
     textPtr->sharedTextPtr->autoSeparators = textPtr->autoSeparators;
 
-    TkUndoSetDepth(textPtr->sharedTextPtr->undoStack,
+    TkUndoSetMaxDepth(textPtr->sharedTextPtr->undoStack,
 	    textPtr->sharedTextPtr->maxUndo);
 
     /*
@@ -5165,10 +5165,12 @@ TextEditCmd(
 {
     int index, setModified, oldModified;
     static const char *const editOptionStrings[] = {
-	"modified", "redo", "reset", "separator", "undo", NULL
+	"modified", "redo", "redodepth", "reset", "separator", "undo",
+        "undodepth", NULL
     };
     enum editOptions {
-	EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, EDIT_SEPARATOR, EDIT_UNDO
+	EDIT_MODIFIED, EDIT_REDO, EDIT_REDODEPTH, EDIT_RESET,
+        EDIT_SEPARATOR, EDIT_UNDO, EDIT_UNDODEPTH
     };
 
     if (objc < 3) {
@@ -5229,6 +5231,17 @@ TextEditCmd(
 	    return TCL_ERROR;
 	}
 	break;
+    case EDIT_REDODEPTH: {
+        int depth;
+
+        if (objc != 3) {
+            Tcl_WrongNumArgs(interp, 3, objv, NULL);
+            return TCL_ERROR;
+        }
+        depth = TkUndoGetDepth(textPtr->sharedTextPtr->undoStack, 1);
+        Tcl_SetObjResult(interp, Tcl_NewIntObj(depth));
+        break;
+    }
     case EDIT_RESET:
 	if (objc != 3) {
 	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
@@ -5254,6 +5267,17 @@ TextEditCmd(
 	    return TCL_ERROR;
 	}
 	break;
+    case EDIT_UNDODEPTH: {
+        int depth;
+
+        if (objc != 3) {
+            Tcl_WrongNumArgs(interp, 3, objv, NULL);
+            return TCL_ERROR;
+        }
+        depth = TkUndoGetDepth(textPtr->sharedTextPtr->undoStack, 0);
+        Tcl_SetObjResult(interp, Tcl_NewIntObj(depth));
+        break;
+    }
     }
     return TCL_OK;
 }
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index 8359e0a..3aa3ee2 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -353,7 +353,7 @@ TkUndoInitStack(
 /*
  *----------------------------------------------------------------------
  *
- * TkUndoSetDepth --
+ * TkUndoSetMaxDepth --
  *
  *	Set the maximum depth of stack.
  *
@@ -368,7 +368,7 @@ TkUndoInitStack(
  */
 
 void
-TkUndoSetDepth(
+TkUndoSetMaxDepth(
     TkUndoRedoStack *stack,	/* An Undo/Redo stack */
     int maxdepth)		/* The maximum stack depth */
 {
@@ -428,6 +428,67 @@ TkUndoSetDepth(
 /*
  *----------------------------------------------------------------------
  *
+ * TkUndoGetDepth
+ *
+ *	Return the depth of the undo (or redo) stack.
+ *
+ * Results:
+ *	An integer representing the number of undoable (or redoable) actions.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkUndoGetDepth(
+    TkUndoRedoStack *stack,	/* An Undo/Redo stack */
+    int whichStack)		/* 0 means the undo stack,
+                                 * otherwise the redo stack */
+{
+    int depth = 0;
+    TkUndoAtom *elem = NULL;
+
+    if (stack != NULL) {
+        if (whichStack) {
+            elem = stack->redoStack;
+        } else {
+            elem = stack->undoStack;
+        }
+
+        if (elem != NULL) {
+            /*
+             * Skip the first (top) separator if there is one.
+             */
+
+            if (elem->type == TK_UNDO_SEPARATOR) {
+                elem = elem->next;
+            }
+
+            /*
+             * The number of compound actions in the stack is then
+             * the number of separators plus one, except if there is
+             * a separator at the bottom of the stack. This latter
+             * case cannot however happen (TkUndoInsertSeparator
+             * prevents from inserting a separator there).
+             */
+
+            while (elem != NULL) {
+                if (elem->type == TK_UNDO_SEPARATOR) {
+                    depth++;
+                }
+                elem = elem->next;
+            }
+            depth++;
+        }
+    }
+    return depth;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
  * TkUndoClearStacks --
  *
  *	Clear both the undo and redo stack.
@@ -498,7 +559,7 @@ TkUndoInsertUndoSeparator(
 {
     if (TkUndoInsertSeparator(&stack->undoStack)) {
 	stack->depth++;
-	TkUndoSetDepth(stack, stack->maxdepth);
+	TkUndoSetMaxDepth(stack, stack->maxdepth);
     }
 }
 
diff --git a/generic/tkUndo.h b/generic/tkUndo.h
index e63aac4..883f6ee 100644
--- a/generic/tkUndo.h
+++ b/generic/tkUndo.h
@@ -96,7 +96,8 @@ MODULE_SCOPE void	TkUndoClearStack(TkUndoAtom **stack);
  */
 
 MODULE_SCOPE TkUndoRedoStack *TkUndoInitStack(Tcl_Interp *interp, int maxdepth);
-MODULE_SCOPE void	TkUndoSetDepth(TkUndoRedoStack *stack, int maxdepth);
+MODULE_SCOPE void	TkUndoSetMaxDepth(TkUndoRedoStack *stack, int maxdepth);
+MODULE_SCOPE int	TkUndoGetDepth(TkUndoRedoStack *stack, int whichStack);
 MODULE_SCOPE void	TkUndoClearStacks(TkUndoRedoStack *stack);
 MODULE_SCOPE void	TkUndoFreeStack(TkUndoRedoStack *stack);
 MODULE_SCOPE void	TkUndoInsertUndoSeparator(TkUndoRedoStack *stack);
-- 
cgit v0.12