Tk Source Code

View Ticket
Login
Ticket UUID: 1561991
Title: text widget : loosing of tags with undo/redo
Type: RFE Version: None
Submitter: nobody Created on: 2006-09-20 08:20:56
Subsystem: 18. [text] Assigned To: nobody
Priority: 5 Medium Severity: Minor
Status: Open Last Modified: 2016-04-04 20:54:29
Resolution: None Closed By: nobody
    Closed on:
Description:
Hello,

I issue this bug report after discussions with Donal
Fellows and Vince Darley, about the behavior of the
Undo/Redo mecanism in handling tags under deletion.

In a text widget, when a tagged text region is deleted
and then the delete is undone, the tags are lost. I
discuss this point with Vince Darley, and the mails are
copied below.

In the meantime, I wrote a Tcl C code to handle tags
with delete events. The code compiles fine and seems to
work with the little tests I've done. PLEASE understand
i'm not an expert at all, so the code may look ugly for
Tcl'er Gurus, and I don't know about the procedures
used to make tests, and so on !

In the tkText.c file (taken from the tk8.4.13
distribution), procedure DeleteCmd, search for
"Handling Tags"

Hope this helps !

----------------------------------------------------------------------
Dr. Luc Moulinier
IGBMC
Laboratoire de Biologie et Genomique Structurale      
 1,rue Laurent FRIES               
BP 10142                tel: (33) (0)3 88 65 32 79
67 404 ILLKIRCH CEDEX            fax: (33) (0)3 88 65 32 76
France
----------------------------------------------------------------------


Dear Vince,

After talking with Donal Fellow, it seems you are the
right person taht may help me, if you don't mind.

I'm currently writing a big app for bioinformatics
purposes. It uses a lot the text widget. And i'm quite
desesparate with the undo/redo behaviour with tags. The
problem is the losing of the tagging status of a text
region when the text is deleted and then the delete is
undone. I'm sure you're aware of that, but in cas, i
enclose a very simple script to illustrate it. This
happens with tcl/tk 8.4.13 and 8.5.0.
Looking at the mailing list and TIPs, i found nothing
said about changing that behaviour, (TIPs 26,104,255),
although someone (maybe you ?) said it should not be a
so difficult task to achieve. The point would be to
dump the text widget before deletion.

Have you any clue about when this behaviour will be
solved ? or
Do you know any script/extension that would meka a
undo/redo working with tagged text ?

Thank you very much in advance !!

----------------------------------------------------------------------
Dr. Luc Moulinier
IGBMC
Laboratoire de Biologie et Genomique Structurale      
 1,rue Laurent FRIES               
BP 10142                tel: (33) (0)3 88 65 32 79
67 404 ILLKIRCH CEDEX            fax: (33) (0)3 88 65 32 76
France
----------------------------------------------------------------------

#!/usr/local/bin/wish

proc Remove {} {
    .t delete 2.19 2.30
    .t edit separator
}

proc Add {} {
    .t edit undo
}

text .t -bg black -fg white \
-height 10 -width 55 \
-state normal \
-undo 1 -autoseparators 0
pack .t

.t insert end "Here is a test.\n"
.t insert end "And this is a line with a blue tagged
region inside\n"
.t insert end "that explicit the undo behaviour with tags"
.t tag configure tblue -background cyan
.t tag add tblue 2.19 2.30
.t edit separator

button .brm -text "1. Remove " -bg green -command [list
Remove]
button .bad -text "2.  Add back" -bg green -command
[list Add]
pack .brm .bad -side left


Vince Darley replies
--------------------
Yes, indeed, the problem here is that the text widget
never has
supported storing text tags with the text it stores to
record 'insert'
and 'delete' events, and therefore has also never supported
re-applying those text tags when text is inserted as a
result of an
undo or redo operation.

This is not something that would probably be that hard
to fix (search
for 'TextPushUndoAction' in tkText.c for the 2 calls
that would need
changing/enhancing). However, some thought would be
needed to ensure
undo/redo behaved well if, for example, a tag in the
undo range was
deleted from the widget, and then the undo applied
(probably the
correct behaviour should be to silently ignore the tag).

