home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / apps / text_ed / elv16b2 / st / redraw.c < prev    next >
C/C++ Source or Header  |  1992-05-13  |  26KB  |  1,314 lines

  1. /* redraw.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  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    UCHAR(*o_nearscroll)
  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.  * redraw 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;        /* boolean: standout mode, too? */
  368.     int        idx = 0;
  369. #endif
  370.     char        numstr[9];
  371.  
  372.     /* show the line number, if necessary */
  373.     if (*o_number)
  374.     {
  375.         sprintf(numstr, "%6ld  ", lno);
  376.         qaddstr(numstr);
  377.     }
  378.  
  379. #ifndef NO_SENTENCE
  380.     /* if we're hiding format lines, and this is one of them, then hide it */
  381.     if (*o_hideformat && *text == '.')
  382.     {
  383.         clrtoeol();
  384. #if OSK
  385.         qaddch('\l');
  386. #else
  387.         qaddch('\n');
  388. #endif
  389.         return;
  390.     }
  391. #endif
  392.  
  393.     /* move some things into registers... */
  394.     limitcol = leftcol;
  395.     tabstop = *o_tabstop;
  396.     abnormal = FALSE;
  397.  
  398. #ifdef SMOOTHREDRAW
  399. #define CRUNCH
  400. #endif
  401. /* ...or was it meant the other way around? :-)  -nox */
  402. #ifndef CRUNCH
  403.     if (clr)
  404.         clrtoeol();
  405. #endif
  406.  
  407.     /* skip stuff that was scrolled off left edge */
  408.     for (col = 0;
  409.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  410.          text++)
  411.     {
  412. #ifndef NO_VISIBLE
  413.         idx++;
  414. #endif
  415.         if (i == '\t' && !*o_list)
  416.         {
  417.             col = col + tabstop - (col % tabstop);
  418.         }
  419.         else if (i >= 0 && i < ' ' || i == '\177')
  420.         {
  421.             col += 2;
  422.         }
  423. #ifndef NO_CHARATTR
  424.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  425.         {
  426.             text += 2; /* plus one more as part of "for" loop */
  427.  
  428.             /* since this attribute might carry over, we need it */
  429.             switch (*text)
  430.             {
  431.               case 'R':
  432.               case 'P':
  433.                 attrset(A_NORMAL);
  434.                 abnormal = FALSE;
  435.                 break;
  436.  
  437.               case 'B':
  438.                 attrset(A_BOLD);
  439.                 abnormal = TRUE;
  440.                 break;
  441.  
  442.               case 'U':
  443.                 attrset(A_UNDERLINE);
  444.                 abnormal = TRUE;
  445.                 break;
  446.  
  447.               case 'I':
  448.                 attrset(A_ALTCHARSET);
  449.                 abnormal = TRUE;
  450.                 break;
  451.             }
  452.         }
  453. #endif
  454.         else
  455.         {
  456.             col++;
  457.         }
  458.     }
  459.  
  460. #ifndef NO_VISIBLE
  461.     /* Should we start hiliting at the first char of this line? */
  462.     if ((lno > vizlow && lno <= vizhigh
  463.         || lno == vizlow && vizleft < idx)
  464.        && !(lno == vizhigh && vizright < idx))
  465.     {
  466.         do_VISIBLE();
  467.         rev = TRUE;
  468.     }
  469. #endif
  470.  
  471.     /* adjust for control char that was partially visible */
  472.     while (col > limitcol)
  473.     {
  474.         qaddch(' ');
  475.         limitcol++;
  476.     }
  477.  
  478.     /* now for the visible characters */
  479.     limitcol = leftcol + COLS;
  480.     if (*o_number)
  481.         limitcol -= 8;
  482.     for (; (i = *text) && col < limitcol; text++)
  483.     {
  484. #ifndef NO_VISIBLE
  485.         /* maybe turn hilite on/off in the middle of the line */
  486.         if (lno == vizlow && vizleft == idx)
  487.         {
  488.             do_VISIBLE();
  489.             rev = TRUE;
  490.         }
  491.         if (lno == vizhigh && vizright == idx)
  492.         {
  493.             do_SE();
  494.             rev = FALSE;
  495.         }
  496.         idx++;
  497.  
  498.         /* if hiliting, never emit physical tabs */
  499.         if (rev && i == '\t' && !*o_list)
  500.         {
  501.             i = col + tabstop - (col % tabstop);
  502.             do
  503.             {
  504.                 qaddch(' ');
  505.                 col++;
  506.             } while (col < i && col < limitcol);
  507.         }
  508.         else
  509. #endif /* !NO_VISIBLE */
  510.         if (i == '\t' && !*o_list)
  511.         {
  512.             i = col + tabstop - (col % tabstop);
  513.             if (i < limitcol)
  514.             {
  515. #ifdef CRUNCH
  516.                 if (!clr && has_PT && !((i - leftcol) & 7))
  517. #else
  518.                 if (has_PT && !((i - leftcol) & 7))
  519. #endif
  520.                 {
  521.                     do
  522.                     {
  523.                         qaddch('\t');
  524.                         col += 8; /* not exact! */
  525.                     } while (col < i);
  526.                     col = i; /* NOW it is exact */
  527.                 }
  528.                 else
  529.                 {
  530.                     do
  531.                     {
  532.                         qaddch(' ');
  533.                         col++;
  534.                     } while (col < i && col < limitcol);
  535.                 }
  536.             }
  537.             else /* tab ending after screen? next line! */
  538.             {
  539. #ifdef CRUNCH
  540.                 /* needed atleast when scrolling the screen right  -nox */
  541.                 if (clr && col < limitcol)
  542.                     clrtoeol();
  543. #endif
  544.                 col = limitcol;
  545.                 if (has_AM)
  546.                 {
  547.                     addch('\n');    /* GB */
  548.                 }
  549.             }
  550.         }
  551.         else if (i >= 0 && i < ' ' || i == '\177')
  552.         {
  553.             col += 2;
  554.             qaddch('^');
  555.             if (col <= limitcol)
  556.             {
  557.                 qaddch(i ^ '@');
  558.             }
  559.         }
  560. #ifndef NO_CHARATTR
  561.         else if (i == '\\' && text[1] == 'f' && text[2] && *o_charattr)
  562.         {
  563.             text += 2; /* plus one more as part of "for" loop */
  564.             switch (*text)
  565.             {
  566.               case 'R':
  567.               case 'P':
  568.                 attrset(A_NORMAL);
  569.                 abnormal = FALSE;
  570.                 break;
  571.  
  572.               case 'B':
  573.                 attrset(A_BOLD);
  574.                 abnormal = TRUE;
  575.                 break;
  576.  
  577.               case 'U':
  578.                 attrset(A_UNDERLINE);
  579.                 abnormal = TRUE;
  580.                 break;
  581.  
  582.               case 'I':
  583.                 attrset(A_ALTCHARSET);
  584.                 abnormal = TRUE;
  585.                 break;
  586.             }
  587.         }
  588. #endif
  589.         else
  590.         {
  591.             col++;
  592.             qaddch(i);
  593.         }
  594.     }
  595.  
  596.     /* get ready for the next line */
  597. #ifndef NO_CHARATTR
  598.     if (abnormal)
  599.     {
  600.         attrset(A_NORMAL);
  601.     }
  602. #endif
  603.     if (*o_list && col < limitcol)
  604.     {
  605.         qaddch('$');
  606.         col++;
  607.     }
  608.  
  609. #ifndef NO_VISIBLE
  610.     /* did we hilite this whole line?  If so, STOP! */
  611.     if (rev)
  612.     {
  613.         do_SE();
  614.     }
  615. #endif
  616.  
  617. #ifdef CRUNCH
  618.     if (clr && col < limitcol)
  619.     {
  620.         clrtoeol();
  621.     }
  622. #endif
  623.     if (!has_AM || col < limitcol)
  624.     {
  625.         addch('\n');
  626.     }
  627.  
  628.     wqrefresh();
  629. }
  630.  
  631. #ifdef SMOOTHREDRAW
  632. #undef CRUNCH
  633. #endif
  634.  
  635. #ifndef CRUNCH
  636. static void nudgecursor(same, scan, new, lno)
  637.     int    same;    /* number of chars to be skipped over */
  638.     char    *scan;    /* where the same chars end */
  639.     char    *new;    /* where the visible part of the line starts */
  640.     long    lno;    /* line number of this line */
  641. {
  642.     int    col;
  643.  
  644.     if (same > 0)
  645.     {
  646.         if (same < 5)
  647.         {
  648.             /* move the cursor by overwriting */
  649.             while (same > 0)
  650.             {
  651.                 qaddch(scan[-same]);
  652.                 same--;
  653.             }
  654.         }
  655.         else
  656.         {
  657.             /* move the cursor by calling move() */
  658.             col = (int)(scan - new);
  659.             if (*o_number)
  660.                 col += 8;
  661.             move((int)(lno - topline), col);
  662.         }
  663.     }
  664. }
  665. #endif /* not CRUNCH */
  666.  
  667. /* This function draws a single line of text on the screen, possibly with
  668.  * some cursor optimization.  The cursor is repositioned before drawing
  669.  * begins, so its position before doesn't really matter.
  670.  */
  671. static void smartdrawtext(text, lno, showit)
  672.     REG char    *text;    /* the text to draw */
  673.     long        lno;    /* line number of the text */
  674.     int        showit;    /* boolean: output line? (else just remember it) */
  675. {
  676. #ifdef CRUNCH
  677.     move((int)(lno - topline), 0);
  678.     if (showit)
  679.     {
  680.         drawtext(text, lno, TRUE);
  681.     }
  682. #else /* not CRUNCH */
  683.     static char    old[256];    /* how the line looked last time */
  684.     char        new[256];    /* how it looks now */
  685.     char        *build;        /* used to put chars into new[] */
  686.     char        *scan;        /* used for moving thru new[] or old[] */
  687.     char        *end;        /* last non-blank changed char */
  688.     char        *shift;        /* used to insert/delete chars */
  689.     int        same;        /* length of a run of unchanged chars */
  690.     int        limitcol;
  691.     int        col;
  692.     int        i;
  693.     char        numstr[9];
  694.  
  695. # ifndef NO_CHARATTR
  696.     /* if this line has attributes, do it the dumb way instead */
  697.     if (hasattr(lno, text))
  698.     {
  699.         move((int)(lno - topline), 0);
  700.         drawtext(text, lno, TRUE);
  701.         return;
  702.     }
  703. # endif
  704. # ifndef NO_SENTENCE
  705.     /* if this line is a format line, & we're hiding format lines, then
  706.      * let the dumb drawtext() function handle it
  707.      */
  708.     if (*o_hideformat && *text == '.')
  709.     {
  710.         move((int)(lno - topline), 0);
  711.         drawtext(text, lno, TRUE);
  712.         return;
  713.     }
  714. # endif
  715. # ifndef NO_VISIBLE
  716.     if (vizchange)
  717.     {
  718.         move((int)(lno - topline), 0);
  719.         drawtext(text, lno, TRUE);
  720.         smartlno = 0L;
  721.         return;
  722.     }
  723. # endif
  724.  
  725.     /* skip stuff that was scrolled off left edge */
  726.     limitcol = leftcol;
  727.     for (col = 0;
  728.          (i = *text) && col < limitcol; /* yes, ASSIGNMENT! */
  729.          text++)
  730.     {
  731.         if (i == '\t' && !*o_list)
  732.         {
  733.             col = col + *o_tabstop - (col % *o_tabstop);
  734.         }
  735.         else if (i >= 0 && i < ' ' || i == '\177')
  736.         {
  737.             col += 2;
  738.         }
  739.         else
  740.         {
  741.             col++;
  742.         }
  743.     }
  744.  
  745.     /* adjust for control char that was partially visible */
  746.     build = new;
  747.     while (col > limitcol)
  748.     {
  749.         *build++ = ' ';
  750.         limitcol++;
  751.     }
  752.  
  753.     /* now for the visible characters */
  754.     limitcol = leftcol + COLS;
  755.     if (*o_number)
  756.         limitcol -= 8;
  757.     for (; (i = *text) && col < limitcol; text++)
  758.     {
  759.         if (i == '\t' && !*o_list)
  760.         {
  761.             i = col + *o_tabstop - (col % *o_tabstop);
  762.             while (col < i && col < limitcol)
  763.             {
  764.                 *build++ = ' ';
  765.                 col++;
  766.             }
  767.         }
  768.         else if (i >= 0 && i < ' ' || i == '\177')
  769.         {
  770.             col += 2;
  771.             *build++ = '^';
  772.             if (col <= limitcol)
  773.             {
  774.                 *build++ = (i ^ '@');
  775.             }
  776.         }
  777.         else
  778.         {
  779.             col++;
  780.             *build++ = i;
  781.         }
  782.     }
  783.     if (col < limitcol && *o_list)
  784.     {
  785.         *build++ = '$';
  786.         col++;
  787.     }
  788.     end = build;
  789.     while (col < limitcol)
  790.     {
  791.         *build++ = ' ';
  792.         col++;
  793.     }
  794.  
  795.     /* if we're just supposed to remember this line, then remember it */
  796.     if (!showit)
  797.     {
  798.         smartlno = lno;
  799.         strncpy(old, new, COLS);
  800.         return;
  801.     }
  802.  
  803.     /* locate the last non-blank character */
  804.     while (end > new && end[-1] == ' ')
  805.     {
  806.         end--;
  807.     }
  808.  
  809.     /* can we optimize the displaying of this line? */
  810.     if (lno != smartlno)
  811.     {
  812.         /* nope, can't optimize - different line */
  813.         move((int)(lno - topline), 0);
  814.  
  815.         /* show the line number, if necessary */
  816.         if (*o_number)
  817.         {
  818.             sprintf(numstr, "%6ld  ", lno);
  819.             qaddstr(numstr);
  820.         }
  821.  
  822.         /* show the new line */
  823.         for (scan = new, build = old; scan < end; )
  824.         {
  825.             qaddch(*scan);
  826.             *build++ = *scan++;
  827.         }
  828.         if (end < new + COLS - (*o_number ? 8 : 0))
  829.         {
  830.             clrtoeol();
  831.             while (build < old + COLS)
  832.             {
  833.                 *build++ = ' ';
  834.             }
  835.         }
  836.         smartlno = lno;
  837.         return;
  838.     }
  839.  
  840.     /* skip any initial unchanged characters */
  841.     for (scan = new, build = old; scan < end && *scan == *build; scan++, build++)
  842.     {
  843.     }
  844.     i = (scan - new);
  845.     if (*o_number)
  846.         i += 8;
  847.     move((int)(lno - topline), i);
  848.  
  849.     /* The in-between characters must be changed */
  850.     same = 0;
  851.     while (scan < end)
  852.     {
  853.         /* is this character a match? */
  854.         if (scan[0] == build[0])
  855.         {
  856.             same++;
  857.         }
  858.         else /* do we want to insert? */
  859.         if (scan < end - 1 && scan[1] == build[0] && (has_IC || has_IM))
  860.         {
  861.             nudgecursor(same, scan, new, lno);
  862.             same = 0;
  863.  
  864.             insch(*scan);
  865.             for (shift = old + COLS; --shift > build; )
  866.             {
  867.                 shift[0] = shift[-1];
  868.             }
  869.             *build = *scan;
  870.         }
  871.         else /* do we want to delete? */
  872.         if (build < old + COLS - 1 && scan[0] == build[1] && has_DC)
  873.         {
  874.             nudgecursor(same, scan, new, lno);
  875.             same = 0;
  876.  
  877.             delch();
  878.             same++;
  879.             for (shift = build; shift < old + COLS - 1; shift++)
  880.             {
  881.                 shift[0] = shift[1];
  882.             }
  883.             if (*o_number)
  884.                 shift -= 8;
  885.             *shift = ' ';
  886.         }
  887.         else /* we must overwrite */
  888.         {
  889.             nudgecursor(same, scan, new, lno);
  890.             same = 0;
  891.  
  892.             addch(*scan);
  893.             *build = *scan;
  894.         }
  895.  
  896.         build++;
  897.         scan++;
  898.     }
  899.  
  900.     /* maybe clear to EOL */
  901.     end = old + COLS - (*o_number ? 8 : 0);
  902.     while (build < end && *build == ' ')
  903.     {
  904.         build++;
  905.     }
  906.     if (build < end)
  907.     {
  908.         nudgecursor(same, scan, new, lno);
  909.         same = 0;
  910.  
  911.         clrtoeol();
  912.         while (build < old + COLS)
  913.         {
  914.             *build++ = ' ';
  915.         }
  916.     }
  917. #endif /* not CRUNCH */
  918. }
  919.  
  920.  
  921. /* This function is used in visual mode for drawing the screen (or just parts
  922.  * of the screen, if that's all thats needed).  It also takes care of
  923.  * scrolling.
  924.  */
  925. void redraw(curs, inputting)
  926.     MARK    curs;        /* where to leave the screen's cursor */
  927.     int    inputting;    /* boolean: being called from input() ? */
  928. {
  929.     char        *text;        /* a line of text to display */
  930.     static long    chgs;        /* previous changes level */
  931.     long        l;
  932.     int        i;
  933. #ifndef CRUNCH
  934.     static long    showtop;    /* top line in window */
  935.     static long    showbottom;    /* bottom line in window */
  936. #endif
  937.  
  938.     /* if curs == MARK_UNSET, then we should reset internal vars */
  939.     if (curs == MARK_UNSET)
  940.     {
  941.         if (topline < 1 || topline > nlines)
  942.         {
  943.             topline = 1L;
  944.         }
  945.         else
  946.         {
  947.             move(LINES - 1, 0);
  948.             clrtoeol();
  949.         }
  950.         leftcol = 0;
  951.         mustredraw = TRUE;
  952.         redrawafter = INFINITY;
  953.         preredraw = 0L;
  954.         postredraw = 0L;
  955.         chgs = 0;
  956.         smartlno = 0L;
  957. #ifndef NO_VISIBLE
  958.         vizlow = vizhigh = 0L;
  959.         vizchange = FALSE;
  960. #endif
  961. #ifndef CRUNCH
  962.         showtop = 0;
  963.         showbottom = INFINITY;
  964. #endif
  965.         return;
  966.     }
  967.  
  968. #ifndef NO_VISIBLE
  969.     /* adjustments to hilited area may force extra lines to be redrawn. */
  970.     setviz(curs);
  971. #endif
  972.  
  973.     /* figure out which column the cursor will be in */
  974.     l = markline(curs);
  975.     text = fetchline(l);
  976.     mark2phys(curs, text, inputting);
  977.  
  978. #ifndef NO_COLOR
  979.     fixcolor();
  980. #endif
  981.  
  982.     /* adjust topline, if necessary, to get the cursor on the screen */
  983.     if (l >= topline && l <= botline)
  984.     {
  985.         /* it is on the screen already */
  986.  
  987.         /* if the file was changed but !mustredraw, then redraw line */
  988.         if (!mustredraw && (chgs != changes
  989. #ifndef NO_VISIBLE
  990.             || V_from
  991. #endif
  992. #ifndef CRUNCH
  993.             || l < showtop || l > showbottom
  994. #endif
  995.                             ))
  996.         {
  997.             smartdrawtext(text, l, (chgs != changes));
  998.         }
  999.     }
  1000.     else if (l < topline && l >= topline - NEAR && (has_SR || has_AL))
  1001.     {
  1002.         /* near top - scroll down */
  1003.         if (!mustredraw)
  1004.         {
  1005.             move(0,0);
  1006.             while (l < topline)
  1007.             {
  1008.                 topline--;
  1009.                 if (has_SR)
  1010.                 {
  1011.                     do_SR();
  1012.                 }
  1013.                 else
  1014.                 {
  1015.                     insertln();
  1016.                 }
  1017.                 text = fetchline(topline);
  1018.                 drawtext(text, topline, FALSE);
  1019.                 do_UP();
  1020.             }
  1021.  
  1022.             /* blank out the last line */
  1023.             move(LINES - 1, 0);
  1024.             clrtoeol();
  1025.         }
  1026.         else
  1027.         {
  1028.             topline = l;
  1029.             redrawrange(0L, INFINITY, INFINITY);
  1030.         }
  1031.     }
  1032.     else if (l > topline && l <= botline + NEAR)
  1033.     {
  1034.         /* near bottom -- scroll up */
  1035.         if (!mustredraw)
  1036.         {
  1037.             move(LINES - 1,0);
  1038.             clrtoeol();
  1039.             while (l > botline)
  1040.             {
  1041.                 topline++; /* <-- also adjusts botline */
  1042.                 text = fetchline(botline);
  1043.                 drawtext(text, botline, FALSE);
  1044.             }
  1045. #ifndef CRUNCH
  1046.             showbottom = l;
  1047. #endif
  1048.         }
  1049.         else
  1050.         {
  1051.             topline = l - (LINES - 2);
  1052.             redrawrange(0L, INFINITY, INFINITY);
  1053.         }
  1054.     }
  1055.     else
  1056.     {
  1057.         /* distant line - center it & force a redraw */
  1058.         topline = l - (LINES / 2) - 1;
  1059.         if (topline < 1)
  1060.         {
  1061.             topline = 1;
  1062.         }
  1063.         redrawrange(0L, INFINITY, INFINITY);
  1064.         smartlno = 0L;
  1065.         changes++;
  1066.     }
  1067.  
  1068. #ifndef CRUNCH
  1069.     /* make sure the current line is included in the "window" */
  1070.     if (l < showtop)
  1071.     {
  1072.         redrawrange(l, showtop, showtop);
  1073.         showtop = l;
  1074.     }
  1075.     if (l > showbottom)
  1076.     {
  1077.         redrawrange(showbottom, l, l);
  1078.         showbottom = l;
  1079.     }
  1080. #endif
  1081.  
  1082.  
  1083.     /* Now... do we really have to redraw? */
  1084.     if (mustredraw)
  1085.     {
  1086.         /* If redrawfter (and friends) aren't set, assume we should
  1087.          * redraw everything.
  1088.          */
  1089.         if (redrawafter == INFINITY)
  1090.         {
  1091.             redrawafter = 0L;
  1092.             preredraw = postredraw = INFINITY;
  1093.         }
  1094.  
  1095. #ifndef CRUNCH
  1096.         /* shrink the window, if possible */
  1097.         if (showtop < topline)
  1098.         {
  1099.             showtop = topline;
  1100.         }
  1101.         if (showbottom > botline)
  1102.         {
  1103.             showbottom = botline;
  1104.         }
  1105.         if (postredraw == INFINITY)
  1106.         {
  1107.             /* these will be set to more reasonable values later */
  1108.             showtop = INFINITY;
  1109.             showbottom = 0L;
  1110.         }
  1111. #endif
  1112.  
  1113.         /* adjust smartlno to correspond with inserted/deleted lines */
  1114.         if (smartlno >= redrawafter)
  1115.         {
  1116.             if (smartlno < preredraw && postredraw != preredraw) /*!!!*/
  1117.             {
  1118.                 smartlno = 0L;
  1119.             }
  1120.             else
  1121.             {
  1122.                 smartlno += (postredraw - preredraw);
  1123.             }
  1124.         }
  1125.  
  1126.         /* should we insert some lines into the screen? */
  1127.         if (preredraw < postredraw && preredraw <= botline)
  1128.         {
  1129.             /* lines were inserted into the file */
  1130.  
  1131.             /* decide where insertion should start */
  1132.             if (preredraw < topline)
  1133.             {
  1134.                 l = topline;
  1135.             }
  1136.             else
  1137.             {
  1138.                 l = preredraw;
  1139.             }
  1140.  
  1141.             /* insert the lines... maybe */
  1142.             if (l + postredraw - preredraw > botline || !has_AL || *o_number)
  1143.             {
  1144.                 /* Whoa!  a whole screen full - just redraw */
  1145.                 preredraw = postredraw = INFINITY;
  1146.             }
  1147.             else
  1148.             {
  1149.                 /* really insert 'em */
  1150.                 move((int)(l - topline), 0);
  1151.                 for (i = postredraw - preredraw; i > 0; i--)
  1152.                 {
  1153.                     insertln();
  1154.                 }
  1155.  
  1156.                 /* NOTE: the contents of those lines will be
  1157.                  * drawn as part of the regular redraw loop.
  1158.                  */
  1159.  
  1160.                 /* clear the last line */
  1161.                 move(LINES - 1, 0);
  1162.                 clrtoeol();
  1163.             }
  1164.         }
  1165.  
  1166.         /* do we want to delete some lines from the screen? */
  1167.         if (preredraw > postredraw && postredraw <= botline)
  1168.         {
  1169.             if (preredraw > botline || !has_DL || *o_number)
  1170.             {
  1171.                 postredraw = preredraw = INFINITY;
  1172.             }
  1173.             else /* we'd best delete some lines from the screen */
  1174.             {
  1175.                 /* clear the last line, so it doesn't look
  1176.                  * ugly as it gets pulled up into the screen
  1177.                  */
  1178.                 move(LINES - 1, 0);
  1179.                 clrtoeol();
  1180.  
  1181.                 /* delete the lines */
  1182.                 move((int)(postredraw - topline), 0);
  1183.                  for (l = postredraw;
  1184.                      l < preredraw && l <= botline;
  1185.                      l++)
  1186.                 {
  1187.                     deleteln();
  1188.                 }
  1189.  
  1190.                 /* draw the lines that are now newly visible
  1191.                  * at the bottom of the screen
  1192.                  */
  1193.                 i = LINES - 1 + (postredraw - preredraw);
  1194.                 move(i, 0);
  1195.                 for (l = topline + i; l <= botline; l++)
  1196.                 {
  1197.                     /* clear this line */
  1198.                     clrtoeol();
  1199.  
  1200.                     /* draw the line, or ~ for non-lines */
  1201.                     if (l <= nlines)
  1202.                     {
  1203.                         text = fetchline(l);
  1204.                         drawtext(text, l, FALSE);
  1205.                     }
  1206.                     else
  1207.                     {
  1208.                         addstr("~\n");
  1209.                     }
  1210.                 }
  1211.             }
  1212.         }
  1213.  
  1214.         /* redraw the current line */
  1215.         l = markline(curs);
  1216.         pfetch(l);
  1217.         smartdrawtext(ptext, l, TRUE);
  1218.  
  1219. #ifndef CRUNCH
  1220.         /* decide which lines must be in the "window" around the cursor */
  1221.         l = markline(curs);
  1222.         if ((*o_window & 0xff) + 1 == LINES)
  1223.         {
  1224.             showtop = 1;
  1225.             showbottom = INFINITY;
  1226.         }
  1227.         else if (l < showtop || l > showbottom)
  1228.         {
  1229.             l -= (*o_window & 0xff) / 2;
  1230.             if (l < topline)
  1231.             {
  1232.                 l = topline;
  1233.             }
  1234.             if (l < showtop)
  1235.             {
  1236.                 showtop = l;
  1237.             }
  1238.             l += (*o_window & 0xff) - 1;
  1239.             if (l > botline)
  1240.             {
  1241.                 showtop = showtop - l + botline;
  1242.                 l = botline;
  1243.             }
  1244.             if (l > showbottom)
  1245.             {
  1246.                 showbottom = l;
  1247.             }
  1248.         }
  1249. #endif
  1250.  
  1251.         /* decide where we should start redrawing from */
  1252.         if (redrawafter < topline)
  1253.         {
  1254.             l = topline;
  1255.         }
  1256.         else
  1257.         {
  1258.             l = redrawafter;
  1259.         }
  1260.         if (l <= botline && l < postredraw && (l != smartlno || botline != smartlno))
  1261.         {
  1262.             /* draw the other lines */
  1263.             move((int)(l - topline), 0);
  1264.             for (; l <= botline && l < postredraw; l++)
  1265.             {
  1266.                 /* we already drew the current line, so skip it now */
  1267.                 if (l == smartlno)
  1268.                 {
  1269. #if OSK
  1270.                     qaddch('\l');
  1271. #else
  1272.                     qaddch('\n');
  1273. #endif
  1274.                     continue;
  1275.                 }
  1276.  
  1277.                 /* draw the line, or ~ for non-lines */
  1278.                 if (l > nlines)
  1279.                 {
  1280.                     qaddch('~');
  1281.                     clrtoeol();
  1282.                     addch('\n');
  1283.                 }
  1284. #ifndef CRUNCH
  1285.                 else if (l < showtop || l > showbottom)
  1286.                 {
  1287.                     qaddch('@');
  1288.                     clrtoeol();
  1289.                     addch('\n');
  1290.                 }
  1291. #endif
  1292.                 else
  1293.                 {
  1294.                     text = fetchline(l);
  1295.                     drawtext(text, l, TRUE);
  1296.                 }
  1297.             }
  1298.         }
  1299.  
  1300.         mustredraw = FALSE;
  1301.     }
  1302.  
  1303.     /* force total (non-partial) redraw next time if not set */
  1304.     redrawafter = INFINITY;
  1305.     preredraw = 0L;
  1306.     postredraw = 0L;
  1307.  
  1308.     /* move the cursor to where it belongs */
  1309.     move((int)(markline(curs) - topline), physcol);
  1310.     wqrefresh();
  1311.  
  1312.     chgs = changes;
  1313. }
  1314.