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

Re: zsh on short terminals



On Mon, 19 Mar 2007 13:13:17 +0000
Peter Stephenson <pws@xxxxxxx> wrote:
> "David Durrleman" <dualmoo@xxxxxxxxx> wrote:
> > If I run a terminal with less than 3 lines (geometry 80x1 for
> > example), then the first 17 chars of the prompt are not displayed
> 
> Yes, it's a bug.
> 
> This is a bit horrible.  Zsh goes into a special mode when the terminal
> height is less than 3, equivalent to single line mode---that's because it
> can't fit the two extra lines the line editor normally expects to be there
> as a minimum under the prompt.  However, it looks like single line mode has
> been allowed to lag behind the normal input mode and hasn't been fixed
> for ages.  I don't have time to rewrite it completely, so I'm not sure what
> to do.

Good news!  I exaggerated wildly.

Index: Src/Zle/zle_refresh.c
===================================================================
RCS file: /cvsroot/zsh/zsh/Src/Zle/zle_refresh.c,v
retrieving revision 1.46
diff -u -r1.46 zle_refresh.c
--- Src/Zle/zle_refresh.c	13 Jan 2006 17:46:09 -0000	1.46
+++ Src/Zle/zle_refresh.c	19 Mar 2007 22:22:56 -0000
@@ -227,7 +227,8 @@
     vcs, vln,			/* video cursor position column & line	    */
     vmaxln,			/* video maximum number of lines	    */
     winw, winh, rwinh,		/* window width & height		    */
-    winpos;			/* singlelinezle: line's position in window */
+    winpos,			/* singlelinezle: line's position in window */
+    winprompt;			/* singlelinezle: part of lprompt showing   */
 
 /**/
 void
@@ -242,7 +243,8 @@
     else
 	winh = (lines < 2) ? 24 : lines;
     rwinh = lines;		/* keep the real number of lines */
