screen.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:133k
源码类别:

编辑器/阅读器

开发平台:

DOS

  1.     /*
  2.      * If the cursor is below the bottom of the window, scroll the window
  3.      * to put the cursor on the window. If the cursor is less than a
  4.      * windowheight down compute the number of lines at the top which have
  5.      * the same or more rows than the rows of the lines below the bottom.
  6.      * When w_botline is invalid, recompute it first, to avoid a redraw later.
  7.      * If w_botline was approximated, we might need a redraw later in a few
  8.      * cases, but we don't want to spend (a lot of) time recomputing w_botline
  9.      * for every small change.
  10.      */
  11.     else
  12.     {
  13. if (!(curwin->w_valid & VALID_BOTLINE_AP))
  14.     validate_botline();
  15. if ((long)curwin->w_cursor.lnum >= (long)curwin->w_botline - p_so &&
  16. curwin->w_botline <= curbuf->b_ml.ml_line_count)
  17. {
  18.     line_count = curwin->w_cursor.lnum - curwin->w_botline + 1 + p_so;
  19.     if (line_count <= curwin->w_height + 1)
  20. scroll_cursor_bot((int)p_sj, FALSE);
  21.     else
  22. scroll_cursor_halfway(FALSE);
  23. }
  24.     }
  25.     /*
  26.      * Need to redraw when topline changed.
  27.      */
  28.     if (curwin->w_topline != old_topline)
  29.     {
  30. if (curwin->w_skipcol)
  31. {
  32.     curwin->w_skipcol = 0;
  33.     redraw_later(NOT_VALID);
  34. }
  35. else
  36.     redraw_later(VALID);
  37.     }
  38. }
  39.     void
  40. update_curswant()
  41. {
  42.     if (curwin->w_set_curswant)
  43.     {
  44. validate_virtcol();
  45. curwin->w_curswant = curwin->w_virtcol;
  46. curwin->w_set_curswant = FALSE;
  47.     }
  48. }
  49.     void
  50. windgoto(row, col)
  51.     int     row;
  52.     int     col;
  53. {
  54.     char_u     *p;
  55.     int     i;
  56.     int     plan;
  57.     int     cost;
  58.     int     wouldbe_col;
  59.     int     noinvcurs;
  60.     char_u     *bs;
  61.     int     goto_cost;
  62.     int     attr;
  63. #define GOTO_COST   7 /* asssume a term_windgoto() takes about 7 chars */
  64. #define HIGHL_COST  5 /* assume unhighlight takes 5 chars */
  65. #define PLAN_LE     1
  66. #define PLAN_CR     2
  67. #define PLAN_NL     3
  68. #define PLAN_WRITE  4
  69.     /* Can't use LinePointers[] unless initialized */
  70.     if (NextScreen == NULL)
  71. return;
  72.     if (row < 0) /* window without text lines? */
  73. row = 0;
  74.     if (col != screen_cur_col || row != screen_cur_row)
  75.     {
  76. /* check if no cursor movement is allowed in highlight mode */
  77. if (screen_attr && *T_MS == NUL)
  78.     noinvcurs = HIGHL_COST;
  79. else
  80.     noinvcurs = 0;
  81. goto_cost = GOTO_COST + noinvcurs;
  82. /*
  83.  * Plan how to do the positioning:
  84.  * 1. Use CR to move it to column 0, same row.
  85.  * 2. Use T_LE to move it a few columns to the left.
  86.  * 3. Use NL to move a few lines down, column 0.
  87.  * 4. Move a few columns to the right with T_ND or by writing chars.
  88.  *
  89.  * Don't do this if the cursor went beyond the last column, the cursor
  90.  * position is unknown then (some terminals wrap, some don't )
  91.  *
  92.  * First check if the highlighting attibutes allow us to write
  93.  * characters to move the cursor to the right.
  94.  */
  95. if (row >= screen_cur_row && screen_cur_col < Columns)
  96. {
  97.     /*
  98.      * If the cursor is in the same row, bigger col, we can use CR
  99.      * or T_LE.
  100.      */
  101.     bs = NULL;     /* init for GCC */
  102.     attr = screen_attr;
  103.     if (row == screen_cur_row && col < screen_cur_col)
  104.     {
  105. /* "le" is preferred over "bc", because "bc" is obsolete */
  106. if (*T_LE)
  107.     bs = T_LE;     /* "cursor left" */
  108. else
  109.     bs = T_BC;     /* "backspace character (old) */
  110. if (*bs)
  111.     cost = (screen_cur_col - col) * STRLEN(bs);
  112. else
  113.     cost = 999;
  114. if (col + 1 < cost)     /* using CR is less characters */
  115. {
  116.     plan = PLAN_CR;
  117.     wouldbe_col = 0;
  118.     cost = 1;     /* CR is just one character */
  119. }
  120. else
  121. {
  122.     plan = PLAN_LE;
  123.     wouldbe_col = col;
  124. }
  125. if (noinvcurs)     /* will stop highlighting */
  126. {
  127.     cost += noinvcurs;
  128.     attr = 0;
  129. }
  130.     }
  131.     /*
  132.      * If the cursor is above where we want to be, we can use CR LF.
  133.      */
  134.     else if (row > screen_cur_row)
  135.     {
  136. plan = PLAN_NL;
  137. wouldbe_col = 0;
  138. cost = (row - screen_cur_row) * 2;  /* CR LF */
  139. if (noinvcurs)     /* will stop highlighting */
  140. {
  141.     cost += noinvcurs;
  142.     attr = 0;
  143. }
  144.     }
  145.     /*
  146.      * If the cursor is in the same row, smaller col, just use write.
  147.      */
  148.     else
  149.     {
  150. plan = PLAN_WRITE;
  151. wouldbe_col = screen_cur_col;
  152. cost = 0;
  153.     }
  154.     /*
  155.      * Check if any characters that need to be written have the
  156.      * correct attributes.
  157.      */
  158.     i = col - wouldbe_col;
  159.     if (i > 0)
  160. cost += i;
  161.     if (cost < goto_cost && i > 0)
  162.     {
  163. /*
  164.  * Check if the attributes are correct without additionally
  165.  * stopping highlighting.
  166.  */
  167. p = LinePointers[row] + wouldbe_col + Columns;
  168. while (i && *p++ == attr)
  169.     --i;
  170. if (i)
  171. {
  172.     /*
  173.      * Try if it works when highlighting is stopped here.
  174.      */
  175.     if (*--p == 0)
  176.     {
  177. cost += noinvcurs;
  178. while (i && *p++ == 0)
  179.     --i;
  180.     }
  181.     if (i)
  182. cost = 999; /* different attributes, don't do it */
  183. }
  184.     }
  185.     /*
  186.      * We can do it without term_windgoto()!
  187.      */
  188.     if (cost < goto_cost)
  189.     {
  190. if (plan == PLAN_LE)
  191. {
  192.     if (noinvcurs)
  193. screen_stop_highlight();
  194.     while (screen_cur_col > col)
  195.     {
  196. out_str(bs);
  197. --screen_cur_col;
  198.     }
  199. }
  200. else if (plan == PLAN_CR)
  201. {
  202.     if (noinvcurs)
  203. screen_stop_highlight();
  204.     out_char('r');
  205.     screen_cur_col = 0;
  206. }
  207. else if (plan == PLAN_NL)
  208. {
  209.     if (noinvcurs)
  210. screen_stop_highlight();
  211.     while (screen_cur_row < row)
  212.     {
  213. out_char('n');
  214. ++screen_cur_row;
  215.     }
  216.     screen_cur_col = 0;
  217. }
  218. i = col - screen_cur_col;
  219. if (i > 0)
  220. {
  221.     /*
  222.      * Use cursor-right if it's one character only.  Avoids
  223.      * removing a line of pixels from the last bold char, when
  224.      * using the bold trick in the GUI.
  225.      */
  226.     if (T_ND[0] != NUL && T_ND[1] == NUL)
  227.     {
  228. while (i--)
  229.     out_char(*T_ND);
  230.     }
  231.     else
  232.     {
  233. p = LinePointers[row] + screen_cur_col;
  234. while (i--)
  235. {
  236.     if (*(p + Columns) != screen_attr)
  237. screen_stop_highlight();
  238.     out_char(*p++);
  239. }
  240.     }
  241. }
  242.     }
  243. }
  244. else
  245.     cost = 999;
  246. if (cost >= goto_cost)
  247. {
  248.     if (noinvcurs)
  249. screen_stop_highlight();
  250.     if (row == screen_cur_row && (col > screen_cur_col) &&
  251. *T_CRI != NUL)
  252. term_cursor_right(col - screen_cur_col);
  253.     else
  254. term_windgoto(row, col);
  255. }
  256. screen_cur_row = row;
  257. screen_cur_col = col;
  258.     }
  259. }
  260. /*
  261.  * Set cursor to current position.
  262.  */
  263.     void
  264. setcursor()
  265. {
  266.     if (redrawing())
  267.     {
  268. validate_cursor();
  269. windgoto(curwin->w_winpos + curwin->w_wrow,
  270. #ifdef RIGHTLEFT
  271. curwin->w_p_rl ? ((int)Columns - 1 - curwin->w_wcol) :
  272. #endif
  273.     curwin->w_wcol);
  274.     }
  275. }
  276. /*
  277.  * Recompute topline to put the cursor at the top of the window.
  278.  * Scroll at least "min_scroll" lines.
  279.  * If "always" is TRUE, always set topline (for "zt").
  280.  */
  281.     void
  282. scroll_cursor_top(min_scroll, always)
  283.     int     min_scroll;
  284.     int     always;
  285. {
  286.     int     scrolled = 0;
  287.     int     extra = 0;
  288.     int     used;
  289.     int     i;
  290.     int     sline; /* screen line for cursor */
  291.     int     old_topline = curwin->w_topline;
  292.     /*
  293.      * Decrease topline until:
  294.      * - it has become 1
  295.      * - (part of) the cursor line is moved off the screen or
  296.      * - moved at least 'scrolljump' lines and
  297.      * - at least 'scrolloff' lines above and below the cursor
  298.      */
  299.     validate_cheight();
  300.     used = curwin->w_cline_height;
  301.     for (sline = 1; sline < curwin->w_cursor.lnum; ++sline)
  302.     {
  303. i = plines(curwin->w_cursor.lnum - sline);
  304. used += i;
  305. extra += i;
  306. if (extra <= p_so &&
  307.    curwin->w_cursor.lnum + sline < curbuf->b_ml.ml_line_count)
  308.     used += plines(curwin->w_cursor.lnum + sline);
  309. if (used > curwin->w_height)
  310.     break;
  311. if (curwin->w_cursor.lnum - sline < curwin->w_topline)
  312.     scrolled += i;
  313. /*
  314.  * If scrolling is needed, scroll at least 'sj' lines.
  315.  */
  316. if ((curwin->w_cursor.lnum - (sline - 1) >= curwin->w_topline ||
  317.       scrolled >= min_scroll) && extra > p_so)
  318.     break;
  319.     }
  320.     /*
  321.      * If we don't have enough space, put cursor in the middle.
  322.      * This makes sure we get the same position when using "k" and "j"
  323.      * in a small window.
  324.      */
  325.     if (used > curwin->w_height)
  326. scroll_cursor_halfway(FALSE);
  327.     else
  328.     {
  329. /*
  330.  * If "always" is FALSE, only adjust topline to a lower value, higher
  331.  * value may happen with wrapping lines
  332.  */
  333. if (curwin->w_cursor.lnum - (sline - 1) < curwin->w_topline || always)
  334.     curwin->w_topline = curwin->w_cursor.lnum - (sline - 1);
  335. if (curwin->w_topline > curwin->w_cursor.lnum)
  336.     curwin->w_topline = curwin->w_cursor.lnum;
  337. if (curwin->w_topline != old_topline)
  338.     curwin->w_valid &=
  339.       ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  340.     }
  341. }
  342. /*
  343.  * Recompute topline to put the cursor at the bottom of the window.
  344.  * Scroll at least "min_scroll" lines.
  345.  * If "set_topbot" is TRUE, set topline and botline first (for "zb").
  346.  * This is messy stuff!!!
  347.  */
  348.     void
  349. scroll_cursor_bot(min_scroll, set_topbot)
  350.     int     min_scroll;
  351.     int     set_topbot;
  352. {
  353.     int used;
  354.     int scrolled = 0;
  355.     int extra = 0;
  356.     int sline; /* screen line for cursor from bottom */
  357.     int i;
  358.     linenr_t lnum;
  359.     linenr_t line_count;
  360.     linenr_t old_topline = curwin->w_topline;
  361.     linenr_t old_botline = curwin->w_botline;
  362.     linenr_t old_valid = curwin->w_valid;
  363.     int old_empty_rows = curwin->w_empty_rows;
  364.     linenr_t cln;     /* Cursor Line Number */
  365.     cln = curwin->w_cursor.lnum;
  366.     if (set_topbot)
  367.     {
  368. used = 0;
  369. curwin->w_botline = cln + 1;
  370. for (curwin->w_topline = curwin->w_botline;
  371. curwin->w_topline != 1;
  372. --curwin->w_topline)
  373. {
  374.     i = plines(curwin->w_topline - 1);
  375.     if (used + i > curwin->w_height)
  376. break;
  377.     used += i;
  378. }
  379. curwin->w_empty_rows = curwin->w_height - used;
  380. curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP;
  381. if (curwin->w_topline != old_topline)
  382.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  383.     }
  384.     else
  385. validate_botline();
  386.     validate_cheight();
  387.     used = curwin->w_cline_height;
  388.     if (cln >= curwin->w_botline)
  389.     {
  390. scrolled = used;
  391. if (cln == curwin->w_botline)
  392.     scrolled -= curwin->w_empty_rows;
  393.     }
  394.     /*
  395.      * Stop counting lines to scroll when
  396.      * - hitting start of the file
  397.      * - scrolled nothing or at least 'sj' lines
  398.      * - at least 'so' lines below the cursor
  399.      * - lines between botline and cursor have been counted
  400.      */
  401.     for (sline = 1; sline < cln; ++sline)
  402.     {
  403. if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= p_so) ||
  404. cln + sline > curbuf->b_ml.ml_line_count) &&
  405. cln - sline < curwin->w_botline)
  406.     break;
  407. i = plines(cln - sline);
  408. used += i;
  409. if (used > curwin->w_height)
  410.     break;
  411. if (cln - sline >= curwin->w_botline)
  412. {
  413.     scrolled += i;
  414.     if (cln - sline == curwin->w_botline)
  415. scrolled -= curwin->w_empty_rows;
  416. }
  417. if (cln + sline <= curbuf->b_ml.ml_line_count)
  418. {
  419.     i = plines(cln + sline);
  420.     used += i;
  421.     if (used > curwin->w_height)
  422. break;
  423.     if (extra < p_so || scrolled < min_scroll)
  424.     {
  425. extra += i;
  426. if (cln + sline >= curwin->w_botline)
  427. {
  428.     scrolled += i;
  429.     if (cln + sline == curwin->w_botline)
  430. scrolled -= curwin->w_empty_rows;
  431. }
  432.     }
  433. }
  434.     }
  435.     /* curwin->w_empty_rows is larger, no need to scroll */
  436.     if (scrolled <= 0)
  437. line_count = 0;
  438.     /* more than a screenfull, don't scroll but redraw */
  439.     else if (used > curwin->w_height)
  440. line_count = used;
  441.     /* scroll minimal number of lines */
  442.     else
  443.     {
  444. for (i = 0, lnum = curwin->w_topline;
  445. i < scrolled && lnum < curwin->w_botline; ++lnum)
  446.     i += plines(lnum);
  447. if (i >= scrolled) /* it's possible to scroll */
  448.     line_count = lnum - curwin->w_topline;
  449. else     /* below curwin->w_botline, don't scroll */
  450.     line_count = 9999;
  451.     }
  452.     /*
  453.      * Scroll up if the cursor is off the bottom of the screen a bit.
  454.      * Otherwise put it at 1/2 of the screen.
  455.      */
  456.     if (line_count >= curwin->w_height && line_count > min_scroll)
  457. scroll_cursor_halfway(FALSE);
  458.     else
  459. scrollup(line_count);
  460.     /*
  461.      * If topline didn't change we need to restore w_botline and w_empty_rows
  462.      * (we changed them).
  463.      * If topline did change, update_screen() will set botline.
  464.      */
  465.     if (curwin->w_topline == old_topline && set_topbot)
  466.     {
  467. curwin->w_botline = old_botline;
  468. curwin->w_empty_rows = old_empty_rows;
  469. curwin->w_valid = old_valid;
  470.     }
  471. }
  472. /*
  473.  * Recompute topline to put the cursor halfway the window
  474.  * If "atend" is TRUE, also put it halfway at the end of the file.
  475.  */
  476.     void
  477. scroll_cursor_halfway(atend)
  478.     int     atend;
  479. {
  480.     int above = 0;
  481.     linenr_t topline;
  482.     int below = 0;
  483.     linenr_t botline;
  484.     int used;
  485.     int i;
  486.     linenr_t cln;     /* Cursor Line Number */
  487.     topline = botline = cln = curwin->w_cursor.lnum;
  488.     used = plines(cln);
  489.     while (topline > 1)
  490.     {
  491. if (below <= above)     /* add a line below the cursor */
  492. {
  493.     if (botline + 1 <= curbuf->b_ml.ml_line_count)
  494.     {
  495. i = plines(botline + 1);
  496. used += i;
  497. if (used > curwin->w_height)
  498.     break;
  499. below += i;
  500. ++botline;
  501.     }
  502.     else
  503.     {
  504. ++below;     /* count a "~" line */
  505. if (atend)
  506.     ++used;
  507.     }
  508. }
  509. if (below > above)     /* add a line above the cursor */
  510. {
  511.     i = plines(topline - 1);
  512.     used += i;
  513.     if (used > curwin->w_height)
  514. break;
  515.     above += i;
  516.     --topline;
  517. }
  518.     }
  519.     curwin->w_topline = topline;
  520.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  521. }
  522. /*
  523.  * Correct the cursor position so that it is in a part of the screen at least
  524.  * 'so' lines from the top and bottom, if possible.
  525.  * If not possible, put it at the same position as scroll_cursor_halfway().
  526.  * When called topline must be valid!
  527.  */
  528.     void
  529. cursor_correct()
  530. {
  531.     int above = 0;     /* screen lines above topline */
  532.     linenr_t topline;
  533.     int below = 0;     /* screen lines below botline */
  534.     linenr_t botline;
  535.     int above_wanted, below_wanted;
  536.     linenr_t cln;     /* Cursor Line Number */
  537.     int max_off;
  538.     /*
  539.      * How many lines we would like to have above/below the cursor depends on
  540.      * whether the first/last line of the file is on screen.
  541.      */
  542.     above_wanted = p_so;
  543.     below_wanted = p_so;
  544.     if (curwin->w_topline == 1)
  545.     {
  546. above_wanted = 0;
  547. max_off = curwin->w_height / 2;
  548. if (below_wanted > max_off)
  549.     below_wanted = max_off;
  550.     }
  551.     validate_botline();
  552.     if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1)
  553.     {
  554. below_wanted = 0;
  555. max_off = (curwin->w_height - 1) / 2;
  556. if (above_wanted > max_off)
  557.     above_wanted = max_off;
  558.     }
  559.     /*
  560.      * If there are sufficient file-lines above and below the cursor, we can
  561.      * return now.
  562.      */
  563.     cln = curwin->w_cursor.lnum;
  564.     if (cln >= curwin->w_topline + above_wanted &&
  565.       cln < curwin->w_botline - below_wanted)
  566. return;
  567.     /*
  568.      * Narrow down the area where the cursor can be put by taking lines from
  569.      * the top and the bottom until:
  570.      * - the desired context lines are found
  571.      * - the lines from the top is past the lines from the bottom
  572.      */
  573.     topline = curwin->w_topline;
  574.     botline = curwin->w_botline - 1;
  575.     while ((above < above_wanted || below < below_wanted) && topline < botline)
  576.     {
  577. if (below < below_wanted && (below <= above || above >= above_wanted))
  578. {
  579.     below += plines(botline);
  580.     --botline;
  581. }
  582. if (above < above_wanted && (above < below || below >= below_wanted))
  583. {
  584.     above += plines(topline);
  585.     ++topline;
  586. }
  587.     }
  588.     if (topline == botline || botline == 0)
  589. curwin->w_cursor.lnum = topline;
  590.     else if (topline > botline)
  591. curwin->w_cursor.lnum = botline;
  592.     else
  593.     {
  594. if (cln < topline && curwin->w_topline > 1)
  595. {
  596.     curwin->w_cursor.lnum = topline;
  597.     curwin->w_valid &=
  598.     ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  599. }
  600. if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  601. {
  602.     curwin->w_cursor.lnum = botline;
  603.     curwin->w_valid &=
  604.     ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW);
  605. }
  606.     }
  607. }
  608. /*
  609.  * Check if the cursor has moved.  Set the w_valid flag accordingly.
  610.  */
  611.     static void
  612. check_cursor_moved(wp)
  613.     WIN     *wp;
  614. {
  615.     if (wp->w_cursor.lnum != wp->w_valid_cursor.lnum)
  616.     {
  617. wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL
  618.    |VALID_CHEIGHT|VALID_CROW);
  619. wp->w_valid_cursor = wp->w_cursor;
  620. wp->w_valid_leftcol = wp->w_leftcol;
  621.     }
  622.     else if (wp->w_cursor.col != wp->w_valid_cursor.col
  623.      || wp->w_leftcol != wp->w_valid_leftcol)
  624.     {
  625. wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL);
  626. wp->w_valid_cursor.col = wp->w_cursor.col;
  627. wp->w_valid_leftcol = wp->w_leftcol;
  628.     }
  629. }
  630. /*
  631.  * Call this function when the length of the cursor line (in screen
  632.  * characters) has changed, and the change is before the cursor.
  633.  * Need to take care of w_botline separately!
  634.  */
  635.     void
  636. changed_cline_bef_curs()
  637. {
  638.     curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CHEIGHT);
  639. }
  640. /*
  641.  * Call this function when the length of the cursor line (in screen
  642.  * characters) has changed, and the position of the cursor doesn't change.
  643.  * Need to take care of w_botline separately!
  644.  */
  645.     void
  646. changed_cline_aft_curs()
  647. {
  648.     curwin->w_valid &= ~VALID_CHEIGHT;
  649. }
  650. /*
  651.  * Call this function when the length of a line (in screen characters) above
  652.  * the cursor have changed.
  653.  * Need to take care of w_botline separately!
  654.  */
  655.     void
  656. changed_line_abv_curs()
  657. {
  658.     curwin->w_valid &=
  659.       ~(VALID_WROW|VALID_WCOL|VALID_VIRTCOL|VALID_CROW|VALID_CHEIGHT);
  660. }
  661. /*
  662.  * Set wp->w_topline to a certain number.
  663.  */
  664.     void
  665. set_topline(wp, lnum)
  666.     WIN     *wp;
  667.     linenr_t     lnum;
  668. {
  669.     /* Approximate the value of w_botline */
  670.     wp->w_botline += lnum - wp->w_topline;
  671.     wp->w_topline = lnum;
  672.     wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  673. }
  674. /*
  675.  * Make sure the value of curwin->w_botline is valid.
  676.  */
  677.     void
  678. validate_botline()
  679. {
  680.     if (!(curwin->w_valid & VALID_BOTLINE))
  681. comp_botline();
  682. }
  683. /*
  684.  * Mark curwin->w_botline as invalid (because of some change in the buffer).
  685.  */
  686.     void
  687. invalidate_botline()
  688. {
  689.     curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  690. }
  691.     void
  692. invalidate_botline_win(wp)
  693.     WIN     *wp;
  694. {
  695.     wp->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP);
  696. }
  697. /*
  698.  * Mark curwin->w_botline as approximated (because of some small change in the
  699.  * buffer).
  700.  */
  701.     void
  702. approximate_botline()
  703. {
  704.     curwin->w_valid &= ~VALID_BOTLINE;
  705. }
  706. /*
  707.  * Return TRUE if curwin->w_botline is valid.
  708.  */
  709.     int
  710. botline_valid()
  711. {
  712.     return (curwin->w_valid & VALID_BOTLINE);
  713. }
  714. /*
  715.  * Return TRUE if curwin->w_botline is valid or approximated.
  716.  */
  717.     int
  718. botline_approximated()
  719. {
  720.     return (curwin->w_valid & VALID_BOTLINE_AP);
  721. }
  722. /*
  723.  * Return TRUE if curwin->w_wrow and curwin->w_wcol are valid.
  724.  */
  725.     int
  726. cursor_valid()
  727. {
  728.     check_cursor_moved(curwin);
  729.     return ((curwin->w_valid & (VALID_WROW|VALID_WCOL)) ==
  730.       (VALID_WROW|VALID_WCOL));
  731. }
  732. /*
  733.  * Validate cursor position.  Makes sure w_wrow and w_wcol are valid.
  734.  * w_topline must be valid, you may need to call update_topline() first!
  735.  */
  736.     void
  737. validate_cursor()
  738. {
  739.     check_cursor_moved(curwin);
  740.     if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW))
  741. curs_columns(TRUE);
  742. }
  743. /*
  744.  * validate w_cline_row.
  745.  */
  746.     void
  747. validate_cline_row()
  748. {
  749.     /*
  750.      * First make sure that w_topline is valid (after moving the cursor).
  751.      */
  752.     update_topline();
  753.     check_cursor_moved(curwin);
  754.     if (!(curwin->w_valid & VALID_CROW))
  755. curs_rows(FALSE);
  756. }
  757. /*
  758.  * Check if w_cline_row and w_cline_height are valid, or can be made valid.
  759.  * Can be called when topline and botline have not been updated.
  760.  * Used to decide to redraw or keep the window update.
  761.  *
  762.  * Return OK if w_cline_row is valid.
  763.  */
  764.     int
  765. may_validate_crow()
  766. {
  767.     if (curwin->w_cursor.lnum < curwin->w_topline ||
  768.     curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count ||
  769.     !(curwin->w_valid & (VALID_BOTLINE|VALID_BOTLINE_AP)) ||
  770.     curwin->w_cursor.lnum >= curwin->w_botline)
  771. return FAIL;
  772.     check_cursor_moved(curwin);
  773.     if ((curwin->w_valid & (VALID_CROW|VALID_CHEIGHT)) !=
  774.   (VALID_CROW|VALID_CHEIGHT))
  775. curs_rows(TRUE);
  776.     return OK;
  777. }
  778. /*
  779.  * Compute curwin->w_cline_row and curwin->w_cline_height.
  780.  * Must only be called when w_topine is valid!
  781.  *
  782.  * Returns OK when cursor is in the window, FAIL when it isn't.
  783.  */
  784.     static void
  785. curs_rows(do_botline)
  786.     int     do_botline; /* also compute w_botline */
  787. {
  788.     linenr_t lnum;
  789.     int i;
  790.     int lsize_invalid;
  791.     /* Check if curwin->w_lsize[] is invalid */
  792.     lsize_invalid = (!redrawing() || curwin->w_lsize_valid == 0 ||
  793. curwin->w_lsize_lnum[0] != curwin->w_topline);
  794.     i = 0;
  795.     curwin->w_cline_row = 0;
  796.     for (lnum = curwin->w_topline; lnum < curwin->w_cursor.lnum; ++lnum)
  797. if (lsize_invalid)
  798.     curwin->w_cline_row += plines(lnum);
  799. else
  800.     curwin->w_cline_row += curwin->w_lsize[i++];
  801.     check_cursor_moved(curwin);
  802.     if (!(curwin->w_valid & VALID_CHEIGHT))
  803.     {
  804. if (lsize_invalid)
  805.     curwin->w_cline_height = plines(lnum);
  806. /* Check for a line that is too long to fit on the last screen line. */
  807. else if (i > curwin->w_lsize_valid)
  808.     curwin->w_cline_height = 0;
  809. else
  810.     curwin->w_cline_height = curwin->w_lsize[i];
  811.     }
  812.     curwin->w_valid |= VALID_CROW|VALID_CHEIGHT;
  813.     /* validate botline too, if update_screen doesn't do it */
  814.     if (do_botline && lsize_invalid)
  815. validate_botline();
  816. }
  817. /*
  818.  * Validate curwin->w_virtcol only.
  819.  */
  820.     void
  821. validate_virtcol()
  822. {
  823.     validate_virtcol_win(curwin);
  824. }
  825. /*
  826.  * Validate wp->w_virtcol only.
  827.  */
  828.     static void
  829. validate_virtcol_win(wp)
  830.     WIN     *wp;
  831. {
  832.     check_cursor_moved(wp);
  833.     if (!(wp->w_valid & VALID_VIRTCOL))
  834.     {
  835. getvcol(wp, &wp->w_cursor, NULL, &(wp->w_virtcol), NULL);
  836. wp->w_valid |= VALID_VIRTCOL;
  837.     }
  838. }
  839. /*
  840.  * Validate curwin->w_cline_height only.
  841.  */
  842.     void
  843. validate_cheight()
  844. {
  845.     check_cursor_moved(curwin);
  846.     if (!(curwin->w_valid & VALID_CHEIGHT))
  847.     {
  848. curwin->w_cline_height = plines(curwin->w_cursor.lnum);
  849. curwin->w_valid |= VALID_CHEIGHT;
  850.     }
  851. }
  852. /*
  853.  * validate w_wcol and w_virtcol only. Only for when 'wrap' on!
  854.  */
  855.     void
  856. validate_cursor_col()
  857. {
  858.     validate_virtcol();
  859.     if (!(curwin->w_valid & VALID_WCOL))
  860.     {
  861. curwin->w_wcol = curwin->w_virtcol;
  862. if (curwin->w_p_nu)
  863.     curwin->w_wcol += 8;
  864. /* long line wrapping, adjust curwin->w_wrow */
  865. if (curwin->w_p_wrap && curwin->w_wcol >= Columns)
  866.     curwin->w_wcol = curwin->w_wcol % Columns;
  867. curwin->w_valid |= VALID_WCOL;
  868.     }
  869. }
  870. /*
  871.  * compute curwin->w_wcol and curwin->w_virtcol.
  872.  * Also updates curwin->w_wrow and curwin->w_cline_row.
  873.  */
  874.     void
  875. curs_columns(scroll)
  876.     int scroll; /* when TRUE, may scroll horizontally */
  877. {
  878.     int     diff;
  879.     int     extra;
  880.     int     new_leftcol;
  881.     colnr_t startcol;
  882.     colnr_t endcol;
  883.     colnr_t prev_skipcol;
  884.     /*
  885.      * First make sure that w_topline is valid (after moving the cursor).
  886.      */
  887.     update_topline();
  888.     /*
  889.      * Next make sure that w_cline_row is valid.
  890.      */
  891.     if (!(curwin->w_valid & VALID_CROW))
  892. curs_rows(FALSE);
  893.     /*
  894.      * Compute the number of virtual columns.
  895.      */
  896.     getvcol(curwin, &curwin->w_cursor,
  897. &startcol, &(curwin->w_virtcol), &endcol);
  898.     /* remove '$' from change command when cursor moves onto it */
  899.     if (startcol > dollar_vcol)
  900. dollar_vcol = 0;
  901.     curwin->w_wcol = curwin->w_virtcol;
  902.     if (curwin->w_p_nu)
  903.     {
  904. curwin->w_wcol += 8;
  905. endcol += 8;
  906.     }
  907.     /*
  908.      * Now compute w_wrow, counting screen lines from w_cline_row.
  909.      */
  910.     curwin->w_wrow = curwin->w_cline_row;
  911.     if (curwin->w_p_wrap) /* long line wrapping, adjust curwin->w_wrow */
  912.     {
  913. while (curwin->w_wcol >= Columns)
  914. {
  915.     curwin->w_wcol -= Columns;
  916.     curwin->w_wrow++;
  917. }
  918.     }
  919.     else if (scroll) /* no line wrapping, compute curwin->w_leftcol if
  920.  * scrolling is on.  If scrolling is off,
  921.  * curwin->w_leftcol is assumed to be 0 */
  922.     {
  923. /* If Cursor is left of the screen, scroll rightwards */
  924. /* If Cursor is right of the screen, scroll leftwards */
  925. if ((extra = (int)startcol - (int)curwin->w_leftcol) < 0 ||
  926.      (extra = (int)endcol - (int)(curwin->w_leftcol + Columns) + 1) > 0)
  927. {
  928.     if (extra < 0)
  929. diff = -extra;
  930.     else
  931. diff = extra;
  932. /* far off, put cursor in middle of window */
  933.     if (p_ss == 0 || diff >= Columns / 2)
  934. new_leftcol = curwin->w_wcol - Columns / 2;
  935.     else
  936.     {
  937. if (diff < p_ss)
  938.     diff = p_ss;
  939. if (extra < 0)
  940.     new_leftcol = curwin->w_leftcol - diff;
  941. else
  942.     new_leftcol = curwin->w_leftcol + diff;
  943.     }
  944.     if (new_leftcol < 0)
  945. curwin->w_leftcol = 0;
  946.     else
  947. curwin->w_leftcol = new_leftcol;
  948.     /* screen has to be redrawn with new curwin->w_leftcol */
  949.     redraw_later(NOT_VALID);
  950. }
  951. curwin->w_wcol -= curwin->w_leftcol;
  952.     }
  953.     else if (curwin->w_wcol > (int)curwin->w_leftcol)
  954. curwin->w_wcol -= curwin->w_leftcol;
  955.     else
  956. curwin->w_wcol = 0;
  957.     prev_skipcol = curwin->w_skipcol;
  958.     if ((curwin->w_wrow > curwin->w_height - 1 || prev_skipcol)
  959.     && curwin->w_height
  960.     && curwin->w_cursor.lnum == curwin->w_topline)
  961.     {
  962. /* Cursor past end of screen.  Happens with a single line that does
  963.  * not fit on screen.  Find a skipcol to show the text around the
  964.  * cursor.  Avoid scrolling all the time. */
  965. if (curwin->w_skipcol > curwin->w_virtcol)
  966. {
  967.     extra = (curwin->w_skipcol - curwin->w_virtcol + Columns - 1)
  968.     / Columns;
  969.     win_ins_lines(curwin, 0, extra, FALSE, FALSE);
  970.     curwin->w_skipcol -= extra * Columns;
  971. }
  972. else if (curwin->w_wrow > curwin->w_height - 1)
  973. {
  974.     endcol = (curwin->w_wrow - curwin->w_height + 1) * Columns;
  975.     if (endcol > curwin->w_skipcol)
  976.     {
  977. win_del_lines(curwin, 0,
  978. (endcol - prev_skipcol) / (int)Columns, FALSE, FALSE);
  979. curwin->w_skipcol = endcol;
  980.     }
  981. }
  982. curwin->w_wrow -= curwin->w_skipcol / Columns;
  983.     }
  984.     else
  985. curwin->w_skipcol = 0;
  986.     if (prev_skipcol != curwin->w_skipcol)
  987. redraw_later(NOT_VALID);
  988.     curwin->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL;
  989. }
  990. /*
  991.  * Scroll up 'line_count' lines.
  992.  */
  993.     void
  994. scrolldown(line_count)
  995.     long    line_count;
  996. {
  997.     long    done = 0; /* total # of physical lines done */
  998.     int     wrow;
  999.     int     moved = FALSE;
  1000.     validate_cursor(); /* w_wrow needs to be valid */
  1001.     while (line_count--)
  1002.     {
  1003. if (curwin->w_topline == 1)
  1004.     break;
  1005. done += plines(--curwin->w_topline);
  1006. --curwin->w_botline; /* approximate w_botline */
  1007. curwin->w_valid &= ~VALID_BOTLINE;
  1008.     }
  1009.     curwin->w_wrow += done; /* keep w_wrow updated */
  1010.     curwin->w_cline_row += done; /* keep w_cline_row updated */
  1011.     /*
  1012.      * Compute the row number of the last row of the cursor line
  1013.      * and move it onto the screen.
  1014.      */
  1015.     wrow = curwin->w_wrow;
  1016.     if (curwin->w_p_wrap)
  1017.     {
  1018. validate_virtcol();
  1019. validate_cheight();
  1020. wrow += curwin->w_cline_height - 1 - curwin->w_virtcol / Columns;
  1021.     }
  1022.     while (wrow >= curwin->w_height && curwin->w_cursor.lnum > 1)
  1023.     {
  1024. wrow -= plines(curwin->w_cursor.lnum--);
  1025. curwin->w_valid &=
  1026.       ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1027. moved = TRUE;
  1028.     }
  1029.     if (moved)
  1030. coladvance(curwin->w_curswant);
  1031. }
  1032.     void
  1033. scrollup(line_count)
  1034.     long    line_count;
  1035. {
  1036.     curwin->w_topline += line_count;
  1037.     curwin->w_botline += line_count;     /* approximate w_botline */
  1038.     curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1039.     if (curwin->w_topline > curbuf->b_ml.ml_line_count)
  1040. curwin->w_topline = curbuf->b_ml.ml_line_count;
  1041.     if (curwin->w_cursor.lnum < curwin->w_topline)
  1042.     {
  1043. curwin->w_cursor.lnum = curwin->w_topline;
  1044. curwin->w_valid &=
  1045.       ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL);
  1046. coladvance(curwin->w_curswant);
  1047.     }
  1048. }
  1049. /*
  1050.  * Scroll the screen one line down, but don't do it if it would move the
  1051.  * cursor off the screen.
  1052.  */
  1053.     void
  1054. scrolldown_clamp()
  1055. {
  1056.     int     end_row;
  1057.     if (curwin->w_topline == 1)
  1058. return;
  1059.     validate_cursor();     /* w_wrow needs to be valid */
  1060.     /*
  1061.      * Compute the row number of the last row of the cursor line
  1062.      * and make sure it doesn't go off the screen. Make sure the cursor
  1063.      * doesn't go past 'scrolloff' lines from the screen end.
  1064.      */
  1065.     end_row = curwin->w_wrow + plines(curwin->w_topline - 1);
  1066.     if (curwin->w_p_wrap)
  1067.     {
  1068. validate_cheight();
  1069. validate_virtcol();
  1070. end_row += curwin->w_cline_height - 1 - curwin->w_virtcol / Columns;
  1071.     }
  1072.     if (end_row < curwin->w_height - p_so)
  1073.     {
  1074. --curwin->w_topline;
  1075. --curwin->w_botline;     /* approximate w_botline */
  1076. curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1077.     }
  1078. }
  1079. /*
  1080.  * Scroll the screen one line up, but don't do it if it would move the cursor
  1081.  * off the screen.
  1082.  */
  1083.     void
  1084. scrollup_clamp()
  1085. {
  1086.     int     start_row;
  1087.     if (curwin->w_topline == curbuf->b_ml.ml_line_count)
  1088. return;
  1089.     validate_cursor();     /* w_wrow needs to be valid */
  1090.     /*
  1091.      * Compute the row number of the first row of the cursor line
  1092.      * and make sure it doesn't go off the screen. Make sure the cursor
  1093.      * doesn't go before 'scrolloff' lines from the screen start.
  1094.      */
  1095.     start_row = curwin->w_wrow - plines(curwin->w_topline);
  1096.     if (curwin->w_p_wrap)
  1097.     {
  1098. validate_virtcol();
  1099. start_row -= curwin->w_virtcol / Columns;
  1100.     }
  1101.     if (start_row >= p_so)
  1102.     {
  1103. ++curwin->w_topline;
  1104. ++curwin->w_botline; /* approximate w_botline */
  1105. curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  1106.     }
  1107. }
  1108. /*
  1109.  * insert 'line_count' lines at 'row' in window 'wp'
  1110.  * if 'invalid' is TRUE the wp->w_lsize_lnum[] is invalidated.
  1111.  * if 'mayclear' is TRUE the screen will be cleared if it is faster than
  1112.  * scrolling.
  1113.  * Returns FAIL if the lines are not inserted, OK for success.
  1114.  */
  1115.     int
  1116. win_ins_lines(wp, row, line_count, invalid, mayclear)
  1117.     WIN     *wp;
  1118.     int     row;
  1119.     int     line_count;
  1120.     int     invalid;
  1121.     int     mayclear;
  1122. {
  1123.     int     did_delete;
  1124.     int     nextrow;
  1125.     int     lastrow;
  1126.     int     retval;
  1127.     if (invalid)
  1128. wp->w_lsize_valid = 0;
  1129.     if (!redrawing() || line_count <= 0 || wp->w_height < 5)
  1130. return FAIL;
  1131.     if (line_count > wp->w_height - row)
  1132. line_count = wp->w_height - row;
  1133.     if (mayclear && Rows - line_count < 5)  /* only a few lines left: redraw is faster */
  1134.     {
  1135. screenclear();     /* will set wp->w_lsize_valid to 0 */
  1136. return FAIL;
  1137.     }
  1138.     /*
  1139.      * Delete all remaining lines
  1140.      */
  1141.     if (row + line_count >= wp->w_height)
  1142.     {
  1143. screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  1144. 0, (int)Columns, ' ', ' ', 0);
  1145. return OK;
  1146.     }
  1147.     /*
  1148.      * when scrolling, the message on the command line should be cleared,
  1149.      * otherwise it will stay there forever.
  1150.      */
  1151.     clear_cmdline = TRUE;
  1152.     /*
  1153.      * if the terminal can set a scroll region, use that
  1154.      */
  1155.     if (scroll_region)
  1156.     {
  1157. scroll_region_set(wp, row);
  1158. retval = screen_ins_lines(wp->w_winpos + row, 0, line_count,
  1159.   wp->w_height - row);
  1160. scroll_region_reset();
  1161. return retval;
  1162.     }
  1163.     if (wp->w_next && p_tf) /* don't delete/insert on fast terminal */
  1164. return FAIL;
  1165.     /*
  1166.      * If there is a next window or a status line, we first try to delete the
  1167.      * lines at the bottom to avoid messing what is after the window.
  1168.      * If this fails and there are following windows, don't do anything to avoid
  1169.      * messing up those windows, better just redraw.
  1170.      */
  1171.     did_delete = FALSE;
  1172.     if (wp->w_next || wp->w_status_height)
  1173.     {
  1174. if (screen_del_lines(0, wp->w_winpos + wp->w_height - line_count,
  1175.   line_count, (int)Rows, FALSE) == OK)
  1176.     did_delete = TRUE;
  1177. else if (wp->w_next)
  1178.     return FAIL;
  1179.     }
  1180.     /*
  1181.      * if no lines deleted, blank the lines that will end up below the window
  1182.      */
  1183.     if (!did_delete)
  1184.     {
  1185. wp->w_redr_status = TRUE;
  1186. redraw_cmdline = TRUE;
  1187. nextrow = wp->w_winpos + wp->w_height + wp->w_status_height;
  1188. lastrow = nextrow + line_count;
  1189. if (lastrow > Rows)
  1190.     lastrow = Rows;
  1191. screen_fill(nextrow - line_count, lastrow - line_count,
  1192. 0, (int)Columns, ' ', ' ', 0);
  1193.     }
  1194.     if (screen_ins_lines(0, wp->w_winpos + row, line_count, (int)Rows) == FAIL)
  1195.     {
  1196.     /* deletion will have messed up other windows */
  1197. if (did_delete)
  1198. {
  1199.     wp->w_redr_status = TRUE;
  1200.     win_rest_invalid(wp->w_next);
  1201. }
  1202. return FAIL;
  1203.     }
  1204.     return OK;
  1205. }
  1206. /*
  1207.  * delete 'line_count' lines at 'row' in window 'wp'
  1208.  * If 'invalid' is TRUE curwin->w_lsize_lnum[] is invalidated.
  1209.  * If 'mayclear' is TRUE the screen will be cleared if it is faster than
  1210.  * scrolling
  1211.  * Return OK for success, FAIL if the lines are not deleted.
  1212.  */
  1213.     int
  1214. win_del_lines(wp, row, line_count, invalid, mayclear)
  1215.     WIN     *wp;
  1216.     int     row;
  1217.     int     line_count;
  1218.     int     invalid;
  1219.     int     mayclear;
  1220. {
  1221.     int retval;
  1222.     if (invalid)
  1223. wp->w_lsize_valid = 0;
  1224.     if (!redrawing() || line_count <= 0)
  1225. return FAIL;
  1226.     if (line_count > wp->w_height - row)
  1227. line_count = wp->w_height - row;
  1228.     /* only a few lines left: redraw is faster */
  1229.     if (mayclear && Rows - line_count < 5)
  1230.     {
  1231. screenclear();     /* will set wp->w_lsize_valid to 0 */
  1232. return FAIL;
  1233.     }
  1234.     /*
  1235.      * Delete all remaining lines
  1236.      */
  1237.     if (row + line_count >= wp->w_height)
  1238.     {
  1239. screen_fill(wp->w_winpos + row, wp->w_winpos + wp->w_height,
  1240. 0, (int)Columns, ' ', ' ', 0);
  1241. return OK;
  1242.     }
  1243.     /*
  1244.      * when scrolling, the message on the command line should be cleared,
  1245.      * otherwise it will stay there forever.
  1246.      */
  1247.     clear_cmdline = TRUE;
  1248.     /*
  1249.      * if the terminal can set a scroll region, use that
  1250.      */
  1251.     if (scroll_region)
  1252.     {
  1253. scroll_region_set(wp, row);
  1254. retval = screen_del_lines(wp->w_winpos + row, 0, line_count,
  1255.    wp->w_height - row, FALSE);
  1256. scroll_region_reset();
  1257. return retval;
  1258.     }
  1259.     if (wp->w_next && p_tf) /* don't delete/insert on fast terminal */
  1260. return FAIL;
  1261.     if (screen_del_lines(0, wp->w_winpos + row, line_count,
  1262.     (int)Rows, FALSE) == FAIL)
  1263. return FAIL;
  1264.     /*
  1265.      * If there are windows or status lines below, try to put them at the
  1266.      * correct place. If we can't do that, they have to be redrawn.
  1267.      */
  1268.     if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
  1269.     {
  1270. if (screen_ins_lines(0, wp->w_winpos + wp->w_height - line_count,
  1271.        line_count, (int)Rows) == FAIL)
  1272. {
  1273.     wp->w_redr_status = TRUE;
  1274.     win_rest_invalid(wp->w_next);
  1275. }
  1276.     }
  1277.     /*
  1278.      * If this is the last window and there is no status line, redraw the
  1279.      * command line later.
  1280.      */
  1281.     else
  1282. redraw_cmdline = TRUE;
  1283.     return OK;
  1284. }
  1285. /*
  1286.  * window 'wp' and everything after it is messed up, mark it for redraw
  1287.  */
  1288.     void
  1289. win_rest_invalid(wp)
  1290.     WIN *wp;
  1291. {
  1292.     while (wp)
  1293.     {
  1294. wp->w_lsize_valid = 0;
  1295. wp->w_redr_type = NOT_VALID;
  1296. wp->w_redr_status = TRUE;
  1297. wp = wp->w_next;
  1298.     }
  1299.     redraw_cmdline = TRUE;
  1300. }
  1301. /*
  1302.  * The rest of the routines in this file perform screen manipulations. The
  1303.  * given operation is performed physically on the screen. The corresponding
  1304.  * change is also made to the internal screen image. In this way, the editor
  1305.  * anticipates the effect of editing changes on the appearance of the screen.
  1306.  * That way, when we call screenupdate a complete redraw isn't usually
  1307.  * necessary. Another advantage is that we can keep adding code to anticipate
  1308.  * screen changes, and in the meantime, everything still works.
  1309.  */
  1310. /*
  1311.  * types for inserting or deleting lines
  1312.  */
  1313. #define USE_T_CAL   1
  1314. #define USE_T_CDL   2
  1315. #define USE_T_AL    3
  1316. #define USE_T_CE    4
  1317. #define USE_T_DL    5
  1318. #define USE_T_SR    6
  1319. #define USE_NL     7
  1320. #define USE_T_CD    8
  1321. /*
  1322.  * insert lines on the screen and update NextScreen
  1323.  * 'end' is the line after the scrolled part. Normally it is Rows.
  1324.  * When scrolling region used 'off' is the offset from the top for the region.
  1325.  * 'row' and 'end' are relative to the start of the region.
  1326.  *
  1327.  * return FAIL for failure, OK for success.
  1328.  */
  1329.     static int
  1330. screen_ins_lines(off, row, line_count, end)
  1331.     int off;
  1332.     int row;
  1333.     int line_count;
  1334.     int end;
  1335. {
  1336.     int i;
  1337.     int j;
  1338.     char_u *temp;
  1339.     int cursor_row;
  1340.     int type;
  1341.     int result_empty;
  1342.     /*
  1343.      * FAIL if
  1344.      * - there is no valid screen
  1345.      * - the screen has to be redrawn completely
  1346.      * - the line count is less than one
  1347.      * - the line count is more than 'ttyscroll'
  1348.      */
  1349.     if (!screen_valid(TRUE) || line_count <= 0 || line_count > p_ttyscroll)
  1350. return FAIL;
  1351.     /*
  1352.      * There are seven ways to insert lines:
  1353.      * 1. Use T_CD (clear to end of display) if it exists and the result of
  1354.      *   the insert is just empty lines
  1355.      * 2. Use T_CAL (insert multiple lines) if it exists and T_AL is not
  1356.      *   present or line_count > 1. It looks better if we do all the inserts
  1357.      *   at once.
  1358.      * 3. Use T_CDL (delete multiple lines) if it exists and the result of the
  1359.      *   insert is just empty lines and T_CE is not present or line_count >
  1360.      *   1.
  1361.      * 4. Use T_AL (insert line) if it exists.
  1362.      * 5. Use T_CE (erase line) if it exists and the result of the insert is
  1363.      *   just empty lines.
  1364.      * 6. Use T_DL (delete line) if it exists and the result of the insert is
  1365.      *   just empty lines.
  1366.      * 7. Use T_SR (scroll reverse) if it exists and inserting at row 0 and
  1367.      *   the 'da' flag is not set or we have clear line capability.
  1368.      *
  1369.      * Careful: In a hpterm scroll reverse doesn't work as expected, it moves
  1370.      * the scrollbar for the window. It does have insert line, use that if it
  1371.      * exists.
  1372.      */
  1373.     result_empty = (row + line_count >= end);
  1374.     if (*T_CD != NUL && result_empty)
  1375. type = USE_T_CD;
  1376.     else if (*T_CAL != NUL && (line_count > 1 || *T_AL == NUL))
  1377. type = USE_T_CAL;
  1378.     else if (*T_CDL != NUL && result_empty && (line_count > 1 || *T_CE == NUL))
  1379. type = USE_T_CDL;
  1380.     else if (*T_AL != NUL)
  1381. type = USE_T_AL;
  1382.     else if (*T_CE != NUL && result_empty)
  1383. type = USE_T_CE;
  1384.     else if (*T_DL != NUL && result_empty)
  1385. type = USE_T_DL;
  1386.     else if (*T_SR != NUL && row == 0 && (*T_DA == NUL || *T_CE))
  1387. type = USE_T_SR;
  1388.     else
  1389. return FAIL;
  1390.     /*
  1391.      * For clearing the lines screen_del_lines is used. This will also take
  1392.      * care of t_db if necessary.
  1393.      */
  1394.     if (type == USE_T_CD || type == USE_T_CDL ||
  1395.  type == USE_T_CE || type == USE_T_DL)
  1396. return screen_del_lines(off, row, line_count, end, FALSE);
  1397.     /*
  1398.      * If text is retained below the screen, first clear or delete as many
  1399.      * lines at the bottom of the window as are about to be inserted so that
  1400.      * the deleted lines won't later surface during a screen_del_lines.
  1401.      */
  1402.     if (*T_DB)
  1403. screen_del_lines(off, end - line_count, line_count, end, FALSE);
  1404. #ifdef USE_GUI_BEOS
  1405.     vim_lock_screen();
  1406. #endif
  1407.     if (*T_CCS != NUL)    /* cursor relative to region */
  1408. cursor_row = row;
  1409.     else
  1410. cursor_row = row + off;
  1411.     /*
  1412.      * Shift LinePointers line_count down to reflect the inserted lines.
  1413.      * Clear the inserted lines in NextScreen.
  1414.      */
  1415.     row += off;
  1416.     end += off;
  1417.     for (i = 0; i < line_count; ++i)
  1418.     {
  1419. j = end - 1 - i;
  1420. temp = LinePointers[j];
  1421. while ((j -= line_count) >= row)
  1422.     LinePointers[j + line_count] = LinePointers[j];
  1423. LinePointers[j + line_count] = temp;
  1424. lineclear(temp);
  1425.     }
  1426. #ifdef USE_GUI_BEOS
  1427.     vim_unlock_screen();
  1428. #endif
  1429.     screen_stop_highlight();
  1430.     windgoto(cursor_row, 0);
  1431.     if (type == USE_T_CAL)
  1432.     {
  1433. term_append_lines(line_count);
  1434. screen_start(); /* don't know where cursor is now */
  1435.     }
  1436.     else
  1437.     {
  1438. for (i = 0; i < line_count; i++)
  1439. {
  1440.     if (type == USE_T_AL)
  1441.     {
  1442. if (i && cursor_row != 0)
  1443.     windgoto(cursor_row, 0);
  1444. out_str(T_AL);
  1445.     }
  1446.     else  /* type == USE_T_SR */
  1447. out_str(T_SR);
  1448.     screen_start();     /* don't know where cursor is now */
  1449. }
  1450.     }
  1451.     /*
  1452.      * With scroll-reverse and 'da' flag set we need to clear the lines that
  1453.      * have been scrolled down into the region.
  1454.      */
  1455.     if (type == USE_T_SR && *T_DA)
  1456.     {
  1457. for (i = 0; i < line_count; ++i)
  1458. {
  1459.     windgoto(off + i, 0);
  1460.     out_str(T_CE);
  1461.     screen_start();     /* don't know where cursor is now */
  1462. }
  1463.     }
  1464. #ifdef USE_GUI
  1465.     if (gui.in_use)
  1466. out_flush(); /* always flush after a scroll */
  1467. #endif
  1468.     return OK;
  1469. }
  1470. /*
  1471.  * delete lines on the screen and update NextScreen
  1472.  * 'end' is the line after the scrolled part. Normally it is Rows.
  1473.  * When scrolling region used 'off' is the offset from the top for the region.
  1474.  * 'row' and 'end' are relative to the start of the region.
  1475.  *
  1476.  * Return OK for success, FAIL if the lines are not deleted.
  1477.  */
  1478.     int
  1479. screen_del_lines(off, row, line_count, end, force)
  1480.     int off;
  1481.     int row;
  1482.     int line_count;
  1483.     int end;
  1484.     int force; /* even when line_count > p_ttyscroll */
  1485. {
  1486.     int j;
  1487.     int i;
  1488.     char_u *temp;
  1489.     int cursor_row;
  1490.     int cursor_end;
  1491.     int result_empty; /* result is empty until end of region */
  1492.     int can_delete; /* deleting line codes can be used */
  1493.     int type;
  1494.     /*
  1495.      * FAIL if
  1496.      * - there is no valid screen
  1497.      * - the screen has to be redrawn completely
  1498.      * - the line count is less than one
  1499.      * - the line count is more than 'ttyscroll'
  1500.      */
  1501.     if (!screen_valid(TRUE) || line_count <= 0 ||
  1502.  (!force && line_count > p_ttyscroll))
  1503. return FAIL;
  1504.     /*
  1505.      * Check if the rest of the current region will become empty.
  1506.      */
  1507.     result_empty = row + line_count >= end;
  1508.     /*
  1509.      * We can delete lines only when 'db' flag not set or when 'ce' option
  1510.      * available.
  1511.      */
  1512.     can_delete = (*T_DB == NUL || *T_CE);
  1513.     /*
  1514.      * There are four ways to delete lines:
  1515.      * 1. Use T_CD if it exists and the result is empty.
  1516.      * 2. Use newlines if row == 0 and count == 1 or T_CDL does not exist.
  1517.      * 3. Use T_CDL (delete multiple lines) if it exists and line_count > 1 or
  1518.      *   none of the other ways work.
  1519.      * 4. Use T_CE (erase line) if the result is empty.
  1520.      * 5. Use T_DL (delete line) if it exists.
  1521.      */
  1522.     if (*T_CD != NUL && result_empty)
  1523. type = USE_T_CD;
  1524. #if defined(__BEOS__) && defined(BEOS_DR8)
  1525.     /*
  1526.      * USE_NL does not seem to work in Terminal of DR8 so we set T_DB="" in
  1527.      * its internal termcap... this works okay for tests which test *T_DB !=
  1528.      * NUL.  It has the disadvantage that the user cannot use any :set t_*
  1529.      * command to get T_DB (back) to empty_option, only :set term=... will do
  1530.      * the trick...
  1531.      * Anyway, this hack will hopefully go away with the next OS release.
  1532.      * (Olaf Seibert)
  1533.      */
  1534.     else if (row == 0 && T_DB == empty_option
  1535. && (line_count == 1 || *T_CDL == NUL))
  1536. #else
  1537.     else if (row == 0 && (
  1538. #ifndef AMIGA
  1539. /* On the Amiga, somehow 'n' on the last line doesn't always scroll
  1540.  * up, so use delete-line command */
  1541.     line_count == 1 ||
  1542. #endif
  1543. *T_CDL == NUL))
  1544. #endif
  1545. type = USE_NL;
  1546.     else if (*T_CDL != NUL && line_count > 1 && can_delete)
  1547. type = USE_T_CDL;
  1548.     else if (*T_CE != NUL && result_empty)
  1549. type = USE_T_CE;
  1550.     else if (*T_DL != NUL && can_delete)
  1551. type = USE_T_DL;
  1552.     else if (*T_CDL != NUL && can_delete)
  1553. type = USE_T_CDL;
  1554.     else
  1555. return FAIL;
  1556. #ifdef USE_GUI_BEOS
  1557.     vim_lock_screen();
  1558. #endif
  1559.     if (*T_CCS != NUL)     /* cursor relative to region */
  1560.     {
  1561. cursor_row = row;
  1562. cursor_end = end;
  1563.     }
  1564.     else
  1565.     {
  1566. cursor_row = row + off;
  1567. cursor_end = end + off;
  1568.     }
  1569.     /*
  1570.      * Now shift LinePointers line_count up to reflect the deleted lines.
  1571.      * Clear the inserted lines in NextScreen.
  1572.      */
  1573.     row += off;
  1574.     end += off;
  1575.     for (i = 0; i < line_count; ++i)
  1576.     {
  1577. j = row + i;
  1578. temp = LinePointers[j];
  1579. while ((j += line_count) <= end - 1)
  1580.     LinePointers[j - line_count] = LinePointers[j];
  1581. LinePointers[j - line_count] = temp;
  1582. lineclear(temp);
  1583.     }
  1584. #ifdef USE_GUI_BEOS
  1585.     vim_unlock_screen();
  1586. #endif
  1587.     /* delete the lines */
  1588.     screen_stop_highlight();
  1589.     if (type == USE_T_CD)
  1590.     {
  1591. windgoto(cursor_row, 0);
  1592. out_str(T_CD);
  1593. screen_start(); /* don't know where cursor is now */
  1594.     }
  1595.     else if (type == USE_T_CDL)
  1596.     {
  1597. windgoto(cursor_row, 0);
  1598. term_delete_lines(line_count);
  1599. screen_start(); /* don't know where cursor is now */
  1600.     }
  1601. /*
  1602.  * Deleting lines at top of the screen or scroll region: Just scroll
  1603.  * the whole screen (scroll region) up by outputting newlines on the
  1604.  * last line.
  1605.  */
  1606.     else if (type == USE_NL)
  1607.     {
  1608. windgoto(cursor_end - 1, 0);
  1609. for (i = line_count; --i >= 0; )
  1610.     out_char('n'); /* cursor will remain on same line */
  1611.     }
  1612.     else
  1613.     {
  1614. for (i = line_count; --i >= 0; )
  1615. {
  1616.     if (type == USE_T_DL)
  1617.     {
  1618. windgoto(cursor_row, 0);
  1619. out_str(T_DL); /* delete a line */
  1620.     }
  1621.     else /* type == USE_T_CE */
  1622.     {
  1623. windgoto(cursor_row + i, 0);
  1624. out_str(T_CE); /* erase a line */
  1625.     }
  1626.     screen_start(); /* don't know where cursor is now */
  1627. }
  1628.     }
  1629.     /*
  1630.      * If the 'db' flag is set, we need to clear the lines that have been
  1631.      * scrolled up at the bottom of the region.
  1632.      */
  1633.     if (*T_DB && (type == USE_T_DL || type == USE_T_CDL))
  1634.     {
  1635. for (i = line_count; i > 0; --i)
  1636. {
  1637.     windgoto(cursor_end - i, 0);
  1638.     out_str(T_CE); /* erase a line */
  1639.     screen_start(); /* don't know where cursor is now */
  1640. }
  1641.     }
  1642. #ifdef USE_GUI
  1643.     if (gui.in_use)
  1644. out_flush(); /* always flush after a scroll */
  1645. #endif
  1646.     return OK;
  1647. }
  1648. /*
  1649.  * show the current mode and ruler
  1650.  *
  1651.  * If clear_cmdline is TRUE, clear the rest of the cmdline.
  1652.  * If clear_cmdline is FALSE there may be a message there that needs to be
  1653.  * cleared only if a mode is shown.
  1654.  * Return the length of the message (0 if no message).
  1655.  */
  1656.     int
  1657. showmode()
  1658. {
  1659.     int     need_clear;
  1660.     int     length = 0;
  1661.     int     do_mode;
  1662.     int     attr;
  1663. #ifdef INSERT_EXPAND
  1664.     int     sub_attr;
  1665. #endif
  1666.     do_mode = (p_smd && ((State & INSERT) || restart_edit || VIsual_active));
  1667.     if (do_mode || Recording)
  1668.     {
  1669. /*
  1670.  * Don't show mode right now, when not redrawing or inside a mapping.
  1671.  * Call char_avail() only when we are going to show something, because
  1672.  * it takes a bit of time.
  1673.  */
  1674. if (!redrawing() || (char_avail() && !KeyTyped))
  1675. {
  1676.     redraw_cmdline = TRUE; /* show mode later */
  1677.     return 0;
  1678. }
  1679. /* wait a bit before overwriting an important message */
  1680. check_for_delay(FALSE);
  1681. /* if the cmdline is more than one line high, erase top lines */
  1682. need_clear = clear_cmdline;
  1683. if (clear_cmdline && cmdline_row < Rows - 1)
  1684.     msg_clr_cmdline(); /* will reset clear_cmdline */
  1685. /* Position on the last line in the window, column 0 */
  1686. msg_col = 0;
  1687. msg_row = Rows - 1;
  1688. cursor_off();
  1689. attr = hl_attr(HLF_CM); /* Highlight mode */
  1690. if (do_mode)
  1691. {
  1692.     MSG_PUTS_ATTR("--", attr);
  1693. #ifdef INSERT_EXPAND
  1694.     if (edit_submode != NULL) /* CTRL-X in Insert mode */
  1695.     {
  1696. msg_puts_attr(edit_submode, attr);
  1697. if (edit_submode_extra != NULL)
  1698. {
  1699.     MSG_PUTS_ATTR(" ", attr); /* add a space in between */
  1700.     if ((int)edit_submode_highl < (int)HLF_COUNT)
  1701. sub_attr = hl_attr(edit_submode_highl);
  1702.     else
  1703. sub_attr = attr;
  1704.     msg_puts_attr(edit_submode_extra, sub_attr);
  1705. }
  1706.     }
  1707.     else
  1708. #endif
  1709.     {
  1710. if (State == INSERT)
  1711. {
  1712. #ifdef RIGHTLEFT
  1713.     if (p_ri)
  1714. MSG_PUTS_ATTR(" REVERSE", attr);
  1715. #endif
  1716.     MSG_PUTS_ATTR(" INSERT", attr);
  1717. }
  1718. else if (State == REPLACE)
  1719.     MSG_PUTS_ATTR(" REPLACE", attr);
  1720. else if (restart_edit == 'I')
  1721.     MSG_PUTS_ATTR(" (insert)", attr);
  1722. else if (restart_edit == 'R')
  1723.     MSG_PUTS_ATTR(" (replace)", attr);
  1724. #ifdef RIGHTLEFT
  1725. if (p_hkmap)
  1726.     MSG_PUTS_ATTR(" Hebrew", attr);
  1727. # ifdef FKMAP
  1728. if (p_fkmap)
  1729.     MSG_PUTS_ATTR(farsi_text_5, attr);
  1730. # endif
  1731. #endif
  1732. if ((State & INSERT) && p_paste)
  1733.     MSG_PUTS_ATTR(" (paste)", attr);
  1734. if (VIsual_active)
  1735. {
  1736.     if (VIsual_select)
  1737. MSG_PUTS_ATTR(" SELECT", attr);
  1738.     else
  1739. MSG_PUTS_ATTR(" VISUAL", attr);
  1740.     if (VIsual_mode == Ctrl('V'))
  1741. MSG_PUTS_ATTR(" BLOCK", attr);
  1742.     else if (VIsual_mode == 'V')
  1743. MSG_PUTS_ATTR(" LINE", attr);
  1744. }
  1745.     }
  1746.     MSG_PUTS_ATTR(" --", attr);
  1747.     need_clear = TRUE;
  1748. }
  1749. if (Recording)
  1750. {
  1751.     MSG_PUTS_ATTR("recording", attr);
  1752.     need_clear = TRUE;
  1753. }
  1754. if (need_clear || clear_cmdline)
  1755.     msg_clr_eos();
  1756. msg_didout = FALSE; /* overwrite this message */
  1757. length = msg_col;
  1758. msg_col = 0;
  1759.     }
  1760.     else if (clear_cmdline) /* just clear anything */
  1761. msg_clr_cmdline(); /* will reset clear_cmdline */
  1762.     win_redr_ruler(lastwin, TRUE);
  1763.     redraw_cmdline = FALSE;
  1764.     clear_cmdline = FALSE;
  1765.     return length;
  1766. }
  1767. /*
  1768.  * delete mode message
  1769.  */
  1770.     void
  1771. unshowmode(force)
  1772.     int     force;
  1773. {
  1774.     /*
  1775.      * Don't delete it right now, when not redrawing or insided a mapping.
  1776.      */
  1777.     if (!redrawing() || (!force && char_avail() && !KeyTyped))
  1778. redraw_cmdline = TRUE; /* delete mode later */
  1779.     else if (Recording)
  1780. MSG("recording");
  1781.     else
  1782. MSG("");
  1783. }
  1784.     static int
  1785. highlight_status(attr, is_curwin)
  1786.     int *attr;
  1787.     int is_curwin;
  1788. {
  1789.     if (is_curwin)
  1790. *attr = hl_attr(HLF_S);
  1791.     else
  1792. *attr = hl_attr(HLF_SNC);
  1793.     /* Use a space when there is highlighting, and highlighting of current
  1794.      * window differs, or this is not the current window */
  1795.     if (*attr && (hl_attr(HLF_S) != hl_attr(HLF_SNC)
  1796.     || !is_curwin || firstwin == lastwin))
  1797. return ' ';
  1798.     if (is_curwin)
  1799. return '^';
  1800.     return '=';
  1801. }
  1802. /*
  1803.  * If ruler option is set: show current cursor position.
  1804.  * If always is FALSE, only print if position has changed.
  1805.  */
  1806.     void
  1807. showruler(always)
  1808.     int     always;
  1809. {
  1810.     win_redr_ruler(curwin, always);
  1811. }
  1812.     static void
  1813. win_redr_ruler(wp, always)
  1814.     WIN     *wp;
  1815.     int     always;
  1816. {
  1817.     char_u     buffer[30];
  1818.     int     row;
  1819.     int     fillchar;
  1820.     int     attr;
  1821.     int     empty_line = FALSE;
  1822.     colnr_t     virtcol;
  1823.     /* If 'ruler' off or redrawing disabled, don't do anything */
  1824.     if (!p_ru || (!always && !redrawing()))
  1825. return;
  1826.     /*
  1827.      * Check if cursor.lnum is valid, since win_redr_ruler() may be called
  1828.      * after deleting lines, before cursor.lnum is corrected.
  1829.      */
  1830.     if (wp->w_cursor.lnum > wp->w_buffer->b_ml.ml_line_count)
  1831. return;
  1832.     /*
  1833.      * Check if the line is empty (will show "0-1").
  1834.      */
  1835.     if (*ml_get_buf(wp->w_buffer, wp->w_cursor.lnum, FALSE) == NUL)
  1836. empty_line = TRUE;
  1837.     /*
  1838.      * Only draw the ruler when something changed.
  1839.      */
  1840.     validate_virtcol_win(wp);
  1841.     if (       redraw_cmdline
  1842.     || always
  1843.     || wp->w_cursor.lnum != wp->w_ru_cursor.lnum
  1844.     || wp->w_cursor.col != wp->w_ru_cursor.col
  1845.     || wp->w_virtcol != wp->w_ru_virtcol
  1846.     || empty_line != wp->w_ru_empty)
  1847.     {
  1848. cursor_off();
  1849. if (wp->w_status_height)
  1850. {
  1851.     row = wp->w_winpos + wp->w_height;
  1852.     fillchar = highlight_status(&attr, wp == curwin);
  1853. }
  1854. else
  1855. {
  1856.     row = Rows - 1;
  1857.     fillchar = ' ';
  1858.     attr = 0;
  1859. }
  1860. /* In list mode virtcol needs to be recomputed */
  1861. virtcol = wp->w_virtcol;
  1862. if (wp->w_p_list && lcs_tab1 == NUL)
  1863. {
  1864.     wp->w_p_list = FALSE;
  1865.     getvcol(wp, &wp->w_cursor, NULL, &virtcol, NULL);
  1866.     wp->w_p_list = TRUE;
  1867. }
  1868. /*
  1869.  * Some sprintfs return the length, some return a pointer.
  1870.  * To avoid portability problems we use strlen() here.
  1871.  */
  1872. sprintf((char *)buffer, "%ld,",
  1873. (wp->w_buffer->b_ml.ml_flags & ML_EMPTY)
  1874.     ? 0L
  1875.     : (long)(wp->w_cursor.lnum));
  1876. col_print(buffer + STRLEN(buffer),
  1877. !(State & INSERT) && empty_line
  1878.     ? 0
  1879.     : (int)wp->w_cursor.col + 1,
  1880. (int)virtcol + 1);
  1881. screen_puts(buffer, row, ru_col, attr);
  1882. screen_fill(row, row + 1, ru_col + (int)STRLEN(buffer),
  1883.       (int)Columns, fillchar, fillchar, attr);
  1884. wp->w_ru_cursor = wp->w_cursor;
  1885. wp->w_ru_virtcol = wp->w_virtcol;
  1886. wp->w_ru_empty = empty_line;
  1887.     }
  1888. }
  1889. /*
  1890.  * Check if there should be a delay.  Used before clearing or redrawing the
  1891.  * screen or the command line.
  1892.  */
  1893.     void
  1894. check_for_delay(check_msg_scroll)
  1895.     int     check_msg_scroll;
  1896. {
  1897.     if (emsg_on_display || (check_msg_scroll && msg_scroll))
  1898.     {
  1899. out_flush();
  1900. ui_delay(1000L, TRUE);
  1901. emsg_on_display = FALSE;
  1902. if (check_msg_scroll)
  1903.     msg_scroll = FALSE;
  1904.     }
  1905. }
  1906. /*
  1907.  * screen_valid -  allocate screen buffers if size changed
  1908.  *   If "clear" is TRUE: clear screen if it has been resized.
  1909.  * Returns TRUE if there is a valid screen to write to.
  1910.  * Returns FALSE when starting up and screen not initialized yet.
  1911.  */
  1912.     int
  1913. screen_valid(clear)
  1914.     int     clear;
  1915. {
  1916.     screenalloc(clear);     /* allocate screen buffers if size changed */
  1917.     return (NextScreen != NULL);
  1918. }
  1919. #ifdef USE_MOUSE
  1920. /*
  1921.  * Move the cursor to the specified row and column on the screen.
  1922.  * Change current window if neccesary. Returns an integer with the
  1923.  * CURSOR_MOVED bit set if the cursor has moved or unset otherwise.
  1924.  *
  1925.  * If flags has MOUSE_FOCUS, then the current window will not be changed, and
  1926.  * if the mouse is outside the window then the text will scroll, or if the
  1927.  * mouse was previously on a status line, then the status line may be dragged.
  1928.  *
  1929.  * If flags has MOUSE_MAY_VIS, then VIsual mode will be started before the
  1930.  * cursor is moved unless the cursor was on a status line.  Ignoring the
  1931.  * CURSOR_MOVED bit, this function returns one of IN_UNKNOWN, IN_BUFFER, or
  1932.  * IN_STATUS_LINE depending on where the cursor was clicked.
  1933.  *
  1934.  * If flags has MOUSE_MAY_STOP_VIS, then Visual mode will be stopped, unless
  1935.  * the mouse is on the status line of the same window.
  1936.  *
  1937.  * If flags has MOUSE_DID_MOVE, nothing is done if the mouse didn't move since
  1938.  * the last call.
  1939.  *
  1940.  * If flags has MOUSE_SETPOS, nothing is done, only the current position is
  1941.  * remembered.
  1942.  */
  1943.     int
  1944. jump_to_mouse(flags, inclusive)
  1945.     int     flags;
  1946.     int     *inclusive; /* used for inclusive operator, can be NULL */
  1947. {
  1948.     static int on_status_line = 0; /* #lines below bottom of window */
  1949.     static int prev_row = -1;
  1950.     static int prev_col = -1;
  1951.     WIN     *wp, *old_curwin;
  1952.     FPOS    old_cursor;
  1953.     int     count;
  1954.     int     first;
  1955.     int     row = mouse_row;
  1956.     int     col = mouse_col;
  1957.     mouse_past_bottom = FALSE;
  1958.     mouse_past_eol = FALSE;
  1959.     if ((flags & MOUSE_DID_MOVE) && prev_row == mouse_row
  1960.      && prev_col == mouse_col)
  1961.     {
  1962. retnomove:
  1963. /* before moving the cursor for a left click wich is NOT in a status
  1964.  * line, stop Visual mode */
  1965. if (on_status_line)
  1966.     return IN_STATUS_LINE;
  1967. if (flags & MOUSE_MAY_STOP_VIS)
  1968. {
  1969.     end_visual_mode();
  1970.     update_curbuf(NOT_VALID); /* delete the inversion */
  1971. }
  1972. return IN_BUFFER;
  1973.     }
  1974.     prev_row = mouse_row;
  1975.     prev_col = mouse_col;
  1976.     if ((flags & MOUSE_SETPOS))
  1977. goto retnomove; /* ugly goto... */
  1978.     old_curwin = curwin;
  1979.     old_cursor = curwin->w_cursor;
  1980.     if (!(flags & MOUSE_FOCUS))
  1981.     {
  1982. if (row < 0 || col < 0) /* check if it makes sense */
  1983.     return IN_UNKNOWN;
  1984. /* find the window where the row is in */
  1985. for (wp = firstwin; wp->w_next; wp = wp->w_next)
  1986.     if (row < wp->w_next->w_winpos)
  1987. break;
  1988. /*
  1989.  * winpos and height may change in win_enter()!
  1990.  */
  1991. row -= wp->w_winpos;
  1992. if (row >= wp->w_height)    /* In (or below) status line */
  1993.     on_status_line = row - wp->w_height + 1;
  1994. else
  1995.     on_status_line = 0;
  1996. /* Before jumping to another buffer, or moving the cursor for a left
  1997.  * click, stop Visual mode. */
  1998. if (VIsual_active
  1999. && (wp->w_buffer != curwin->w_buffer
  2000.     || (!on_status_line && (flags & MOUSE_MAY_STOP_VIS))))
  2001. {
  2002.     end_visual_mode();
  2003.     update_curbuf(NOT_VALID); /* delete the inversion */
  2004. }
  2005. win_enter(wp, TRUE);     /* can make wp invalid! */
  2006. if (on_status_line)     /* In (or below) status line */
  2007. {
  2008.     /* Don't use start_arrow() if we're in the same window */
  2009.     if (curwin == old_curwin)
  2010. return IN_STATUS_LINE;
  2011.     else
  2012. return IN_STATUS_LINE | CURSOR_MOVED;
  2013. }
  2014. curwin->w_cursor.lnum = curwin->w_topline;
  2015. #ifdef USE_GUI
  2016. /* remember topline, needed for double click */
  2017. gui_prev_topline = curwin->w_topline;
  2018. #endif
  2019.     }
  2020.     else if (on_status_line)
  2021.     {
  2022. /* Drag the status line */
  2023. count = row - curwin->w_winpos - curwin->w_height + 1 - on_status_line;
  2024. win_drag_status_line(count);
  2025. return IN_STATUS_LINE;     /* Cursor didn't move */
  2026.     }
  2027.     else /* keep_window_focus must be TRUE */
  2028.     {
  2029. /* before moving the cursor for a left click, stop Visual mode */
  2030. if (flags & MOUSE_MAY_STOP_VIS)
  2031. {
  2032.     end_visual_mode();
  2033.     update_curbuf(NOT_VALID); /* delete the inversion */
  2034. }
  2035. row -= curwin->w_winpos;
  2036. /*
  2037.  * When clicking beyond the end of the window, scroll the screen.
  2038.  * Scroll by however many rows outside the window we are.
  2039.  */
  2040. if (row < 0)
  2041. {
  2042.     count = 0;
  2043.     for (first = TRUE; curwin->w_topline > 1; --curwin->w_topline)
  2044.     {
  2045. count += plines(curwin->w_topline - 1);
  2046. if (!first && count > -row)
  2047.     break;
  2048. first = FALSE;
  2049.     }
  2050.     curwin->w_valid &=
  2051.       ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2052.     redraw_later(VALID);
  2053.     row = 0;
  2054. }
  2055. else if (row >= curwin->w_height)
  2056. {
  2057.     count = 0;
  2058.     for (first = TRUE; curwin->w_topline < curbuf->b_ml.ml_line_count;
  2059. ++curwin->w_topline)
  2060.     {
  2061. count += plines(curwin->w_topline);
  2062. if (!first && count > row - curwin->w_height + 1)
  2063.     break;
  2064. first = FALSE;
  2065.     }
  2066.     redraw_later(VALID);
  2067.     curwin->w_valid &=
  2068.       ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2069.     row = curwin->w_height - 1;
  2070. }
  2071. curwin->w_cursor.lnum = curwin->w_topline;
  2072.     }
  2073. #ifdef RIGHTLEFT
  2074.     if (curwin->w_p_rl)
  2075. col = Columns - 1 - col;
  2076. #endif
  2077.     if (curwin->w_p_wrap) /* lines wrap */
  2078.     {
  2079. while (row)
  2080. {
  2081.     count = plines(curwin->w_cursor.lnum);
  2082.     if (count > row)
  2083.     {
  2084. col += row * Columns;
  2085. break;
  2086.     }
  2087.     if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
  2088.     {
  2089. mouse_past_bottom = TRUE;
  2090. break;
  2091.     }
  2092.     row -= count;
  2093.     ++curwin->w_cursor.lnum;
  2094. }
  2095.     }
  2096.     else /* lines don't wrap */
  2097.     {
  2098. curwin->w_cursor.lnum += row;
  2099. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  2100. {
  2101.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2102.     mouse_past_bottom = TRUE;
  2103. }
  2104. col += curwin->w_leftcol;
  2105.     }
  2106.     if (curwin->w_p_nu) /* skip number in front of the line */
  2107. if ((col -= 8) < 0)
  2108.     col = 0;
  2109.     /* Start Visual mode before coladvance(), for when 'sel' != "old" */
  2110.     if ((flags & MOUSE_MAY_VIS) && !VIsual_active)
  2111.     {
  2112. check_visual_highlight();
  2113. VIsual = old_cursor;
  2114. VIsual_active = TRUE;
  2115. VIsual_reselect = TRUE;
  2116. /* if 'selectmode' contains "mouse", start Select mode */
  2117. may_start_select('o');
  2118. setmouse();
  2119. if (p_smd)
  2120.     redraw_cmdline = TRUE; /* show visual mode later */
  2121.     }
  2122.     curwin->w_curswant = col;
  2123.     curwin->w_set_curswant = FALSE; /* May still have been TRUE */
  2124.     if (coladvance(col) == FAIL) /* Mouse click beyond end of line */
  2125.     {
  2126. if (inclusive != NULL)
  2127.     *inclusive = TRUE;
  2128. mouse_past_eol = TRUE;
  2129.     }
  2130.     else if (inclusive != NULL)
  2131. *inclusive = FALSE;
  2132.     if (curwin == old_curwin && curwin->w_cursor.lnum == old_cursor.lnum &&
  2133.        curwin->w_cursor.col == old_cursor.col)
  2134. return IN_BUFFER; /* Cursor has not moved */
  2135.     return IN_BUFFER | CURSOR_MOVED; /* Cursor has moved */
  2136. }
  2137. #endif /* USE_MOUSE */
  2138. /*
  2139.  * Return TRUE if redrawing should currently be done.
  2140.  */
  2141.     int
  2142. redrawing()
  2143. {
  2144.     return (!RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped));
  2145. }
  2146. /*
  2147.  * Return TRUE if printing messages should currently be done.
  2148.  */
  2149.     int
  2150. messaging()
  2151. {
  2152.     return (!(p_lz && char_avail() && !KeyTyped));
  2153. }
  2154. /*
  2155.  * move screen 'count' pages up or down and update screen
  2156.  *
  2157.  * return FAIL for failure, OK otherwise
  2158.  */
  2159.     int
  2160. onepage(dir, count)
  2161.     int     dir;
  2162.     long    count;
  2163. {
  2164.     linenr_t     lp;
  2165.     long     n;
  2166.     int     off;
  2167.     int     retval = OK;
  2168.     if (curbuf->b_ml.ml_line_count == 1)    /* nothing to do */
  2169.     {
  2170. beep_flush();
  2171. return FAIL;
  2172.     }
  2173.     for ( ; count > 0; --count)
  2174.     {
  2175. validate_botline();
  2176. /*
  2177.  * It's an error to move a page up when the first line is already on
  2178.  * the screen. It's an error to move a page down when the last line
  2179.  * is on the screen and the topline is 'scrolloff' lines from the
  2180.  * last line.
  2181.  */
  2182. if (dir == FORWARD
  2183. ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - p_so) &&
  2184. curwin->w_botline > curbuf->b_ml.ml_line_count)
  2185. : (curwin->w_topline == 1))
  2186. {
  2187.     beep_flush();
  2188.     retval = FAIL;
  2189.     break;
  2190. }
  2191. if (dir == FORWARD)
  2192. {
  2193. /* at end of file */
  2194.     if (curwin->w_botline > curbuf->b_ml.ml_line_count)
  2195.     {
  2196. curwin->w_topline = curbuf->b_ml.ml_line_count;
  2197. curwin->w_valid &= ~(VALID_WROW|VALID_CROW);
  2198.     }
  2199.     else
  2200.     {
  2201. /*
  2202.  * When there are three or less lines on the screen, move them
  2203.  * all to above the screen.
  2204.  */
  2205. if (curwin->w_botline - curwin->w_topline <= 3)
  2206.     off = 0;
  2207. /*
  2208.  * Make sure at least w_botline gets onto the screen, also
  2209.  * when 'scrolloff' is non-zero and with very long lines.
  2210.  */
  2211. else if (plines(curwin->w_botline) +
  2212. plines(curwin->w_botline - 1) +
  2213. plines(curwin->w_botline - 2) >= curwin->w_height - 2)
  2214.     off = 0;
  2215. else
  2216.     off = 2;
  2217. curwin->w_topline = curwin->w_botline - off;
  2218. curwin->w_cursor.lnum = curwin->w_topline;
  2219. curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|
  2220.    VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP);
  2221.     }
  2222. }
  2223. else /* dir == BACKWARDS */
  2224. {
  2225.     lp = curwin->w_topline;
  2226.     /*
  2227.      * If the first two lines on the screen are not too big, we keep
  2228.      * them on the screen.
  2229.      */
  2230.     if ((n = plines(lp)) > curwin->w_height / 2)
  2231. --lp;
  2232.     else if (lp < curbuf->b_ml.ml_line_count &&
  2233.     n + plines(lp + 1) < curwin->w_height / 2)
  2234. ++lp;
  2235.     curwin->w_cursor.lnum = lp;
  2236.     n = 0;
  2237.     while (n <= curwin->w_height && lp >= 1)
  2238.     {
  2239. n += plines(lp);
  2240. --lp;
  2241.     }
  2242.     if (n <= curwin->w_height)     /* at begin of file */
  2243.     {
  2244. curwin->w_topline = 1;
  2245. curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2246.     }
  2247.     else if (lp >= curwin->w_topline - 2)   /* very long lines */
  2248.     {
  2249. --curwin->w_topline;
  2250. comp_botline();
  2251. curwin->w_cursor.lnum = curwin->w_botline - 1;
  2252. curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|
  2253.        VALID_WROW|VALID_CROW);
  2254.     }
  2255.     else
  2256.     {
  2257. curwin->w_topline = lp + 2;
  2258. curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE);
  2259.     }
  2260. }
  2261.     }
  2262.     cursor_correct();
  2263.     beginline(BL_SOL | BL_FIX);
  2264.     curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL);
  2265.     /*
  2266.      * Avoid the screen jumping up and down when 'scrolloff' is non-zero.
  2267.      */
  2268.     if (dir == FORWARD && curwin->w_cursor.lnum < curwin->w_topline + p_so)
  2269. scroll_cursor_top(1, FALSE);
  2270.     update_screen(VALID);
  2271.     return retval;
  2272. }
  2273. /* #define KEEP_SCREEN_LINE */
  2274.     void
  2275. halfpage(flag, Prenum)
  2276.     int flag;
  2277.     linenr_t Prenum;
  2278. {
  2279.     long scrolled = 0;
  2280.     int i;
  2281.     int n;
  2282.     int room;
  2283.     if (Prenum)
  2284. curwin->w_p_scroll = (Prenum > curwin->w_height) ?
  2285. curwin->w_height : Prenum;
  2286.     n = (curwin->w_p_scroll <= curwin->w_height) ?
  2287.     curwin->w_p_scroll : curwin->w_height;
  2288.     validate_botline();
  2289.     room = curwin->w_empty_rows;
  2290.     if (flag)     /* scroll down */
  2291.     {
  2292. while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count)
  2293. {
  2294.     i = plines(curwin->w_topline);
  2295.     n -= i;
  2296.     if (n < 0 && scrolled)
  2297. break;
  2298.     ++curwin->w_topline;
  2299.     curwin->w_valid &= ~(VALID_CROW|VALID_WROW);
  2300.     scrolled += i;
  2301.     /*
  2302.      * Correct w_botline for changed w_topline.
  2303.      */
  2304.     room += i;
  2305.     do
  2306.     {
  2307. i = plines(curwin->w_botline);
  2308. if (i > room)
  2309.     break;
  2310. ++curwin->w_botline;
  2311. room -= i;
  2312.     } while (curwin->w_botline <= curbuf->b_ml.ml_line_count);
  2313. #ifndef KEEP_SCREEN_LINE
  2314.     if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  2315.     {
  2316. ++curwin->w_cursor.lnum;
  2317. curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2318.     }
  2319. #endif
  2320. }
  2321. #ifndef KEEP_SCREEN_LINE
  2322. /*
  2323.  * When hit bottom of the file: move cursor down.
  2324.  */
  2325. if (n > 0)
  2326. {
  2327.     curwin->w_cursor.lnum += n;
  2328.     if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  2329. curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  2330. }
  2331. #else
  2332.     /* try to put the cursor in the same screen line */
  2333. while ((curwin->w_cursor.lnum < curwin->w_topline || scrolled > 0)
  2334.      && curwin->w_cursor.lnum < curwin->w_botline - 1)
  2335. {
  2336.     scrolled -= plines(curwin->w_cursor.lnum);
  2337.     if (scrolled < 0 && curwin->w_cursor.lnum >= curwin->w_topline)
  2338. break;
  2339.     ++curwin->w_cursor.lnum;
  2340. }
  2341. #endif
  2342.     }
  2343.     else     /* scroll up */
  2344.     {
  2345. while (n > 0 && curwin->w_topline > 1)
  2346. {
  2347.     i = plines(curwin->w_topline - 1);
  2348.     n -= i;
  2349.     if (n < 0 && scrolled)
  2350. break;
  2351.     scrolled += i;
  2352.     --curwin->w_topline;
  2353.     curwin->w_valid &= ~(VALID_CROW|VALID_WROW|
  2354.       VALID_BOTLINE|VALID_BOTLINE_AP);
  2355. #ifndef KEEP_SCREEN_LINE
  2356.     if (curwin->w_cursor.lnum > 1)
  2357.     {
  2358. --curwin->w_cursor.lnum;
  2359. curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL);
  2360.     }
  2361. #endif
  2362. }
  2363. #ifndef KEEP_SCREEN_LINE
  2364. /*
  2365.  * When hit top of the file: move cursor up.
  2366.  */
  2367. if (n > 0)
  2368. {
  2369.     if (curwin->w_cursor.lnum > (linenr_t)n)
  2370. curwin->w_cursor.lnum -= n;
  2371.     else
  2372. curwin->w_cursor.lnum = 1;
  2373. }
  2374. #else
  2375.     /* try to put the cursor in the same screen line */
  2376. scrolled += n;     /* move cursor when topline is 1 */
  2377. while (curwin->w_cursor.lnum > curwin->w_topline &&
  2378.  (scrolled > 0 || curwin->w_cursor.lnum >= curwin->w_botline))
  2379. {
  2380.     scrolled -= plines(curwin->w_cursor.lnum - 1);
  2381.     if (scrolled < 0 && curwin->w_cursor.lnum < curwin->w_botline)
  2382. break;
  2383.     --curwin->w_cursor.lnum;
  2384. }
  2385. #endif
  2386.     }
  2387.     cursor_correct();
  2388.     beginline(BL_SOL | BL_FIX);
  2389.     update_screen(VALID);
  2390. }
  2391. /*
  2392.  * Give an introductory message about Vim.
  2393.  * Only used when starting Vim on an empty file, without a file name.
  2394.  * Or with the ":intro" command (for Sven :-).
  2395.  */
  2396.     static void
  2397. intro_message()
  2398. {
  2399.     int i;
  2400.     int row;
  2401.     int col;
  2402.     static char *(lines[]) =
  2403.     {
  2404. "VIM - Vi IMproved",
  2405. "",
  2406. "version ",
  2407. "by Bram Moolenaar et al.",
  2408. "",
  2409. "Vim is freely distributable",
  2410. "type  :help uganda<Enter>     if you like Vim ",
  2411. "",
  2412. "type  :q<Enter>               to exit         ",
  2413. "type  :help<Enter>  or  <F1>  for on-line help",
  2414. "type  :help version5<Enter>   for version info",
  2415. NULL,
  2416. "",
  2417. "Running in Vi compatible mode",
  2418. "type  :set nocp<Enter>        for Vim defaults",
  2419. "type  :help cp-default<Enter> for info on this",
  2420.     };
  2421.     row = ((int)Rows - (int)(sizeof(lines) / sizeof(char *))) / 2;
  2422.     if (!p_cp)
  2423. row += 2;
  2424. #if defined(WIN32) && !defined(USE_GUI_WIN32)
  2425.     if (mch_windows95())
  2426. row -= 2;
  2427. #endif
  2428. #if defined(__BEOS__) && defined(__INTEL__)
  2429.     row -= 2;
  2430. #endif
  2431.     if (row > 2 && Columns >= 50)
  2432.     {
  2433. for (i = 0; i < (int)(sizeof(lines) / sizeof(char *)); ++i)
  2434. {
  2435.     if (lines[i] == NULL)
  2436.     {
  2437. if (!p_cp)
  2438.     break;
  2439. continue;
  2440.     }
  2441.     col = strlen(lines[i]);
  2442.     if (i == 2)
  2443. col += strlen(mediumVersion);
  2444.     col = (Columns - col) / 2;
  2445.     if (col < 0)
  2446. col = 0;
  2447.     screen_puts((char_u *)lines[i], row, col, 0);
  2448.     if (i == 2)
  2449. screen_puts((char_u *)mediumVersion, row, col + 8, 0);
  2450.     ++row;
  2451. }
  2452. #if defined(WIN32) && !defined(USE_GUI_WIN32)
  2453. if (mch_windows95())
  2454. {
  2455.     screen_puts((char_u *)"WARNING: Windows 95 detected", row + 1, col + 8, hl_attr(HLF_E));
  2456.     screen_puts((char_u *)"type  :help windows95<Enter>  for info on this", row + 2, col, 0);
  2457. }
  2458. #endif
  2459. #if defined(__BEOS__) && defined(__INTEL__)
  2460. screen_puts((char_u *)"     WARNING: Intel CPU detected.    ", row + 1, col + 4, hl_attr(HLF_E));
  2461. screen_puts((char_u *)" PPC has a much better architecture. ", row + 2, col + 4, hl_attr(HLF_E));
  2462. #endif
  2463.     }
  2464. }
  2465. /*
  2466.  * ":intro" command: clear screen, display intro screen and wait for return.
  2467.  */
  2468.     void
  2469. do_intro()
  2470. {
  2471.     screenclear();
  2472.     intro_message();
  2473.     wait_return(TRUE);
  2474. }