diff options
-rw-r--r-- | Src/Zle/zle_refresh.c | 309 |
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; } |