about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Src/Zle/zle_refresh.c309
1 files changed, 190 insertions, 119 deletions
diff --git a/Src/Zle/zle_refresh.c b/Src/Zle/zle_refresh.c
index 4621b5124..a05b6634b 100644
--- a/Src/Zle/zle_refresh.c
+++ b/Src/Zle/zle_refresh.c
@@ -33,7 +33,7 @@
 /* Expanded prompts */
 
 /**/
-char *lpptbuf, *rpptbuf;
+char *lpromptbuf, *rpromptbuf;
 
 /* Text attributes after displaying prompts */
 
@@ -43,22 +43,38 @@ unsigned pmpt_attr, rpmpt_attr;
 /* number of lines displayed */
 
 /**/
-int nlnct;
+mod_export int nlnct;
 
 /* Most lines of the buffer we've shown at once with the current list *
  * showing.  == 0 if there is no list.  == -1 if a new list has just  *
- * been put on the screen.  == -2 if refresh() needs to put up a new  *
+ * been put on the screen.  == -2 if zrefresh() needs to put up a new *
  * list.                                                              */
 
 /**/
-int showinglist;
+mod_export int showinglist;
+
+/* > 0 if a completion list is displayed below the prompt,
+ * < 0 if a list is displayed above the prompt. */
+
+/**/
+mod_export int listshown;
+
+/* Length of last list displayed (if it is below the prompt). */
+
+/**/
+mod_export int lastlistlen;
 
 /* Non-zero if ALWAYS_LAST_PROMPT has been used, meaning that the *
  * screen below the buffer display should not be cleared by       *
- * refresh(), but should be by trashzle().                        */
+ * zrefresh(), but should be by trashzle().                       */
+
+/**/
+mod_export int clearflag;
+
+/* Non-zero if zrefresh() should clear the list below the prompt. */
 
 /**/
-int clearflag;
+mod_export int clearlist;
 
 #ifdef HAVE_SELECT
 /* cost of last update */
@@ -75,19 +91,20 @@ int cost;
 #endif
 
 /* Oct/Nov 94: <mason> some code savagely redesigned to fix several bugs -
-   refreshline() & tc_rightcurs() majorly rewritten; refresh() fixed -
+   refreshline() & tc_rightcurs() majorly rewritten; zrefresh() fixed -
    I've put my fingers into just about every routine in here -
-   any queries about updates to mason@werple.net.au */
+   any queries about updates to mason@primenet.com.au */
 
 static char **nbuf = NULL,	/* new video buffer line-by-line char array */
     **obuf = NULL;		/* old video buffer line-by-line char array */
 static int more_start,		/* more text before start of screen?	    */
     more_end,			/* more stuff after end of screen?	    */
-    lppth,			/* lines taken up by the prompt		    */
     olnct,			/* previous number of lines		    */
     ovln,			/* previous video cursor position line	    */
-    pptw, rpw,                  /* prompt widths on screen                  */
-    rppth,			/* right prompt height                      */
+    lpromptw, rpromptw,		/* prompt widths on screen                  */
+    lpromptwof,			/* left prompt width with real end position */
+    lprompth,			/* lines taken up by the prompt		    */
+    rprompth,			/* right prompt height                      */
     vcs, vln,			/* video cursor position column & line	    */
     vmaxln,			/* video maximum number of lines	    */
     winw, winh, rwinh,		/* window width & height		    */
@@ -100,7 +117,6 @@ resetvideo(void)
     int ln;
     static int lwinw = -1, lwinh = -1;	/* last window width & height */
  
-    genprompts();
     winw = columns;  /* terminal width */
     if (termflags & TERM_SHORT)
 	winh = 1;
@@ -132,13 +148,22 @@ resetvideo(void)
 	    *obuf[ln] = '\0';
     }
 