Probably the biggest work is just in building up (in
TextPushUndoAction's implementation) the script that
must be executed
for the undo/redo.  It's always a pain to do that from
C code, so
perhaps it could be pushed out into a Tcl supporting
script in
text.tcl.

Vince.
User Comments: fvogel added on 2016-04-04 20:54:29:

TIP #104 had undo/redo of tags in line of sight.


fvogel added on 2015-10-01 19:57:17:
Considering the issues raised in the present ticket, which are real IMO, I think that departing from the current clear situation where tags are not part of the undo/redo mechanism can only be done based on a TIP addressing all cases in depth.

Until that happens I suggest closure of this ticket as "Postponed".

fvogel added on 2015-01-16 18:18:37:
See also:

https://groups.google.com/forum/#!topic/comp.lang.tcl/zWBn6206QlM

danckaert added on 2006-12-05 22:59:58:
Logged In: YES 
user_id=1388916
Originator: NO

Hi, 
I do not like this idea. This patch only considers one particular case of the undo/redo mechanism, and ignores other cases.

An example:
text .t -undo 1
.t tag configure mytag -background yellow
.t insert end "some text" mytag
.t edit undo
.t edit redo
--> "some text" appears again, but without the tag mytag

Also, the simple adding/removing of tags is still not recorded in the undo stack.
Consider for example the following:
- user deletes some text with tag X
- as a result of some other action, tag X is removed (not deleted) from the whole text
- user presses undo --> tag X will again be present in the text, which was
probably not intended

Currently we have a clear situation: tags are not part of the undo/redo mechanism. I think it is best to keep it that way.

Regards,
Koen

luckyluke67 added on 2006-10-05 15:13:35:
Logged In: YES 
user_id=1483252

Vince, 

Unfortunatly, we're not using CVS at the moment (I know we
should but ....). Here is the diff file (I could attach a
file when i opened this bug, but I can't figure out haw to
do it now. I can just add comments ....) :

--- tkText.c2006-10-05 09:55:13.000000000 +0200
+++ tkTextold.c2006-10-05 09:48:44.485631000 +0200
@@ -1672,6 +1672,7 @@
 Tcl_DStringAppend(&actionCommand, "; ", -1);
 Tcl_DStringAppendElement(&actionCommand, cmdName);
 Tcl_DStringAppend(&actionCommand, " see insert", -1);
+
 TextGetText(&index1, &index2, &ds);
 
 Tcl_DStringAppendElement(&revertCommand, cmdName);
@@ -1689,139 +1690,8 @@
 Tcl_DStringAppendElement(&revertCommand, cmdName);
 Tcl_DStringAppend(&revertCommand, " see insert", -1);
 
