summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/text.n12
-rw-r--r--generic/tkText.c39
-rw-r--r--generic/tkUndo.c26
-rw-r--r--generic/tkUndo.h4
-rw-r--r--tests/text.test30
5 files changed, 88 insertions, 23 deletions
diff --git a/doc/text.n b/doc/text.n
index e2bb01f..9633e37 100644
--- a/doc/text.n
+++ b/doc/text.n
@@ -1305,8 +1305,9 @@ of the widget to \fIboolean\fR.
\fIpathName \fBedit redo\fR
.
When the \fB\-undo\fR option is true, reapplies the last undone edits provided
-no other edits were done since then. Generates an error when the redo stack is
-empty. Does nothing when the \fB\-undo\fR option is false.
+no other edits were done since then, and returns a list of indices indicating
+what ranges were changed by the redo operation. Generates an error when the
+redo stack is empty. Does nothing when the \fB\-undo\fR option is false.
.TP
\fIpathName \fBedit reset\fR
.
@@ -1319,9 +1320,10 @@ Inserts a separator (boundary) on the undo stack. Does nothing when the
.TP
\fIpathName \fBedit undo\fR
.
-Undoes the last edit action when the \fB\-undo\fR option is true. An edit
-action is defined as all the insert and delete commands that are recorded on
-the undo stack in between two separators. Generates an error when the undo
+Undoes the last edit action when the \fB\-undo\fR option is true, and returns a
+list of indices indicating what ranges were changed by the undo operation. An
+edit action is defined as all the insert and delete commands that are recorded
+on the undo stack in between two separators. Generates an error when the undo
stack is empty. Does nothing when the \fB\-undo\fR option is false.
.RE
.TP
diff --git a/generic/tkText.c b/generic/tkText.c
index 8be8881..e028a54 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -398,8 +398,8 @@ static int DumpSegment(TkText *textPtr, Tcl_Interp *interp,
const char *key, const char *value,
Tcl_Obj *command, const TkTextIndex *index,
int what);
-static int TextEditUndo(TkText *textPtr);
-static int TextEditRedo(TkText *textPtr);
+static int TextEditUndo(TkText *textPtr, Tcl_Obj *rangesObj);
+static int TextEditRedo(TkText *textPtr, Tcl_Obj *rangesObj);
static Tcl_Obj * TextGetText(const TkText *textPtr,
const TkTextIndex *index1,
const TkTextIndex *index2, int visibleOnly);
@@ -2784,6 +2784,7 @@ TextPushUndoAction(
Tcl_Obj *markSet2InsertObj = NULL;
Tcl_Obj *insertCmdObj = Tcl_NewObj();
Tcl_Obj *deleteCmdObj = Tcl_NewObj();
+ Tcl_Obj *returnCmdObj = Tcl_NewObj();
/*
* Get the index positions.
@@ -2833,6 +2834,11 @@ TextPushUndoAction(
Tcl_ListObjAppendElement(NULL, deleteCmdObj, index1Obj);
Tcl_ListObjAppendElement(NULL, deleteCmdObj, index2Obj);
+ Tcl_ListObjAppendElement(NULL, returnCmdObj,
+ Tcl_NewStringObj("list", 4));
+ Tcl_ListObjAppendElement(NULL, returnCmdObj, index1Obj);
+ Tcl_ListObjAppendElement(NULL, returnCmdObj, index2Obj);
+
/*
* Note: we don't wish to use textPtr->widgetCmd in these callbacks
* because if we delete the textPtr, but peers still exist, we will then
@@ -2850,11 +2856,13 @@ TextPushUndoAction(
insertCmdObj, NULL);
TkUndoMakeCmdSubAtom(NULL, markSet2InsertObj, iAtom);
TkUndoMakeCmdSubAtom(NULL, seeInsertObj, iAtom);
+ TkUndoMakeCmdSubAtom(NULL, returnCmdObj, iAtom);
dAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, textPtr->sharedTextPtr,
deleteCmdObj, NULL);
TkUndoMakeCmdSubAtom(NULL, markSet1InsertObj, dAtom);
TkUndoMakeCmdSubAtom(NULL, seeInsertObj, dAtom);
+ TkUndoMakeCmdSubAtom(NULL, returnCmdObj, dAtom);
Tcl_DecrRefCount(seeInsertObj);
Tcl_DecrRefCount(index1Obj);
@@ -5055,7 +5063,7 @@ DumpSegment(
* Undo the last change.
*
* Results:
- * None.
+ * The ranges of text that were changed by the undo operation.
*
* Side effects:
* Apart from manipulating the undo and redo stacks, the state of the
@@ -5066,7 +5074,8 @@ DumpSegment(
static int
TextEditUndo(
- TkText *textPtr) /* Overall information about text widget. */
+ TkText *textPtr, /* Overall information about text widget. */
+ Tcl_Obj *rangesObj) /* Ranges of text that were changed. */
{
int status;
@@ -5085,7 +5094,7 @@ TextEditUndo(
textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_UNDO;
}
- status = TkUndoRevert(textPtr->sharedTextPtr->undoStack);
+ status = TkUndoRevert(textPtr->sharedTextPtr->undoStack, rangesObj);
if (textPtr->sharedTextPtr->dirtyMode != TK_TEXT_DIRTY_FIXED) {
textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL;
@@ -5103,7 +5112,7 @@ TextEditUndo(
* Redo the last undone change.
*
* Results:
- * None.
+ * The ranges of text that were changed by the undo operation.
*
* Side effects:
* Apart from manipulating the undo and redo stacks, the state of the
@@ -5114,7 +5123,8 @@ TextEditUndo(
static int
TextEditRedo(
- TkText *textPtr) /* Overall information about text widget. */
+ TkText *textPtr, /* Overall information about text widget. */
+ Tcl_Obj *rangesObj) /* Ranges of text that were changed. */
{
int status;
@@ -5133,7 +5143,7 @@ TextEditRedo(
textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_REDO;
}
- status = TkUndoApply(textPtr->sharedTextPtr->undoStack);
+ status = TkUndoApply(textPtr->sharedTextPtr->undoStack, rangesObj);
if (textPtr->sharedTextPtr->dirtyMode != TK_TEXT_DIRTY_FIXED) {
textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL;
@@ -5169,6 +5179,7 @@ TextEditCmd(
int index, setModified, oldModified;
int canRedo = 0;
int canUndo = 0;
+ Tcl_Obj *rangesObj = Tcl_NewObj();
static const char *const editOptionStrings[] = {
"canundo", "canredo", "modified", "redo", "reset", "separator",
@@ -5252,11 +5263,13 @@ TextEditCmd(
return TCL_ERROR;
}
canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
- if (TextEditRedo(textPtr)) {
+ if (TextEditRedo(textPtr, rangesObj)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL);
return TCL_ERROR;
- }
+ } else {
+ Tcl_SetObjResult(interp, rangesObj);
+ }
canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
if (!canUndo || !canRedo) {
GenerateUndoStackEvent(textPtr);
@@ -5287,11 +5300,13 @@ TextEditCmd(
return TCL_ERROR;
}
canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
- if (TextEditUndo(textPtr)) {
+ if (TextEditUndo(textPtr, rangesObj)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL);
return TCL_ERROR;
- }
+ } else {
+ Tcl_SetObjResult(interp, rangesObj);
+ }
canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
if (!canRedo || !canUndo) {
GenerateUndoStackEvent(textPtr);
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index c66905d..f364326 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -556,7 +556,8 @@ TkUndoInsertUndoSeparator(
* Undo a compound action on the stack.
*
* Results:
- * A Tcl status code
+ * A Tcl status code. Also, the passed Tcl_(List)Obj is appended by the
+ * interp results from evaluation of each element of the undo stack.
*
* Side effects:
* None.
@@ -566,7 +567,8 @@ TkUndoInsertUndoSeparator(
int
TkUndoRevert(
- TkUndoRedoStack *stack)
+ TkUndoRedoStack *stack,
+ Tcl_Obj *retObj)
{
TkUndoAtom *elem;
@@ -598,6 +600,13 @@ TkUndoRevert(
EvaluateActionList(stack->interp, elem->revert);
+ /*
+ * The interp result is appended to the returned object for each
+ * element of the undo stack (not for each sub-atom).
+ */
+
+ Tcl_ListObjAppendList(NULL, retObj, Tcl_GetObjResult(stack->interp));
+
TkUndoPushStack(&stack->redoStack, elem);
elem = TkUndoPopStack(&stack->undoStack);
}
@@ -619,7 +628,8 @@ TkUndoRevert(
* Redo a compound action on the stack.
*
* Results:
- * A Tcl status code
+ * A Tcl status code. Also, the passed Tcl_(List)Obj is appended by the
+ * interp results from evaluation of each element of the redo stack.
*
* Side effects:
* None.
@@ -629,7 +639,8 @@ TkUndoRevert(
int
TkUndoApply(
- TkUndoRedoStack *stack)
+ TkUndoRedoStack *stack,
+ Tcl_Obj *retObj)
{
TkUndoAtom *elem;
@@ -660,6 +671,13 @@ TkUndoApply(
EvaluateActionList(stack->interp, elem->apply);
+ /*
+ * The interp result is appended to the returned object for each
+ * element of the redo stack (not for each sub-atom).
+ */
+
+ Tcl_ListObjAppendList(NULL, retObj, Tcl_GetObjResult(stack->interp));
+
TkUndoPushStack(&stack->undoStack, elem);
elem = TkUndoPopStack(&stack->redoStack);
}
diff --git a/generic/tkUndo.h b/generic/tkUndo.h
index 490ede9..505e0f0 100644
--- a/generic/tkUndo.h
+++ b/generic/tkUndo.h
@@ -109,7 +109,7 @@ MODULE_SCOPE TkUndoSubAtom *TkUndoMakeSubAtom(TkUndoProc *funcPtr,
TkUndoSubAtom *subAtomList);
MODULE_SCOPE void TkUndoPushAction(TkUndoRedoStack *stack,
TkUndoSubAtom *apply, TkUndoSubAtom *revert);
-MODULE_SCOPE int TkUndoRevert(TkUndoRedoStack *stack);
-MODULE_SCOPE int TkUndoApply(TkUndoRedoStack *stack);
+MODULE_SCOPE int TkUndoRevert(TkUndoRedoStack *stack, Tcl_Obj *retObj);
+MODULE_SCOPE int TkUndoApply(TkUndoRedoStack *stack, Tcl_Obj *retObj);
#endif /* _TKUNDO */
diff --git a/tests/text.test b/tests/text.test
index 720afbe..a3f9afe 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -6577,6 +6577,36 @@ test text-27.25 {<<UndoStack>> virtual event} -setup {
} -cleanup {
destroy .t
} -result {0 0 1 2 3 4 4 5 6 6 7 8 8 9}
+test text-27.26 {edit undo and edit redo return ranges} -setup {
+ destroy .t
+ set res {}
+} -body {
+ text .t -undo true -autoseparators false
+ .t insert end "Hello "
+ .t edit separator
+ .t insert end "World!\n"
+ .t insert 1.6 "GREAT "
+ .t insert end "Another edit here!!"
+ lappend res [.t edit undo]
+ lappend res [.t edit redo]
+ .t edit separator
+ .t delete 1.6
+ .t delete 1.9 1.10
+ .t insert 1.9 L
+ lappend res [.t edit undo]
+ lappend res [.t edit redo]
+ .t replace 1.6 1.10 Tcl/Tk
+ .t replace 2.8 2.12 "one bites the dust"
+ lappend res [.t edit undo]
+ lappend res [.t edit redo]
+} -cleanup {
+ destroy .t
+} -result [list {2.0 2.19 1.6 1.12 1.6 2.0} \
+ {1.6 2.0 1.6 1.12 2.0 2.19} \
+ {1.9 1.10 1.9 1.10 1.6 1.7} \
+ {1.6 1.7 1.9 1.10 1.9 1.10} \
+ {2.8 2.26 2.8 2.12 1.6 1.12 1.6 1.10} \
+ {1.6 1.10 1.6 1.12 2.8 2.12 2.8 2.26} ]
test text-28.1 {bug fix - 624372, ControlUtfProc long lines} -body {