diff options
-rw-r--r-- | doc/text.n | 12 | ||||
-rw-r--r-- | generic/tkText.c | 39 | ||||
-rw-r--r-- | generic/tkUndo.c | 26 | ||||
-rw-r--r-- | generic/tkUndo.h | 4 | ||||
-rw-r--r-- | tests/text.test | 30 |
5 files changed, 88 insertions, 23 deletions
@@ -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 { |