about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2006-08-11 21:30:38 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2006-08-11 21:30:38 +0000
commit2ccad2310ef04e5dff8a3717182cb7b065553185 (patch)
tree4a044bf7e5be5a1ac94d75e94e9a1b00ca3598e3
parent36c7a0a0b351c6a1d3cc51f7947e4c929e2f8aa8 (diff)
downloadzsh-2ccad2310ef04e5dff8a3717182cb7b065553185.tar.gz
zsh-2ccad2310ef04e5dff8a3717182cb7b065553185.tar.xz
zsh-2ccad2310ef04e5dff8a3717182cb7b065553185.zip
22599: use wide character widths in completion
-rw-r--r--ChangeLog6
-rw-r--r--Src/Zle/complist.c73
-rw-r--r--Src/Zle/compresult.c37
-rw-r--r--Src/Zle/zle_tricky.c27
-rw-r--r--Src/utils.c11
-rw-r--r--Src/zsh.h13
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  <p.w.stephenson@ntlworld.com>
+
+	* 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  <pws@csr.com>
 
 	* 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 == <number of matches>). */
-	/* 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