-/* Hangling Tags :
- * ---------------
- *
- * In all the following, we do not care about 
- * the "sel" tag
- */
-
-Tcl_Obj *objDump = NULL;
-Tcl_Obj *objTag = NULL;
-Tcl_Obj **lstDump, **lstTag;
-CONST char *argv[5];
-char *key, *val, *tname, *spos;
-char StartZone[TK_POS_CHARS];
-char EndZone[TK_POS_CHARS];
-int argc, i, j, k, nDump, nTag, exist, result;
-
-/* First : retrieve all tags of the widget */
-
-Tcl_ResetResult(textPtr->interp);
-
-argc = 3;
-argv[0] = cmdName;
-argv[1] = "tag";
-argv[2] = "names";
-argv[3] = NULL;
-result = TkTextTagCmd(textPtr, textPtr->interp, argc, argv);
-objTag = Tcl_NewObj();
-objTag = Tcl_DuplicateObj(Tcl_GetObjResult(textPtr->interp));
-Tcl_ListObjGetElements(NULL, objTag, &nTag, &lstTag);
-char *TagAdd[nTag];
-Tcl_DString WrtTag[nTag];
-
-/* initialise a DString for each tag, that will contain
- * pos1 pos2 pairs
- */
-
-for(i=0;i<nTag;i++) {
-  TagAdd[i]=NULL;
-  Tcl_DStringInit(&WrtTag[i]);
-}
-Tcl_ResetResult(textPtr->interp);
-
-/* Second : dump the tags for the deleted region */
-
-argv[0] = cmdName;
-argv[1] = "dump";
-argv[2] = "-tag";
-TkTextPrintIndex(&index1, StartZone);
-argv[3] = StartZone;
-TkTextPrintIndex(&index2, EndZone);
-argv[4] = EndZone;
-argv[5] = NULL;
-argc=5;
-TextDumpCmd(textPtr, textPtr->interp, argc, argv);
-objDump = Tcl_NewListObj(0, NULL);
-objDump = Tcl_DuplicateObj(Tcl_GetObjResult(textPtr->interp));
-Tcl_ListObjGetElements(NULL, objDump, &nDump, &lstDump);
-Tcl_ResetResult(textPtr->interp);
-
-/* Third : for each tag, create pairs of tagon/tagoff, 
- * and append the pair to its corresponding DString.
- * Check first if the tag still exists in the widget. 
- * If not, ignore it.
- *
- * Beware : a region may contain a tagon without a tagoff,
- * the ending is then the end of the region. Similarly,
- * a region may contain a tagoff without a tagon, the
beginning
- * is then the beginning of the region
- */
-
-for (i=0; i < nDump; i+=3) {
-  key  = Tcl_GetString(lstDump[i]);
-  val  = Tcl_GetString(lstDump[i+1]);
-  if (strcmp(val,"sel") == 0) continue;
-  spos = Tcl_GetString(lstDump[i+2]);
-
-  /* Check if the current tag still exists */
-
-  exist = 0;
-  for (j = 0; j<nTag; j++) {
-    tname = Tcl_GetString(lstTag[j]);
-    if (strcmp(val,tname) == 0) {
-      exist = 1;
-      k=j;
-      break;
-    }
-  }
-  if (exist == 0) continue;
-
-  /* treat "tagon" and "tagoff" events. 
-   *  - Record tagon position.
-   *  - If tagoff, write the pair 
-   */
-  
-  if (strcmp(key,"tagon") == 0) {
-      TagAdd[k] = spos;
-  } else {
-    if (TagAdd[k] == NULL) {
-      Tcl_DStringAppendElement(&WrtTag[k],StartZone);
-    } else {
-      Tcl_DStringAppendElement(&WrtTag[k], TagAdd[k]);
-    }
-    Tcl_DStringAppend(&WrtTag[k]," ", -1);
-    Tcl_DStringAppendElement(&WrtTag[k],spos);
-    Tcl_DStringAppend(&WrtTag[k]," ", -1);
-    TagAdd[k] = NULL;
-  }
-}
-/* As the writing is done with tagoff events, we end up
- * here with tags having only a tagon defined
- */
-for (j = 0; j<nTag; j++) {
-  if (TagAdd[j] != NULL) {
-    Tcl_DStringAppendElement(&WrtTag[j], TagAdd[j]);    
-    Tcl_DStringAppend(&WrtTag[j]," ", -1);
-    Tcl_DStringAppendElement(&WrtTag[j],EndZone);
-  }
-
-  /* Everything done, append to the revert command */
-
-  if (Tcl_DStringLength(&WrtTag[j]) > 0) {
-    printf("fait if\n");
-    Tcl_DStringAppend(&revertCommand,"; ",-1);
-    Tcl_DStringAppendElement(&revertCommand,cmdName);
-    Tcl_DStringAppend(&revertCommand," tag add ",-1);
-   
Tcl_DStringAppendElement(&revertCommand,Tcl_GetString(lstTag[j]));
-    Tcl_DStringAppend(&revertCommand," ",-1);
-    Tcl_DStringAppend(&revertCommand,
Tcl_DStringValue(&WrtTag[j]), -1);
-  }
-  Tcl_DStringFree(&WrtTag[j]);
-}
-
 TkUndoPushAction(textPtr->undoStack, &actionCommand,
&revertCommand);
+
 Tcl_DStringFree(&actionCommand);
 Tcl_DStringFree(&revertCommand);
     }


I also send a copy by normal e-mail

Luc

nobody added on 2006-10-05 05:57:46:
Logged In: NO 

Luc,

If possible can you attach a unified diff between your file and the original. 
Assuming you got the source from cvs you can do this with 'cvs -z5 diff -bu 
tkText.c', else just with 'diff -bu tkText.c tkTextOld.c'. That way we can see what 
has changed, and can easily apply such changes to any version of tkText.c (not 
just the version you happen to be working on now).

thanks,

Vince.

nobody added on 2006-09-20 15:20:56:

File Added - 194318: tkText.c

Attachments: