From 2ccad2310ef04e5dff8a3717182cb7b065553185 Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 11 Aug 2006 21:30:38 +0000 Subject: 22599: use wide character widths in completion --- ChangeLog | 6 +++++ Src/Zle/complist.c | 73 +++++++++++++++++++++++++++++++++++----------------- Src/Zle/compresult.c | 37 ++++++++++++++++---------- Src/Zle/zle_tricky.c | 27 ++++++++++++------- Src/utils.c | 11 +++++--- Src/zsh.h | 13 +++++++++- 6 files changed, 116 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index 45cdc3731..d126bf235 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2006-08-11 Peter Stephenson + + * 22599: Src/utils.c, Src/zsh.h, Src/Zle/complist.c, + Src/Zle/compresult.c, Src/Zle/zle_tricky.c: use wide character + widths in completion. + 2006-08-10 Peter Stephenson * unposted: Doc/Zsh/compsys.yo: trivial typo. diff --git a/Src/Zle/complist.c b/Src/Zle/complist.c index c90af8480..d982b22ce 100644 --- a/Src/Zle/complist.c +++ b/Src/Zle/complist.c @@ -888,57 +888,78 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) } else fmt = mlistp; } - for (p = fmt; *p; p++) { - int chr = (*p == Meta) ? *++p ^ 32 : *p; - if (doesc && chr == '%') { - chr = (*++p == Meta) ? *++p ^ 32 : *p; - if (chr) { + MB_METACHARINIT(); + for (p = fmt; *p; ) { + convchar_t cchar; + int len, width; + + len = MB_METACHARLENCONV(p, &cchar); +#ifdef MULTIBYTE_SUPPORT + if (cchar == WEOF) { + cchar = (wchar_t)p; + width = 1; + } + else +#endif + width = WCWIDTH(cchar); + + if (doesc && cchar == ZWC('%')) { + p += len; + if (*p) { + len = MB_METACHARLENCONV(p, &cchar); +#ifdef MULTIBYTE_SUPPORT + if (cchar == WEOF) + cchar = (wchar_t)p; +#endif + p += len; + m = 0; - switch (chr) { - case '%': + switch (cchar) { + case ZWC('%'): if (dopr == 1) putc('%', shout); cc++; break; - case 'n': + case ZWC('n'): if (!stat) { sprintf(nc, "%d", n); if (dopr == 1) fputs(nc, shout); + /* everything here is ASCII... */ cc += strlen(nc); } break; - case 'B': + case ZWC('B'): b = 1; if (dopr) tcout(TCBOLDFACEBEG); break; - case 'b': + case ZWC('b'): b = 0; m = 1; if (dopr) tcout(TCALLATTRSOFF); break; - case 'S': + case ZWC('S'): s = 1; if (dopr) tcout(TCSTANDOUTBEG); break; - case 's': + case ZWC('s'): s = 0; m = 1; if (dopr) tcout(TCSTANDOUTEND); break; - case 'U': + case ZWC('U'): u = 1; if (dopr) tcout(TCUNDERLINEBEG); break; - case 'u': + case ZWC('u'): u = 0; m = 1; if (dopr) tcout(TCUNDERLINEEND); break; - case '{': + case ZWC('{'): for (p++; *p && (*p != '%' || p[1] != '}'); p++) if (dopr) putc(*p == Meta ? *++p ^ 32 : *p, shout); @@ -947,14 +968,14 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) else p--; break; - case 'm': + case ZWC('m'): if (stat) { sprintf(nc, "%d/%d", (n ? mlastm : mselect), listdat.nlist); m = 2; } break; - case 'M': + case ZWC('M'): if (stat) { sprintf(nbuf, "%d/%d", (n ? mlastm : mselect), listdat.nlist); @@ -962,20 +983,20 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) m = 2; } break; - case 'l': + case ZWC('l'): if (stat) { sprintf(nc, "%d/%d", ml + 1, listdat.nlines); m = 2; } break; - case 'L': + case ZWC('L'): if (stat) { sprintf(nbuf, "%d/%d", ml + 1, listdat.nlines); sprintf(nc, "%-9s", nbuf); m = 2; } break; - case 'p': + case ZWC('p'): if (stat) { if (ml == listdat.nlines - 1) strcpy(nc, "Bottom"); @@ -987,7 +1008,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) m = 2; } break; - case 'P': + case ZWC('P'): if (stat) { if (ml == listdat.nlines - 1) strcpy(nc, "Bottom"); @@ -1001,6 +1022,7 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) break; } if (m == 2 && dopr == 1) { + /* nc only contains ASCII text */ int l = strlen(nc); if (l + cc > columns - 2) @@ -1018,9 +1040,11 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) } else break; } else { - if ((++cc == columns - 2 || chr == '\n') && stat) + cc += width; + + if ((cc >= columns - 2 || cchar == ZWC('\n')) && stat) dopr = 2; - if (chr == '\n') { + if (cchar == ZWC('\n')) { if (dopr == 1 && mlbeg >= 0 && tccan(TCCLEAREOL)) tcout(TCCLEAREOL); l += 1 + ((cc - 1) / columns); @@ -1031,7 +1055,8 @@ compprintfmt(char *fmt, int n, int dopr, int doesc, int ml, int *stop) dopr = 0; continue; } - putc(chr, shout); + while (len--) + putc(*p++, shout); if ((beg = !(cc % columns)) && !stat) { ml++; fputs(" \010", shout); diff --git a/Src/Zle/compresult.c b/Src/Zle/compresult.c index e3adc0803..e28212c19 100644 --- a/Src/Zle/compresult.c +++ b/Src/Zle/compresult.c @@ -573,7 +573,7 @@ unambig_data(int *cp, char **pp, char **ip) return scache; } -/* Insert the given match. This returns the number of characters inserted. +/* Insert the given match. This returns the number of bytes inserted. * scs is used to return the position where a automatically created suffix * has to be inserted. */ @@ -986,7 +986,12 @@ do_single(Cmatch m) if (m->suf) { havesuff = 1; - minfo.insc = ztrlen(m->suf); + /* + * This strlen(0 got converted to a ztrlen(), but I don't + * think that's correct since it's dealing with raw bytes, + * right? + */ + minfo.insc = strlen(m->suf); minfo.len -= minfo.insc; if (minfo.we) { minfo.end += minfo.insc; @@ -1466,7 +1471,7 @@ calclist(int showall) /* We have an ylist, lets see, if it contains newlines. */ hidden = 1; while (!nl && *pp) { - if (ztrlen(*pp) >= columns) + if (MB_METASTRWIDTH(*pp) >= columns) nl = 1; else nl = !!strchr(*pp++, '\n'); @@ -1479,12 +1484,16 @@ calclist(int showall) g->flags |= CGF_LINES; hidden = 1; while ((sptr = *pp)) { - while (sptr && *sptr) { - /* TODO: we need to use wcwidth() here */ - nlines += (nlptr = strchr(sptr, '\n')) - ? 1 + (nlptr - sptr - 1) / columns - : (ztrlen(sptr) - 1) / columns; - sptr = nlptr ? nlptr+1 : NULL; + while (*sptr) { + if ((nlptr = strchr(sptr, '\n'))) { + *nlptr = '\0'; + nlines += 1 + (MB_METASTRWIDTH(sptr)-1) / columns; + *nlptr = '\n'; + sptr = nlptr + 1; + } else { + nlines += (MB_METASTRWIDTH(sptr)-1) / columns; + break; + } } nlines++; pp++; @@ -1492,7 +1501,7 @@ calclist(int showall) /*** nlines--; */ } else { while (*pp) { - l = ztrlen(*pp); + l = MB_METASTRWIDTH(*pp); ndisp++; if (l > glong) glong = l; @@ -1605,7 +1614,7 @@ calclist(int showall) g->width = 1; while (*pp) - glines += 1 + (ztrlen(*pp++) / columns); + glines += 1 + (MB_METASTRWIDTH(*pp++) / columns); } } } else { @@ -1648,7 +1657,7 @@ calclist(int showall) VARARR(int, ylens, yl); for (i = 0; *pp; i++, pp++) - ylens[i] = ztrlen(*pp) + CM_SPACE; + ylens[i] = MB_METASTRWIDTH(*pp) + CM_SPACE; if (g->flags & CGF_ROWS) { int nth, tcol, len; @@ -1954,7 +1963,7 @@ printlist(int over, CLPrintFunc printm, int showall) while ((p = *pp++)) { zputs(p, shout); if (*pp) { - if (ztrlen(p) % columns) + if (MB_METASTRWIDTH(p) % columns) putc('\n', shout); else fputs(" \010", shout); @@ -1976,7 +1985,7 @@ printlist(int over, CLPrintFunc printm, int showall) zputs(*pq, shout); if (i) { a = (g->widths ? g->widths[mc] : g->width) - - strlen(*pq); + MB_METASTRWIDTH(*pq); while (a--) putc(' ', shout); } diff --git a/Src/Zle/zle_tricky.c b/Src/Zle/zle_tricky.c index fbe04ca5d..50c4a50da 100644 --- a/Src/Zle/zle_tricky.c +++ b/Src/Zle/zle_tricky.c @@ -2072,9 +2072,9 @@ printfmt(char *fmt, int n, int dopr, int doesc) char *p = fmt, nc[DIGBUFSIZE]; int l = 0, cc = 0, b = 0, s = 0, u = 0, m; - for (; *p; p++) { + MB_METACHARINIT(); + for (; *p; ) { /* Handle the `%' stuff (%% == %, %n == ). */ - /* TODO: we need to use wcwidth() to count cc */ if (doesc && *p == '%') { if (*++p) { m = 0; @@ -2088,7 +2088,7 @@ printfmt(char *fmt, int n, int dopr, int doesc) sprintf(nc, "%d", n); if (dopr) fprintf(shout, nc); - cc += strlen(nc); + cc += MB_METASTRWIDTH(nc); break; case 'B': b = 1; @@ -2140,9 +2140,10 @@ printfmt(char *fmt, int n, int dopr, int doesc) } } else break; + p++; } else { - cc++; if (*p == '\n') { + cc++; if (dopr) { if (tccan(TCCLEAREOL)) tcout(TCCLEAREOL); @@ -2155,12 +2156,20 @@ printfmt(char *fmt, int n, int dopr, int doesc) } l += 1 + ((cc - 1) / columns); cc = 0; + putc('\n', shout); + p++; + } else { + convchar_t cchar; + int clen = MB_METACHARLENCONV(p, &cchar); + if (dopr) { + while (clen--) + putc(*p++, shout); + } else + p += clen; + cc += WCWIDTH(cchar); + if (dopr && !(cc % columns)) + fputs(" \010", shout); } - if (dopr) { - putc(*p, shout); - if (!(cc % columns)) - fputs(" \010", shout); - } } } if (dopr) { diff --git a/Src/utils.c b/Src/utils.c index 8fdf2c0ab..2bfae667c 100644 --- a/Src/utils.c +++ b/Src/utils.c @@ -3937,11 +3937,13 @@ mb_metacharlenconv(const char *s, wint_t *wcp) * Total number of multibyte characters in metafied string s. * Same answer as iterating mb_metacharlen() and counting calls * until end of string. + * + * If width is 1, return total character width rather than number. */ /**/ int -mb_metastrlen(char *ptr) +mb_metastrlen(char *ptr, int width) { char inchar, *laststart; size_t ret; @@ -3971,9 +3973,12 @@ mb_metastrlen(char *ptr) /* Reset, treat as single character */ memset(&mb_shiftstate, 0, sizeof(mb_shiftstate)); ptr = laststart + (*laststart == Meta) + 1; - } + num++; + } else if (width) + num += wcwidth(wc); + else + num++; laststart = ptr; - num++; num_in_char = 0; } } diff --git a/Src/zsh.h b/Src/zsh.h index 25399b9d9..3c455b939 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -1928,7 +1928,15 @@ typedef char *(*ZleGetLineFn) _((int *, int *)); typedef wint_t convchar_t; #define MB_METACHARLENCONV(str, cp) mb_metacharlenconv((str), (cp)) #define MB_METACHARLEN(str) mb_metacharlenconv(str, NULL) -#define MB_METASTRLEN(str) mb_metastrlen(str) +#define MB_METASTRLEN(str) mb_metastrlen(str, 0) +#define MB_METASTRWIDTH(str) mb_metastrlen(str, 1) + +/* + * Note WCWIDTH() takes wint_t, typically as a convchar_t. + * It's written to use the wint_t from mb_metacharlenconv() without + * further tests. + */ +#define WCWIDTH(wc) ((wc == WEOF) ? 1 : wcwidth(wc)) #define MB_INCOMPLETE ((size_t)-2) #define MB_INVALID ((size_t)-1) @@ -1954,6 +1962,9 @@ typedef int convchar_t; #define MB_METACHARLENCONV(str, cp) metacharlenconv((str), (cp)) #define MB_METACHARLEN(str) (*(str) == Meta ? 2 : 1) #define MB_METASTRLEN(str) ztrlen(str) +#define MB_METASTRWIDTH(str) ztrlen(str) + +#define WCWIDTH(c) (1) /* Leave character or string as is. */ #define ZWC(c) c -- cgit 1.4.1