From ec8cf7ef92f7cdbbfbcbbf95cb6cc12afe303d6d Mon Sep 17 00:00:00 2001 From: vincentdarley Date: Thu, 4 Dec 2003 12:28:37 +0000 Subject: fix to text widget tabs and xy-scroll-command --- ChangeLog | 22 ++++++++++++++++ doc/text.n | 10 ++++--- generic/tkText.c | 44 ++++++++++++++++++++++++------- generic/tkTextDisp.c | 69 +++++++++++++++++++++++-------------------------- generic/tkTextImage.c | 6 ++--- generic/tkTextWind.c | 6 ++--- library/demos/twind.tcl | 67 +++++++++++++++++++++++++++++++++++++++++++++-- library/demos/widget | 4 +-- tests/text.test | 20 +++++++++++++- 9 files changed, 188 insertions(+), 60 deletions(-) diff --git a/ChangeLog b/ChangeLog index 121adac..f42702f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,27 @@ 2003-12-04 Vince Darley + * generic/tkText.c: disallow negative or decreasing tab-stops + + * generic/tkTextDisp.c: restore previous meaning of + -[xy]scrollcommand [Bug 852954], and remove unused argument + to 'MeasureChars' + + * generic/tkTextWind.c: + * generic/tkTextImage.c: better border handling and fixed + typos in comments. + + * tests/text.test: tests for negative and decreasing tab stops. + + * doc/text.n: documentation of '-tabs', to clarify Tk's + longstanding interpretation of all distances as relative to + the left edge of the widget. + + * library/demos/twind.tcl: + * library/demos/widget: minor enhancements to text widget + demo, showing embedded images, for example. + +2003-12-04 Vince Darley + * win/tkWinFont.c: applied [Patch 852669] which fixes [Bug 478568] with certain bold or italic fonts on Windows. * tests/textDisp.test: added test for the font measurement diff --git a/doc/text.n b/doc/text.n index 2c65ba8..e30b728 100644 --- a/doc/text.n +++ b/doc/text.n @@ -5,7 +5,7 @@ '\" See the file "license.terms" for information on usage and redistribution '\" of this file, and for a DISCLAIMER OF ALL WARRANTIES. '\" -'\" RCS: @(#) $Id: text.n,v 1.22 2003/11/16 14:13:09 vincentdarley Exp $ +'\" RCS: @(#) $Id: text.n,v 1.23 2003/12/04 12:28:37 vincentdarley Exp $ '\" .so man.macros .TH text n 8.5 Tk "Tk Built-In Commands" @@ -81,7 +81,9 @@ and no insertion cursor will be displayed, even if the input focus is in the widget. .OP \-tabs tabs Tabs Specifies a set of tab stops for the window. The option's value consists -of a list of screen distances giving the positions of the tab stops. Each +of a list of screen distances giving the positions of the tab stops, +each of which is a distance relative to the left edge of the widget +(excluding borders, padding, etc). Each position may optionally be followed in the next list element by one of the keywords \fBleft\fR, \fBright\fR, \fBcenter\fR, or \fBnumeric\fR, which specifies how to justify @@ -100,7 +102,9 @@ tab stops at two-centimeter intervals; the first two use left justification and the third uses center justification. If the list of tab stops does not have enough elements to cover all of the tabs in a text line, then Tk extrapolates new tab stops using -the spacing and alignment from the last tab stop in the list. +the spacing and alignment from the last tab stop in the list. Tab +distances must be strictly positive, and must always increase from one +tab stop to the next (if not, an error is thrown). The value of the \fBtabs\fR option may be overridden by \fB\-tabs\fR options in tags. If no \fB\-tabs\fR option is specified, or if it is specified as diff --git a/generic/tkText.c b/generic/tkText.c index c5c8baa..cdb376d 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -14,7 +14,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkText.c,v 1.45 2003/11/21 18:51:18 vincentdarley Exp $ + * RCS: @(#) $Id: tkText.c,v 1.46 2003/12/04 12:28:37 vincentdarley Exp $ */ #include "default.h" @@ -1713,7 +1713,8 @@ TextWorldChanged(textPtr, mask) * has changed */ { Tk_FontMetrics fm; - + int border; + textPtr->charWidth = Tk_TextWidth(textPtr->tkfont, "0", 1); if (textPtr->charWidth <= 0) { textPtr->charWidth = 1; @@ -1724,14 +1725,17 @@ TextWorldChanged(textPtr, mask) if (textPtr->charHeight <= 0) { textPtr->charHeight = 1; } + border = textPtr->borderWidth + textPtr->highlightWidth; Tk_GeometryRequest(textPtr->tkwin, - textPtr->width * textPtr->charWidth + 2*textPtr->borderWidth - + 2*textPtr->padX + 2*textPtr->highlightWidth, + textPtr->width * textPtr->charWidth + + 2*textPtr->padX + 2*border, textPtr->height * (fm.linespace + textPtr->spacing1 - + textPtr->spacing3) + 2*textPtr->borderWidth - + 2*textPtr->padY + 2*textPtr->highlightWidth); - Tk_SetInternalBorder(textPtr->tkwin, - textPtr->borderWidth + textPtr->highlightWidth); + + textPtr->spacing3) + + 2*textPtr->padY + 2*border); + + Tk_SetInternalBorderEx(textPtr->tkwin, + border + textPtr->padX, border + textPtr->padX, + border + textPtr->padY, border + textPtr->padY); if (textPtr->setGrid) { Tk_SetGrid(textPtr->tkwin, textPtr->width, textPtr->height, textPtr->charWidth, textPtr->charHeight); @@ -3352,6 +3356,13 @@ TkTextGetTabs(interp, tkwin, stringPtr) != TCL_OK) { goto error; } + + if (tabPtr->location <= 0) { + Tcl_AppendResult(interp, + "tab stop \"", Tcl_GetString(objv[i]), + "\" is not at a positive distance", NULL); + goto error; + } prevStop = lastStop; if (Tk_GetMMFromObj(interp, tkwin, objv[i], &lastStop) != TCL_OK) { @@ -3360,6 +3371,19 @@ TkTextGetTabs(interp, tkwin, stringPtr) lastStop *= WidthOfScreen(Tk_Screen(tkwin)); lastStop /= WidthMMOfScreen(Tk_Screen(tkwin)); + if (i > 0 && (tabPtr->location <= (tabPtr-1)->location)) { + /* + * This tab is actually to the left of the previous + * one, which is illegal. + */ + Tcl_AppendResult(interp, + "tabs must be monotonically increasing, but \"", + Tcl_GetString(objv[i]), + "\" is smaller than or equal to the previous tab", + NULL); + goto error; + } + tabArrayPtr->numTabs++; /* @@ -3388,7 +3412,9 @@ TkTextGetTabs(interp, tkwin, stringPtr) /* * For when we need to interpolate tab stops, store * these two so we know the tab stop size to very - * high precision. + * high precision. With the above checks, we can + * guarantee that tabIncrement is strictly positive + * here. */ tabArrayPtr->lastTab = lastStop; tabArrayPtr->tabIncrement = lastStop - prevStop; diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index b218a79..f015fd1 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextDisp.c,v 1.35 2003/11/21 18:51:18 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextDisp.c,v 1.36 2003/12/04 12:28:37 vincentdarley Exp $ */ #include "tkPort.h" @@ -418,7 +418,7 @@ static DLine * LayoutDLine _ANSI_ARGS_((TkText *textPtr, CONST TkTextIndex *indexPtr)); static int MeasureChars _ANSI_ARGS_((Tk_Font tkfont, CONST char *source, int maxBytes, int startX, - int maxX, int tabOrigin, int *nextXPtr)); + int maxX, int *nextXPtr)); static void MeasureUp _ANSI_ARGS_((TkText *textPtr, CONST TkTextIndex *srcPtr, int distance, TkTextIndex *dstPtr, int *overlap)); @@ -5285,14 +5285,13 @@ GetXView(interp, textPtr, report) dInfoPtr->xScrollFirst = first; dInfoPtr->xScrollLast = last; if (textPtr->xScrollCmd != NULL) { - listObj = Tcl_NewStringObj(textPtr->xScrollCmd, -1); - code = Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewDoubleObj(first)); - if (code == TCL_OK) { - Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(last)); - code = Tcl_EvalObjEx(interp, listObj, - TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); - } + char buf1[TCL_DOUBLE_SPACE+1]; + char buf2[TCL_DOUBLE_SPACE+1]; + buf1[0] = ' '; + buf2[0] = ' '; + Tcl_PrintDouble(NULL, first, buf1+1); + Tcl_PrintDouble(NULL, last, buf2+1); + code = Tcl_VarEval(interp, textPtr->xScrollCmd, buf1, buf2, NULL); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (horizontal scrolling command executed by text)"); @@ -5543,14 +5542,13 @@ GetYView(interp, textPtr, report) dInfoPtr->yScrollFirst = first; dInfoPtr->yScrollLast = last; if (textPtr->yScrollCmd != NULL) { - listObj = Tcl_NewStringObj(textPtr->yScrollCmd, -1); - code = Tcl_ListObjAppendElement(interp, listObj, - Tcl_NewDoubleObj(first)); - if (code == TCL_OK) { - Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(last)); - code = Tcl_EvalObjEx(interp, listObj, - TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL); - } + char buf1[TCL_DOUBLE_SPACE+1]; + char buf2[TCL_DOUBLE_SPACE+1]; + buf1[0] = ' '; + buf2[0] = ' '; + Tcl_PrintDouble(NULL, first, buf1+1); + Tcl_PrintDouble(NULL, last, buf2+1); + code = Tcl_VarEval(interp, textPtr->yScrollCmd, buf1, buf2, NULL); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (vertical scrolling command executed by text)"); @@ -6228,14 +6226,14 @@ TkTextCharLayoutProc(textPtr, indexPtr, segPtr, byteOffset, maxX, maxBytes, p = segPtr->body.chars + byteOffset; tkfont = chunkPtr->stylePtr->sValuePtr->tkfont; - bytesThatFit = MeasureChars(tkfont, p, maxBytes, chunkPtr->x, maxX, 0, - &nextX); + bytesThatFit = MeasureChars(tkfont, p, maxBytes, chunkPtr->x, maxX, + &nextX); if (bytesThatFit < maxBytes) { if ((bytesThatFit == 0) && noCharsYet) { Tcl_UniChar ch; bytesThatFit = MeasureChars(tkfont, p, Tcl_UtfToUniChar(p, &ch), - chunkPtr->x, -1, 0, &nextX); + chunkPtr->x, -1, &nextX); } if ((nextX < maxX) && ((p[bytesThatFit] == ' ') || (p[bytesThatFit] == '\t'))) { @@ -6382,7 +6380,7 @@ CharDisplayProc(chunkPtr, x, y, height, baseline, display, dst, screenY) offsetBytes = 0; if (x < 0) { offsetBytes = MeasureChars(sValuePtr->tkfont, ciPtr->chars, - ciPtr->numBytes, x, 0, x - chunkPtr->x, &offsetX); + ciPtr->numBytes, x, 0, &offsetX); } /* @@ -6475,7 +6473,7 @@ CharMeasureProc(chunkPtr, x) int endX; return MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, - chunkPtr->numBytes - 1, chunkPtr->x, x, 0, &endX); + chunkPtr->numBytes - 1, chunkPtr->x, x, &endX); /* CHAR OFFSET */ } @@ -6527,7 +6525,7 @@ CharBboxProc(chunkPtr, byteIndex, y, lineHeight, baseline, xPtr, yPtr, maxX = chunkPtr->width + chunkPtr->x; MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, ciPtr->chars, - byteIndex, chunkPtr->x, -1, 0, xPtr); + byteIndex, chunkPtr->x, -1, xPtr); if (byteIndex == ciPtr->numBytes) { /* @@ -6547,7 +6545,7 @@ CharBboxProc(chunkPtr, byteIndex, y, lineHeight, baseline, xPtr, yPtr, *widthPtr = maxX - *xPtr; } else { MeasureChars(chunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars + byteIndex, 1, *xPtr, -1, 0, widthPtr); + ciPtr->chars + byteIndex, 1, *xPtr, -1, widthPtr); if (*widthPtr > maxX) { *widthPtr = maxX - *xPtr; } else { @@ -6698,7 +6696,7 @@ AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) ciPtr = (CharInfo *) decimalChunkPtr->clientData; MeasureChars(decimalChunkPtr->stylePtr->sValuePtr->tkfont, - ciPtr->chars, decimal, decimalChunkPtr->x, -1, 0, &curX); + ciPtr->chars, decimal, decimalChunkPtr->x, -1, &curX); desired = tabX - (curX - x); goto update; } else { @@ -6723,7 +6721,7 @@ AdjustForTab(textPtr, tabArrayPtr, index, chunkPtr) update: delta = desired - x; - MeasureChars(textPtr->tkfont, " ", 1, 0, -1, 0, &spaceWidth); + MeasureChars(textPtr->tkfont, " ", 1, 0, -1, &spaceWidth); if (delta < spaceWidth) { delta = spaceWidth; } @@ -6852,7 +6850,7 @@ SizeOfTab(textPtr, tabArrayPtr, indexPtr, x, maxX) } done: - MeasureChars(textPtr->tkfont, " ", 1, 0, -1, 0, &spaceWidth); + MeasureChars(textPtr->tkfont, " ", 1, 0, -1, &spaceWidth); if (result < spaceWidth) { result = spaceWidth; } @@ -6911,15 +6909,14 @@ NextTabStop(tkfont, x, tabOrigin) * * Determine the number of characters from the string that will fit * in the given horizontal span. The measurement is done under the - * assumption that Tk_DrawTextLayout will be used to actually display + * assumption that Tk_DrawChars will be used to actually display * the characters. * * If tabs are encountered in the string, they will be expanded - * to the next tab stop, unless the TK_IGNORE_TABS flag is specified. + * to the next tab stop. * * If a newline is encountered in the string, the line will be - * broken at that point, unless the TK_NEWSLINES_NOT_SPECIAL flag - * is specified. + * broken at that point. * * Results: * The return value is the number of bytes from source @@ -6935,7 +6932,7 @@ NextTabStop(tkfont, x, tabOrigin) */ static int -MeasureChars(tkfont, source, maxBytes, startX, maxX, tabOrigin, nextXPtr) +MeasureChars(tkfont, source, maxBytes, startX, maxX, nextXPtr) Tk_Font tkfont; /* Font in which to draw characters. */ CONST char *source; /* Characters to be displayed. Need not * be NULL-terminated. */ @@ -6945,8 +6942,6 @@ MeasureChars(tkfont, source, maxBytes, startX, maxX, tabOrigin, nextXPtr) * be drawn. */ int maxX; /* Don't consider any character that would * cross this x-position. */ - int tabOrigin; /* X-location that serves as "origin" for - * tab stops. */ int *nextXPtr; /* Return x-position of terminating * character here. */ { @@ -6979,8 +6974,8 @@ MeasureChars(tkfont, source, maxBytes, startX, maxX, tabOrigin, nextXPtr) if ((maxX >= 0) && (curX >= maxX)) { break; } - start += Tk_MeasureChars(tkfont, start, special - start, maxX - curX, - 0, &width); + start += Tk_MeasureChars(tkfont, start, special - start, + maxX - curX, 0, &width); curX += width; if (start < special) { /* diff --git a/generic/tkTextImage.c b/generic/tkTextImage.c index f086fbd..4f6535f 100644 --- a/generic/tkTextImage.c +++ b/generic/tkTextImage.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextImage.c,v 1.10 2003/11/07 15:36:26 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextImage.c,v 1.11 2003/12/04 12:28:37 vincentdarley Exp $ */ #include "tk.h" @@ -711,9 +711,9 @@ EmbImageBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, int *xPtr, *yPtr; /* Gets filled in with coords of * character's upper-left pixel. */ int *widthPtr; /* Gets filled in with width of - * character, in pixels. */ + * image, in pixels. */ int *heightPtr; /* Gets filled in with height of - * character, in pixels. */ + * image, in pixels. */ { TkTextSegment *eiPtr = (TkTextSegment *) chunkPtr->clientData; Tk_Image image; diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c index ab0a4e9..b5da014 100644 --- a/generic/tkTextWind.c +++ b/generic/tkTextWind.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextWind.c,v 1.10 2003/11/15 02:33:51 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextWind.c,v 1.11 2003/12/04 12:28:37 vincentdarley Exp $ */ #include "tk.h" @@ -997,9 +997,9 @@ EmbWinBboxProc(chunkPtr, index, y, lineHeight, baseline, xPtr, yPtr, int *xPtr, *yPtr; /* Gets filled in with coords of * character's upper-left pixel. */ int *widthPtr; /* Gets filled in with width of - * character, in pixels. */ + * window, in pixels. */ int *heightPtr; /* Gets filled in with height of - * character, in pixels. */ + * window, in pixels. */ { TkTextSegment *ewPtr = (TkTextSegment *) chunkPtr->clientData; Tk_Window tkwin; diff --git a/library/demos/twind.tcl b/library/demos/twind.tcl index d03c818..48a0c20 100644 --- a/library/demos/twind.tcl +++ b/library/demos/twind.tcl @@ -3,7 +3,7 @@ # This demonstration script creates a text widget with a bunch of # embedded windows. # -# RCS: @(#) $Id: twind.tcl,v 1.4 2003/08/20 23:02:18 hobbs Exp $ +# RCS: @(#) $Id: twind.tcl,v 1.5 2003/12/04 12:28:37 vincentdarley Exp $ if {![info exists widgetDemo]} { error "This script should be run from the \"widget\" demo." @@ -12,7 +12,7 @@ if {![info exists widgetDemo]} { set w .twind catch {destroy $w} toplevel $w -wm title $w "Text Demonstration - Embedded Windows" +wm title $w "Text Demonstration - Embedded Windows and Other Features" wm iconname $w "Embedded Windows" positionWindow $w @@ -41,6 +41,12 @@ button $t.click -text "Click Here" -command "textWindPlot $t" \ button $t.delete -text "Delete" -command "textWindDel $w" \ -cursor top_left_arrow +$t insert end "A text widget can contain many different kinds of items, " +$t insert end "both active and passive. It can lay these out in various " +$t insert end "ways, with wrapping, tabs, centering, etc. In addition, " +$t insert end "when the contents are too big for the window, smooth " +$t insert end "scrolling in all directions is provided.\n\n" + $t insert end "A text widget can contain other widgets embedded " $t insert end "it. These are called \"embedded windows\", " $t insert end "and they can consist of arbitrary widgets. " @@ -97,6 +103,63 @@ foreach color {AntiqueWhite3 Bisque1 Bisque2 Bisque3 Bisque4 } $t tag add buttons $t.default end +button $t.bigB -text "Big borders" -command "textWindBigB $t" \ + -cursor top_left_arrow +button $t.smallB -text "Small borders" -command "textWindSmallB $t" \ + -cursor top_left_arrow +button $t.bigH -text "Big highlight" -command "textWindBigH $t" \ + -cursor top_left_arrow +button $t.smallH -text "Small highlight" -command "textWindSmallH $t" \ + -cursor top_left_arrow +button $t.bigP -text "Big pad" -command "textWindBigP $t" \ + -cursor top_left_arrow +button $t.smallP -text "Small pad" -command "textWindSmallP $t" \ + -cursor top_left_arrow + +set text_normal(border) [$t cget -borderwidth] +set text_normal(highlight) [$t cget -highlightthickness] +set text_normal(pad) [$t cget -padx] + +$t insert end "\nYou can also change the usual border width and " +$t insert end "highlightthickness and padding.\n" +$t window create end -window $t.bigB +$t window create end -window $t.smallB +$t window create end -window $t.bigH +$t window create end -window $t.smallH +$t window create end -window $t.bigP +$t window create end -window $t.smallP + +$t insert end "\n\nFinally, images fit comfortably in text widgets too:" + +$t image create end -image \ + [image create bitmap -file [file join $tk_demoDirectory images face.bmp]] + + +proc textWindBigB w { + $w configure -borderwidth 15 +} + +proc textWindBigH w { + $w configure -highlightthickness 15 +} + +proc textWindBigP w { + $w configure -padx 15 -pady 15 +} + +proc textWindSmallB w { + $w configure -borderwidth $::text_normal(border) +} + +proc textWindSmallH w { + $w configure -highlightthickness $::text_normal(highlight) +} + +proc textWindSmallP w { + $w configure -padx $::text_normal(pad) -pady $::text_normal(pad) +} + + proc textWindOn w { catch {destroy $w.scroll2} set t $w.f.text diff --git a/library/demos/widget b/library/demos/widget index 4a1c3c5..a0c1458 100644 --- a/library/demos/widget +++ b/library/demos/widget @@ -11,7 +11,7 @@ exec wish "$0" "$@" # ".tcl" files is this directory, which are sourced by this script # as needed. # -# RCS: @(#) $Id: widget,v 1.20 2003/11/05 13:31:12 dkf Exp $ +# RCS: @(#) $Id: widget,v 1.21 2003/12/04 12:28:37 vincentdarley Exp $ package require Tcl 8.4 package require Tk 8.4 @@ -298,7 +298,7 @@ addDemoSection "Text" { text "Basic editable text" style "Text display styles" bind "Hypertext (tag bindings)" - twind "A text widget with embedded windows" + twind "A text widget with embedded windows and other features" search "A search tool built with a text widget" } addDemoSection "Canvases" { diff --git a/tests/text.test b/tests/text.test index 9e85c8b..f7d0113 100644 --- a/tests/text.test +++ b/tests/text.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: text.test,v 1.25 2003/11/08 17:22:46 vincentdarley Exp $ +# RCS: @(#) $Id: text.test,v 1.26 2003/12/04 12:28:37 vincentdarley Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -2899,6 +2899,24 @@ test text-26.1 {bug fix - 624372, ControlUtfProc long lines} { .t insert end [string repeat "\1" 500] } {} +test text-27.1 {tabs - must be positive and must be increasing} { + destroy .t + pack [text .t -wrap none] + list [catch {.t configure -tabs {0}} msg] $msg +} {1 {tab stop "0" is not at a positive distance}} + +test text-27.2 {tabs - must be positive and must be increasing} { + destroy .t + pack [text .t -wrap none] + list [catch {.t configure -tabs {-5}} msg] $msg +} {1 {tab stop "-5" is not at a positive distance}} + +test text-27.3 {tabs - must be positive and must be increasing} { + destroy .t + pack [text .t -wrap none] + list [catch {.t configure -tabs {10c 5c}} msg] $msg +} {1 {tabs must be monotonically increasing, but "5c" is smaller than or equal to the previous tab}} + deleteWindows option clear -- cgit v0.12