Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | (1) Bugfix for handling of last line deletion. (2) Redo of deletion fixed. (3) Additional test case text-37.12 testing a critical edge case. (4) Test cases 37.1-11 re-formatted, but not changed. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | revised_text | tip-466 |
Files: | files | file ages | folders |
SHA1: |
ac2df497761e41440d4b286fd241220e |
User & Date: | gcramer 2017-04-27 11:33:41 |
Context
2017-04-27
| ||
15:27 | (1) Bugfix in delete algorithm with test case text-37.12. (2) Test case text-37.12 fixed. (3) Optimization in space when deleting chars, very significant if the range is large. (4) Adaption of UndoDeleteInspect(), but it is still unclear how to show the surrogate newline. check-in: 1324fb8c user: gcramer tags: revised_text, tip-466 | |
11:33 | (1) Bugfix for handling of last line deletion. (2) Redo of deletion fixed. (3) Additional test case text-37.12 testing a critical edge case. (4) Test cases 37.1-11 re-formatted, but not changed. check-in: ac2df497 user: gcramer tags: revised_text, tip-466 | |
2017-04-26
| ||
19:20 | (1) Watch command now triggers changes in image or window. (2) Handling of the watch command a bit simplified. (3) Update of manual. (4) Minor fix in text-27.26. check-in: 40340286 user: gcramer tags: revised_text, tip-466 | |
Changes
Changes to generic/tkText.c.
︙ | ︙ | |||
2413 2414 2415 2416 2417 2418 2419 | TkTextIndexSave(&textPtr->topIndex); if (triggerWatch) { TkTextSaveCursorIndex(textPtr); } TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); | | | | 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 | TkTextIndexSave(&textPtr->topIndex); if (triggerWatch) { TkTextSaveCursorIndex(textPtr); } TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); if (TkTextIndexCompare(&indexFrom, &index) < 0 && TkTextIndexCompare(&index, &indexTo) <= 0) { /* * The insertion point is inside the range to be replaced, so * we have to do some calculations to ensure it doesn't move * unnecessarily. */ int deleteInsertOffset, insertLength, j; |
︙ | ︙ | |||
5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 | TkTextClearTags(sharedTextPtr, textPtr, &index1, &index3, false); } else { assert(TkTextTagSetIsEmpty(lastLinePtr->prevPtr->lastPtr->tagInfoPtr)); } } return true; /* nothing to do */ } } /* * Call the "watch" command for deletion. Take into account that the * receiver might change the text content inside the callback, although * he shouldn't do this. */ | > > > > > | 5716 5717 5718 5719 5720 5721 5722 5723 5724 5725 5726 5727 5728 5729 5730 5731 5732 5733 5734 | TkTextClearTags(sharedTextPtr, textPtr, &index1, &index3, false); } else { assert(TkTextTagSetIsEmpty(lastLinePtr->prevPtr->lastPtr->tagInfoPtr)); } } return true; /* nothing to do */ } if (lastLinePtr->prevPtr->lastPtr->tagInfoPtr != sharedTextPtr->emptyTagInfoPtr) { /* last newline is tagged, so we have to re-include this character */ index2 = index3; } } /* * Call the "watch" command for deletion. Take into account that the * receiver might change the text content inside the callback, although * he shouldn't do this. */ |
︙ | ︙ |
Changes to generic/tkText.h.
︙ | ︙ | |||
1664 1665 1666 1667 1668 1669 1670 | * Used as 'action' values in calls to TkTextInvalidateLineMetrics */ typedef enum { TK_TEXT_INVALIDATE_ONLY, TK_TEXT_INVALIDATE_INSERT, TK_TEXT_INVALIDATE_DELETE, | | > | 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 | * Used as 'action' values in calls to TkTextInvalidateLineMetrics */ typedef enum { TK_TEXT_INVALIDATE_ONLY, TK_TEXT_INVALIDATE_INSERT, TK_TEXT_INVALIDATE_DELETE, TK_TEXT_INVALIDATE_ELIDE, TK_TEXT_INVALIDATE_REINSERTED } TkTextInvalidateAction; /* * Used as special 'pickPlace' values in calls to TkTextSetYView. Zero or * positive values indicate a number of pixels. */ |
︙ | ︙ |
Changes to generic/tkTextBTree.c.
︙ | ︙ | |||
1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 | { const UndoTokenDelete *token = (const UndoTokenDelete *) undoInfo->token; if (token->startIndex.lineIndex == -1 && token->endIndex.lineIndex == -1) { TkTextSegment *segPtr1 = token->startIndex.u.markPtr; TkTextSegment *segPtr2 = token->endIndex.u.markPtr; int flags = token->inclusive ? DELETE_INCLUSIVE : 0; DeleteRange(sharedTextPtr, segPtr1, segPtr2, flags, redoInfo); assert(segPtr1 != segPtr2); segPtr1->protectionFlag = true; segPtr2->protectionFlag = true; CleanupSplitPoint(segPtr1, sharedTextPtr); | > > > > > > > > > > > > > > | 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | { const UndoTokenDelete *token = (const UndoTokenDelete *) undoInfo->token; if (token->startIndex.lineIndex == -1 && token->endIndex.lineIndex == -1) { TkTextSegment *segPtr1 = token->startIndex.u.markPtr; TkTextSegment *segPtr2 = token->endIndex.u.markPtr; int flags = token->inclusive ? DELETE_INCLUSIVE : 0; if (redoInfo) { UndoTokenDelete *redoToken; redoToken = malloc(sizeof(UndoTokenDelete)); redoToken->undoType = &undoTokenDeleteType; redoToken->segments = NULL; redoToken->numSegments = 0; redoToken->startIndex = token->startIndex; redoToken->endIndex = token->endIndex; redoInfo->token = (TkTextUndoToken *) redoToken; redoInfo->byteSize = 0; DEBUG_ALLOC(tkTextCountNewUndoToken++); } DeleteRange(sharedTextPtr, segPtr1, segPtr2, flags, redoInfo); assert(segPtr1 != segPtr2); segPtr1->protectionFlag = true; segPtr2->protectionFlag = true; CleanupSplitPoint(segPtr1, sharedTextPtr); |
︙ | ︙ | |||
2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 | int changeToPixels = 0; assert(textPtr->pixelReference != -1); for ( ; numLines > 0; --numLines) { TkTextPixelInfo *pixelInfo = TkBTreeLinePixelInfo(textPtr, linePtr); changeToDispLines += (int) GetDisplayLines(linePtr, pixelReference); changeToPixels += pixelInfo->height; pixelInfo->epoch = 0; pixelInfo->height = 0; linePtr = linePtr->nextPtr; if (pixelInfo->dispLineInfo) { free(pixelInfo->dispLineInfo); pixelInfo->dispLineInfo = NULL; DEBUG_ALLOC(tkTextCountDestroyDispInfo++); } if (nodePtr != linePtr->parentPtr) { PropagateDispLineChange(nodePtr, pixelReference, changeToDispLines, changeToPixels); changeToDispLines = 0; changeToPixels = 0; nodePtr = linePtr->parentPtr; } } | > > > > > > | 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 | int changeToPixels = 0; assert(textPtr->pixelReference != -1); for ( ; numLines > 0; --numLines) { TkTextPixelInfo *pixelInfo = TkBTreeLinePixelInfo(textPtr, linePtr); pixelInfo = TkBTreeLinePixelInfo(textPtr, linePtr); changeToDispLines += (int) GetDisplayLines(linePtr, pixelReference); changeToPixels += pixelInfo->height; pixelInfo->epoch = 0; pixelInfo->height = 0; linePtr = linePtr->nextPtr; if (pixelInfo->dispLineInfo) { free(pixelInfo->dispLineInfo); pixelInfo->dispLineInfo = NULL; DEBUG_ALLOC(tkTextCountDestroyDispInfo++); } if (!linePtr) { assert(numLines == 1); break; } if (nodePtr != linePtr->parentPtr) { PropagateDispLineChange(nodePtr, pixelReference, changeToDispLines, changeToPixels); changeToDispLines = 0; changeToPixels = 0; nodePtr = linePtr->parentPtr; } } |
︙ | ︙ | |||
7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 | TkTextIndexSetSegment(&index, beforeSurrogate); } else { TkTextIndexSetupToStartOfText(&index, NULL, sharedTextPtr->tree); } DEBUG(tkBTreeDebug = false); /* otherwise protected segment will be complained */ TkBTreeInsertChars(sharedTextPtr->tree, &index, "\n", sharedTextPtr->emptyTagInfoPtr, NULL, NULL); DEBUG(tkBTreeDebug = oldTreeDebug); } } /* *---------------------------------------------------------------------- * | > > > | 7332 7333 7334 7335 7336 7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 | TkTextIndexSetSegment(&index, beforeSurrogate); } else { TkTextIndexSetupToStartOfText(&index, NULL, sharedTextPtr->tree); } DEBUG(tkBTreeDebug = false); /* otherwise protected segment will be complained */ TkBTreeInsertChars(sharedTextPtr->tree, &index, "\n", sharedTextPtr->emptyTagInfoPtr, NULL, NULL); /* don't forget to reset pixel info of very last line */ TkTextInvalidateLineMetrics(treePtr->sharedTextPtr, NULL, sharedTextPtr->endMarker->sectionPtr->linePtr, 0, TK_TEXT_INVALIDATE_REINSERTED); DEBUG(tkBTreeDebug = oldTreeDebug); } } /* *---------------------------------------------------------------------- * |
︙ | ︙ |
Changes to generic/tkTextDisp.c.
︙ | ︙ | |||
6918 6919 6920 6921 6922 6923 6924 | unsigned totalLines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); unsigned epoch = textPtr->dInfoPtr->lineMetricUpdateEpoch; bool isMonospaced = UseMonospacedLineHeights(textPtr); unsigned lineNum = 0; /* suppress compiler warning */ assert(linePtr || action == TK_TEXT_INVALIDATE_ONLY); assert(TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL) + lineCount | | > > < | 6918 6919 6920 6921 6922 6923 6924 6925 6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 | unsigned totalLines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); unsigned epoch = textPtr->dInfoPtr->lineMetricUpdateEpoch; bool isMonospaced = UseMonospacedLineHeights(textPtr); unsigned lineNum = 0; /* suppress compiler warning */ assert(linePtr || action == TK_TEXT_INVALIDATE_ONLY); assert(TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, NULL) + lineCount < totalLines + (action == TK_TEXT_INVALIDATE_INSERT || action == TK_TEXT_INVALIDATE_DELETE || action == TK_TEXT_INVALIDATE_REINSERTED)); if (linePtr) { int deviation; lineNum = TkBTreeLinesTo(textPtr->sharedTextPtr->tree, textPtr, linePtr, &deviation); assert(deviation >= 0); if (deviation) { lineCount -= MIN((int) lineCount, deviation); } if (action == TK_TEXT_INVALIDATE_INSERT && !isMonospaced |
︙ | ︙ | |||
6962 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 | int high = TkRangeListHigh(ranges); TkRangeListClear(ranges); ranges = TkRangeListAdd(ranges, low, high); } switch (action) { case TK_TEXT_INVALIDATE_ONLY: { int counter = MIN(lineCount, totalLines - lineNum); if (isMonospaced) { TkBTreeUpdatePixelHeights(textPtr, linePtr, lineCount, epoch); } else { TkTextLine *logicalLinePtr; | > > > > > > > > > > | 6963 6964 6965 6966 6967 6968 6969 6970 6971 6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 | int high = TkRangeListHigh(ranges); TkRangeListClear(ranges); ranges = TkRangeListAdd(ranges, low, high); } switch (action) { case TK_TEXT_INVALIDATE_REINSERTED: { /* * Special case: the very last line has been re-inserted. */ assert(lineNum == totalLines); assert(lineNum > 0); TkRangeListTruncateAtEnd(ranges, lineNum - 1); TkBTreeResetDisplayLineCounts(textPtr, linePtr, 1); break; } case TK_TEXT_INVALIDATE_ONLY: { int counter = MIN(lineCount, totalLines - lineNum); if (isMonospaced) { TkBTreeUpdatePixelHeights(textPtr, linePtr, lineCount, epoch); } else { TkTextLine *logicalLinePtr; |
︙ | ︙ | |||
7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 | FreeDLines(textPtr, dlPtr, FindDLine(textPtr, dlPtr, &index), DLINE_UNLINK); } } if (lineNum + lineCount < totalLines) { ranges = TkRangeListAdd(ranges, lineNum, lineNum); } else { TkRangeListTruncateAtEnd(ranges, lineNum - 1); } ResetPixelInfo(TkBTreeLinePixelInfo(textPtr, TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr))); break; case TK_TEXT_INVALIDATE_INSERT: if (lineCount > 0 && lineNum + 1 < totalLines) { int lastLine = MIN(lineNum + lineCount, totalLines - 1); | > > | 7090 7091 7092 7093 7094 7095 7096 7097 7098 7099 7100 7101 7102 7103 7104 7105 | FreeDLines(textPtr, dlPtr, FindDLine(textPtr, dlPtr, &index), DLINE_UNLINK); } } if (lineNum + lineCount < totalLines) { ranges = TkRangeListAdd(ranges, lineNum, lineNum); } else { TkRangeListTruncateAtEnd(ranges, lineNum - 1); ResetPixelInfo(TkBTreeLinePixelInfo(textPtr, textPtr->sharedTextPtr->endMarker->sectionPtr->linePtr)); } ResetPixelInfo(TkBTreeLinePixelInfo(textPtr, TkBTreeGetLogicalLine(textPtr->sharedTextPtr, textPtr, linePtr))); break; case TK_TEXT_INVALIDATE_INSERT: if (lineCount > 0 && lineNum + 1 < totalLines) { int lastLine = MIN(lineNum + lineCount, totalLines - 1); |
︙ | ︙ |
Changes to tests/text.test.
︙ | ︙ | |||
7774 7775 7776 7777 7778 7779 7780 | } -cleanup { destroy $w } -result {} test text-37.1 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} | < > | | < > | | < > | | < > | > > < > > | > < > | | < > > | > < > | > > < > | > > < > | > > > > > > > > > > > > > > > > > > > > > | 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785 7786 7787 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 7831 7832 7833 7834 7835 7836 7837 7838 7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850 7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 7948 7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 | } -cleanup { destroy $w } -result {} test text-37.1 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} set res {} } -body { .t delete begin end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {}}}\ {{break {}}}} test text-37.2 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} set res {} } -body { .t delete 2.0 end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {n1}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {}}}\ {{text 1 {}} {break {n1}} {break {}}}} test text-37.3 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} set res {} } -body { .t delete 1.end end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {}}}\ {{text 1 {}} {break {}}}} test text-37.4 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} set res {} } -body { .t delete 2.end end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {n1}} {text 2 {}} {break {}}}\ {{break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {}}}} test text-37.5 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} "\n" {n2} set res {} } -body { .t delete begin end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {n2}} {break {}}}\ {{break {}}}} test text-37.6 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} "\n" {n2} set res {} } -body { .t delete 2.0 end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {n1}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {n2}} {break {}}}\ {{text 1 {}} {break {n1}} {break {}}}} test text-37.7 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} "\n" {n2} set res {} } -body { .t delete 1.end end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {n2}} {break {}}}\ {{text 1 {}} {break {}}}} test text-37.8 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" {} "\n" n1 "2" {} "\n" {n2} set res {} } -body { .t delete 2.end end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{text 1 {}} {break {n1}} {text 2 {}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {n2}} {break {}}}\ {{text 1 {}} {break {n1}} {text 2 {}} {break {}}}} test text-37.9 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t tag add n begin .t edit separator -immediately set res {} } -body { .t delete begin end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{break {}}}\ {{break {n}}}\ {{break {}}}} test text-37.10 {deletion - clean widget} -setup { text .t -undo on set res {} } -body { lappend res [.t inspect -chars -tag] .t delete begin end lappend res [.t inspect -chars -tag] catch { .t edit undo lappend res [.t inspect -chars -tag] } set res } -cleanup { destroy .t unset res } -result {{{break {}}}\ {{break {}}}} test text-37.11 {deletion - test optimization} -setup { text .t -undo on .t tag add n begin .t edit separator -immediately } -body { .t delete begin end .t edit inspect } -cleanup { destroy .t } -result {{{{tag clear {n 0 1}}} {{tag add n}}} {}} test text-37.12 {deletion - newline behavior - undo/redo behavior} -setup { text .t -undo on .t insert end "1" .t tag add n begin end .t edit separator -immediately set res {} } -body { .t delete begin end lappend res [.t inspect -chars -tag] .t edit undo lappend res [.t inspect -chars -tag] .t edit redo lappend res [.t inspect -chars -tag] set res } -cleanup { destroy .t unset res } -result {{{break {}}}\ {{break {}} {text 1 {n}} {break {n}}}\ {{break {}}}} # cleanup cleanupTests return # Local Variables: # mode: tcl |
︙ | ︙ |