-    winpos = vln = vmaxln = 0;
+    vln = vmaxln = winprompt = 0;
+    winpos = -1;
     if (lwinw != winw || lwinh != winh) {
 	if (nbuf) {
 	    for (ln = 0; ln != lwinh; ln++) {
@@ -1443,21 +1445,12 @@
 {
     REFRESH_STRING vbuf, vp,	/* video buffer and pointer    */
 	*qbuf,			/* tmp			       */
-	refreshop = *obuf;	/* pointer to old video buffer */
+	refreshop;	        /* pointer to old video buffer */
     int t0,			/* tmp			       */
 	vsiz,			/* size of new video buffer    */
-	nvcs = 0;		/* new video cursor column     */
-#ifdef MULTIBYTE_SUPPORT
-    int eol = 0;		/* has mbrtowc() returned -2?  */
-    /*
-     * converted lprompt and pointer: no WEOF hack here since
-     * we always output the full prompt and count its width.
-     */
-    ZLE_STRING_T lpwbuf, lpwp;
-    char *lpptr,		/* pointer into multibyte lprompt */
-	*lpend;			/* end of multibyte lprompt */
-    mbstate_t mbs;		/* shift state */
-#endif
+	nvcs = 0,		/* new video cursor column     */
+	owinpos = winpos,	/* previous window position    */
+	owinprompt = winprompt;	/* previous winprompt          */
 
     nlnct = 1;
 /* generate the new line buffer completely */
@@ -1480,56 +1473,10 @@
 	tmpcs = 0;
     }
 
-    /* only use last part of prompt */
-#ifdef MULTIBYTE_SUPPORT
-    /*
-     * Convert the entire lprompt so that we know how to count
-     * characters.
-     */
-    lpend = strchr(lpromptbuf, 0);
-    /* Worst case number of characters, not null-terminated */
-    lpwp = lpwbuf = (ZLE_STRING_T)zalloc((lpend - lpromptbuf)
-					 * sizeof(*lpwbuf));
-    /* Reset shift state, maybe. */
-    memset(&mbs, '\0', sizeof mbs);
-    for (lpptr = lpromptbuf; lpptr < lpend; ) {
-	size_t cnt = eol ? MB_INVALID : mbrtowc(lpwp, lpptr, lpend-lpptr, &mbs);
-	switch (cnt) {
-	case MB_INCOMPLETE:
-	    eol = 1;
-	    /* FALL THROUGH */
-	case MB_INVALID:
-	    memset(&mbs, '\0', sizeof mbs);
-	    /* FALL THROUGH */
-	case 0:
-	    /* dunno, try to recover */
-	    lpptr++;
-	    *lpwp++ = ZWC('?');
-	    break;
-	default:
-	    /* successfully converted */
-	    lpptr += cnt;
-	    lpwp++;
-	    break;
-	}
-    }
-    if (lpwp - lpwbuf < lpromptw) {
-	/* Not enough characters for lpromptw. */
-	ZR_memcpy(vbuf, lpwbuf, lpwp - lpwbuf);
-	vp = vbuf + (lpwp - lpwbuf);
-	while (vp < vbuf + lpromptw)
-	    *vp++ = ZWC(' ');
-    } else {
-	ZR_memcpy(vbuf, lpwp - lpromptw, lpromptw);
-	vp = vbuf + lpromptw;
-    }
-    *vp = ZWC('\0');
-    zfree(lpwbuf, lpromptw * sizeof(*lpwbuf));
-#else
-    memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw);
-    vbuf[lpromptw] = '\0';
+    /* prompt is not directly copied into the video buffer */
+    ZR_memset(vbuf, ZWC(' '), lpromptw);
     vp = vbuf + lpromptw;
-#endif
+    *vp = ZWC('\0');
 
     for (t0 = 0; t0 < tmpll; t0++) {
 	if (tmpline[t0] == ZWC('\t')) {
@@ -1561,6 +1508,8 @@
     *vp = ZWC('\0');
 
 /* determine which part of the new line buffer we want for the display */
+    if (winpos == -1)
+	winpos = 0;
     if ((winpos && nvcs < winpos + 1) || (nvcs > winpos + winw - 2)) {
 	if ((winpos = nvcs - ((winw - hasam) / 2)) < 0)
 	    winpos = 0;
@@ -1575,10 +1524,71 @@
     zfree(vbuf, vsiz * sizeof(*vbuf));
     nvcs -= winpos;
 
-/* display the `visable' portion of the line buffer */
-    for (t0 = 0, vp = *nbuf;;) {
-    /* skip past all matching characters */
-	for (; *vp && *vp == *refreshop; t0++, vp++, refreshop++) ;
+    if (winpos < lpromptw) {
+	/* skip start of buffer corresponding to prompt */
+	winprompt = lpromptw - winpos;
+    } else {
+	/* don't */
+	winprompt = 0;
+    }
+    if (winpos != owinpos && winprompt) {
+	char *pptr;
+	int skipping = 0, skipchars = winpos;
+	/*
+	 * Need to output such part of the left prompt as fits.
+	 * Skip the first winpos characters, outputting
+	 * any characters marked with %{...%}.
+	 */
+	singmoveto(0);
+	MB_METACHARINIT();
+	for (pptr = lpromptbuf; *pptr; ) {
+	    if (*pptr == Inpar) {
+		skipping = 1;
+		pptr++;
+	    } else if (*pptr == Outpar) {
+		skipping = 0;
+		pptr++;
+	    } else {
+		convchar_t cc;
+		int mblen = MB_METACHARLENCONV(pptr, &cc);
+		if (skipping || skipchars == 0)
+		{
+		    while (mblen) {
+#ifdef MULTIBYTE_SUPPORT
+			if (cc == WEOF)
+			    fputc('?', shout);
+			else
+#endif
+			    if (*pptr == Meta) {
+				mblen--;
+				fputc(*++pptr ^ 32, shout);
+			    } else {
+				fputc(*pptr, shout);
+			    }
+			pptr++;
+			mblen--;
+		    }
+		} else {
+		    skipchars--;
+		    pptr += mblen;
+		}
+	    }
+	}
+	vcs = winprompt;
+    }
+
+/* display the `visible' portion of the line buffer */
+    t0 = winprompt;
+    vp = *nbuf + winprompt;
+    refreshop = *obuf + winprompt;
+    for (;;) {
+	/*
+	 * Skip past all matching characters, but if there used
+	 * to be a prompt here be careful since all manner of
+	 * nastiness may be around.
+	 */
+	if (vp - *nbuf >= owinprompt)
+	    for (; *vp && *vp == *refreshop; t0++, vp++, refreshop++) ;
 
 	if (!*vp && !*refreshop)
 	    break;

-- 
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