home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / z / zsh220.zip / zsh2.2 / src / zle_refresh.c < prev    next >
C/C++ Source or Header  |  1992-05-07  |  12KB  |  642 lines

  1. /*
  2.  *
  3.  * zle_refresh.c - screen update
  4.  *
  5.  * This file is part of zsh, the Z shell.
  6.  *
  7.  * This software is Copyright 1992 by Paul Falstad
  8.  *
  9.  * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  10.  * use this software as long as: there is no monetary profit gained
  11.  * specifically from the use or reproduction of this software, it is not
  12.  * sold, rented, traded or otherwise marketed, and this copyright notice is
  13.  * included prominently in any copy made. 
  14.  *
  15.  * The author make no claims as to the fitness or correctness of this software
  16.  * for any use whatsoever, and it is provided as is. Any use of this software
  17.  * is at the user's own risk. 
  18.  *
  19.  */
  20.  
  21. #define ZLE
  22. #include "zsh.h"
  23.  
  24. char **obuf = NULL,**nbuf = NULL;
  25. int olnct,nlnct;
  26. int winw,winh,winpos;
  27.  
  28. int vcs,vln,vmaxln;
  29.  
  30. void resetvideo() /**/
  31. {
  32. int ln;
  33. static int lwinw = -1,lwinh = -1;
  34.  
  35.     setterm();
  36.     winw = columns-1;
  37.     if (isset(SINGLELINEZLE) || !termok)
  38.         winh = 1;
  39.     else
  40.         winh = (lines < 2) ? 24 : lines;
  41.     winpos = vln = vmaxln = 0;
  42.     if (lwinw != winw || lwinh != winh)
  43.         {
  44.         if (nbuf)
  45.             {
  46.             for (ln = 0; ln != lwinh; ln++)
  47.                 {
  48.                 free(nbuf[ln]);
  49.                 free(obuf[ln]);
  50.                 }
  51.             free(nbuf);
  52.             free(obuf);
  53.             }
  54.         nbuf = (char **) zalloc((winh+1)*sizeof(char *));
  55.         obuf = (char **) zalloc((winh+1)*sizeof(char *));
  56.         for (ln = 0; ln != winh+1; ln++)
  57.             {
  58.             nbuf[ln] = zalloc(winw+1);
  59.             obuf[ln] = zalloc(winw+1);
  60.             }
  61.         lwinw = winw;
  62.         lwinh = winh;
  63.         }
  64.     for (ln = 0; ln != winh+1; ln++)
  65.         {
  66.         *nbuf[ln] = '\0';
  67.         *obuf[ln] = '\0';
  68.         }
  69.     if (!pptlen)
  70.         nbuf[0][0] = obuf[0][0] = '\0';
  71.     else
  72.         {
  73.         for (ln = 0; ln != pptlen-1; ln++)
  74.             nbuf[0][ln] = obuf[0][ln] = ' ';
  75.         nbuf[0][ln] = obuf[0][ln] = '>';
  76.         nbuf[0][pptlen] = obuf[0][pptlen] = '\0';
  77.         }
  78.     vcs = pptlen;
  79.     olnct = nlnct = 1;
  80. }
  81.  
  82. int scrollwindow() /**/
  83. {
  84. int t0,hwinh = winh/2;
  85.  
  86.     for (t0 = 0; t0 != winh-hwinh; t0++)
  87.         {
  88.         char *s;
  89.  
  90.         s = nbuf[t0];
  91.         nbuf[t0] = nbuf[t0+hwinh];
  92.         nbuf[t0+hwinh] = s;
  93.         }
  94.     for (t0 = 0; t0 != pptlen-1; t0++)
  95.         nbuf[0][t0] = ' ';
  96.     strcpy(nbuf[0]+t0,"> ...");
  97.     return winh-hwinh;
  98. }
  99.  
  100. /* this is the messy part. */
  101. /* this define belongs where it's used!!! */
  102.  
  103. #define nextline { *s = (unsigned char)'\0'; \
  104.     if (winh == ln+1) if (nvln != -1) break; else ln = scrollwindow()-1; \
  105.     s = (unsigned char *)nbuf[++ln]; sen = s+winw; \
  106.     }
  107.  
  108. void refresh() /**/
  109. {
  110. unsigned char *s,*t,*sen,*scs = line+cs; char **qbuf;
  111. int ln = 0,nvcs,nvln = -1,t0;
  112.  
  113.     cost = 0;
  114.     if (resetneeded)
  115.         {
  116.         resetvideo();
  117.         resetneeded = 0;
  118.         if (isset(SINGLELINEZLE) || !termok)
  119.             vcs = 0;
  120.         else
  121.             printf("%s",pmpt);
  122.         }
  123.     zleactive = 1;
  124.     if (isset(SINGLELINEZLE) || !termok)
  125.         {
  126.         singlerefresh();
  127.         return;
  128.         }
  129.  
  130. /* first, we generate the video line buffers so we know what to
  131.     put on the screen. 
  132.  
  133.     s = ptr into the video buffer.
  134.     t = ptr into the real buffer.
  135.     sen = end of the video buffer (eol)
  136. */
  137.  
  138.     s = (unsigned char *)(nbuf[ln = 0]+pptlen);
  139.     t = line;
  140.     sen = (unsigned char *)(*nbuf+winw);
  141.     for (; *t; t++)
  142.         {
  143.         if (icntrl((char)*t))
  144.             if (*t == '\n')
  145.                 {
  146.                 if (t == scs)
  147.                     {
  148.                     nvcs = (char *)s-nbuf[nvln = ln];
  149.                     scs = (unsigned char *)NULL;
  150.                     }
  151.                 nextline
  152.                 }
  153.             else if ((char)*t == '\t')
  154.                 {
  155.                 int t1 = (char *)s-nbuf[ln];
  156.  
  157.                 if ((t1|7)+1 >= winw) nextline
  158.                 else
  159.                     do
  160.                         *s++ = ' ';
  161.                     while ((++t1) & 7);
  162.                 }
  163.             else
  164.                 {
  165.                 if (s == sen) nextline
  166.                 *s++ = '^';
  167.                 if (s == sen) nextline
  168.                 *s++ = (*t == 127) ? '?' : (*t | '@');
  169.                 }
  170.         else
  171.             {
  172.             if (s == sen) nextline
  173.             *s++ = *t;
  174.             }
  175. /* if the cursor is here, remember it */
  176.  
  177.         if (t == scs)
  178.             nvcs = s-(unsigned char *)nbuf[nvln = ln]-1;
  179.         }
  180.     if (scs == t)
  181.         nvcs = s-(unsigned char *)nbuf[nvln = ln];
  182.     *s = '\0';
  183.     nlnct = ln+1;
  184.     if (statusline)
  185.         strcpy(nbuf[(nlnct == winh) ? winh-1 : nlnct++],statusline);
  186.  
  187. /* do RPROMPT */
  188.  
  189.     if (pmpt2 && ln == 0 && strlen(nbuf[0])+strlen(pmpt2) < winw)
  190.         {
  191.         for (t0 = strlen(nbuf[0]); t0 != winw; t0++)
  192.             nbuf[0][t0] = ' ';
  193.         strcpy(nbuf[0]+winw-strlen(pmpt2),pmpt2);
  194.         }
  195.     for (ln = 0; ln < nlnct; ln++)
  196.         {
  197.  
  198. /* if old line and new line are different,
  199.     see if we can insert/delete a line */
  200.  
  201.         if (ln < olnct && strncmp(nbuf[ln],obuf[ln],16))
  202.             {
  203.             if (tccan(TCDELLINE) && !strncmp(nbuf[ln],obuf[ln+1],16)
  204.                     && obuf[ln+1][0] && ln != olnct)
  205.                 {
  206.                 int t0;
  207.  
  208.                 moveto(ln,0);
  209.                 tcout(TCDELLINE);
  210.                 for (t0 = ln; t0 != olnct; t0++)
  211.                     strcpy(obuf[t0],obuf[t0+1]);
  212.                 olnct--;
  213.                 }
  214.  
  215. /* don't try to insert a line if olnct < vmaxln (vmaxln is the number
  216.     of lines that have been displayed by this routine) so that we don't
  217.     go off the end of the screen. */
  218.  
  219.             else if (tccan(TCINSLINE) && !strncmp(nbuf[ln+1],obuf[ln],16) &&
  220.                     olnct < vmaxln && nbuf[ln+1][0] && ln != olnct)
  221.                 {
  222.                 int t0;
  223.  
  224.                 moveto(ln,0);
  225.                 tcout(TCINSLINE);
  226.                 for (t0 = olnct; t0 != ln; t0--)
  227.                     strcpy(obuf[t0],obuf[t0-1]);
  228.                 *obuf[ln] = '\0';
  229.                 olnct++;
  230.                 }
  231.             }
  232.         refreshline(ln);
  233.         }
  234.  
  235. /* if old buffer had extra lines, do a clear-end-of-display if we can,
  236.     otherwise, just fill new buffer with blank lines and refresh them */
  237.  
  238.     if (olnct > nlnct)
  239.         {
  240.         for (ln = nlnct; ln < olnct; ln++)
  241.             nbuf[ln][0] = '\0';
  242.         if (tccan(TCCLEAREOD))
  243.             {
  244.             moveto(nlnct,0);
  245.             tcout(TCCLEAREOD);
  246.             }
  247.         else
  248.             for (ln = nlnct; ln < olnct; ln++)
  249.                 refreshline(ln);
  250.         }
  251.  
  252. /* move to the new cursor position */
  253.  
  254.     moveto(nvln,nvcs);
  255.     qbuf = nbuf;
  256.     nbuf = obuf;
  257.     obuf = qbuf;
  258.     olnct = nlnct;
  259.     if (nlnct > vmaxln)
  260.         vmaxln = nlnct;
  261.     fflush(stdout);
  262. }
  263.  
  264. #define tcinscost(X) (tccan(TCMULTINS) ? tclen[TCMULTINS] : (X)*tclen[TCINS])
  265. #define tcdelcost(X) (tccan(TCMULTDEL) ? tclen[TCMULTDEL] : (X)*tclen[TCDEL])
  266. #define tc_delchars(X) tcmultout(TCDEL,TCMULTDEL,(X))
  267. #define tc_inschars(X) tcmultout(TCINS,TCMULTINS,(X))
  268. #define tc_upcurs(X) tcmultout(TCUP,TCMULTUP,(X))
  269. #define tc_leftcurs(X) tcmultout(TCLEFT,TCMULTLEFT,(X))
  270.  
  271. void refreshline(ln) /**/
  272. int ln;
  273. {
  274. char *nl = nbuf[ln],*ol = obuf[ln];
  275. char *p1;
  276. char junk,*truncptr = &junk;
  277. int ccs = 0;
  278.  
  279.     if (ln >= olnct)
  280.         *ol = '\0';
  281.     for (;;)
  282.         {
  283.         while (*nl && *nl == *ol)
  284.             {
  285.             nl++,ol++,ccs++;
  286.             }
  287.         if (!*nl && !*ol)
  288.             { *truncptr = '\0'; return; }
  289.  
  290. /* if this is the end of the new buffer but the old buffer has stuff
  291.     here, clear to end of line if we can, otherwise fill the new buffer
  292.     with blanks and continue. */
  293.  
  294.         if (!*nl)
  295.             {
  296.             if (tccan(TCCLEAREOL) && strlen(ol) > tclen[TCCLEAREOL])
  297.                 {
  298.                 moveto(ln,ccs);
  299.                 tcout(TCCLEAREOL);
  300.                 *ol = '\0';
  301.                 *truncptr = '\0';
  302.                 return;
  303.                 }
  304.             else
  305.                 {
  306.                 int x = strlen(ol);
  307.                 char *p = nl;
  308.  
  309.                 truncptr = p;
  310.                 while (x--)
  311.                     *p++ = ' ';
  312.                 *p = '\0';
  313.                 continue;
  314.                 }
  315.             }
  316.  
  317. /* if this is the end of the old buffer, just dump the rest of the
  318.     new buffer. */
  319.  
  320.         if (!*ol)
  321.             {
  322.             while (*nl == ' ')
  323.                 nl++,ccs++;
  324.             if (*nl)
  325.                 {
  326.                 moveto(ln,ccs);
  327.                 fwrite(nl,strlen(nl),1,stdout);
  328.                 cost += strlen(nl);
  329.                 ccs = (vcs += strlen(nl));
  330.                 }
  331.             *truncptr = 0;
  332.             return;
  333.             }
  334.         moveto(ln,ccs);
  335.  
  336. /* try to insert/delete characters */
  337.  
  338.         if (ol[1] != nl[1] && tccan(TCDEL))
  339.             {
  340.             int ct = 0;
  341.  
  342.             for (p1 = ol; *p1; p1++,ct++)
  343.                 if (tcdelcost(ct) < streqct(p1,nl))
  344.                     {
  345.                     tc_delchars(ct);
  346.                     ol = p1;
  347.                     break;
  348.                     }
  349.             if (*p1)
  350.                 continue;
  351.             }
  352.  
  353.         if (ol[1] != nl[1] && tccan(TCINS))
  354.             {
  355.             int ct = 0;
  356.  
  357.             for (p1 = nl; *p1; p1++,ct++)
  358.                 if (tcinscost(ct) < streqct(p1,ol)+ct)
  359.                     {
  360. #if 0
  361. /* make sure we aren't inserting characters off the end of the screen;
  362.     if we are, jump to the end and truncate the line, if we can do
  363.     it quickly (gee, clever idea, Paul!) */
  364.                     if (ct+ccs+strlen(ol) >= winw-1)
  365.                         {
  366.                         if (!tccan(TCMULTRIGHT) || ccs > winw-tclen[TCMULTRIGHT])
  367.                             continue;
  368.                         moveto(ln,winw-1-ct);
  369.                         if (!tccan(TCCLEAREOL) || ct < tclen[TCCLEAREOL])
  370.                             {
  371.                             int x = ct;
  372.  
  373.                             while (vcs++,x--)
  374.                                 putchar(' ');
  375.                             }
  376.                         else
  377.                             tcout(TCCLEAREOL);
  378.                         moveto(ln,ccs);
  379.                         }
  380. #endif
  381.                     if (ct+ccs+strlen(ol) < winw-1)
  382.                         {
  383.                         tc_inschars(ct = p1-nl);
  384.                         ccs = (vcs += p1-nl);
  385.                         cost += ct;
  386.                         fwrite(nl,ct,1,stdout);
  387.                         nl += ct;
  388.                         break;
  389.                         }
  390.                     }
  391.             if (*p1)
  392.                 continue;
  393.             }
  394.  
  395. /* if we can't do anything fancy, just write the new character and
  396.     keep going. */
  397.  
  398.         putchar(*nl);
  399.         cost++;
  400.         nl++,ol++,ccs = ++vcs;
  401.         }
  402. }
  403.  
  404. void moveto(ln,cl) /**/
  405. int ln;int cl;
  406. {
  407.  
  408. /* move up */
  409.  
  410.     if (ln < vln)
  411.         {
  412.         tc_upcurs(vln-ln);
  413.         vln = ln;
  414.         }
  415.  
  416. /* move down; if we might go off the end of the screen, use newlines
  417.     instead of TCDOWN */
  418.  
  419.     while (ln > vln)
  420.         if (cl < (vcs/2) || ln >= vmaxln || !tccan(TCLEFT))
  421.             {
  422.             putchar('\r');
  423.             putchar('\n');
  424.             cost+=2;
  425.             vln++;
  426.             vcs = 0;
  427.             }
  428.         else
  429.             {
  430.             tc_downcurs(ln-vln);
  431.             vln = ln;
  432.             }
  433.     if (cl < (vcs/2) || !tccan(TCLEFT))
  434.         {
  435.         putchar('\r');
  436.         cost++;
  437.         vcs = 0;
  438.         }
  439.     if (vcs < cl)
  440.         tc_rightcurs(cl-vcs);
  441.     else if (vcs > cl)
  442.         tc_leftcurs(vcs-cl);
  443.     vcs = cl;
  444. }
  445.  
  446. void tcmultout(cap,multcap,ct) /**/
  447. int cap;int multcap;int ct;
  448. {
  449.     if (tccan(multcap) && (!tccan(cap) || tclen[multcap] < tclen[cap]*ct))
  450.         tcoutarg(multcap,ct);
  451.     else while (ct--)
  452.         tcout(cap);
  453. }
  454.  
  455. void tc_rightcurs(ct) /**/
  456. int ct;
  457. {
  458.  
  459. /* do a multright if it's cheaper or if we're walking over the prompt.  */
  460.  
  461.     if (tccan(TCMULTRIGHT) &&
  462.             (ct > tclen[TCMULTRIGHT] || vln == 0 && vcs < pptlen))
  463.         tcoutarg(TCMULTRIGHT,ct);
  464.  
  465. /* if we're walking over the prompt and we can do a bunch of cursor rights,
  466.     do them, even though they're more expensive.  (We can't redraw the
  467.     prompt very easily in general.)  */
  468.  
  469.     else if (vln == 0 && vcs < pptlen && tccan(TCRIGHT))
  470.         while (ct--)
  471.             tcout(TCRIGHT);
  472.  
  473. /* otherwise write the contents of the video buffer. */
  474.  
  475.     else
  476.         fwrite(nbuf[vln]+vcs,ct,1,stdout);
  477. }
  478.  
  479. void tc_downcurs(ct) /**/
  480. int ct;
  481. {
  482.     if (tccan(TCMULTDOWN) &&
  483.             (!tccan(TCDOWN) || tclen[TCMULTDOWN] < tclen[TCDOWN]*ct))
  484.         tcoutarg(TCMULTDOWN,ct);
  485.     else if (tccan(TCDOWN))
  486.         while (ct--)
  487.             tcout(TCDOWN);
  488.     else
  489.         {
  490.         while (ct--)
  491.             putchar('\n');
  492.         vcs = 0;
  493.         }
  494. }
  495.  
  496. /* I'm NOT going to worry about padding unless anyone complains. */
  497.  
  498. void tcout(cap) /**/
  499. int cap;
  500. {
  501.     tputs(tcstr[cap],1,putraw);
  502. }
  503.  
  504. void tcoutarg(cap,arg) /**/
  505. int cap;int arg;
  506. {
  507.     tputs(tgoto(tcstr[cap],arg,arg),1,putraw);
  508. }
  509.  
  510. void clearscreen() /**/
  511. {
  512.     tcout(TCCLEARSCREEN);
  513.     resetneeded = 1;
  514. }
  515.  
  516. void redisplay() /**/
  517. {
  518.     trashzle();
  519. }
  520.  
  521. void trashzle() /**/
  522. {
  523.     if (zleactive)
  524.         {
  525.         refresh();
  526.         moveto(nlnct,0);
  527.         printf("%s",postedit);
  528.         fflush(stdout);
  529.         unsetterm();
  530.         resetneeded = 1;
  531.         }
  532. }
  533.  
  534. void singlerefresh() /**/
  535. {
  536. char *vbuf,*vp,**qbuf,*op;
  537. int t0,vsiz,nvcs;
  538.  
  539.     for (vsiz = 1+pptlen, t0 = 0; t0 != ll; t0++,vsiz++)
  540.         if (line[t0] == '\t')
  541.             vsiz += 7;
  542.         else if (icntrl(line[t0]))
  543.             vsiz++;
  544.     vbuf = zalloc(vsiz);
  545.     strcpy(vbuf,pmpt);
  546.     vp = vbuf+pptlen;
  547.     for (t0 = 0; t0 != ll; t0++)
  548.         {
  549.         if (line[t0] == '\t')
  550.             do
  551.                 *vp++ = ' ';
  552.             while ((vp-vbuf) & 7);
  553.         else if (line[t0] == '\n')
  554.             {
  555.             *vp++ = '\\';
  556.             *vp++ = 'n';
  557.             }
  558.         else if (line[t0] == 0x7f)
  559.             {
  560.             *vp++ = '^';
  561.             *vp++ = '?';
  562.             }
  563.         else if (icntrl(line[t0]))
  564.             {
  565.             *vp++ = '^';
  566.             *vp++ = line[t0] | '@';
  567.             }
  568.         else
  569.             *vp++ = line[t0];
  570.         if (t0 == cs)
  571.             nvcs = vp-vbuf-1;
  572.         }
  573.     if (t0 == cs)
  574.         nvcs = vp-vbuf;
  575.     *vp = '\0';
  576.     if ((winpos && nvcs < winpos+1) || (nvcs > winpos+winw-1))
  577.         {
  578.         if ((winpos = nvcs-(winw/2)) < 0)
  579.             winpos = 0;
  580.         }
  581.     if (winpos)
  582.         vbuf[winpos] = '<';
  583.     if (strlen(vbuf+winpos) > winw)
  584.         {
  585.         vbuf[winpos+winw-1] = '>';
  586.         vbuf[winpos+winw] = '\0';
  587.         }
  588.     strcpy(nbuf[0],vbuf+winpos);
  589.     free(vbuf);
  590.     nvcs -= winpos;
  591.     for (t0 = 0,vp = *nbuf,op = *obuf; *vp; t0++,vp++)
  592.         {
  593.         if (*vp != *op && !(*vp == ' ' && !*op))
  594.             {
  595.             singmoveto(t0);
  596.             putchar(*vp);
  597.             vcs++;
  598.             }
  599.         if (*op)
  600.             op++;
  601.         }
  602.     if (*op)
  603.         {
  604.         singmoveto(t0);
  605.         for (; *op; op++)
  606.             {
  607.             putchar(' ');
  608.             vcs++;
  609.             }
  610.         }
  611.     singmoveto(nvcs);
  612.     qbuf = nbuf;
  613.     nbuf = obuf;
  614.     obuf = qbuf;
  615.     fflush(stdout);
  616. }
  617.  
  618. void singmoveto(pos) /**/
  619. int pos;
  620. {
  621.     while (pos < vcs)
  622.         {
  623.         vcs--;
  624.         putchar('\b');
  625.         }
  626.     while (pos > vcs)
  627.         {
  628.         putchar(nbuf[0][vcs]);
  629.         vcs++;
  630.         }
  631. }
  632.  
  633. int streqct(s,t) /**/
  634. char *s;char *t;
  635. {
  636. int ct = 0;
  637.  
  638.     while (*s && *s == *t) s++,t++,ct++;
  639.     return ct;
  640. }
  641.  
  642.