home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / elvis184.zip / src / redraw.c < prev    next >
C/C++ Source or Header  |  1994-03-26  |  27KB  |  1,349 lines

  1. /* redraw.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    1500 SW Park #326
  6.  *    Portland OR, 97201
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains functions that draw text on the screen.  The major entry
  12.  * points are:
  13.  *    redrawrange()    - called from modify.c to give hints about what parts
  14.  *              of the screen need to be redrawn.
  15.  *    redraw()    - redraws the screen (or part of it) and positions
  16.  *              the cursor where it belongs.
  17.  *    idx2col()    - converts a markidx() value to a logical column number.
  18.  */
  19.  
  20. #include "config.h"
  21. #include "vi.h"
  22. #ifdef CRUNCH
  23. # define NEAR    LINES
  24. #else
  25. # define NEAR    (*o_nearscroll&0xff)
  26. #endif
  27.  
  28. /* This variable contains the line number that smartdrawtext() knows best */
  29. static long smartlno;
  30.  
  31. /* This function remembers where changes were made, so that the screen can be
  32.  * redrawn in a more efficient manner.
  33.  */
  34. static long    redrawafter;    /* line# of first line that must be redrawn */
  35. static long    preredraw;    /* line# of last line changed, before change */
  36. static long    postredraw;    /* line# of last line changed, after change */
  37. static int    mustredraw;    /* boolean: anything forcing a screen update? */
  38. void redrawrange(after, pre, post)
  39.     long    after;    /* lower bound of redrawafter */
  40.     long    pre;    /* upper bound of preredraw */
  41.     long    post;    /* upper bound of postredraw */
  42. {
  43.     if (after == redrawafter)
  44.     {
  45.         /* multiple insertions/deletions at the same place -- combine
  46.          * them
  47.          */
  48.         preredraw -= (post - pre);
  49.         if (postredraw < post)
  50.         {
  51.             preredraw += (post - postredraw);
  52.             postredraw = post;
  53.         }
  54.         if (redrawafter > preredraw)
  55.         {
  56.             redrawafter = preredraw;
  57.         }
  58.         if (redrawafter < 1L)
  59.         {
  60.             redrawafter = 0L;
  61.             preredraw = postredraw = INFINITY;
  62.         }
  63.     }
  64.     else if (postredraw > 0L)
  65.     {
  66.         /* multiple changes in different places -- redraw everything
  67.          * after "after".
  68.          */
  69.         postredraw = preredraw = INFINITY;
  70.         if (after < redrawafter)
  71.             redrawafter = after;
  72.     }
  73.     else
  74.     {
  75.         /* first change */
  76.         redrawafter = after;
  77.         preredraw = pre;
  78.         postredraw = post;
  79.     }
  80.     mustredraw = TRUE;
  81. }
  82.  
  83.  
  84. #ifndef NO_CHARATTR
  85. /* see if a given line uses character attribute strings */
  86. static int hasattr(lno, text)
  87.     long        lno;    /* the line# of the cursor */
  88.     REG char    *text;    /* the text of the line, from fetchline */
  89. {
  90.     static long    plno;    /* previous line number */
  91.     static long    chgs;    /* previous value of changes counter */
  92.     static int    panswer;/* previous answer */
  93.     char        *scan;
  94.  
  95.     /* if charattr is off, then the answer is "no, it doesn't" */
  96.     if (!*o_charattr)
  97.     {
  98.         chgs = 0; /* <- forces us to check if charattr is later set */
  99.         return FALSE;
  100.     }
  101.  
  102.     /* if we already know the answer, return it... */
  103.     if (lno == plno && chgs == changes)
  104.     {
  105.         return panswer;
  106.     }
  107.  
  108.     /* get the line & look for "\fX" */
  109.     if (!text[0] || !text[1] || !text[2])
  110.     {
  111.         panswer = FALSE;
  112.     }
  113.     else
  114.     {
  115.         for (scan = text; scan[2] && !(scan[0] == '\\' && scan[1] == 'f'); scan++)
  116.         {
  117.         }
  118.         panswer = (scan[2] != '\0');
  119.     }
  120.  
  121.     /* save the results */
  122.     plno = lno;
  123.     chgs = changes;
  124.  
  125.     /* return the results */
  126.     return panswer;
  127. }
  128. #endif
  129.  
  130.  
  131. #ifndef NO_VISIBLE
  132. /* This function checks to make sure that the correct lines are shown in
  133.  * reverse-video.  This is used to handle the "v" and "V" commands.
  134.  */
  135. static long    vizlow, vizhigh;    /* the starting and ending lines */
  136. static int    vizleft, vizright;    /* starting & ending indicies */
  137. static int    vizchange;        /* boolean: must use stupid drawtext? */
  138. static void setviz(curs)
  139.     MARK        curs;
  140. {
  141.     long        newlow, newhigh;
  142.     long        extra = 0L;
  143.  
  144.     /* for now, assume the worst... */
  145.     vizchange = TRUE;
  146.  
  147.     /* set newlow & newhigh according to V_from and cursor */
  148.     if (!V_from)
  149.     {
  150.         /* no lines should have reverse-video */
  151.         if (vizlow)
  152.         {
  153.             redrawrange(vizlow, vizhigh + 1L, vizhigh + 1L);
  154.             vizlow = vizhigh = 0L;
  155.         }
  156.         else
  157.         {
  158.             vizchange = FALSE;
  159.         }
  160.         return;
  161.     }
  162.  
  163.     /* figure out which lines *SHOULD* have hilites */
  164.     if (V_from < curs)
  165.     {
  166.         newlow = markline(V_from);
  167.         newhigh = markline(curs);
  168.         vizleft = markidx(V_from);
  169.         vizright = markidx(curs) + 1;
  170.     }
  171.     else
  172.     {
  173.         newlow = markline(curs);
  174.         newhigh = markline(V_from);
  175.         vizleft = markidx(curs);
  176.         vizright = markidx(V_from) + 1;
  177.     }
  178.  
  179.     /* adjust for line-mode hiliting */
  180.     if (V_linemd)
  181.     {
  182.         vizleft = 0;
  183.         vizright = BLKSIZE - 1;
  184.     }
  185.     else
  186.     {
  187.         extra = 1L;
  188.     }
  189.  
  190.     /* arrange for the necessary lines to be redrawn */
  191.     if (vizlow == 0L)
  192.     {
  193.         /* just starting to redraw */
  194.         redrawrange(newlow, newhigh, newhigh);
  195.     }
  196.     else
  197.     {
  198.         /* Were new lines added/removed at the front? */
  199.         if (newlow != vizlow)
  200.         {
  201.             if (newlow < vizlow)
  202.                 redrawrange(newlow, vizlow + extra, vizlow + extra);
  203.             else
  204.                 redrawrange(vizlow, newlow + extra, newlow + extra);
  205.         }
  206.  
  207.         /* Were new lines added/removed at the back? */
  208.         if (newhigh != vizhigh)
  209.         {
  210.             if (newhigh < vizhigh)
  211.                 redrawrange(newhigh + 1L - extra, vizhigh + 1L, vizhigh + 1L);
  212.             else
  213.                 redrawrange(vizhigh + 1L - extra, newhigh, newhigh);
  214.         }
  215.     }
  216.  
  217.     /* remember which lines will contain hilighted text now */
  218.     vizlow = newlow;
  219.     vizhigh = newhigh;
  220. }
  221. #endif /* !NO_VISIBLE */
  222.  
  223.  
  224. /* This function converts a MARK to a column number.  It doesn't automatically
  225.  * adjust for leftcol; that must be done by the calling function
  226.  */
  227. int idx2col(curs, text, inputting)
  228.     MARK        curs;    /* the line# & index# of the cursor */
  229.     REG char    *text;    /* the text of the line, from fetchline */
  230.     int        inputting;    /* boolean: called from input() ? */
  231. {
  232.     static MARK    pcursor;/* previous cursor, for possible shortcut */
  233.     static MARK    pcol;    /* column number for pcol */
  234.     static long    chgs;    /* previous value of changes counter */
  235.     REG int        col;    /* used to count column numbers */
  236.     REG int        idx;    /* used to count down the index */
  237.     REG int        i;
  238.  
  239.     /* for now, assume we have to start counting at the left edge */
  240.     col = 0;
  241.     idx = markidx(curs);
  242.  
  243.     /* if the file hasn't changed & line number is the same & it has no
  244.      * embedded character attribute strings, can we do shortcuts?
  245.      */
  246.     if (chgs == changes
  247.      && !((curs ^ pcursor) & ~(BLKSIZE - 1))
  248. #ifndef NO_CHARATTR
  249.      && !hasattr(markline(curs), text)
  250. #endif
  251.     )
  252.     {
  253.         /* no movement? */
  254.         if (curs == pcursor)
  255.         {
  256.             /* return the column of the char; for tabs, return its last column */
  257.             if (text[idx] == '\t' && !inputting && !*o_list)
  258.             {
  259.                 return pcol + *o_tabstop - (pcol % *o_tabstop) - 1;
  260.             }
  261.             else
  262.             {
  263.                 return pcol;
  264.             }
  265.         }
  266.  
  267.         /* movement to right? */
  268.         if (curs > pcursor)
  269.         {
  270.             /* start counting from previous place */
  271.             col = pcol;
  272.             idx = markidx(curs) - markidx(pcursor);
  273.             text += markidx(pcursor);
  274.         }
  275.     }
  276.  
  277.     /* count over to the char after the idx position */
  278.     while (idx > 0 && (i = *text)) /* yes, ASSIGNMENT! */
  279.     {
  280.         if (i == '\t' && !*o_list)
  281.         {
  282.             col += *o_tabstop;
  283.             col -= col % *o_tabstop;
  284.         }
  285.         else if (i >= '\0' && i < ' ' || i == '\177')
  286.         {
  287.             col += 2;
  288.         }
  289. #ifndef NO_CHARATTR
  290.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  291.         {
  292.             text += 2; /* plus one more at bottom of loop */
  293.             idx -= 2;
  294.         }            
  295. #endif
  296.         else
  297.         {
  298.             col++;
  299.         }
  300.         text++;
  301.         idx--;
  302.     }
  303.  
  304.     /* save stuff to speed next call */
  305.     pcursor = curs;
  306.     pcol = col;
  307.     chgs = changes;
  308.  
  309.     /* return the column of the char; for tabs, return its last column */
  310.     if (*text == '\t' && !inputting && !*o_list)
  311.     {
  312.         return col + *o_tabstop - (col % *o_tabstop) - 1;
  313.     }
  314.     else
  315.     {
  316.         return col;
  317.     }
  318. }
  319.  
  320.  
  321. /* This function is similar to idx2col except that it takes care of sideways
  322.  * scrolling - for the given line, at least.
  323.  */
  324. int mark2phys(m, text, inputting)
  325.     MARK    m;        /* a mark to convert */
  326.     char    *text;        /* the line that m refers to */
  327.     int    inputting;    /* boolean: caled from input() ? */
  328. {
  329.     int    i;
  330.  
  331.     i = idx2col(m, text, inputting);
  332.     while (i < leftcol)
  333.     {
  334.         leftcol -= *o_sidescroll;
  335.         mustredraw = TRUE;
  336.         redrawrange(1L, INFINITY, INFINITY);
  337.     }
  338.     while (i > rightcol)
  339.     {
  340.         leftcol += *o_sidescroll;
  341.         mustredraw = TRUE;
  342.         redrawrange(1L, INFINITY, INFINITY);
  343.     }
  344.     physrow = markline(m) - topline;
  345.     physcol = i - leftcol;
  346.     if (*o_number)
  347.         physcol += 8;
  348.  
  349.     return physcol;
  350. }
  351.  
  352. /* This function draws a single line of text on the screen.  The screen's
  353.  * cursor is assumed to be located at the leftmost column of the appropriate
  354.  * row.
  355.  */
  356. static void drawtext(text, lno, clr)
  357.     REG char    *text;    /* the text to draw */
  358.     long        lno;    /* the number of the line to draw */
  359.     int        clr;    /* boolean: do a clrtoeol? */
  360. {
  361.     REG int        col;    /* column number */
  362.     REG int        i;
  363.     REG int        tabstop;    /* *o_tabstop */
  364.     REG int        limitcol;    /* leftcol or leftcol + COLS */
  365.     int        abnormal;    /* boolean: charattr != A_NORMAL? */
  366. #ifndef NO_VISIBLE
  367.     int        rev = FALSE;    /* boolean: standout mode, too? */
  368.                     /* init added -dg */
  369.     int        idx = 0;
  370. #endif
  371.     char        numstr[9];
  372.  
  373.     /* show the line number, if necessary */
  374.     if (*o_number)
  375.     {
  376.         sprintf(numstr, "%6ld  ", lno);
  377.         qaddstr(numstr);
  378.     }
  379.  
  380. #ifndef NO_SENTENCE
  381.     /* if we're hiding format lines, and this is one of them, then hide it */
  382.     if (*o_hideformat && *text == '.')
  383.     {
  384.         clrtoeol();
  385. #if OSK
  386.         qaddch('\l');
  387. #else
  388.         qaddch('\n');
  389. #endif
  390.         return;
  391.     }
  392. #endif
  393.  
  394.     /* move some things into registers... */
  395.     limitcol = leftcol;
  396.     tabstop = *o_tabstop;
  397.     abnormal = FALSE;
  398.  
  399. #ifndef CRUNCH
  400.     if (clr)
  401.         clrtoeol();
  402. #endif
  403.  
  404.     /* skip stuff that was scrolled off left edge */
  405.     for (col = 0;
  406.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  407.          text++)
  408.     {
  409. #ifndef NO_VISIBLE
  410.         idx++;
  411. #endif
  412.         if (i == '\t' && !*o_list)
  413.         {
  414.             col = col + tabstop - (col % tabstop);
  415.         }
  416.         else if (i >= 0 && i < ' ' || i == '\177')
  417.         {
  418.             col += 2;
  419.         }
  420. #ifndef NO_CHARATTR
  421.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  422.         {
  423.             text += 2; /* plus one more as part of "for" loop */
  424.  
  425.             /* since this attribute might carry over, we need it */
  426.             switch (*text)
  427.             {
  428.               case 'R':
  429.               case 'P':
  430.                 attrset(A_NORMAL);
  431.                 abnormal = FALSE;
  432.                 break;
  433.  
  434.               case 'B':
  435.                 attrset(A_BOLD);
  436.                 abnormal = TRUE;
  437.                 break;
  438.  
  439.               case 'U':
  440.                 attrset(A_UNDERLINE);
  441.                 abnormal = TRUE;
  442.                 break;
  443.  
  444.               case 'I':
  445.                 attrset(A_ALTCHARSET);
  446.                 abnormal = TRUE;
  447.                 break;
  448.             }
  449.         }
  450. #endif
  451.         else
  452.         {
  453.             col++;
  454.         }
  455.     }
  456.  
  457. #ifndef NO_VISIBLE
  458.     /* Should we start hiliting at the first char of this line? */
  459.     if ((lno > vizlow && lno <= vizhigh
  460.         || lno == vizlow && vizleft < idx)
  461.        && !(lno == vizhigh && vizright < idx))
  462.     {
  463.         do_VISIBLE();
  464.         rev = TRUE;
  465.     }
  466. #endif
  467.  
  468.     /* adjust for control char that was partially visible */
  469.     while (col > limitcol)
  470.     {
  471.         qaddch(' ');
  472.         limitcol++;
  473.     }
  474.  
  475.     /* now for the visible characters */
  476.     limitcol = leftcol + COLS;
  477.     if (*o_number)
  478.         limitcol -= 8;
  479.     for (; (i = *text) && col < limitcol; text++)
  480.     {
  481. #ifndef NO_VISIBLE
  482.         /* maybe turn hilite on/off in the middle of the line */
  483.         if (lno == vizlow && vizleft == idx)
  484.         {
  485.             do_VISIBLE();
  486.             rev = TRUE;
  487.         }
  488.         if (lno == vizhigh && vizright == idx)
  489.         {
  490.             do_SE();
  491.             rev = FALSE;
  492.         }
  493.         idx++;
  494.  
  495.         /* if hiliting, never emit physical tabs */
  496.         if (rev && i == '\t' && !*o_list)
  497.         {
  498.             i = col + tabstop - (col % tabstop);
  499.             do
  500.             {
  501.                 qaddch(' ');
  502.                 col++;
  503.             } while (col < i && col < limitcol);
  504.         }
  505.         else
  506. #endif /* !NO_VISIBLE */
  507.         if (i == '\t' && !*o_list)
  508.         {
  509.             i = col + tabstop - (col % tabstop);
  510.             if (i < limitcol)
  511.             {
  512. #ifdef CRUNCH
  513.                 if (!clr && has_PT && !((i - leftcol) & 7))
  514. #else
  515.                 if (has_PT && !((i - leftcol) & 7))
  516. #endif
  517.                 {
  518.                     do
  519.                     {
  520.                         qaddch('\t');
  521.                         col += 8; /* not exact! */
  522.                     } while (col < i);
  523.                     col = i; /* NOW it is exact */
  524.                 }
  525.                 else
  526.                 {
  527.                     do
  528.                     {
  529.                         qaddch(' ');
  530.                         col++;
  531.                     } while (col < i && col < limitcol);
  532.                 }
  533.             }
  534.             else /* tab ending after screen? next line! */
  535.             {
  536. #ifdef CRUNCH
  537.                 /* needed at least when scrolling the screen right  -nox */
  538.                 if (clr && col < limitcol)
  539.                     clrtoeol();
  540. #endif
  541.                 col = limitcol;
  542.                 if (has_AM)
  543.                 {
  544.                     addch('\n');    /* GB */
  545.                 }
  546.             }
  547.         }
  548.         else if (i >= 0 && i < ' ' || i == '\177')
  549.         {
  550.             col += 2;
  551.             qaddch('^');
  552.             if (col <= limitcol)
  553.             {
  554.                 qaddch(i ^ '@');
  555.             }
  556.         }
  557. #ifndef NO_CHARATTR
  558.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  559.         {
  560.             text += 2; /* plus one more as part of "for" loop */
  561.             switch (*text)
  562.             {
  563.               case 'R':
  564.               case 'P':
  565.                 attrset(A_NORMAL);
  566.                 abnormal = FALSE;
  567.                 break;
  568.  
  569.               case 'B':
  570.                 attrset(A_BOLD);
  571.                 abnormal = TRUE;
  572.                 break;
  573.  
  574.               case 'U':
  575.                 attrset(A_UNDERLINE);
  576.                 abnormal = TRUE;
  577.                 break;
  578.  
  579.               case 'I':
  580.                 attrset(A_ALTCHARSET);
  581.                 abnormal = TRUE;
  582.                 break;
  583.             }
  584.         }
  585. #endif
  586.         else
  587.         {
  588.             col++;
  589.             qaddch(i);
  590.         }
  591.     }
  592.  
  593.     /* get ready for the next line */
  594. #ifndef NO_CHARATTR
  595.     if (abnormal)
  596.     {
  597.         attrset(A_NORMAL);
  598.     }
  599. #endif
  600.     if (*o_list && col < limitcol)
  601.     {
  602.         qaddch('$');
  603.         col++;
  604.     }
  605.  
  606. #ifndef NO_VISIBLE
  607.     /* did we hilite this whole line?  If so, STOP! */
  608.     if (rev)
  609.     {
  610.         do_SE();
  611.     }
  612. #endif
  613.  
  614. #ifdef CRUNCH
  615.     if (clr && col < limitcol)
  616.     {
  617.         clrtoeol();
  618.     }
  619. #endif
  620.     if (!has_AM || col < limitcol)
  621.     {
  622.         addch('\n');
  623.     }
  624.  
  625.     wqrefresh();
  626. }
  627.  
  628.  
  629. #ifndef CRUNCH
  630. static void nudgecursor(same, scan, new, lno)
  631.     int    same;    /* number of chars to be skipped over */
  632.     char    *scan;    /* where the same chars end */
  633.     char    *new;    /* where the visible part of the line starts */
  634.     long    lno;    /* line number of this line */
  635. {
  636.     int    col;
  637.  
  638.     if (same > 0)
  639.     {
  640.         if (same < 5)
  641.         {
  642.             /* move the cursor by overwriting */
  643.             while (same > 0)
  644.             {
  645.                 qaddch(scan[-same]);
  646.                 same--;
  647.             }
  648.         }
  649.         else
  650.         {
  651.             /* move the cursor by calling move() */
  652.             col = (int)(scan - new);
  653.             if (*o_number)
  654.                 col += 8;
  655.             move((int)(lno - topline), col);
  656.         }
  657.     }
  658. }
  659. #endif /* not CRUNCH */
  660.  
  661. /* This function draws a single line of text on the screen, possibly with
  662.  * some cursor optimization.  The cursor is repositioned before drawing
  663.  * begins, so its position before doesn't really matter.
  664.  */
  665. static void smartdrawtext(text, lno, showit)
  666.     REG char    *text;    /* the text to draw */
  667.     long        lno;    /* line number of the text */
  668.     int        showit;    /* boolean: output line? (else just remember it) */
  669. {
  670. #ifdef CRUNCH
  671.     move((int)(lno - topline), 0);
  672.     if (showit)
  673.     {
  674.         drawtext(text, lno, TRUE);
  675.     }
  676. #else /* not CRUNCH */
  677.     static char    old[256];    /* how the line looked last time */
  678.     char        new[256];    /* how it looks now */
  679.     char        *build;        /* used to put chars into new[] */
  680.     char        *scan;        /* used for moving thru new[] or old[] */
  681.     char        *end;        /* last non-blank changed char */
  682.     char        *shift;        /* used to insert/delete chars */
  683.     int        same;        /* length of a run of unchanged chars */
  684.     int        limitcol;
  685.     int        col;
  686.     int        i;
  687.     char        numstr[9];
  688.  
  689. # ifndef NO_CHARATTR
  690.     /* if this line has attributes, do it the dumb way instead */
  691.     if (hasattr(lno, text))
  692.     {
  693.         move((int)(lno - topline), 0);
  694.         drawtext(text, lno, TRUE);
  695.         return;
  696.     }
  697. # endif
  698. # ifndef NO_SENTENCE
  699.     /* if this line is a format line, & we're hiding format lines, then
  700.      * let the dumb drawtext() function handle it
  701.      */
  702.     if (*o_hideformat && *text == '.')
  703.     {
  704.         move((int)(lno - topline), 0);
  705.         drawtext(text, lno, TRUE);
  706.         return;
  707.     }
  708. # endif
  709. # ifndef NO_VISIBLE
  710.     if (vizchange)
  711.     {
  712.         move((int)(lno - topline), 0);
  713.         drawtext(text, lno, TRUE);
  714.         smartlno = 0L;
  715.         return;
  716.     }
  717. # endif
  718.  
  719.     /* skip stuff that was scrolled off left edge */
  720.     limitcol = leftcol;
  721.     for (col = 0;
  722.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  723.          text++)
  724.     {
  725.         if (i == '\t' && !*o_list)
  726.         {
  727.             col = col + *o_tabstop - (col % *o_tabstop);
  728.         }
  729.         else if (i >= 0 && i < ' ' || i == '\177')
  730.         {
  731.             col += 2;
  732.         }
  733.         else
  734.         {
  735.             col++;
  736.         }
  737.     }
  738.  
  739.     /* adjust for control char that was partially visible */
  740.     build = new;
  741.     while (col > limitcol)
  742.     {
  743.         *build++ = ' ';
  744.         limitcol++;
  745.     }
  746.  
  747.     /* now for the visible characters */
  748.     limitcol = leftcol + COLS;
  749.     if (*o_number)
  750.         limitcol -= 8;
  751.     for (; (i = *text) && col < limitcol; text++)
  752.     {
  753.         if (i == '\t' && !*o_list)
  754.         {
  755.             i = col + *o_tabstop - (col % *o_tabstop);
  756.             while (col < i && col < limitcol)
  757.             {
  758.                 *build++ = ' ';
  759.                 col++;
  760.             }
  761.         }
  762.         else if (i >= 0 && i < ' ' || i == '\177')
  763.         {
  764.             col += 2;
  765.             *build++ = '^';
  766.             if (col <= limitcol)
  767.             {
  768.                 *build++ = (i ^ '@');
  769.             }
  770.         }
  771.         else
  772.         {
  773.             col++;
  774.             *build++ = i;
  775.         }
  776.     }
  777.     if (col < limitcol && *o_list)
  778.     {
  779.         *build++ = '$';
  780.         col++;
  781.     }
  782.     end = build;
  783.     while (col < limitcol)
  784.     {
  785.         *build++ = ' ';
  786.         col++;
  787.     }
  788.  
  789.     /* if we're just supposed to remember this line, then remember it */
  790.     if (!showit)
  791.     {
  792.         smartlno = lno;
  793.         strncpy(old, new, COLS);
  794.         return;
  795.     }
  796.  
  797.     /* locate the last non-blank character */
  798.     while (end > new && end[-1] == ' ')
  799.     {
  800.         end--;
  801.     }
  802.  
  803.     /* can we optimize the displaying of this line? */
  804.     if (lno != smartlno)
  805.     {
  806.         /* nope, can't optimize - different line */
  807.         move((int)(lno - topline), 0);
  808.  
  809.         /* show the line number, if necessary */
  810.         if (*o_number)
  811.         {
  812.             sprintf(numstr, "%6ld  ", lno);
  813.             qaddstr(numstr);
  814.         }
  815.  
  816.         /* show the new line */
  817.         for (scan = new, build = old; scan < end; )
  818.         {
  819.             qaddch(*scan);
  820.             *build++ = *scan++;
  821.         }
  822.         if (end < new + COLS - (*o_number ? 8 : 0))
  823.         {
  824.             clrtoeol();
  825.             while (build < old + COLS)
  826.             {
  827.                 *build++ = ' ';
  828.             }
  829.         }
  830.         smartlno = lno;
  831.         return;
  832.     }
  833.  
  834.     /* skip any initial unchanged characters */
  835.     for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
  836.     {
  837.     }
  838.     i = (scan - new);
  839.     if (*o_number)
  840.         i += 8;
  841.     move((int)(lno - topline), i);
  842.  
  843.     /* The in-between characters must be changed */
  844.     same = 0;
  845.     while (scan < end)
  846.     {
  847.         /* is this character a match? */
  848.         if (scan[0] == build[0])
  849.         {
  850.             same++;
  851.         }
  852.         else /* do we want to insert? */
  853.         if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
  854.         {
  855.             nudgecursor(same, scan, new, lno);
  856.             same = 0;
  857.  
  858.             insch(*scan);
  859.             for (shift = old + COLS; --shift > build; )
  860.             {
  861.                 shift[0] = shift[-1];
  862.             }
  863.             *build = *scan;
  864.         }
  865.         else /* do we want to delete? */
  866.         if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
  867.         {
  868.             nudgecursor(same, scan, new, lno);
  869.             same = 0;
  870.  
  871.             delch();
  872.             same++;
  873.             for (shift = build; shift < old + COLS - 1; shift++)
  874.             {
  875.                 shift[0] = shift[1];
  876.             }
  877.             if (*o_number)
  878.                 shift -= 8;
  879.             *shift = ' ';
  880.         }
  881.         else /* we must overwrite */
  882.         {
  883.             nudgecursor(same, scan, new, lno);
  884.             same = 0;
  885.  
  886.             addch(*scan);
  887.             *build = *scan;
  888.         }
  889.  
  890.         build++;
  891.         scan++;
  892.     }
  893.  
  894.     /* maybe clear to EOL */
  895.     end = old + COLS - (*o_number ? 8 : 0);
  896.     while (build < end && *build == ' ')
  897.     {
  898.         build++;
  899.     }
  900.     if (build < end)
  901.     {
  902.         nudgecursor(same, scan, new, lno);
  903.         same = 0;
  904.  
  905.         clrtoeol();
  906.         while (build < old + COLS)
  907.         {
  908.             *build++ = ' ';
  909.         }
  910.     }
  911. #endif /* not CRUNCH */
  912. }
  913.  
  914.  
  915. /* This function is used in visual mode for drawing the screen (or just parts
  916.  * of the screen, if that's all thats needed).  It also takes care of
  917.  * scrolling.
  918.  */
  919. void redraw(curs, inputting)
  920.     MARK    curs;        /* where to leave the screen's cursor */
  921.     int    inputting;    /* boolean: being called from input() ? */
  922. {
  923.     char        *text;        /* a line of text to display */
  924.     static long    chgs;        /* previous changes level */
  925.     long        l;
  926.     int        i;
  927. #ifndef CRUNCH
  928.     int        winlines;    /* number of lines to show */
  929.     static long    showtop;    /* top line in window */
  930.     static long    showbottom;    /* bottom line in window */
  931.  
  932.     /* figure out the window size */
  933.     winlines = (*o_window ? (*o_window & 255) : (LINES - 1) );
  934. #endif
  935.  
  936.     /* if curs == MARK_UNSET, then we should reset internal vars */
  937.     if (curs == MARK_UNSET)
  938.     {
  939.         if (topline < 1 || topline > nlines)
  940.         {
  941.             topline = 1L;
  942.         }
  943.         else
  944.         {
  945.             move(LINES - 1, 0);
  946.             clrtoeol();
  947.         }
  948.         leftcol = 0;
  949.         mustredraw = TRUE;
  950.         redrawafter = INFINITY;
  951.         preredraw = 0L;
  952.         postredraw = 0L;
  953.         chgs = 0;
  954.         smartlno = 0L;
  955. #ifndef NO_VISIBLE
  956.         vizlow = vizhigh = 0L;
  957.         vizchange = FALSE;
  958. #endif
  959. #ifndef CRUNCH
  960.         showtop = 0;
  961.         showbottom = INFINITY;
  962. #endif
  963.         return;
  964.     }
  965.  
  966. #ifndef NO_VISIBLE
  967.     /* adjustments to hilited area may force extra lines to be redrawn. */
  968. #ifndef CRUNCH
  969.     if (curs == cursor)
  970. #endif
  971.         setviz(curs);
  972. #endif
  973.  
  974.     /* figure out which column the cursor will be in */
  975.     l = markline(curs);
  976.     text = fetchline(l);
  977.     mark2phys(curs, text, inputting);
  978.  
  979. #ifndef NO_COLOR
  980.     fixcolor();
  981. #endif
  982.  
  983.     /* adjust topline, if necessary, to get the cursor on the screen */
  984.     if (l >= topline && l <= botline)
  985.     {
  986.         /* it is on the screen already */
  987.  
  988.         /* if the file was changed but !mustredraw, then redraw line */
  989.         if (!mustredraw && (chgs != changes
  990. #ifndef NO_VISIBLE
  991.             || V_from
  992. #endif
  993. #ifndef CRUNCH
  994.             || l < showtop || l > showbottom
  995. #endif
  996.                             ))
  997.         {
  998.             smartdrawtext(text, l, (chgs != changes));
  999.         }
  1000.     }
  1001.     else if (l < topline && l >= topline - NEAR)
  1002.     {
  1003.         /* near top - scroll down */
  1004.         if (!mustredraw)
  1005.         {
  1006.             move(0,0);
  1007.             if (!has_SR && !has_AL)
  1008.             {
  1009.               topline = l;
  1010.               redrawrange(0L, INFINITY, INFINITY);
  1011.               smartlno = 0L;
  1012.             }
  1013.             else
  1014.             while (l < topline)
  1015.             {
  1016.                 topline--;
  1017.                 if (has_SR)
  1018.                 {
  1019.                     do_SR();
  1020.                 }
  1021.                 else
  1022.                 {
  1023.                     insertln();
  1024.                 }
  1025.                 text = fetchline(topline);
  1026.                 drawtext(text, topline, FALSE);
  1027.                 do_UP();
  1028.             }
  1029.  
  1030.             /* blank out the last line */
  1031.             move(LINES - 1, 0);
  1032.             clrtoeol();
  1033.  
  1034.             /* smartlno still on screen?    -nox */
  1035.             if (smartlno > botline)
  1036.                 smartlno = 0;
  1037.         }
  1038.         else
  1039.         {
  1040.             topline = l;
  1041.             redrawrange(0L, INFINITY, INFINITY);
  1042. #ifndef NO_VISIBLE
  1043. # ifndef CRUNCH
  1044.             if (V_from && curs != cursor)
  1045.                 return;
  1046. # endif
  1047. #endif
  1048.         }
  1049.     }
  1050.     else if (l > topline && l <= botline + NEAR)
  1051.     {
  1052.         /* near bottom -- scroll up */
  1053.         if (!mustredraw)
  1054.         {
  1055.             move(LINES - 1,0);
  1056.             clrtoeol();
  1057.             while (l > botline)
  1058.             {
  1059.                 topline++; /* <-- also adjusts botline */
  1060.                 text = fetchline(botline);
  1061.                 drawtext(text, botline, FALSE);
  1062.             }
  1063.             /* smartlno still on screen?    -nox */
  1064.             if (topline > smartlno)
  1065.                 smartlno = 0;
  1066. #ifndef CRUNCH
  1067.             showbottom = l;
  1068. #endif
  1069.         }
  1070.         else
  1071.         {
  1072.             topline = l - (LINES - 2);
  1073.             redrawrange(0L, INFINITY, INFINITY);
  1074. #ifndef NO_VISIBLE
  1075. # ifndef CRUNCH
  1076.             if (V_from && curs != cursor)
  1077.                 return;
  1078. # endif
  1079. #endif
  1080.         }
  1081.     }
  1082.     else
  1083.     {
  1084.         /* distant line - center it & force a redraw */
  1085.         topline = l - (LINES - 1) / 2;
  1086.         if (topline < 1)
  1087.         {
  1088.             topline = 1;
  1089.         }
  1090.         redrawrange(0L, INFINITY, INFINITY);
  1091. #ifndef NO_VISIBLE
  1092. # ifndef CRUNCH
  1093.         if (V_from && curs != cursor)
  1094.             return;
  1095. # endif
  1096. #endif
  1097.         smartlno = 0L;
  1098.         changes++;
  1099.     }
  1100.  
  1101. #ifndef CRUNCH
  1102.     /* make sure the current line is included in the "window" */
  1103.     if (l < showtop)
  1104.     {
  1105.         redrawrange(l, showtop, showtop);
  1106.         showtop = l;
  1107.     }
  1108.     if (l > showbottom)
  1109.     {
  1110.         redrawrange(showbottom, l, l);
  1111.         showbottom = l;
  1112.     }
  1113. #endif
  1114.  
  1115.  
  1116.     /* Now... do we really have to redraw? */
  1117.     if (mustredraw)
  1118.     {
  1119.         /* If redrawfter (and friends) aren't set, assume we should
  1120.          * redraw everything.
  1121.          */
  1122.         if (redrawafter == INFINITY)
  1123.         {
  1124.             redrawafter = 0L;
  1125.             preredraw = postredraw = INFINITY;
  1126.         }
  1127.  
  1128. #ifndef CRUNCH
  1129.         /* shrink the window, if possible */
  1130.         if (showtop < topline)
  1131.         {
  1132.             showtop = topline;
  1133.         }
  1134.         if (showbottom > botline)
  1135.         {
  1136.             showbottom = botline;
  1137.         }
  1138.         if (postredraw == INFINITY)
  1139.         {
  1140.             /* these will be set to more reasonable values later */
  1141.             showtop = INFINITY;
  1142.             showbottom = 0L;
  1143.         }
  1144. #endif
  1145.  
  1146.         /* adjust smartlno to correspond with inserted/deleted lines */
  1147.         if (smartlno >= redrawafter)
  1148.         {
  1149.             if (smartlno <= preredraw && postredraw != preredraw) /*!!!*/
  1150.             {
  1151.                 smartlno = 0L;
  1152.             }
  1153.             else
  1154.             {
  1155.                 smartlno += (postredraw - preredraw);
  1156.             }
  1157.         }
  1158.  
  1159.         /* should we insert some lines into the screen? */
  1160.         if (preredraw < postredraw && preredraw <= botline)
  1161.         {
  1162.             /* lines were inserted into the file */
  1163.  
  1164.             /* decide where insertion should start */
  1165.             if (preredraw < topline)
  1166.             {
  1167.                 l = topline;
  1168.             }
  1169.             else
  1170.             {
  1171.                 l = preredraw;
  1172.             }
  1173.  
  1174.             /* insert the lines... maybe */
  1175.             if (l + postredraw - preredraw > botline || !has_AL || *o_number)
  1176.             {
  1177.                 /* Whoa!  a whole screen full - just redraw */
  1178.                 preredraw = postredraw = INFINITY;
  1179.                 smartlno = 0;
  1180.             }
  1181.             else
  1182.             {
  1183.                 /* really insert 'em */
  1184.                 move((int)(l - topline), 0);
  1185.                 for (i = postredraw - preredraw; i > 0; i--)
  1186.                 {
  1187.                     insertln();
  1188.                 }
  1189.  
  1190.                 /* NOTE: the contents of those lines will be
  1191.                  * drawn as part of the regular redraw loop.
  1192.                  */
  1193.  
  1194.                 /* clear the last line */
  1195.                 move(LINES - 1, 0);
  1196.                 clrtoeol();
  1197.             }
  1198.         }
  1199.  
  1200.         /* do we want to delete some lines from the screen? */
  1201.         if (preredraw > postredraw && postredraw <= botline)
  1202.         {
  1203.             if (preredraw > botline || !has_DL || *o_number)
  1204.             {
  1205.                 postredraw = preredraw = INFINITY;
  1206.                 smartlno = 0;
  1207.             }
  1208.             else /* we'd best delete some lines from the screen */
  1209.             {
  1210.                 /* clear the last line, so it doesn't look
  1211.                  * ugly as it gets pulled up into the screen
  1212.                  */
  1213.                 move(LINES - 1, 0);
  1214.                 clrtoeol();
  1215.  
  1216.                 /* delete the lines */
  1217.                 move((int)(postredraw - topline), 0);
  1218.                  for (l = postredraw;
  1219.                      l < preredraw && l <= botline;
  1220.                      l++)
  1221.                 {
  1222.                     deleteln();
  1223.                 }
  1224.  
  1225.                 /* draw the lines that are now newly visible
  1226.                  * at the bottom of the screen
  1227.                  */
  1228.                 i = LINES - 1 + (postredraw - preredraw);
  1229.                 move(i, 0);
  1230.                 for (l = topline + i; l <= botline; l++)
  1231.                 {
  1232.                     /* clear this line */
  1233.                     clrtoeol();
  1234.  
  1235.                     /* draw the line, or ~ for non-lines */
  1236.                     if (l <= nlines)
  1237.                     {
  1238.                         text = fetchline(l);
  1239.                         drawtext(text, l, FALSE);
  1240.                     }
  1241.                     else
  1242.                     {
  1243.                         addstr("~\n");
  1244.                     }
  1245.                 }
  1246.             }
  1247.         }
  1248.  
  1249.         /* redraw the current line */
  1250.         l = markline(curs);
  1251.         pfetch(l);
  1252.         smartdrawtext(ptext, l, TRUE);
  1253.  
  1254. #ifndef CRUNCH
  1255.         /* decide which lines must be in the "window" around the cursor */
  1256.         l = markline(curs);
  1257.         if (winlines + 1 == LINES)
  1258.         {
  1259.             showtop = 1;
  1260.             showbottom = INFINITY;
  1261.         }
  1262.         else if (l < showtop || l > showbottom)
  1263.         {
  1264.             l -= winlines / 2;
  1265.             if (l < topline)
  1266.             {
  1267.                 l = topline;
  1268.             }
  1269.             if (l < showtop)
  1270.             {
  1271.                 showtop = l;
  1272.             }
  1273.             l += winlines - 1;
  1274.             if (l > botline)
  1275.             {
  1276.                 showtop = showtop - l + botline;
  1277.                 l = botline;
  1278.             }
  1279.             if (l > showbottom)
  1280.             {
  1281.                 showbottom = l;
  1282.             }
  1283.         }
  1284. #endif
  1285.  
  1286.         /* decide where we should start redrawing from */
  1287.         if (redrawafter < topline)
  1288.         {
  1289.             l = topline;
  1290.         }
  1291.         else
  1292.         {
  1293.             l = redrawafter;
  1294.         }
  1295.         if (l <= botline && l <= postredraw && (l != smartlno || botline != smartlno))
  1296.         {
  1297.             /* draw the other lines */
  1298.             move((int)(l - topline), 0);
  1299.             for (; l <= botline && l < postredraw; l++)
  1300.             {
  1301.                 /* we already drew the current line, so skip it now */
  1302.                 if (l == smartlno)
  1303.                 {
  1304. #if OSK
  1305.                     qaddch('\l');
  1306. #else
  1307.                     qaddch('\n');
  1308. #endif
  1309.                     continue;
  1310.                 }
  1311.  
  1312.                 /* draw the line, or ~ for non-lines */
  1313.                 if (l > nlines)
  1314.                 {
  1315.                     qaddch('~');
  1316.                     clrtoeol();
  1317.                     addch('\n');
  1318.                 }
  1319. #ifndef CRUNCH
  1320.                 else if (l < showtop || l > showbottom)
  1321.                 {
  1322.                     qaddch('@');
  1323.                     clrtoeol();
  1324.                     addch('\n');
  1325.                 }
  1326. #endif
  1327.                 else
  1328.                 {
  1329.                     text = fetchline(l);
  1330.                     drawtext(text, l, TRUE);
  1331.                 }
  1332.             }
  1333.         }
  1334.  
  1335.         mustredraw = FALSE;
  1336.     }
  1337.  
  1338.     /* force total (non-partial) redraw next time if not set */
  1339.     redrawafter = INFINITY;
  1340.     preredraw = 0L;
  1341.     postredraw = 0L;
  1342.  
  1343.     /* move the cursor to where it belongs */
  1344.     move((int)(markline(curs) - topline), physcol);
  1345.     wqrefresh();
  1346.  
  1347.     chgs = changes;
  1348. }
  1349.