Fossil SCM

Take into account zero-width and double-width unicode character when formatting the command-line timeline.

drh 2024-09-28 18:21 trunk merge
Commit 83743188a37564c29035c46689d77b8eff198bb4136fc18ece6961de85d00ddc
1 file changed +149 -1
+149 -1
--- src/comformat.c
+++ src/comformat.c
@@ -31,10 +31,146 @@
3131
#define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
3232
#define COMMENT_PRINT_DEFAULT (COMMENT_PRINT_LEGACY) /* Defaults. */
3333
#define COMMENT_PRINT_UNSET (-1) /* Not initialized. */
3434
#endif
3535
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
+
36172
/*
37173
** This is the previous value used by most external callers when they
38174
** needed to specify a default maximum line length to be used with the
39175
** comment_print() function.
40176
*/
@@ -294,10 +430,15 @@
294430
while( cchUTF8<maxUTF8 &&
295431
(zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
296432
cchUTF8++;
297433
zBuf[iBuf++] = zLine[index++];
298434
}
435
+ if( cchUTF8>1 ){
436
+ int utf32;
437
+ decodeUtf8((const unsigned char*)&zLine[index-cchUTF8],&utf32);
438
+ useChars += cli_wcwidth(utf32) - 1;
439
+ }
299440
maxChars -= useChars;
300441
if( maxChars<=0 ) break;
301442
if( c=='\n' ) break;
302443
}
303444
if( charCnt>0 ){
@@ -380,10 +521,15 @@
380521
(zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */
381522
cchUTF8++;
382523
zBuf[k++] = zText[++i];
383524
}
384525
}
526
+ if( cchUTF8>1 ){
527
+ int utf32;
528
+ decodeUtf8((const unsigned char*)&zText[k-cchUTF8],&utf32);
529
+ kc += cli_wcwidth(utf32) - 1;
530
+ }
385531
else if( fossil_isspace(c) ){
386532
si = i;
387533
sk = k;
388534
if( k==0 || zBuf[k-1]!=' ' ){
389535
zBuf[k++] = ' ';
@@ -497,11 +643,13 @@
497643
zLine = zText;
498644
for(;;){
499645
comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0,
500646
maxChars, trimCrLf, trimSpace, wordBreak, origBreak,
501647
&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;
503651
}
504652
return lineCnt;
505653
}
506654
507655
/*
508656
--- 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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button