Fossil SCM
Take into account zero-width and double-width unicode character when formatting the command-line timeline.
Commit
83743188a37564c29035c46689d77b8eff198bb4136fc18ece6961de85d00ddc
Parent
c0f0e1dc7b80fe5…
1 file changed
+149
-1
+149
-1
| --- src/comformat.c | ||
| +++ src/comformat.c | ||
| @@ -31,10 +31,146 @@ | ||
| 31 | 31 | #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */ |
| 32 | 32 | #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */ |
| 33 | 33 | #define COMMENT_PRINT_UNSET (-1) /* Not initialized. */ |
| 34 | 34 | #endif |
| 35 | 35 | |
| 36 | +/********* Code copied from SQLite src/shell.c.in on 2024-09-28 **********/ | |
| 37 | +/* Lookup table to estimate the number of columns consumed by a Unicode | |
| 38 | +** character. | |
| 39 | +*/ | |
| 40 | +static const struct { | |
| 41 | + unsigned char w; /* Width of the character in columns */ | |
| 42 | + int iFirst; /* First character in a span having this width */ | |
| 43 | +} aUWidth[] = { | |
| 44 | + /* {0, 0x00000}, {1, 0x00020}, {0, 0x0007f}, {1, 0x000a0}, */ | |
| 45 | + {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488}, | |
| 46 | + {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0}, | |
| 47 | + {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7}, | |
| 48 | + {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616}, | |
| 49 | + {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6}, | |
| 50 | + {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee}, | |
| 51 | + {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730}, | |
| 52 | + {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4}, | |
| 53 | + {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941}, | |
| 54 | + {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955}, | |
| 55 | + {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc}, | |
| 56 | + {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce}, | |
| 57 | + {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c}, | |
| 58 | + {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49}, | |
| 59 | + {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81}, | |
| 60 | + {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6}, | |
| 61 | + {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2}, | |
| 62 | + {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d}, | |
| 63 | + {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d}, | |
| 64 | + {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83}, | |
| 65 | + {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e}, | |
| 66 | + {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e}, | |
| 67 | + {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf}, | |
| 68 | + {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce}, | |
| 69 | + {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d}, | |
| 70 | + {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5}, | |
| 71 | + {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34}, | |
| 72 | + {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2}, | |
| 73 | + {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8}, | |
| 74 | + {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36}, | |
| 75 | + {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71}, | |
| 76 | + {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88}, | |
| 77 | + {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6}, | |
| 78 | + {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033}, | |
| 79 | + {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058}, | |
| 80 | + {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f}, | |
| 81 | + {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735}, | |
| 82 | + {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4}, | |
| 83 | + {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7}, | |
| 84 | + {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b}, | |
| 85 | + {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923}, | |
| 86 | + {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939}, | |
| 87 | + {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04}, | |
| 88 | + {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c}, | |
| 89 | + {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74}, | |
| 90 | + {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b}, | |
| 91 | + {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064}, | |
| 92 | + {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329}, | |
| 93 | + {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f}, | |
| 94 | + {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806}, | |
| 95 | + {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827}, | |
| 96 | + {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e}, | |
| 97 | + {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20}, | |
| 98 | + {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00}, | |
| 99 | + {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc}, | |
| 100 | + {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c}, | |
| 101 | + {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40}, | |
| 102 | + {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185}, | |
| 103 | + {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245}, | |
| 104 | + {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001}, | |
| 105 | + {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0} | |
| 106 | +}; | |
| 107 | + | |
| 108 | +/* | |
| 109 | +** Return an estimate of the width, in columns, for the single Unicode | |
| 110 | +** character c. For normal characters, the answer is always 1. But the | |
| 111 | +** estimate might be 0 or 2 for zero-width and double-width characters. | |
| 112 | +** | |
| 113 | +** Different display devices display unicode using different widths. So | |
| 114 | +** it is impossible to know that true display width with 100% accuracy. | |
| 115 | +** Inaccuracies in the width estimates might cause columns to be misaligned. | |
| 116 | +** Unfortunately, there is nothing we can do about that. | |
| 117 | +*/ | |
| 118 | +static int cli_wcwidth(int c){ | |
| 119 | + int iFirst, iLast; | |
| 120 | + | |
| 121 | + /* Fast path for common characters */ | |
| 122 | + if( c<0x20 ) return 0; | |
| 123 | + if( c<0x7f ) return 1; | |
| 124 | + if( c<0xa0 ) return 0; | |
| 125 | + if( c<=0x300 ) return 1; | |
| 126 | + | |
| 127 | + /* The general case */ | |
| 128 | + iFirst = 0; | |
| 129 | + iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1; | |
| 130 | + while( iFirst<iLast-1 ){ | |
| 131 | + int iMid = (iFirst+iLast)/2; | |
| 132 | + int cMid = aUWidth[iMid].iFirst; | |
| 133 | + if( cMid < c ){ | |
| 134 | + iFirst = iMid; | |
| 135 | + }else if( cMid > c ){ | |
| 136 | + iLast = iMid - 1; | |
| 137 | + }else{ | |
| 138 | + return aUWidth[iMid].w; | |
| 139 | + } | |
| 140 | + } | |
| 141 | + if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w; | |
| 142 | + return aUWidth[iLast].w; | |
| 143 | +} | |
| 144 | + | |
| 145 | +/* | |
| 146 | +** Compute the value and length of a multi-byte UTF-8 character that | |
| 147 | +** begins at z[0]. Return the length. Write the Unicode value into *pU. | |
| 148 | +** | |
| 149 | +** This routine only works for *multi-byte* UTF-8 characters. | |
| 150 | +*/ | |
| 151 | +static int decodeUtf8(const unsigned char *z, int *pU){ | |
| 152 | + if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){ | |
| 153 | + *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f); | |
| 154 | + return 2; | |
| 155 | + } | |
| 156 | + if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){ | |
| 157 | + *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f); | |
| 158 | + return 3; | |
| 159 | + } | |
| 160 | + if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 | |
| 161 | + && (z[3] & 0xc0)==0x80 | |
| 162 | + ){ | |
| 163 | + *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6 | |
| 164 | + | (z[4] & 0x3f); | |
| 165 | + return 4; | |
| 166 | + } | |
| 167 | + *pU = 0; | |
| 168 | + return 1; | |
| 169 | +} | |
| 170 | +/******* End of code copied from SQLite *************************************/ | |
| 171 | + | |
| 36 | 172 | /* |
| 37 | 173 | ** This is the previous value used by most external callers when they |
| 38 | 174 | ** needed to specify a default maximum line length to be used with the |
| 39 | 175 | ** comment_print() function. |
| 40 | 176 | */ |
| @@ -294,10 +430,15 @@ | ||
| 294 | 430 | while( cchUTF8<maxUTF8 && |
| 295 | 431 | (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 296 | 432 | cchUTF8++; |
| 297 | 433 | zBuf[iBuf++] = zLine[index++]; |
| 298 | 434 | } |
| 435 | + if( cchUTF8>1 ){ | |
| 436 | + int utf32; | |
| 437 | + decodeUtf8((const unsigned char*)&zLine[index-cchUTF8],&utf32); | |
| 438 | + useChars += cli_wcwidth(utf32) - 1; | |
| 439 | + } | |
| 299 | 440 | maxChars -= useChars; |
| 300 | 441 | if( maxChars<=0 ) break; |
| 301 | 442 | if( c=='\n' ) break; |
| 302 | 443 | } |
| 303 | 444 | if( charCnt>0 ){ |
| @@ -380,10 +521,15 @@ | ||
| 380 | 521 | (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 381 | 522 | cchUTF8++; |
| 382 | 523 | zBuf[k++] = zText[++i]; |
| 383 | 524 | } |
| 384 | 525 | } |
| 526 | + if( cchUTF8>1 ){ | |
| 527 | + int utf32; | |
| 528 | + decodeUtf8((const unsigned char*)&zText[k-cchUTF8],&utf32); | |
| 529 | + kc += cli_wcwidth(utf32) - 1; | |
| 530 | + } | |
| 385 | 531 | else if( fossil_isspace(c) ){ |
| 386 | 532 | si = i; |
| 387 | 533 | sk = k; |
| 388 | 534 | if( k==0 || zBuf[k-1]!=' ' ){ |
| 389 | 535 | zBuf[k++] = ' '; |
| @@ -497,11 +643,13 @@ | ||
| 497 | 643 | zLine = zText; |
| 498 | 644 | for(;;){ |
| 499 | 645 | comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0, |
| 500 | 646 | maxChars, trimCrLf, trimSpace, wordBreak, origBreak, |
| 501 | 647 | &lineCnt, &zLine); |
| 502 | - if( !zLine || !zLine[0] ) break; | |
| 648 | + if( zLine==0 ) break; | |
| 649 | + while( fossil_isspace(zLine[0]) ) zLine++; | |
| 650 | + if( zLine[0]==0 ) break; | |
| 503 | 651 | } |
| 504 | 652 | return lineCnt; |
| 505 | 653 | } |
| 506 | 654 | |
| 507 | 655 | /* |
| 508 | 656 |
| --- src/comformat.c | |
| +++ src/comformat.c | |
| @@ -31,10 +31,146 @@ | |
| 31 | #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */ |
| 32 | #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */ |
| 33 | #define COMMENT_PRINT_UNSET (-1) /* Not initialized. */ |
| 34 | #endif |
| 35 | |
| 36 | /* |
| 37 | ** This is the previous value used by most external callers when they |
| 38 | ** needed to specify a default maximum line length to be used with the |
| 39 | ** comment_print() function. |
| 40 | */ |
| @@ -294,10 +430,15 @@ | |
| 294 | while( cchUTF8<maxUTF8 && |
| 295 | (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 296 | cchUTF8++; |
| 297 | zBuf[iBuf++] = zLine[index++]; |
| 298 | } |
| 299 | maxChars -= useChars; |
| 300 | if( maxChars<=0 ) break; |
| 301 | if( c=='\n' ) break; |
| 302 | } |
| 303 | if( charCnt>0 ){ |
| @@ -380,10 +521,15 @@ | |
| 380 | (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 381 | cchUTF8++; |
| 382 | zBuf[k++] = zText[++i]; |
| 383 | } |
| 384 | } |
| 385 | else if( fossil_isspace(c) ){ |
| 386 | si = i; |
| 387 | sk = k; |
| 388 | if( k==0 || zBuf[k-1]!=' ' ){ |
| 389 | zBuf[k++] = ' '; |
| @@ -497,11 +643,13 @@ | |
| 497 | zLine = zText; |
| 498 | for(;;){ |
| 499 | comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0, |
| 500 | maxChars, trimCrLf, trimSpace, wordBreak, origBreak, |
| 501 | &lineCnt, &zLine); |
| 502 | if( !zLine || !zLine[0] ) break; |
| 503 | } |
| 504 | return lineCnt; |
| 505 | } |
| 506 | |
| 507 | /* |
| 508 |
| --- src/comformat.c | |
| +++ src/comformat.c | |
| @@ -31,10 +31,146 @@ | |
| 31 | #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */ |
| 32 | #define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */ |
| 33 | #define COMMENT_PRINT_UNSET (-1) /* Not initialized. */ |
| 34 | #endif |
| 35 | |
| 36 | /********* Code copied from SQLite src/shell.c.in on 2024-09-28 **********/ |
| 37 | /* Lookup table to estimate the number of columns consumed by a Unicode |
| 38 | ** character. |
| 39 | */ |
| 40 | static const struct { |
| 41 | unsigned char w; /* Width of the character in columns */ |
| 42 | int iFirst; /* First character in a span having this width */ |
| 43 | } aUWidth[] = { |
| 44 | /* {0, 0x00000}, {1, 0x00020}, {0, 0x0007f}, {1, 0x000a0}, */ |
| 45 | {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488}, |
| 46 | {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0}, |
| 47 | {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7}, |
| 48 | {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616}, |
| 49 | {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6}, |
| 50 | {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee}, |
| 51 | {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730}, |
| 52 | {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4}, |
| 53 | {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941}, |
| 54 | {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955}, |
| 55 | {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc}, |
| 56 | {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce}, |
| 57 | {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c}, |
| 58 | {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49}, |
| 59 | {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81}, |
| 60 | {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6}, |
| 61 | {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2}, |
| 62 | {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d}, |
| 63 | {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d}, |
| 64 | {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83}, |
| 65 | {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e}, |
| 66 | {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e}, |
| 67 | {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf}, |
| 68 | {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce}, |
| 69 | {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d}, |
| 70 | {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5}, |
| 71 | {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34}, |
| 72 | {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2}, |
| 73 | {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8}, |
| 74 | {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36}, |
| 75 | {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71}, |
| 76 | {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88}, |
| 77 | {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6}, |
| 78 | {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033}, |
| 79 | {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058}, |
| 80 | {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f}, |
| 81 | {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735}, |
| 82 | {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4}, |
| 83 | {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7}, |
| 84 | {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b}, |
| 85 | {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923}, |
| 86 | {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939}, |
| 87 | {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04}, |
| 88 | {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c}, |
| 89 | {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74}, |
| 90 | {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b}, |
| 91 | {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064}, |
| 92 | {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329}, |
| 93 | {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f}, |
| 94 | {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806}, |
| 95 | {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827}, |
| 96 | {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e}, |
| 97 | {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20}, |
| 98 | {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00}, |
| 99 | {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc}, |
| 100 | {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c}, |
| 101 | {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40}, |
| 102 | {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185}, |
| 103 | {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245}, |
| 104 | {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001}, |
| 105 | {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0} |
| 106 | }; |
| 107 | |
| 108 | /* |
| 109 | ** Return an estimate of the width, in columns, for the single Unicode |
| 110 | ** character c. For normal characters, the answer is always 1. But the |
| 111 | ** estimate might be 0 or 2 for zero-width and double-width characters. |
| 112 | ** |
| 113 | ** Different display devices display unicode using different widths. So |
| 114 | ** it is impossible to know that true display width with 100% accuracy. |
| 115 | ** Inaccuracies in the width estimates might cause columns to be misaligned. |
| 116 | ** Unfortunately, there is nothing we can do about that. |
| 117 | */ |
| 118 | static int cli_wcwidth(int c){ |
| 119 | int iFirst, iLast; |
| 120 | |
| 121 | /* Fast path for common characters */ |
| 122 | if( c<0x20 ) return 0; |
| 123 | if( c<0x7f ) return 1; |
| 124 | if( c<0xa0 ) return 0; |
| 125 | if( c<=0x300 ) return 1; |
| 126 | |
| 127 | /* The general case */ |
| 128 | iFirst = 0; |
| 129 | iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1; |
| 130 | while( iFirst<iLast-1 ){ |
| 131 | int iMid = (iFirst+iLast)/2; |
| 132 | int cMid = aUWidth[iMid].iFirst; |
| 133 | if( cMid < c ){ |
| 134 | iFirst = iMid; |
| 135 | }else if( cMid > c ){ |
| 136 | iLast = iMid - 1; |
| 137 | }else{ |
| 138 | return aUWidth[iMid].w; |
| 139 | } |
| 140 | } |
| 141 | if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w; |
| 142 | return aUWidth[iLast].w; |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 | ** Compute the value and length of a multi-byte UTF-8 character that |
| 147 | ** begins at z[0]. Return the length. Write the Unicode value into *pU. |
| 148 | ** |
| 149 | ** This routine only works for *multi-byte* UTF-8 characters. |
| 150 | */ |
| 151 | static int decodeUtf8(const unsigned char *z, int *pU){ |
| 152 | if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){ |
| 153 | *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f); |
| 154 | return 2; |
| 155 | } |
| 156 | if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){ |
| 157 | *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f); |
| 158 | return 3; |
| 159 | } |
| 160 | if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 |
| 161 | && (z[3] & 0xc0)==0x80 |
| 162 | ){ |
| 163 | *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6 |
| 164 | | (z[4] & 0x3f); |
| 165 | return 4; |
| 166 | } |
| 167 | *pU = 0; |
| 168 | return 1; |
| 169 | } |
| 170 | /******* End of code copied from SQLite *************************************/ |
| 171 | |
| 172 | /* |
| 173 | ** This is the previous value used by most external callers when they |
| 174 | ** needed to specify a default maximum line length to be used with the |
| 175 | ** comment_print() function. |
| 176 | */ |
| @@ -294,10 +430,15 @@ | |
| 430 | while( cchUTF8<maxUTF8 && |
| 431 | (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 432 | cchUTF8++; |
| 433 | zBuf[iBuf++] = zLine[index++]; |
| 434 | } |
| 435 | if( cchUTF8>1 ){ |
| 436 | int utf32; |
| 437 | decodeUtf8((const unsigned char*)&zLine[index-cchUTF8],&utf32); |
| 438 | useChars += cli_wcwidth(utf32) - 1; |
| 439 | } |
| 440 | maxChars -= useChars; |
| 441 | if( maxChars<=0 ) break; |
| 442 | if( c=='\n' ) break; |
| 443 | } |
| 444 | if( charCnt>0 ){ |
| @@ -380,10 +521,15 @@ | |
| 521 | (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ |
| 522 | cchUTF8++; |
| 523 | zBuf[k++] = zText[++i]; |
| 524 | } |
| 525 | } |
| 526 | if( cchUTF8>1 ){ |
| 527 | int utf32; |
| 528 | decodeUtf8((const unsigned char*)&zText[k-cchUTF8],&utf32); |
| 529 | kc += cli_wcwidth(utf32) - 1; |
| 530 | } |
| 531 | else if( fossil_isspace(c) ){ |
| 532 | si = i; |
| 533 | sk = k; |
| 534 | if( k==0 || zBuf[k-1]!=' ' ){ |
| 535 | zBuf[k++] = ' '; |
| @@ -497,11 +643,13 @@ | |
| 643 | zLine = zText; |
| 644 | for(;;){ |
| 645 | comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0, |
| 646 | maxChars, trimCrLf, trimSpace, wordBreak, origBreak, |
| 647 | &lineCnt, &zLine); |
| 648 | if( zLine==0 ) break; |
| 649 | while( fossil_isspace(zLine[0]) ) zLine++; |
| 650 | if( zLine[0]==0 ) break; |
| 651 | } |
| 652 | return lineCnt; |
| 653 | } |
| 654 | |
| 655 | /* |
| 656 |