-    if (pptw) {
-    	memset(nbuf[0], ' ', pptw);
-	memset(obuf[0], ' ', pptw);
-	nbuf[0][pptw] = obuf[0][pptw] = '\0';
+    countprompt(lpromptbuf, &lpromptwof, &lprompth, 1);
+    countprompt(rpromptbuf, &rpromptw, &rprompth, 0);
+    if (lpromptwof != winw)
+	lpromptw = lpromptwof;
+    else {
+	lpromptw = 0;
+	lprompth++;
+    }
+
+    if (lpromptw) {
+    	memset(nbuf[0], ' ', lpromptw);
+	memset(obuf[0], ' ', lpromptw);
+	nbuf[0][lpromptw] = obuf[0][lpromptw] = '\0';
     }
 
-    vcs = pptw;
+    vcs = lpromptw;
     olnct = nlnct = 0;
     if (showinglist > 0)
 	showinglist = -2;
@@ -198,16 +223,25 @@ scrollwindow(int tline)
     if (ln != winh - 1)					\
 	ln++;						\
     else						\
-	if (tosln < 3) {				\
+	if (tosln > ln) {				\
+	    tosln--;					\
+	    if (nvln > 1) {				\
+		scrollwindow(0);			\
+		nvln--;					\
+	    } else					\
+		more_end = 1;				\
+	} else if (tosln > 2 && nvln > 1) {		\
+	    tosln--;					\
+	    if (tosln <= nvln) {			\
+		scrollwindow(0);			\
+		nvln--;					\
+	    } else {					\
+		scrollwindow(tosln);			\
+		more_end = 1;				\
+	    }						\
+	} else {					\
 	    more_status = 1;				\
 	    scrollwindow(tosln + 1);			\
-	} else if (tosln - 1 <= nvln) {			\
-	    scrollwindow(0);				\
-	    if (nvln)					\
-		nvln--, tosln--;			\
-	} else {					\
-	    tosln--;					\
-	    scrollwindow(tosln);			\
 	}						\
     if (!nbuf[ln])					\
 	nbuf[ln] = (char *)zalloc(winw + 2);		\
@@ -223,8 +257,8 @@ static int cleareol,		/* clear to end-of-line (if can't cleareod) */
     numscrolls, onumscrolls;
 
 /**/
-void
-refresh(void)
+mod_export void
+zrefresh(void)
 {
     static int inlist;		/* avoiding recursion                        */
     int canscroll = 0,		/* number of lines we are allowed to scroll  */
@@ -240,19 +274,45 @@ refresh(void)
     char **qbuf;		/* tmp					     */
 
     /* If this is called from listmatches() (indirectly via trashzle()), and *
-     * that was called from the end of refresh(), then we don't need to do   *
+     * that was called from the end of zrefresh(), then we don't need to do  *
      * anything.  All this `inlist' code is actually unnecessary, but it     *
      * improves speed a little in a common case.                             */
     if (inlist)
 	return;
 
+    if (clearlist && listshown > 0) {
+	if (tccan(TCCLEAREOD)) {
+	    int ovln = vln, ovcs = vcs;
+	    char *nb = nbuf[vln];
+
+	    nbuf[vln] = obuf[vln];
+	    moveto(nlnct, 0);
+	    tcout(TCCLEAREOD);
+	    moveto(ovln, ovcs);
+	    nbuf[vln] = nb;
+	} else {
+	    invalidatelist();
+	    moveto(0, 0);
+	    clearflag = 0;
+	    resetneeded = 1;
+	}
+	listshown = lastlistlen = 0;
+	if (showinglist != -2)
+	    showinglist = 0;
+    }
+    clearlist = 0;
+
 #ifdef HAVE_SELECT
     cost = 0;			/* reset */
 #endif
 
 /* Nov 96: <mason>  I haven't checked how complete this is.  sgtty stuff may
    or may not work */
+#if defined(SGTABTYPE)
     oxtabs = ((SGTTYFLAG & SGTABTYPE) == SGTABTYPE);
+#else
+    oxtabs = 0;
+#endif
 
     cleareol = 0;		/* unset */
     more_start = more_end = 0;	/* unset */
@@ -263,12 +323,13 @@ refresh(void)
 	termflags &= ~TERM_SHORT;
     if (resetneeded) {
 	onumscrolls = 0;
-	setterm();
+	zsetterm();
 #ifdef TIOCGWINSZ
 	if (winchanged) {
 	    moveto(0, 0);
 	    t0 = olnct;		/* this is to clear extra lines even when */
 	    winchanged = 0;	/* the terminal cannot TCCLEAREOD	  */
+	    listshown = 0;
 	}
 #endif
 	resetvideo();
@@ -280,21 +341,27 @@ refresh(void)
 	tsetcap(TCSTANDOUTEND, 0);
 	tsetcap(TCUNDERLINEEND, 0);
 
-        if (!clearflag)
+        if (!clearflag) {
             if (tccan(TCCLEAREOD))
                 tcout(TCCLEAREOD);
             else
                 cleareol = 1;   /* request: clear to end of line */
+	    if (listshown > 0)
+		listshown = 0;
+	}
         if (t0 > -1)
             olnct = t0;
         if (termflags & TERM_SHORT)
             vcs = 0;
-        else if (!clearflag && lpptbuf[0])
-            zputs(lpptbuf, shout);
+        else if (!clearflag && lpromptbuf[0]) {
+            zputs(lpromptbuf, shout);
+	    if (lpromptwof == winw)
+		zputs("\n", shout);	/* works with both hasam and !hasam */
+	}
 	if (clearflag) {
 	    zputc('\r', shout);
 	    vcs = 0;
-	    moveto(0, pptw);
+	    moveto(0, lpromptw);
 	}
 	fflush(shout);
 	clearf = clearflag;
@@ -326,7 +393,7 @@ refresh(void)
     if (!*nbuf)
 	*nbuf = (char *)zalloc(winw + 2);
 
-    s = (unsigned char *)(nbuf[ln = 0] + pptw);
+    s = (unsigned char *)(nbuf[ln = 0] + lpromptw);
     t = line;
     sen = (unsigned char *)(*nbuf + winw);
     for (; t < line+ll; t++) {
@@ -377,13 +444,6 @@ refresh(void)
 
     if (statusline) {
 	tosln = ln + 1;
-        if (ln == winh - 1) {
-	    if (nvln > 0) {
-		scrollwindow(0);
-		nvln--;
-	    }
-	    tosln--;
-	}
 	nbuf[ln][winw + 1] = '\0';	/* text not wrapped */
 	snextline
 	t = (unsigned char *)statusline;
@@ -402,38 +462,59 @@ refresh(void)
 		snextline
 	    }
 	}
+	if (s == sen)
+	    snextline
     }
+    *s = '\0';
 
 /* insert <.... at end of last line if there is more text past end of screen */
     if (more_end) {
 	if (!statusline)
 	    tosln = winh;
-	strncpy(nbuf[tosln - 1] + winw - 7, " <.... ", 7);
+	s = nbuf[tosln - 1];
+	sen = s + winw - 7;
+	for (; s < sen; s++) {
+	    if (*s == '\0') {
+		for (; s < sen; )
+		    *s++ = ' ';
+		break;
+	    }
+	}
+	strncpy(sen, " <.... ", 7);
 	nbuf[tosln - 1][winw] = nbuf[tosln - 1][winw + 1] = '\0';
     }
 
 /* insert <....> at end of first status line if status is too big */
     if (more_status) {
-	strncpy(nbuf[tosln] + winw - 8, " <....> ", 8);
+	s = nbuf[tosln];
+	sen = s + winw - 8;
+	for (; s < sen; s++) {
+	    if (*s == '\0') {
+		for (; s < sen; )
+		    *s++ = ' ';
+		break;
+	    }
+	}
+	strncpy(sen, " <....> ", 8);
 	nbuf[tosln][winw] = nbuf[tosln][winw + 1] = '\0';
     }
 
-    *s = '\0';
     nlnct = ln + 1;
     for (ln = nlnct; ln < winh; ln++)
 	zfree(nbuf[ln], winw + 2), nbuf[ln] = NULL;
 
 /* determine whether the right-prompt exists and can fit on the screen */
     if (!more_start)
-	put_rpmpt = rppth == 1 && rpptbuf[0] && !strchr(rpptbuf, '\t') &&
-	    (int)strlen(nbuf[0]) + rpw < winw - 1;
+	put_rpmpt = rprompth == 1 && rpromptbuf[0] &&
+	    !strchr(rpromptbuf, '\t') &&
+	    (int)strlen(nbuf[0]) + rpromptw < winw - 1;
     else {
 /* insert >.... on first line if there is more text before start of screen */
-	memset(nbuf[0], ' ', pptw);
-	t0 = winw - pptw;
+	memset(nbuf[0], ' ', lpromptw);
+	t0 = winw - lpromptw;
 	t0 = t0 > 5 ? 5 : t0;
-	strncpy(nbuf[0] + pptw, ">....", t0);
-	memset(nbuf[0] + pptw + t0, ' ', winw - t0 - pptw);
+	strncpy(nbuf[0] + lpromptw, ">....", t0);
+	memset(nbuf[0] + lpromptw + t0, ' ', winw - t0 - lpromptw);
 	nbuf[0][winw] = nbuf[0][winw + 1] = '\0';
     }
 
@@ -445,7 +526,7 @@ refresh(void)
     /* if old line and new line are different,
        see if we can insert/delete a line to speed up update */
 
-	if (ln < olnct - 1 && !(hasam && vcs == winw) &&
+	if (ln > 0 && ln < olnct - 1 && !(hasam && vcs == winw) &&
 	    nbuf[ln] && obuf[ln] &&
 	    strncmp(nbuf[ln], obuf[ln], 16)) {
 	    if (tccan(TCDELLINE) && obuf[ln + 1] && obuf[ln + 1][0] &&
@@ -477,8 +558,8 @@ refresh(void)
 
     /* output the right-prompt if appropriate */
 	if (put_rpmpt && !ln && !oput_rpmpt) {
-	    moveto(0, winw - 1 - rpw);
-	    zputs(rpptbuf, shout);
+	    moveto(0, winw - 1 - rpromptw);
+	    zputs(rpromptbuf, shout);
 	    vcs = winw - 1;
 	/* reset character attributes to that set by the main prompt */
 	    txtchange = pmpt_attr;
@@ -547,7 +628,7 @@ individually */
 	inlist = 1;
 	listmatches();
 	inlist = 0;
-	refresh();
+	zrefresh();
     }
     if (showinglist == -1)
 	showinglist = nlnct;
@@ -596,7 +677,7 @@ refreshline(int ln)
     if (cleareol 		/* request to clear to end of line */
 	|| !nllen 		/* no line buffer given */
 	|| (ln == 0 && (put_rpmpt != oput_rpmpt))) {	/* prompt changed */
-	p1 = halloc(winw + 2);
+	p1 = zhalloc(winw + 2);
 	if (nllen)
 	    strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', winw - nllen);
@@ -608,7 +689,7 @@ refreshline(int ln)
 	    nl = p1;		/* don't keep the padding for prompt line */
 	nllen = winw;
     } else if (ollen > nllen) { /* make new line at least as long as old */
-	p1 = halloc(ollen + 1);
+	p1 = zhalloc(ollen + 1);
 	strncpy(p1, nl, nllen);
 	memset(p1 + nllen, ' ', ollen - nllen);
 	p1[ollen] = '\0';
@@ -659,12 +740,12 @@ refreshline(int ln)
 /* 2c: if we're on the first line, start checking at the end of the prompt;
    we shouldn't be doing anything within the prompt */
 
-    if (ln == 0 && pptw) {
-	i = pptw - ccs;
+    if (ln == 0 && lpromptw) {
+	i = lpromptw - ccs;
 	j = strlen(ol);
 	nl += i;
 	ol += (i > j ? j : i);	/* if ol is too short, point it to '\0' */
-	ccs = pptw;
+	ccs = lpromptw;
     }
 
 /* 3: main display loop - write out the buffer using whatever tricks we can */
@@ -815,7 +896,7 @@ moveto(int ln, int cl)
    instead of TCDOWN */
 
     while (ln > vln) {
-	if (vln < vmaxln - 1)
+	if (vln < vmaxln - 1) {
 	    if (ln > vmaxln - 1) {
 		if (tc_downcurs(vmaxln - 1 - vln))
 		    vcs = 0;
@@ -826,6 +907,7 @@ moveto(int ln, int cl)
 		vln = ln;
 		continue;
 	    }
+	}
 	zputc('\r', shout), vcs = 0; /* safety precaution */
 	while (ln > vln) {
 	    zputc('\n', shout);
@@ -833,24 +915,12 @@ moveto(int ln, int cl)
 	}
     }
 
-    if (cl == vcs)
-	return;
-
-/* choose cheapest movements for ttys without multiple movement capabilities -
-   do this now because it's easier (to code) */
-    if (cl <= vcs / 2) {
-	zputc('\r', shout);
-	vcs = 0;
-    }
-    if (vcs < cl)
-	tc_rightcurs(cl);
-    else if (vcs > cl)
-	tc_leftcurs(vcs - cl);
-    vcs = cl;
+    if (cl != vcs)
+        singmoveto(cl);
 }
 
 /**/
-int
+mod_export int
 tcmultout(int cap, int multcap, int ct)
 {
     if (tccan(multcap) && (!tccan(cap) || tclen[multcap] <= tclen[cap] * ct)) {
@@ -864,16 +934,17 @@ tcmultout(int cap, int multcap, int ct)
     return 0;
 }
 
+/* ct: number of characters to move across */
 /**/
 static void
-tc_rightcurs(int cl)
+tc_rightcurs(int ct)
 {
-    int ct,			/* number of characters to move across	    */
+    int cl,			/* ``desired'' absolute horizontal position */
 	i = vcs,		/* cursor position after initial movements  */
 	j;
     char *t;
 
-    ct = cl - vcs;
+    cl = ct + vcs;
 
 /* do a multright if we can - it's the most reliable */
     if (tccan(TCMULTRIGHT)) {
@@ -881,6 +952,13 @@ tc_rightcurs(int cl)
 	return;
     }
 
+/* do an absolute horizontal position if we can */
+    if (tccan(TCHORIZPOS)) {
+	tcoutarg(TCHORIZPOS, cl);
+	return;
+    }
+
+/* XXX: should really check "it" in termcap and use / and % */
 /* try tabs if tabs are non destructive and multright is not possible */
     if (!oxtabs && tccan(TCNEXTTAB) && ((vcs | 7) < cl)) {
 	i = (vcs | 7) + 1;
@@ -893,21 +971,23 @@ tc_rightcurs(int cl)
 
 /* otherwise _carefully_ write the contents of the video buffer.
    if we're anywhere in the prompt, goto the left column and write the whole
-   prompt out unless ztrlen(lpptbuf) == pptw : we can cheat then */
-    if (vln == 0 && i < pptw) {
-	if (strlen(lpptbuf) == pptw)
-	    fputs(lpptbuf + i, shout);
-	else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpptbuf)))
+   prompt out unless ztrlen(lpromptbuf) == lpromptw : we can cheat then */
+    if (vln == 0 && i < lpromptw && !(termflags & TERM_SHORT)) {
+	if (strlen(lpromptbuf) == lpromptw)
+	    fputs(lpromptbuf + i, shout);
+	else if (tccan(TCRIGHT) && (tclen[TCRIGHT] * ct <= ztrlen(lpromptbuf)))
 	    /* it is cheaper to send TCRIGHT than reprint the whole prompt */
-	    for (ct = pptw - i; ct--; )
+	    for (ct = lpromptw - i; ct--; )
 		tcout(TCRIGHT);
         else {
 	    if (i != 0)
 		zputc('\r', shout);
-	    tc_upcurs(lppth - 1);
-	    zputs(lpptbuf, shout);
+	    tc_upcurs(lprompth - 1);
+	    zputs(lpromptbuf, shout);
+	    if (lpromptwof == winw)
+		zputs("\n", shout);	/* works with both hasam and !hasam */
 	}
-	i = pptw;
+	i = lpromptw;
 	ct = cl - i;
     }
 
@@ -936,7 +1016,7 @@ tc_downcurs(int ct)
 }
 
 /**/
-void
+mod_export void
 tcout(int cap)
 {
     tputs(tcstr[cap], 1, putshout);
@@ -955,23 +1035,25 @@ tcoutarg(int cap, int arg)
 }
 
 /**/
-void
-clearscreen(void)
+mod_export int
+clearscreen(char **args)
 {
     tcout(TCCLEARSCREEN);
     resetneeded = 1;
     clearflag = 0;
+    return 0;
 }
 
 /**/
-void
-redisplay(void)
+mod_export int
+redisplay(char **args)
 {
     moveto(0, 0);
     zputc('\r', shout);		/* extra care */
-    tc_upcurs(lppth - 1);
+    tc_upcurs(lprompth - 1);
     resetneeded = 1;
     clearflag = 0;
+    return 0;
 }
 
 /**/
@@ -987,7 +1069,7 @@ singlerefresh(void)
 
     nlnct = 1;
 /* generate the new line buffer completely */
-    for (vsiz = 1 + pptw, t0 = 0; t0 != ll; t0++, vsiz++)
+    for (vsiz = 1 + lpromptw, t0 = 0; t0 != ll; t0++, vsiz++)
 	if (line[t0] == '\t')
 	    vsiz = (vsiz | 7) + 1;
 	else if (icntrl(line[t0]))
@@ -1002,9 +1084,10 @@ singlerefresh(void)
 	cs = 0;
     }
 
-    memcpy(vbuf, strchr(lpptbuf, 0) - pptw, pptw); /* only use last part of prompt */
-    vbuf[pptw] = '\0';
-    vp = vbuf + pptw;
+    /* only use last part of prompt */
+    memcpy(vbuf, strchr(lpromptbuf, 0) - lpromptw, lpromptw);
+    vbuf[lpromptw] = '\0';
+    vp = vbuf + lpromptw;
 
     for (t0 = 0; t0 != ll; t0++) {
 	if (line[t0] == '\t')
@@ -1086,31 +1169,19 @@ singmoveto(int pos)
 {
     if (pos == vcs)
 	return;
-    if (pos <= vcs / 2) {
+
+/* choose cheapest movements for ttys without multiple movement capabilities -
+   do this now because it's easier (to code) */
+
+    if ((!tccan(TCMULTLEFT) || pos == 0) && (pos <= vcs / 2)) {
 	zputc('\r', shout);
 	vcs = 0;
     }
-    if (pos < vcs) {
-	tc_leftcurs(vcs - pos);
-	vcs = pos;
-    }
-    if (pos > vcs) {
-	if (tcmultout(TCRIGHT, TCMULTRIGHT, pos - vcs))
-	    vcs = pos;
-	else
-	    while (pos > vcs) {
-		zputc(nbuf[0][vcs], shout);
-		vcs++;
-	    }
-    }
-}
 
-/* recheck size of prompts */
+    if (pos < vcs)
+	tc_leftcurs(vcs - pos);
+    else if (pos > vcs)
+	tc_rightcurs(pos - vcs);
 
-/**/
-static void
-genprompts(void)
-{
-    countprompt(lpptbuf, &pptw, &lppth);
-    countprompt(rpptbuf, &rpw, &rppth);
+    vcs = pos;
 }