Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

PATCH: character widths in completion



Some more points where we need character widths, as well as one that
looks like it needs downgrading from ztrlen() to strlen() since (unless
anyone can tell me otherwise) it looks like it operates on raw strings
rather than either metafied characters or multibyte characters.  But I
get so confused.

Index: Src/utils.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/utils.c,v
retrieving revision 1.133
diff -u -r1.133 utils.c
--- Src/utils.c	4 Aug 2006 13:38:27 -0000	1.133
+++ Src/utils.c	11 Aug 2006 21:20:03 -0000
@@ -3937,11 +3937,13 @@
  * 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 @@
 		/* 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;
 	}
     }
Index: Src/zsh.h
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/zsh.h,v
retrieving revision 1.94
diff -u -r1.94 zsh.h
--- Src/zsh.h	24 Jul 2006 22:00:21 -0000	1.94
+++ Src/zsh.h	11 Aug 2006 21:20:05 -0000
@@ -1928,7 +1928,15 @@
 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 @@
 #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
Index: Src/Zle/complist.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/complist.c,v
retrieving revision 1.90
diff -u -r1.90 complist.c
--- Src/Zle/complist.c	10 Aug 2006 16:34:19 -0000	1.90
+++ Src/Zle/complist.c	11 Aug 2006 21:20:06 -0000
@@ -888,57 +888,78 @@
 	} 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 @@
 		    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 @@
 			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 @@
 			m = 2;
 		    }
 		    break;
-		case 'P':
+		case ZWC('P'):
 		    if (stat) {
 			if (ml == listdat.nlines - 1)
 			    strcpy(nc, "Bottom");
@@ -1001,6 +1022,7 @@
 		    break;
 		}
 		if (m == 2 && dopr == 1) {
+		    /* nc only contains ASCII text */
 		    int l = strlen(nc);
 
 		    if (l + cc > columns - 2)
@@ -1018,9 +1040,11 @@
 	    } 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 @@
 		    dopr = 0;
 		    continue;
 		}
-		putc(chr, shout);
+		while (len--)
+		    putc(*p++, shout);
 		if ((beg = !(cc % columns)) && !stat) {
 		    ml++;
                     fputs(" \010", shout);
Index: Src/Zle/compresult.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/compresult.c,v
retrieving revision 1.64
diff -u -r1.64 compresult.c
--- Src/Zle/compresult.c	9 Aug 2006 22:08:39 -0000	1.64
+++ Src/Zle/compresult.c	11 Aug 2006 21:20:08 -0000
@@ -573,7 +573,7 @@
     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 @@
 
     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 @@
 	    /* 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 @@
 		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 @@
 		/*** nlines--; */
 	    } else {
 		while (*pp) {
-		    l = ztrlen(*pp);
+		    l = MB_METASTRWIDTH(*pp);
 		    ndisp++;
 		    if (l > glong)
 			glong = l;
@@ -1605,7 +1614,7 @@
 			g->width = 1;
 			
 			while (*pp)
-			    glines += 1 + (ztrlen(*pp++) / columns);
+			    glines += 1 + (MB_METASTRWIDTH(*pp++) / columns);
 		    }
 		}
 	    } else {
@@ -1648,7 +1657,7 @@
 		    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 @@
 		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 @@
 			zputs(*pq, shout);
 			if (i) {
 			    a = (g->widths ? g->widths[mc] : g->width) -
-				strlen(*pq);
+				MB_METASTRWIDTH(*pq);
 			    while (a--)
 				putc(' ', shout);
 			}
Index: Src/Zle/zle_tricky.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_tricky.c,v
retrieving revision 1.72
diff -u -r1.72 zle_tricky.c
--- Src/Zle/zle_tricky.c	10 Aug 2006 16:34:19 -0000	1.72
+++ Src/Zle/zle_tricky.c	11 Aug 2006 21:20:09 -0000
@@ -2072,9 +2072,9 @@
     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 @@
 		    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 @@
 		}
 	    } else
 		break;
+	    p++;
 	} else {
-	    cc++;
 	    if (*p == '\n') {
+		cc++;
 		if (dopr) {
 		    if (tccan(TCCLEAREOL))
 			tcout(TCCLEAREOL);
@@ -2155,12 +2156,20 @@
 		}
 		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) {

-- 
Peter Stephenson <p.w.stephenson@xxxxxxxxxxxx>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/



Messages sorted by: Reverse Date, Date, Thread, Author