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

编辑器/阅读器

开发平台:

DOS

  1.      * Use ins_char() to insert the text, it is a bit slower than
  2.      * ins_str(), but it takes care of replace mode.
  3.      */
  4.     ptr = curr_match->str + curwin->w_cursor.col - complete_col;
  5.     while (*ptr)
  6. ins_char(*ptr++);
  7.     update_screenline();
  8.     if (temp > 1)
  9.     {
  10. if (ctrl_x_mode == 0 || ctrl_x_mode == CTRL_X_WHOLE_LINE)
  11.     ptr = (char_u *)"All %d matches have now been found";
  12. else if (ctrl_x_mode == CTRL_X_FILES)
  13.     ptr = (char_u *)"There are %d matching file names";
  14. else if (ctrl_x_mode == CTRL_X_TAGS)
  15.     ptr = (char_u *)"There are %d matching tags";
  16. else
  17.     ptr = (char_u *)"There are %d matches";
  18. sprintf((char *)IObuff, (char *)ptr, temp);
  19. if (dollar_vcol)
  20.     curs_columns(FALSE);
  21. msg_attr(IObuff, hl_attr(HLF_R));
  22. if (!char_avail())
  23. {
  24.     setcursor();
  25.     out_flush();
  26.     ui_delay(1500L, FALSE);
  27. }
  28.     }
  29.     showmode();
  30.     if (edit_submode_extra != NULL)
  31.     {
  32. if (!p_smd)
  33.     msg_attr(edit_submode_extra,
  34.     edit_submode_highl < HLF_COUNT
  35.     ? hl_attr(edit_submode_highl) : 0);
  36. if (!char_avail())
  37. {
  38.     setcursor();
  39.     out_flush();
  40.     ui_delay(1500L, FALSE);
  41. }
  42. edit_submode_extra = NULL;
  43.     }
  44.     /*
  45.      * Show the file name for the match (if any)
  46.      * Truncate the file name to avoid a wait for return.
  47.      */
  48.     if (curr_match->fname != NULL)
  49.     {
  50. STRCPY(IObuff, "match in file ");
  51. i = (vim_strsize(curr_match->fname) + 16) - sc_col;
  52. if (i <= 0)
  53.     i = 0;
  54. else
  55.     STRCAT(IObuff, "<");
  56. STRCAT(IObuff, curr_match->fname + i);
  57. msg(IObuff);
  58. redraw_cmdline = FALSE;     /* don't overwrite! */
  59.     }
  60.     return TRUE;
  61. }
  62. /*
  63.  * Looks in the first "len" chars. of "src" for search-metachars.
  64.  * If dest is not NULL the chars. are copied there quoting (with
  65.  * a backslash) the metachars, and dest would be NUL terminated.
  66.  * Returns the length (needed) of dest
  67.  */
  68.     static int
  69. quote_meta(dest, src, len)
  70.     char_u *dest;
  71.     char_u *src;
  72.     int len;
  73. {
  74.     int m;
  75.     for (m = len; --len >= 0; src++)
  76.     {
  77. switch (*src)
  78. {
  79.     case '.':
  80.     case '*':
  81.     case '[':
  82. if (ctrl_x_mode == CTRL_X_DICTIONARY)
  83.     break;
  84.     case '~':
  85. if (!p_magic) /* quote these only if magic is set */
  86.     break;
  87.     case '\':
  88. if (ctrl_x_mode == CTRL_X_DICTIONARY)
  89.     break;
  90.     case '^': /* currently it's not needed. */
  91.     case '$':
  92. m++;
  93. if (dest)
  94.     *dest++ = '\';
  95. break;
  96. }
  97. if (dest)
  98.     *dest++ = *src;
  99.     }
  100.     if (dest)
  101. *dest = NUL;
  102.     return m;
  103. }
  104. #endif /* INSERT_EXPAND */
  105. /*
  106.  * Next character is interpreted literally.
  107.  * A one, two or three digit decimal number is interpreted as its byte value.
  108.  * If one or two digits are entered, the next character is given to vungetc().
  109.  */
  110.     int
  111. get_literal()
  112. {
  113.     int cc;
  114.     int nc;
  115.     int i;
  116.     int hexmode = 0, octalmode = 0;
  117.     if (got_int)
  118. return Ctrl('C');
  119. #ifdef USE_GUI
  120.     /*
  121.      * In GUI there is no point inserting the internal code for a special key.
  122.      * It is more useful to insert the string "<KEY>" instead. This would
  123.      * probably be useful in a text window too, but it would not be
  124.      * vi-compatible (maybe there should be an option for it?) -- webb
  125.      */
  126.     if (gui.in_use)
  127. ++allow_keys;
  128. #endif
  129. #ifdef USE_GUI_WIN32
  130.     dont_scroll = TRUE; /* disallow scrolling here */
  131. #endif
  132.     ++no_mapping;     /* don't map the next key hits */
  133.     cc = 0;
  134.     i = 0;
  135.     for (;;)
  136.     {
  137. do
  138.     nc = vgetc();
  139. while (nc == K_IGNORE || nc == K_SCROLLBAR || nc == K_HORIZ_SCROLLBAR);
  140. #ifdef SHOWCMD
  141. if (!(State & CMDLINE)
  142. #ifdef MULTI_BYTE
  143. && (is_dbcs && !IsLeadByte(nc))
  144. #endif
  145. )
  146.     add_to_showcmd(nc);
  147. #endif
  148. if (nc == 'x' || nc == 'X')
  149.     hexmode++;
  150. else if (nc == 'o' || nc == 'O')
  151.     octalmode++;
  152. else
  153. {
  154.     if (hexmode)
  155.     {
  156. if (!vim_isdigit(nc) && !isxdigit(nc))
  157.     break;
  158. nc = tolower(nc);
  159. if (nc >= 'a')
  160.     nc = 10 + nc - 'a';
  161. else
  162.     nc = nc - '0';
  163. cc = cc * 16 + nc ;
  164.     }
  165.     else if (octalmode)
  166.     {
  167. if (!vim_isdigit(nc) || (nc > '7'))
  168.     break;
  169. cc = cc * 8 + nc - '0';
  170.     }
  171.     else
  172.     {
  173. if (!vim_isdigit(nc))
  174.     break;
  175. cc = cc * 10 + nc - '0';
  176.     }
  177.     ++i;
  178. }
  179. if (cc > 255)
  180.     cc = 255; /* limit range to 0-255 */
  181. nc = 0;
  182. if (hexmode && (i >= 2))
  183.     break;
  184. if (!hexmode && (i >= 3))
  185.     break;
  186.     }
  187.     if (i == 0)     /* no number entered */
  188.     {
  189. if (nc == K_ZERO)   /* NUL is stored as NL */
  190. {
  191.     cc = 'n';
  192.     nc = 0;
  193. }
  194. else
  195. {
  196.     cc = nc;
  197.     nc = 0;
  198. }
  199.     }
  200.     if (cc == 0) /* NUL is stored as NL */
  201. cc = 'n';
  202.     --no_mapping;
  203. #ifdef USE_GUI
  204.     if (gui.in_use)
  205. --allow_keys;
  206. #endif
  207.     if (nc)
  208. vungetc(nc);
  209.     got_int = FALSE;     /* CTRL-C typed after CTRL-V is not an interrupt */
  210.     return cc;
  211. }
  212. /*
  213.  * Insert character, taking care of special keys and mod_mask
  214.  */
  215.     static void
  216. insert_special(c, allow_modmask, ctrlv)
  217.     int     c;
  218.     int     allow_modmask;
  219.     int     ctrlv;     /* c was typed after CTRL-V */
  220. {
  221.     char_u  *p;
  222.     int     len;
  223.     /*
  224.      * Special function key, translate into "<Key>". Up to the last '>' is
  225.      * inserted with ins_str(), so as not to replace characters in replace
  226.      * mode.
  227.      * Only use mod_mask for special keys, to avoid things like <S-Space>,
  228.      * unless 'allow_modmask' is TRUE.
  229.      */
  230.     if (IS_SPECIAL(c) || (mod_mask && allow_modmask))
  231.     {
  232. p = get_special_key_name(c, mod_mask);
  233. len = STRLEN(p);
  234. c = p[len - 1];
  235. if (len > 2)
  236. {
  237.     p[len - 1] = NUL;
  238.     ins_str(p);
  239.     AppendToRedobuff(p);
  240.     ctrlv = FALSE;
  241. }
  242.     }
  243.     insertchar(c, FALSE, -1, ctrlv);
  244. }
  245. /*
  246.  * Special characters in this context are those that need processing other
  247.  * than the simple insertion that can be performed here. This includes ESC
  248.  * which terminates the insert, and CR/NL which need special processing to
  249.  * open up a new line. This routine tries to optimize insertions performed by
  250.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  251.  * stop and defer processing to the "normal" mechanism.
  252.  * '0' and '^' are special, because they can be followed by CTRL-D.
  253.  */
  254. #define ISSPECIAL(c) ((c) < ' ' || (c) >= DEL || (c) == '0' || (c) == '^')
  255.     void
  256. insertchar(c, force_formatting, second_indent, ctrlv)
  257.     unsigned c;
  258.     int force_formatting; /* format line regardless of p_fo */
  259.     int second_indent; /* indent for second line if >= 0 */
  260.     int ctrlv; /* c typed just after CTRL-V */
  261. {
  262.     int haveto_redraw = FALSE;
  263.     int textwidth;
  264.     colnr_t leader_len;
  265.     int first_line = TRUE;
  266.     int fo_ins_blank;
  267.     int save_char = NUL;
  268.     int cc;
  269.     stop_arrow();
  270.     textwidth = comp_textwidth(force_formatting);
  271.     fo_ins_blank = has_format_option(FO_INS_BLANK);
  272.     /*
  273.      * Try to break the line in two or more pieces when:
  274.      * - Always do this if we have been called to do formatting only.
  275.      * - Otherwise:
  276.      *  - Don't do this if inserting a blank
  277.      *  - Don't do this if an existing character is being replaced.
  278.      *  - Do this if the cursor is not on the line where insert started
  279.      *  or - 'formatoptions' doesn't have 'l' or the line was not too long
  280.      *        before the insert.
  281.      *     - 'formatoptions' doesn't have 'b' or a blank was inserted at or
  282.      *       before 'textwidth'
  283.      */
  284.     if (textwidth
  285.     && (force_formatting
  286. || (!vim_iswhite(c)
  287.     && !(State == REPLACE && *ml_get_cursor() != NUL)
  288.     && (curwin->w_cursor.lnum != Insstart.lnum
  289. || ((!has_format_option(FO_INS_LONG)
  290. || Insstart_textlen <= (colnr_t)textwidth)
  291.     && (!fo_ins_blank
  292. || Insstart_blank_vcol <= (colnr_t)textwidth
  293.     ))))))
  294.     {
  295. /*
  296.  * When 'ai' is off we don't want a space under the cursor to be
  297.  * deleted.  Replace it with an 'x' temporarily.
  298.  */
  299. if (!curbuf->b_p_ai)
  300. {
  301.     cc = gchar_cursor();
  302.     if (vim_iswhite(cc))
  303.     {
  304. save_char = cc;
  305. pchar_cursor('x');
  306.     }
  307. }
  308. /*
  309.  * Repeat breaking lines, until the current line is not too long.
  310.  */
  311. while (!got_int)
  312. {
  313.     int startcol; /* Cursor column at entry */
  314.     int wantcol; /* column at textwidth border */
  315.     int foundcol; /* column for start of spaces */
  316.     int end_foundcol = 0; /* column for start of word */
  317.     colnr_t len;
  318.     colnr_t virtcol;
  319.     virtcol = get_nolist_virtcol();
  320.     if (virtcol < (colnr_t)textwidth)
  321. break;
  322.     if (!force_formatting && has_format_option(FO_WRAP_COMS))
  323. fo_do_comments = TRUE;
  324.     /* Don't break until after the comment leader */
  325.     leader_len = get_leader_len(ml_get_curline(), NULL);
  326.     if (!force_formatting && leader_len == 0 &&
  327.   !has_format_option(FO_WRAP))
  328.     {
  329. textwidth = 0;
  330. break;
  331.     }
  332.     if ((startcol = curwin->w_cursor.col) == 0)
  333. break;
  334. /* find column of textwidth border */
  335.     coladvance((colnr_t)textwidth);
  336.     wantcol = curwin->w_cursor.col;
  337.     curwin->w_cursor.col = startcol - 1;
  338.     foundcol = 0;
  339.     /*
  340.      * Find position to break at.
  341.      * Stop at start of line.
  342.      * Stop at first entered white when 'formatoptions' has 'v'
  343.      */
  344.     while (curwin->w_cursor.col > 0 &&
  345.   ((!fo_ins_blank && !has_format_option(FO_INS_VI)) ||
  346.  curwin->w_cursor.lnum != Insstart.lnum ||
  347.      curwin->w_cursor.col >= Insstart.col))
  348.     {
  349. cc = gchar_cursor();
  350. if (vim_iswhite(cc))
  351. {
  352.     /* remember position of blank just before text */
  353.     end_foundcol = curwin->w_cursor.col;
  354.     while (curwin->w_cursor.col > 0 && vim_iswhite(cc))
  355.     {
  356. --curwin->w_cursor.col;
  357. cc = gchar_cursor();
  358.     }
  359.     if (curwin->w_cursor.col == 0 && vim_iswhite(cc))
  360. break; /* only spaces in front of text */
  361.     /* Don't break until after the comment leader */
  362.     if (curwin->w_cursor.col < leader_len)
  363. break;
  364.     foundcol = curwin->w_cursor.col + 1;
  365.     if (curwin->w_cursor.col < (colnr_t)wantcol)
  366. break;
  367. }
  368. --curwin->w_cursor.col;
  369.     }
  370.     if (foundcol == 0) /* no spaces, cannot break line */
  371.     {
  372. curwin->w_cursor.col = startcol;
  373. break;
  374.     }
  375.     /*
  376.      * offset between cursor position and line break is used by
  377.      * replace stack functions
  378.      */
  379.     replace_offset = startcol - end_foundcol - 1;
  380.     /*
  381.      * adjust startcol for spaces that will be deleted and
  382.      * characters that will remain on top line
  383.      */
  384.     curwin->w_cursor.col = foundcol;
  385.     while (cc = gchar_cursor(), vim_iswhite(cc))
  386.     {
  387. ++curwin->w_cursor.col;
  388. --startcol;
  389.     }
  390.     startcol -= foundcol;
  391.     if (startcol < 0)
  392. startcol = 0;
  393.     /* put cursor after pos. to break line */
  394.     curwin->w_cursor.col = foundcol;
  395.     /*
  396.      * Split the line before just the margin.
  397.      * Only insert/delete lines, but don't really redraw the window.
  398.      */
  399.     open_line(FORWARD, (redrawing() && !force_formatting) ? -1 : 0,
  400.     TRUE, old_indent);
  401.     old_indent = 0;
  402.     replace_offset = 0;
  403.     if (second_indent >= 0 && first_line)
  404. set_indent(second_indent, TRUE);
  405.     first_line = FALSE;
  406.     /*
  407.      * check if cursor is not past the NUL off the line, cindent may
  408.      * have added or removed indent.
  409.      */
  410.     curwin->w_cursor.col += startcol;
  411.     len = STRLEN(ml_get_curline());
  412.     if (curwin->w_cursor.col > len)
  413. curwin->w_cursor.col = len;
  414.     haveto_redraw = TRUE;
  415. #ifdef CINDENT
  416.     can_cindent = TRUE;
  417. #endif
  418.     /* moved the cursor, don't autoindent or cindent now */
  419.     did_ai = FALSE;
  420. #ifdef SMARTINDENT
  421.     did_si = FALSE;
  422.     can_si = FALSE;
  423.     can_si_back = FALSE;
  424. #endif
  425.     line_breakcheck();
  426. }
  427. if (save_char) /* put back space after cursor */
  428.     pchar_cursor(save_char);
  429. if (c == NUL) /* formatting only */
  430.     return;
  431. fo_do_comments = FALSE;
  432. if (haveto_redraw)
  433. {
  434.     update_topline();
  435.     update_screen(NOT_VALID);
  436. }
  437.     }
  438.     if (c == NUL)     /* only formatting was wanted */
  439. return;
  440.     did_ai = FALSE;
  441. #ifdef SMARTINDENT
  442.     did_si = FALSE;
  443.     can_si = FALSE;
  444.     can_si_back = FALSE;
  445. #endif
  446.     /*
  447.      * If there's any pending input, grab up to INPUT_BUFLEN at once.
  448.      * This speeds up normal text input considerably.
  449.      * Don't do this when 'cindent' is set, because we might need to re-indent
  450.      * at a ':', or any other character.
  451.      */
  452. #ifdef USE_GUI_WIN32
  453.     dont_scroll = FALSE; /* allow scrolling here */
  454. #endif
  455. #define INPUT_BUFLEN 100
  456.     if (       !ISSPECIAL(c)
  457.     && vpeekc() != NUL
  458.     && State != REPLACE
  459. #ifdef CINDENT
  460.     && !curbuf->b_p_cin
  461. #endif
  462. #ifdef RIGHTLEFT
  463.     && !p_ri
  464. #endif
  465.        )
  466.     {
  467. char_u p[INPUT_BUFLEN + 1];
  468. int i;
  469. colnr_t virtcol = 0;
  470. p[0] = c;
  471. i = 1;
  472. if (textwidth)
  473.     virtcol = get_nolist_virtcol();
  474. while (    (c = vpeekc()) != NUL
  475. && !ISSPECIAL(c)
  476. && i < INPUT_BUFLEN
  477. && (textwidth == 0
  478.     || (virtcol += charsize(p[i - 1])) < (colnr_t)textwidth)
  479. && !(!no_abbr && !vim_iswordc(c) && vim_iswordc(p[i - 1])))
  480. {
  481. #ifdef RIGHTLEFT
  482.     c = vgetc();
  483.     if (p_hkmap && KeyTyped)
  484. c = hkmap(c);     /* Hebrew mode mapping */
  485. #ifdef FKMAP
  486.     if (p_fkmap && KeyTyped)
  487. c = fkmap(c);     /* Farsi mode mapping */
  488. #endif
  489.     p[i++] = c;
  490. #else
  491.     p[i++] = vgetc();
  492. #endif
  493. }
  494. #ifdef DIGRAPHS
  495. do_digraph(-1); /* clear digraphs */
  496. do_digraph(p[i-1]); /* may be the start of a digraph */
  497. #endif
  498. p[i] = NUL;
  499. ins_str(p);
  500. if (ctrlv)
  501. {
  502.     redo_literal(*p);
  503.     i = 1;
  504. }
  505. else
  506.     i = 0;
  507. if (p[i] != NUL)
  508.     AppendToRedobuff(p + i);
  509.     }
  510.     else
  511.     {
  512. ins_char(c);
  513. if (ctrlv)
  514.     redo_literal(c);
  515. else
  516.     AppendCharToRedobuff(c);
  517.     }
  518. }
  519. /*
  520.  * Find out textwidth to be used for formatting:
  521.  * if 'textwidth' option is set, use it
  522.  * else if 'wrapmargin' option is set, use Columns - 'wrapmargin'
  523.  * if invalid value, use 0.
  524.  * Set default to window width (maximum 79) for "Q" command.
  525.  */
  526.     int
  527. comp_textwidth(ff)
  528.     int ff; /* force formatting (for "Q" command) */
  529. {
  530.     int textwidth;
  531.     textwidth = curbuf->b_p_tw;
  532.     if (textwidth == 0 && curbuf->b_p_wm)
  533. textwidth = Columns - curbuf->b_p_wm;
  534.     if (textwidth < 0)
  535. textwidth = 0;
  536.     if (ff && textwidth == 0)
  537.     {
  538. textwidth = Columns - 1;
  539. if (textwidth > 79)
  540.     textwidth = 79;
  541.     }
  542.     return textwidth;
  543. }
  544. /*
  545.  * Put a character in the redo buffer, for when just after a CTRL-V.
  546.  */
  547.     static void
  548. redo_literal(c)
  549.     int     c;
  550. {
  551.     char_u buf[10];
  552.     /* Only digits need special treatment.  Translate them into a string of
  553.      * three digits. */
  554.     if (vim_isdigit(c))
  555.     {
  556. sprintf((char *)buf, "%03d", c);
  557. AppendToRedobuff(buf);
  558.     }
  559.     else
  560. AppendCharToRedobuff(c);
  561. }
  562. /*
  563.  * start_arrow() is called when an arrow key is used in insert mode.
  564.  * It resembles hitting the <ESC> key.
  565.  */
  566.     static void
  567. start_arrow(end_insert_pos)
  568.     FPOS    *end_insert_pos;
  569. {
  570.     if (!arrow_used)     /* something has been inserted */
  571.     {
  572. AppendToRedobuff(ESC_STR);
  573. arrow_used = TRUE; /* this means we stopped the current insert */
  574. stop_insert(end_insert_pos);
  575.     }
  576. }
  577. /*
  578.  * stop_arrow() is called before a change is made in insert mode.
  579.  * If an arrow key has been used, start a new insertion.
  580.  */
  581.     void
  582. stop_arrow()
  583. {
  584.     if (arrow_used)
  585.     {
  586. (void)u_save_cursor();     /* errors are ignored! */
  587. Insstart = curwin->w_cursor; /* new insertion starts here */
  588. Insstart_textlen = linetabsize(ml_get_curline());
  589. ResetRedobuff();
  590. AppendToRedobuff((char_u *)"1i");   /* pretend we start an insertion */
  591. arrow_used = FALSE;
  592.     }
  593. }
  594. /*
  595.  * do a few things to stop inserting
  596.  */
  597.     static void
  598. stop_insert(end_insert_pos)
  599.     FPOS    *end_insert_pos; /* where insert ended */
  600. {
  601.     int     cc;
  602.     stop_redo_ins();
  603.     replace_flush(); /* abandon replace stack */
  604.     /*
  605.      * save the inserted text for later redo with ^@
  606.      */
  607.     vim_free(last_insert);
  608.     last_insert = get_inserted();
  609.     last_insert_skip = new_insert_skip;
  610.     /*
  611.      * If we just did an auto-indent, remove the white space from the end of
  612.      * the line, and put the cursor back.
  613.      */
  614.     if (did_ai && !arrow_used)
  615.     {
  616. if (gchar_cursor() == NUL && curwin->w_cursor.col > 0)
  617.     --curwin->w_cursor.col;
  618. while (cc = gchar_cursor(), vim_iswhite(cc))
  619.     (void)del_char(TRUE);
  620. if (cc != NUL)
  621.     ++curwin->w_cursor.col; /* put cursor back on the NUL */
  622. /* the deletion is only seen in list mode and when 'hls' is set */
  623. if (curwin->w_p_list || p_hls)
  624.     update_screenline();
  625.     }
  626.     did_ai = FALSE;
  627. #ifdef SMARTINDENT
  628.     did_si = FALSE;
  629.     can_si = FALSE;
  630.     can_si_back = FALSE;
  631. #endif
  632.     /* set '[ and '] to the inserted text */
  633.     curbuf->b_op_start = Insstart;
  634.     curbuf->b_op_end = *end_insert_pos;
  635. }
  636. /*
  637.  * Set the last inserted text to a single character.
  638.  * Used for the replace command.
  639.  */
  640.     void
  641. set_last_insert(c)
  642.     int     c;
  643. {
  644.     vim_free(last_insert);
  645.     last_insert = alloc(4);
  646.     if (last_insert != NULL)
  647.     {
  648. last_insert[0] = Ctrl('V');
  649. last_insert[1] = c;
  650. last_insert[2] = ESC;
  651. last_insert[3] = NUL;
  652.     /* Use the CTRL-V only when not entering a digit */
  653. last_insert_skip = isdigit(c) ? 1 : 0;
  654.     }
  655. }
  656. /*
  657.  * move cursor to start of line
  658.  * if flags & BL_WHITE move to first non-white
  659.  * if flags & BL_SOL move to first non-white if startofline is set,
  660.  *     otherwise keep "curswant" column
  661.  * if flags & BL_FIX don't leave the cursor on a NUL.
  662.  */
  663.     void
  664. beginline(flags)
  665.     int flags;
  666. {
  667.     if ((flags & BL_SOL) && !p_sol)
  668. coladvance(curwin->w_curswant);
  669.     else
  670.     {
  671. curwin->w_cursor.col = 0;
  672. if (flags & (BL_WHITE | BL_SOL))
  673. {
  674.     char_u  *ptr;
  675.     for (ptr = ml_get_curline(); vim_iswhite(*ptr)
  676.        && !((flags & BL_FIX) && ptr[1] == NUL); ++ptr)
  677. ++curwin->w_cursor.col;
  678. }
  679. curwin->w_set_curswant = TRUE;
  680.     }
  681. }
  682. /*
  683.  * oneright oneleft cursor_down cursor_up
  684.  *
  685.  * Move one char {right,left,down,up}.
  686.  * Return OK when successful, FAIL when we hit a line of file boundary.
  687.  */
  688.     int
  689. oneright()
  690. {
  691.     char_u *ptr;
  692.     ptr = ml_get_cursor();
  693.     if (*ptr++ == NUL || *ptr == NUL)
  694. return FAIL;
  695. #ifdef MULTI_BYTE
  696.     if (is_dbcs)
  697.     {
  698. /* if the character on the current cursor is a multi-byte character,
  699.    move two characters right */
  700. char_u *base;
  701. base = ml_get(curwin->w_cursor.lnum);
  702. if (*(ptr+1) != NUL && IsTrailByte(base, ptr))
  703.     ++curwin->w_cursor.col;
  704.     }
  705. #endif
  706.     curwin->w_set_curswant = TRUE;
  707.     ++curwin->w_cursor.col;
  708.     return OK;
  709. }
  710.     int
  711. oneleft()
  712. {
  713.     if (curwin->w_cursor.col == 0)
  714. return FAIL;
  715.     curwin->w_set_curswant = TRUE;
  716.     --curwin->w_cursor.col;
  717. #ifdef MULTI_BYTE
  718.     /* if the character on the left of the current cursor is a multi-byte
  719.      * character, move two characters left */
  720.     if (is_dbcs)
  721. AdjustCursorForMultiByteCharacter();
  722. #endif
  723.     return OK;
  724. }
  725.     int
  726. cursor_up(n, upd_topline)
  727.     long n;
  728.     int upd_topline;     /* When TRUE: update topline */
  729. {
  730.     if (n != 0)
  731.     {
  732. if (curwin->w_cursor.lnum <= 1)
  733.     return FAIL;
  734. if (n >= curwin->w_cursor.lnum)
  735.     curwin->w_cursor.lnum = 1;
  736. else
  737.     curwin->w_cursor.lnum -= n;
  738.     }
  739.     /* try to advance to the column we want to be at */
  740.     coladvance(curwin->w_curswant);
  741.     if (upd_topline)
  742. update_topline(); /* make sure curwin->w_topline is valid */
  743.     return OK;
  744. }
  745.     int
  746. cursor_down(n, upd_topline)
  747.     long    n;
  748.     int     upd_topline;     /* When TRUE: update topline */
  749. {
  750.     if (n != 0)
  751.     {
  752. if (curwin->w_cursor.lnum >= curbuf->b_ml.ml_line_count)
  753.     return FAIL;
  754. curwin->w_cursor.lnum += n;
  755. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
  756.     curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  757.     }
  758.     /* try to advance to the column we want to be at */
  759.     coladvance(curwin->w_curswant);
  760.     if (upd_topline)
  761. update_topline(); /* make sure curwin->w_topline is valid */
  762.     return OK;
  763. }
  764. /*
  765.  * Stuff the last inserted text in the read buffer.
  766.  * Last_insert actually is a copy of the redo buffer, so we
  767.  * first have to remove the command.
  768.  */
  769.     int
  770. stuff_inserted(c, count, no_esc)
  771.     int     c; /* Command character to be inserted */
  772.     long    count; /* Repeat this many times */
  773.     int     no_esc; /* Don't add an ESC at the end */
  774. {
  775.     char_u *esc_ptr;
  776.     char_u *ptr;
  777.     char_u *last_ptr;
  778.     char_u last = NUL;
  779.     ptr = get_last_insert();
  780.     if (ptr == NULL)
  781.     {
  782. EMSG(e_noinstext);
  783. return FAIL;
  784.     }
  785.     /* may want to stuff the command character, to start Insert mode */
  786.     if (c)
  787. stuffcharReadbuff(c);
  788.     if ((esc_ptr = (char_u *)vim_strrchr(ptr, ESC)) != NULL)
  789. *esc_ptr = NUL;     /* remove the ESC */
  790.     /* when the last char is either "0" or "^" it will be quoted if no ESC
  791.      * comes after it OR if it will inserted more than once and "ptr"
  792.      * starts with ^D. -- Acevedo
  793.      */
  794.     last_ptr = (esc_ptr ? esc_ptr : ptr + STRLEN(ptr)) - 1;
  795.     if (last_ptr >= ptr && (*last_ptr == '0' || *last_ptr == '^')
  796.     && (no_esc || (*ptr == Ctrl('D') && count > 1)))
  797.     {
  798. last = *last_ptr;
  799. *last_ptr = NUL;
  800.     }
  801.     do
  802.     {
  803. stuffReadbuff(ptr);
  804. /* a trailing "0" is inserted as "<C-V>048", "^" as "<C-V>^" */
  805. if (last)
  806.     stuffReadbuff((char_u *)(last == '0' ? "26048" : "26^"));
  807.     }
  808.     while (--count > 0);
  809.     if (last)
  810. *last_ptr = last;
  811.     if (esc_ptr != NULL)
  812. *esc_ptr = ESC;     /* put the ESC back */
  813.     /* may want to stuff a trailing ESC, to get out of Insert mode */
  814.     if (!no_esc)
  815. stuffcharReadbuff(ESC);
  816.     return OK;
  817. }
  818.     char_u *
  819. get_last_insert()
  820. {
  821.     if (last_insert == NULL)
  822. return NULL;
  823.     return last_insert + last_insert_skip;
  824. }
  825. /*
  826.  * Get last inserted string, and remove trailing <Esc>.
  827.  * Returns pointer to allocated memory (must be freed) or NULL.
  828.  */
  829.     char_u *
  830. get_last_insert_save()
  831. {
  832.     char_u *s;
  833.     int len;
  834.     if (last_insert == NULL)
  835. return NULL;
  836.     s = vim_strsave(last_insert + last_insert_skip);
  837.     if (s != NULL)
  838.     {
  839. len = STRLEN(s);
  840. if (len > 0 && s[len - 1] == ESC) /* remove trailing ESC */
  841.     s[len - 1] = NUL;
  842.     }
  843.     return s;
  844. }
  845. /*
  846.  * Check the word in front of the cursor for an abbreviation.
  847.  * Called when the non-id character "c" has been entered.
  848.  * When an abbreviation is recognized it is removed from the text and
  849.  * the replacement string is inserted in typebuf[], followed by "c".
  850.  */
  851.     static int
  852. echeck_abbr(c)
  853.     int c;
  854. {
  855.     if (p_paste || no_abbr)     /* no abbreviations or in paste mode */
  856. return FALSE;
  857.     return check_abbr(c, ml_get_curline(), curwin->w_cursor.col,
  858. curwin->w_cursor.lnum == Insstart.lnum ? Insstart.col : 0);
  859. }
  860. /*
  861.  * replace-stack functions
  862.  *
  863.  * When replacing characters, the replaced characters are remembered for each
  864.  * new character.  This is used to re-insert the old text when backspacing.
  865.  *
  866.  * There is a NUL headed list of characters for each character that is
  867.  * currently in the file after the insertion point.  When BS is used, one NUL
  868.  * headed list is put back for the deleted character.
  869.  *
  870.  * For a newline, there are two NUL headed lists.  One contains the characters
  871.  * that the NL replaced.  The extra one stores the characters after the cursor
  872.  * that were deleted (always white space).
  873.  *
  874.  * Replace_offset is normally 0, in which case replace_push will add a new
  875.  * character at the end of the stack.  If replace_offset is not 0, that many
  876.  * characters will be left on the stack above the newly inserted character.
  877.  */
  878. char_u *replace_stack = NULL;
  879. long replace_stack_nr = 0;     /* next entry in replace stack */
  880. long replace_stack_len = 0;     /* max. number of entries */
  881.     void
  882. replace_push(c)
  883.     int     c;     /* character that is replaced (NUL is none) */
  884. {
  885.     char_u  *p;
  886.     if (replace_stack_nr < replace_offset) /* nothing to do */
  887. return;
  888.     if (replace_stack_len <= replace_stack_nr)
  889.     {
  890. replace_stack_len += 50;
  891. p = lalloc(sizeof(char_u) * replace_stack_len, TRUE);
  892. if (p == NULL)     /* out of memory */
  893. {
  894.     replace_stack_len -= 50;
  895.     return;
  896. }
  897. if (replace_stack != NULL)
  898. {
  899.     mch_memmove(p, replace_stack,
  900.  (size_t)(replace_stack_nr * sizeof(char_u)));
  901.     vim_free(replace_stack);
  902. }
  903. replace_stack = p;
  904.     }
  905.     p = replace_stack + replace_stack_nr - replace_offset;
  906.     if (replace_offset)
  907. mch_memmove(p + 1, p, (size_t)(replace_offset * sizeof(char_u)));
  908.     *p = c;
  909.     ++replace_stack_nr;
  910. }
  911. /*
  912.  * call replace_push(c) with replace_offset set to the first NUL.
  913.  */
  914.     static void
  915. replace_push_off(c)
  916.     int     c;
  917. {
  918.     char_u *p;
  919.     p = replace_stack + replace_stack_nr;
  920.     for (replace_offset = 1; replace_offset < replace_stack_nr;
  921.      ++replace_offset)
  922. if (*--p == NUL)
  923.     break;
  924.     replace_push(c);
  925.     replace_offset = 0;
  926. }
  927. /*
  928.  * Pop one item from the replace stack.
  929.  * return -1 if stack empty
  930.  * return replaced character or NUL otherwise
  931.  */
  932.     static int
  933. replace_pop()
  934. {
  935.     if (replace_stack_nr == 0)
  936. return -1;
  937.     return (int)replace_stack[--replace_stack_nr];
  938. }
  939. /*
  940.  * Join the top two items on the replace stack.  This removes to "off"'th NUL
  941.  * encountered.
  942.  */
  943.     static void
  944. replace_join(off)
  945.     int     off; /* offset for which NUL to remove */
  946. {
  947.     int     i;
  948.     for (i = replace_stack_nr; --i >= 0; )
  949. if (replace_stack[i] == NUL && off-- <= 0)
  950. {
  951.     --replace_stack_nr;
  952.     mch_memmove(replace_stack + i, replace_stack + i + 1,
  953.       (size_t)(replace_stack_nr - i));
  954.     return;
  955. }
  956. }
  957. /*
  958.  * Pop characters from the replace stack until a NUL is found, and insert them
  959.  * before the cursor.  Can only be used in REPLACE mode.
  960.  */
  961.     static void
  962. replace_pop_ins()
  963. {
  964.     int     cc;
  965.     State = NORMAL; /* don't want REPLACE here */
  966.     while ((cc = replace_pop()) > 0)
  967.     {
  968. ins_char(cc);
  969. dec_cursor();
  970.     }
  971.     State = REPLACE;
  972. }
  973. /*
  974.  * make the replace stack empty
  975.  * (called when exiting replace mode)
  976.  */
  977.     static void
  978. replace_flush()
  979. {
  980.     vim_free(replace_stack);
  981.     replace_stack = NULL;
  982.     replace_stack_len = 0;
  983.     replace_stack_nr = 0;
  984. }
  985. /*
  986.  * Handle doing a BS for one character.
  987.  * cc < 0: replace stack empty, just move cursor
  988.  * cc == 0: character was inserted, delete it
  989.  * cc > 0: character was replace, put original back
  990.  */
  991.     static void
  992. replace_do_bs()
  993. {
  994.     int     cc;
  995.     cc = replace_pop();
  996.     if (cc > 0)
  997.     {
  998. pchar_cursor(cc);
  999. replace_pop_ins();
  1000.     }
  1001.     else if (cc == 0)
  1002. (void)del_char(FALSE);
  1003. }
  1004. #if defined(LISPINDENT) || defined(CINDENT)
  1005. /*
  1006.  * Re-indent the current line, based on the current contents of it and the
  1007.  * surrounding lines. Fixing the cursor position seems really easy -- I'm very
  1008.  * confused what all the part that handles Control-T is doing that I'm not.
  1009.  * "get_the_indent" should be get_c_indent or get_lisp_indent.
  1010.  */
  1011.     void
  1012. fixthisline(get_the_indent)
  1013.     int (*get_the_indent) __ARGS((void));
  1014. {
  1015.     change_indent(INDENT_SET, get_the_indent(), FALSE, 0);
  1016.     if (linewhite(curwin->w_cursor.lnum))
  1017. did_ai = TRUE;     /* delete the indent if the line stays empty */
  1018. }
  1019. #endif /* defined(LISPINDENT) || defined(CINDENT) */
  1020. #ifdef CINDENT
  1021. /*
  1022.  * return TRUE if 'cinkeys' contains the key "keytyped",
  1023.  * when == '*':     Only if key is preceded with '*' (indent before insert)
  1024.  * when == '!':     Only if key is prededed with '!' (don't insert)
  1025.  * when == ' ':     Only if key is not preceded with '*'(indent afterwards)
  1026.  *
  1027.  * If line_is_empty is TRUE accept keys with '0' before them.
  1028.  */
  1029.     int
  1030. in_cinkeys(keytyped, when, line_is_empty)
  1031.     int keytyped;
  1032.     int when;
  1033.     int line_is_empty;
  1034. {
  1035.     char_u  *look;
  1036.     int     try_match;
  1037.     char_u  *p;
  1038.     int     i;
  1039.     for (look = curbuf->b_p_cink; *look; )
  1040.     {
  1041. /*
  1042.  * Find out if we want to try a match with this key, depending on
  1043.  * 'when' and a '*' or '!' before the key.
  1044.  */
  1045. switch (when)
  1046. {
  1047.     case '*': try_match = (*look == '*'); break;
  1048.     case '!': try_match = (*look == '!'); break;
  1049.      default: try_match = (*look != '*'); break;
  1050. }
  1051. if (*look == '*' || *look == '!')
  1052.     ++look;
  1053. /*
  1054.  * If there is a '0', only accept a match if the line is empty.
  1055.  */
  1056. if (*look == '0')
  1057. {
  1058.     if (!line_is_empty)
  1059. try_match = FALSE;
  1060.     ++look;
  1061. }
  1062. /*
  1063.  * does it look like a control character?
  1064.  */
  1065. if (*look == '^' && look[1] >= '@' && look[1] <= '_')
  1066. {
  1067.     if (try_match && keytyped == Ctrl(look[1]))
  1068. return TRUE;
  1069.     look += 2;
  1070. }
  1071. /*
  1072.  * 'o' means "o" command, open forward.
  1073.  * 'O' means "O" command, open backward.
  1074.  */
  1075. else if (*look == 'o')
  1076. {
  1077.     if (try_match && keytyped == KEY_OPEN_FORW)
  1078. return TRUE;
  1079.     ++look;
  1080. }
  1081. else if (*look == 'O')
  1082. {
  1083.     if (try_match && keytyped == KEY_OPEN_BACK)
  1084. return TRUE;
  1085.     ++look;
  1086. }
  1087. /*
  1088.  * 'e' means to check for "else" at start of line and just before the
  1089.  * cursor.
  1090.  */
  1091. else if (*look == 'e')
  1092. {
  1093.     if (try_match && keytyped == 'e' && curwin->w_cursor.col >= 4)
  1094.     {
  1095. p = ml_get_curline();
  1096. if (skipwhite(p) == p + curwin->w_cursor.col - 4 &&
  1097. STRNCMP(p + curwin->w_cursor.col - 4, "else", 4) == 0)
  1098.     return TRUE;
  1099.     }
  1100.     ++look;
  1101. }
  1102. /*
  1103.  * ':' only causes an indent if it is at the end of a label or case
  1104.  * statement, or when it was before typing the ':' (to fix
  1105.  * class::method for C++).
  1106.  */
  1107. else if (*look == ':')
  1108. {
  1109.     if (try_match && keytyped == ':')
  1110.     {
  1111. p = ml_get_curline();
  1112. if (cin_iscase(p) || cin_isscopedecl(p) || cin_islabel(30))
  1113.     return TRUE;
  1114. if (curwin->w_cursor.col > 2
  1115. && p[curwin->w_cursor.col - 1] == ':'
  1116. && p[curwin->w_cursor.col - 2] == ':')
  1117. {
  1118.     p[curwin->w_cursor.col - 1] = ' ';
  1119.     i = (cin_iscase(p) || cin_isscopedecl(p)
  1120.   || cin_islabel(30));
  1121.     p = ml_get_curline();
  1122.     p[curwin->w_cursor.col - 1] = ':';
  1123.     if (i)
  1124. return TRUE;
  1125. }
  1126.     }
  1127.     ++look;
  1128. }
  1129. /*
  1130.  * Is it a key in <>, maybe?
  1131.  */
  1132. else if (*look == '<')
  1133. {
  1134.     if (try_match)
  1135.     {
  1136. /*
  1137.  * make up some named keys <o>, <O>, <e>, <0>, <>>, <<>, <*>
  1138.  * and <!> so that people can re-indent on o, O, e, 0, <, >, *
  1139.  * and ! keys if they really really want to.
  1140.  */
  1141. if (vim_strchr((char_u *)"<>!*oOe0", look[1]) != NULL &&
  1142.   keytyped == look[1])
  1143.     return TRUE;
  1144. if (keytyped == get_special_key_code(look + 1))
  1145.     return TRUE;
  1146.     }
  1147.     while (*look && *look != '>')
  1148. look++;
  1149.     while (*look == '>')
  1150. look++;
  1151. }
  1152. /*
  1153.  * ok, it's a boring generic character.
  1154.  */
  1155. else
  1156. {
  1157.     if (try_match && *look == keytyped)
  1158. return TRUE;
  1159.     ++look;
  1160. }
  1161. /*
  1162.  * Skip over ", ".
  1163.  */
  1164. look = skip_to_option_part(look);
  1165.     }
  1166.     return FALSE;
  1167. }
  1168. #endif /* CINDENT */
  1169. #if defined(RIGHTLEFT) || defined(PROTO)
  1170. /*
  1171.  * Map Hebrew keyboard when in hkmap mode.
  1172.  */
  1173.     int
  1174. hkmap(c)
  1175.     int c;
  1176. {
  1177.     if (p_hkmapp)   /* phonetic mapping, by Ilya Dogolazky */
  1178.     {
  1179. enum {hALEF=0, BET, GIMEL, DALET, HEI, VAV, ZAIN, HET, TET, IUD,
  1180.     KAFsofit, hKAF, LAMED, MEMsofit, MEM, NUNsofit, NUN, SAMEH, AIN,
  1181.     PEIsofit, PEI, ZADIsofit, ZADI, KOF, RESH, hSHIN, TAV};
  1182. static char_u map[26] =
  1183.     {(char_u)hALEF/*a*/, (char_u)BET  /*b*/, (char_u)hKAF    /*c*/,
  1184.      (char_u)DALET/*d*/, (char_u)-1   /*e*/, (char_u)PEIsofit/*f*/,
  1185.      (char_u)GIMEL/*g*/, (char_u)HEI  /*h*/, (char_u)IUD     /*i*/,
  1186.      (char_u)HET  /*j*/, (char_u)KOF  /*k*/, (char_u)LAMED   /*l*/,
  1187.      (char_u)MEM  /*m*/, (char_u)NUN  /*n*/, (char_u)SAMEH   /*o*/,
  1188.      (char_u)PEI  /*p*/, (char_u)-1   /*q*/, (char_u)RESH    /*r*/,
  1189.      (char_u)ZAIN /*s*/, (char_u)TAV  /*t*/, (char_u)TET     /*u*/,
  1190.      (char_u)VAV  /*v*/, (char_u)hSHIN/*w*/, (char_u)-1      /*x*/,
  1191.      (char_u)AIN  /*y*/, (char_u)ZADI /*z*/};
  1192. if (c == 'N' || c == 'M' || c == 'P' || c == 'C' || c == 'Z')
  1193.     return map[tolower(c) - 'a'] - 1 + p_aleph; /* '-1'='sofit' */
  1194. else if (c == 'x')
  1195.     return 'X';
  1196. else if (c == 'q')
  1197.     return '''; /* {geresh}={'} */
  1198. else if (c == 246)
  1199.     return ' ';  /* "o --> ' ' for a german keyboard */
  1200. else if (c == 228)
  1201.     return ' ';  /* "a --> ' '      -- / --        */
  1202. else if (c == 252)
  1203.     return ' ';  /* "u --> ' '      -- / --        */
  1204. else if ('a' <= c && c <= 'z')
  1205.     return map[c - 'a'] + p_aleph;
  1206. else
  1207.     return c;
  1208.     }
  1209.     else
  1210.     {
  1211. switch (c)
  1212. {
  1213.     case '`': return ';';
  1214.     case '/': return '.';
  1215.     case ''': return ',';
  1216.     case 'q': return '/';
  1217.     case 'w': return ''';
  1218. /* Hebrew letters - set offset from 'a' */
  1219.     case ',': c = '{'; break;
  1220.     case '.': c = 'v'; break;
  1221.     case ';': c = 't'; break;
  1222.     default: {
  1223.  static char str[] = "zqbcxlsjphmkwonu ydafe rig";
  1224.  if (c < 'a' || c > 'z')
  1225.      return c;
  1226.  c = str[c - 'a'];
  1227.  break;
  1228.      }
  1229. }
  1230. return c - 'a' + p_aleph;
  1231.     }
  1232. }
  1233. #endif
  1234.     static int
  1235. ins_reg()
  1236. {
  1237.     int     need_redraw = FALSE;
  1238.     int     cc;
  1239.     int     literally = FALSE;
  1240.     /*
  1241.      * If we are going to wait for a character, show a '"'.
  1242.      */
  1243.     if (redrawing() && !char_avail())
  1244.     {
  1245. edit_putchar('"', TRUE);
  1246. #ifdef SHOWCMD
  1247. add_to_showcmd_c(Ctrl('R'));
  1248. #endif
  1249.     }
  1250. #ifdef USE_GUI_WIN32
  1251.     dont_scroll = TRUE; /* disallow scrolling here */
  1252. #endif
  1253.     /*
  1254.      * Don't map the register name. This also prevents the mode message to be
  1255.      * deleted when ESC is hit.
  1256.      */
  1257.     ++no_mapping;
  1258.     cc = vgetc();
  1259.     if (cc == Ctrl('R'))
  1260.     {
  1261. literally = TRUE;
  1262. cc = vgetc();
  1263.     }
  1264.     --no_mapping;
  1265. #ifdef HAVE_LANGMAP
  1266.     LANGMAP_ADJUST(cc, TRUE);
  1267. #endif
  1268. #ifdef WANT_EVAL
  1269.     /*
  1270.      * Don't call u_sync while getting the expression,
  1271.      * evaluating it or giving an error message for it!
  1272.      */
  1273.     ++no_u_sync;
  1274.     if (cc == '=')
  1275. cc = get_expr_register();
  1276.     if (cc == NUL)
  1277. need_redraw = TRUE; /* remove the '"' */
  1278.     else
  1279.     {
  1280. #endif
  1281. if (insert_reg(cc, literally) == FAIL)
  1282. {
  1283.     beep_flush();
  1284.     need_redraw = TRUE; /* remove the '"' */
  1285. }
  1286. #ifdef WANT_EVAL
  1287.     }
  1288.     --no_u_sync;
  1289. #endif
  1290. #ifdef SHOWCMD
  1291.     clear_showcmd();
  1292. #endif
  1293.     /* If the inserted register is empty, we need to remove the '"' */
  1294.     if (stuff_empty())
  1295. need_redraw = TRUE;
  1296.     return need_redraw;
  1297. }
  1298. /*
  1299.  * Handle ESC in insert mode.
  1300.  * Returns TRUE when leaving insert mode, FALSE when going to repeat the
  1301.  * insert.
  1302.  */
  1303.     static int
  1304. ins_esc(count, need_redraw, cmdchar)
  1305.     long *count;
  1306.     int need_redraw;
  1307.     int cmdchar;
  1308. {
  1309.     int  temp;
  1310.     static int  disabled_redraw = FALSE;
  1311. #if defined(MULTI_BYTE_IME) && defined(USE_GUI_WIN32)
  1312.     ImeSetEnglishMode();
  1313. #endif
  1314.     temp = curwin->w_cursor.col;
  1315.     if (disabled_redraw)
  1316.     {
  1317. --RedrawingDisabled;
  1318. disabled_redraw = FALSE;
  1319.     }
  1320.     if (!arrow_used)
  1321.     {
  1322. /*
  1323.  * Don't append the ESC for "r<CR>".
  1324.  */
  1325. if (cmdchar != 'r')
  1326.     AppendToRedobuff(ESC_STR);
  1327. /*
  1328.  * Repeating insert may take a long time.  Check for
  1329.  * interrupt now and then.
  1330.  */
  1331. if (*count)
  1332. {
  1333.     line_breakcheck();
  1334.     if (got_int)
  1335. *count = 0;
  1336. }
  1337. if (--*count > 0) /* repeat what was typed */
  1338. {
  1339.     (void)start_redo_ins();
  1340.     ++RedrawingDisabled;
  1341.     disabled_redraw = TRUE;
  1342.     return FALSE; /* repeat the insert */
  1343. }
  1344. stop_insert(&curwin->w_cursor);
  1345. if (dollar_vcol)
  1346. {
  1347.     dollar_vcol = 0;
  1348.     /* may have to redraw status line if this was the
  1349.      * first change, show "[+]" */
  1350.     if (curwin->w_redr_status == TRUE)
  1351. redraw_later(NOT_VALID);
  1352.     else
  1353. need_redraw = TRUE;
  1354. }
  1355.     }
  1356.     if (need_redraw)
  1357. update_screenline();
  1358.     /* When an autoindent was removed, curswant stays after the
  1359.      * indent */
  1360.     if (!restart_edit && (colnr_t)temp == curwin->w_cursor.col)
  1361. curwin->w_set_curswant = TRUE;
  1362.     /*
  1363.      * The cursor should end up on the last inserted character.
  1364.      */
  1365.     if (       curwin->w_cursor.col != 0
  1366.     && (!restart_edit
  1367. || gchar_cursor() == NUL)
  1368. #ifdef RIGHTLEFT
  1369.     && !revins_on
  1370. #endif
  1371.       )
  1372. --curwin->w_cursor.col;
  1373.     /* need to position cursor again (e.g. when on a TAB ) */
  1374.     changed_cline_bef_curs();
  1375.     State = NORMAL;
  1376. #ifdef USE_MOUSE
  1377.     setmouse();
  1378. #endif
  1379. #ifdef CURSOR_SHAPE
  1380.     ui_cursor_shape(); /* may show different cursor shape */
  1381. #endif
  1382.     /*
  1383.      * When recording or for CTRL-O, need to display the new mode.
  1384.      * Otherwise remove the mode message.
  1385.      */
  1386.     if (Recording || restart_edit)
  1387. showmode();
  1388.     else if (p_smd)
  1389. MSG("");
  1390.     return TRUE;     /* exit Insert mode */
  1391. }
  1392. #ifdef RIGHTLEFT
  1393. /*
  1394.  * Toggle language: khmap and revins_on.
  1395.  * Move to end of reverse inserted text.
  1396.  */
  1397.     static void
  1398. ins_ctrl_()
  1399. {
  1400.     if (revins_on && revins_chars && revins_scol >= 0)
  1401.     {
  1402. while (gchar_cursor() != NUL && revins_chars--)
  1403.     ++curwin->w_cursor.col;
  1404.     }
  1405.     p_ri = !p_ri;
  1406.     revins_on = (State == INSERT && p_ri);
  1407.     if (revins_on)
  1408.     {
  1409. revins_scol = curwin->w_cursor.col;
  1410. revins_legal++;
  1411. revins_chars = 0;
  1412. undisplay_dollar();
  1413.     }
  1414.     else
  1415. revins_scol = -1;
  1416. #ifdef FKMAP
  1417.     if (p_altkeymap)
  1418.     {
  1419. /*
  1420.  * to be consistent also for redo command, using '.'
  1421.  * set arrow_used to true and stop it - causing to redo
  1422.  * characters entered in one mode (normal/reverse insert).
  1423.  */
  1424. arrow_used = TRUE;
  1425. stop_arrow();
  1426. p_fkmap = curwin->w_p_rl ^ p_ri;
  1427. if (p_fkmap && p_ri)
  1428.     State = INSERT;
  1429.     }
  1430.     else
  1431. #endif
  1432. p_hkmap = curwin->w_p_rl ^ p_ri;    /* be consistent! */
  1433.     showmode();
  1434. }
  1435. #endif
  1436. /*
  1437.  * If the cursor is on an indent, ^T/^D insert/delete one
  1438.  * shiftwidth. Otherwise ^T/^D behave like a "<<" or ">>".
  1439.  * Always round the indent to 'shiftwith', this is compatible
  1440.  * with vi.  But vi only supports ^T and ^D after an
  1441.  * autoindent, we support it everywhere.
  1442.  */
  1443.     static void
  1444. ins_shift(c, lastc)
  1445.     int     c;
  1446.     int     lastc;
  1447. {
  1448.     stop_arrow();
  1449.     AppendCharToRedobuff(c);
  1450.     /*
  1451.      * 0^D and ^^D: remove all indent.
  1452.      */
  1453.     if ((lastc == '0' || lastc == '^') && curwin->w_cursor.col)
  1454.     {
  1455. --curwin->w_cursor.col;
  1456. (void)del_char(FALSE); /* delete the '^' or '0' */
  1457. /* In Replace mode, restore the characters that '^' or '0' replaced. */
  1458. if (State == REPLACE)
  1459.     replace_pop_ins();
  1460. if (lastc == '^')
  1461.     old_indent = get_indent(); /* remember curr. indent */
  1462. change_indent(INDENT_SET, 0, TRUE, 0);
  1463.     }
  1464.     else
  1465. change_indent(c == Ctrl('D') ? INDENT_DEC : INDENT_INC, 0, TRUE, 0);
  1466.     did_ai = FALSE;
  1467. #ifdef SMARTINDENT
  1468.     did_si = FALSE;
  1469.     can_si = FALSE;
  1470.     can_si_back = FALSE;
  1471. #endif
  1472. #ifdef CINDENT
  1473.     can_cindent = FALSE; /* no cindenting after ^D or ^T */
  1474. #endif
  1475. }
  1476.     static void
  1477. ins_del()
  1478. {
  1479.     int     temp;
  1480.     stop_arrow();
  1481.     if (gchar_cursor() == NUL) /* delete newline */
  1482.     {
  1483. temp = curwin->w_cursor.col;
  1484. if (!p_bs /* only if 'bs' set */
  1485. || u_save((linenr_t)(curwin->w_cursor.lnum - 1),
  1486.     (linenr_t)(curwin->w_cursor.lnum + 2)) == FAIL
  1487. || do_join(FALSE, TRUE) == FAIL)
  1488.     beep_flush();
  1489. else
  1490. {
  1491.     curwin->w_cursor.col = temp;
  1492.     redraw_later(VALID_TO_CURSCHAR);
  1493. }
  1494.     }
  1495.     else if (del_char(FALSE) == FAIL)/* delete char under cursor */
  1496. beep_flush();
  1497.     did_ai = FALSE;
  1498. #ifdef SMARTINDENT
  1499.     did_si = FALSE;
  1500.     can_si = FALSE;
  1501.     can_si_back = FALSE;
  1502. #endif
  1503.     AppendCharToRedobuff(K_DEL);
  1504. }
  1505. /*
  1506.  * Handle Backspace, delete-word and delete-line in Insert mode.
  1507.  * Return TRUE when backspace was actually used.
  1508.  */
  1509.     static int
  1510. ins_bs(c, mode, inserted_space_p)
  1511.     int c;
  1512.     int mode;
  1513.     int *inserted_space_p;
  1514. {
  1515.     linenr_t lnum;
  1516.     int cc;
  1517.     int temp = 0;     /* init for GCC */
  1518.     colnr_t mincol;
  1519.     int did_backspace = FALSE;
  1520.     int in_indent;
  1521.     /*
  1522.      * can't delete anything in an empty file
  1523.      * can't backup past first character in buffer
  1524.      * can't backup past starting point unless 'backspace' > 1
  1525.      * can backup to a previous line if 'backspace' == 0
  1526.      */
  1527.     if (       bufempty()
  1528.     || (
  1529. #ifdef RIGHTLEFT
  1530. !revins_on &&
  1531. #endif
  1532. ((curwin->w_cursor.lnum == 1 && curwin->w_cursor.col <= 0)
  1533.     || (p_bs < 2
  1534. && (arrow_used
  1535.     || (curwin->w_cursor.lnum == Insstart.lnum
  1536. && curwin->w_cursor.col <= Insstart.col)
  1537.     || (curwin->w_cursor.col <= 0 && p_bs == 0))))))
  1538.     {
  1539. beep_flush();
  1540. return FALSE;
  1541.     }
  1542.     stop_arrow();
  1543.     in_indent = inindent(0);
  1544. #ifdef CINDENT
  1545.     if (in_indent)
  1546. can_cindent = FALSE;
  1547. #endif
  1548. #ifdef RIGHTLEFT
  1549.     if (revins_on)     /* put cursor after last inserted char */
  1550. inc_cursor();
  1551. #endif
  1552.     /*
  1553.      * delete newline!
  1554.      */
  1555.     if (curwin->w_cursor.col <= 0)
  1556.     {
  1557. lnum = Insstart.lnum;
  1558. if (curwin->w_cursor.lnum == Insstart.lnum
  1559. #ifdef RIGHTLEFT
  1560. || revins_on
  1561. #endif
  1562.     )
  1563. {
  1564.     if (u_save((linenr_t)(curwin->w_cursor.lnum - 2),
  1565.        (linenr_t)(curwin->w_cursor.lnum + 1)) == FAIL)
  1566. return FALSE;
  1567.     --Insstart.lnum;
  1568.     Insstart.col = 0;
  1569. }
  1570. /*
  1571.  * In replace mode:
  1572.  * cc < 0: NL was inserted, delete it
  1573.  * cc >= 0: NL was replaced, put original characters back
  1574.  */
  1575. cc = -1;
  1576. if (State == REPLACE)
  1577.     cc = replace_pop();     /* returns -1 if NL was inserted */
  1578. /*
  1579.  * In replace mode, in the line we started replacing, we only move the
  1580.  * cursor.
  1581.  */
  1582. if (State != REPLACE || curwin->w_cursor.lnum > lnum)
  1583. {
  1584.     temp = gchar_cursor(); /* remember current char */
  1585.     --curwin->w_cursor.lnum;
  1586.     (void)do_join(FALSE, TRUE);
  1587.     redraw_later(VALID_TO_CURSCHAR);
  1588.     if (temp == NUL && gchar_cursor() != NUL)
  1589. ++curwin->w_cursor.col;
  1590.     /*
  1591.      * In REPLACE mode we have to put back the text that was replace
  1592.      * by the NL. On the replace stack is first a NUL-terminated
  1593.      * sequence of characters that were deleted and then the
  1594.      * characters that NL replaced.
  1595.      */
  1596.     if (State == REPLACE)
  1597.     {
  1598. /*
  1599.  * Do the next ins_char() in NORMAL state, to
  1600.  * prevent ins_char() from replacing characters and
  1601.  * avoiding showmatch().
  1602.  */
  1603. State = NORMAL;
  1604. /*
  1605.  * restore characters (blanks) deleted after cursor
  1606.  */
  1607. while (cc > 0)
  1608. {
  1609.     temp = curwin->w_cursor.col;
  1610.     ins_char(cc);
  1611.     curwin->w_cursor.col = temp;
  1612.     cc = replace_pop();
  1613. }
  1614. /* restore the characters that NL replaced */
  1615. replace_pop_ins(); /* will set State back to REPLACE */
  1616.     }
  1617. }
  1618. else
  1619.     dec_cursor();
  1620. did_ai = FALSE;
  1621.     }
  1622.     else
  1623.     {
  1624. /*
  1625.  * Delete character(s) before the cursor.
  1626.  */
  1627. #ifdef RIGHTLEFT
  1628. if (revins_on) /* put cursor on last inserted char */
  1629.     dec_cursor();
  1630. #endif
  1631. mincol = 0;
  1632. /* keep indent */
  1633. if (mode == BACKSPACE_LINE && curbuf->b_p_ai
  1634. #ifdef RIGHTLEFT
  1635. && !revins_on
  1636. #endif
  1637.     )
  1638. {
  1639.     temp = curwin->w_cursor.col;
  1640.     beginline(BL_WHITE);
  1641.     if (curwin->w_cursor.col < (colnr_t)temp)
  1642. mincol = curwin->w_cursor.col;
  1643.     curwin->w_cursor.col = temp;
  1644. }
  1645. /*
  1646.  * Handle deleting one 'shiftwidth' or 'softtabstop'.
  1647.  */
  1648. if (    mode == BACKSPACE_CHAR
  1649. && ((p_sta && in_indent)
  1650.     || (curbuf->b_p_sts
  1651. && (*(ml_get_cursor() - 1) == TAB
  1652.     || (*(ml_get_cursor() - 1) == ' '
  1653. && (!*inserted_space_p
  1654.     || arrow_used))))))
  1655. {
  1656.     int ts;
  1657.     colnr_t vcol;
  1658.     int want_vcol;
  1659.     int extra = 0;
  1660.     *inserted_space_p = FALSE;
  1661.     if (p_sta)
  1662. ts = curbuf->b_p_sw;
  1663.     else
  1664. ts = curbuf->b_p_sts;
  1665.     /* compute the virtual column where we want to be */
  1666.     getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
  1667.     want_vcol = ((vcol - 1) / ts) * ts;
  1668.     /* delete characters until we are at or before want_vcol */
  1669.     while ((int)vcol > want_vcol
  1670.     && (cc = *(ml_get_cursor() - 1), vim_iswhite(cc)))
  1671.     {
  1672. dec_cursor();
  1673. /* TODO: calling getvcol() each time is slow */
  1674. getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
  1675. if (State == REPLACE)
  1676. {
  1677.     /* don't delete characters before the insert point when in
  1678.      * Replace mode */
  1679.     if (curwin->w_cursor.lnum != Insstart.lnum
  1680.     || curwin->w_cursor.col >= Insstart.col)
  1681.     {
  1682. if ((int)vcol < want_vcol)
  1683. {
  1684.     (void)del_char(FALSE);
  1685.     extra = 2; /* don't pop too much */
  1686. }
  1687. else
  1688.     replace_do_bs();
  1689.     }
  1690. }
  1691. else
  1692.     (void)del_char(FALSE);
  1693.     }
  1694.     /* insert extra spaces until we are at want_vcol */
  1695.     while ((int)vcol < want_vcol)
  1696.     {
  1697. ins_str((char_u *)" ");
  1698. if (State == REPLACE && extra <= 1)
  1699. {
  1700.     if (extra)
  1701. replace_push_off(NUL);
  1702.     else
  1703. replace_push(NUL);
  1704. }
  1705. getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL);
  1706. if (extra == 2)
  1707.     extra = 1;
  1708.     }
  1709. }
  1710. /*
  1711.  * Delete upto starting point, start of line or previous word.
  1712.  */
  1713. else do
  1714. {
  1715. #ifdef RIGHTLEFT
  1716.     if (!revins_on) /* put cursor on char to be deleted */
  1717. #endif
  1718. dec_cursor();
  1719.     /* start of word? */
  1720.     if (mode == BACKSPACE_WORD && !vim_isspace(gchar_cursor()))
  1721.     {
  1722. mode = BACKSPACE_WORD_NOT_SPACE;
  1723. temp = vim_iswordc(gchar_cursor());
  1724.     }
  1725.     /* end of word? */
  1726.     else if (mode == BACKSPACE_WORD_NOT_SPACE
  1727.     && (vim_isspace(cc = gchar_cursor())
  1728.     || vim_iswordc(cc) != temp))
  1729.     {
  1730. #ifdef RIGHTLEFT
  1731. if (!revins_on)
  1732. #endif
  1733.     inc_cursor();
  1734. #ifdef RIGHTLEFT
  1735. else if (State == REPLACE)
  1736.     dec_cursor();
  1737. #endif
  1738. break;
  1739.     }
  1740.     if (State == REPLACE)
  1741. replace_do_bs();
  1742.     else  /* State != REPLACE */
  1743.     {
  1744. (void)del_char(FALSE);
  1745. #ifdef RIGHTLEFT
  1746. if (revins_chars)
  1747. {
  1748.     revins_chars--;
  1749.     revins_legal++;
  1750. }
  1751. if (revins_on && gchar_cursor() == NUL)
  1752.     break;
  1753. #endif
  1754.     }
  1755.     /* Just a single backspace?: */
  1756.     if (mode == BACKSPACE_CHAR)
  1757. break;
  1758. } while (
  1759. #ifdef RIGHTLEFT
  1760. revins_on ||
  1761. #endif
  1762. (curwin->w_cursor.col > mincol &&
  1763. (curwin->w_cursor.lnum != Insstart.lnum ||
  1764. curwin->w_cursor.col != Insstart.col)));
  1765. did_backspace = TRUE;
  1766.     }
  1767. #ifdef SMARTINDENT
  1768.     did_si = FALSE;
  1769.     can_si = FALSE;
  1770.     can_si_back = FALSE;
  1771. #endif
  1772.     if (curwin->w_cursor.col <= 1)
  1773. did_ai = FALSE;
  1774.     /*
  1775.      * It's a little strange to put backspaces into the redo
  1776.      * buffer, but it makes auto-indent a lot easier to deal
  1777.      * with.
  1778.      */
  1779.     AppendCharToRedobuff(c);
  1780.     /* If deleted before the insertion point, adjust it */
  1781.     if (curwin->w_cursor.lnum == Insstart.lnum
  1782.        && curwin->w_cursor.col < Insstart.col)
  1783. Insstart.col = curwin->w_cursor.col;
  1784.     return did_backspace;
  1785. }
  1786. #ifdef USE_MOUSE
  1787.     static void
  1788. ins_mouse(c)
  1789.     int     c;
  1790. {
  1791.     FPOS tpos;
  1792. # ifdef USE_GUI
  1793.     /* When GUI is active, also move/paste when 'mouse' is empty */
  1794.     if (!gui.in_use)
  1795. # endif
  1796. if (!mouse_has(MOUSE_INSERT))
  1797.     return;
  1798.     undisplay_dollar();
  1799.     tpos = curwin->w_cursor;
  1800.     if (do_mouse(NULL, c, BACKWARD, 1L, 0))
  1801.     {
  1802. start_arrow(&tpos);
  1803. # ifdef CINDENT
  1804. can_cindent = TRUE;
  1805. # endif
  1806.     }
  1807.     /* redraw status lines (in case another window became active) */
  1808.     redraw_statuslines();
  1809. }
  1810. #endif
  1811. #ifdef USE_GUI
  1812.     void
  1813. ins_scroll()
  1814. {
  1815.     FPOS tpos;
  1816.     undisplay_dollar();
  1817.     tpos = curwin->w_cursor;
  1818.     if (gui_do_scroll())
  1819.     {
  1820. start_arrow(&tpos);
  1821. # ifdef CINDENT
  1822. can_cindent = TRUE;
  1823. # endif
  1824.     }
  1825. }
  1826.     void
  1827. ins_horscroll()
  1828. {
  1829.     FPOS tpos;
  1830.     undisplay_dollar();
  1831.     tpos = curwin->w_cursor;
  1832.     if (gui_do_horiz_scroll())
  1833.     {
  1834. start_arrow(&tpos);
  1835. #ifdef CINDENT
  1836. can_cindent = TRUE;
  1837. #endif
  1838.     }
  1839. }
  1840. #endif
  1841.     static void
  1842. ins_left()
  1843. {
  1844.     FPOS tpos;
  1845.     undisplay_dollar();
  1846.     tpos = curwin->w_cursor;
  1847.     if (oneleft() == OK)
  1848.     {
  1849. start_arrow(&tpos);
  1850. #ifdef RIGHTLEFT
  1851. /* If exit reversed string, position is fixed */
  1852. if (revins_scol != -1 && (int)curwin->w_cursor.col >= revins_scol)
  1853.     revins_legal++;
  1854. revins_chars++;
  1855. #endif
  1856.     }
  1857.     /*
  1858.      * if 'whichwrap' set for cursor in insert mode may go to
  1859.      * previous line
  1860.      */
  1861.     else if (vim_strchr(p_ww, '[') != NULL && curwin->w_cursor.lnum > 1)
  1862.     {
  1863. start_arrow(&tpos);
  1864. --(curwin->w_cursor.lnum);
  1865. coladvance(MAXCOL);
  1866. curwin->w_set_curswant = TRUE; /* so we stay at the end */
  1867.     }
  1868.     else
  1869. beep_flush();
  1870. }
  1871.     static void
  1872. ins_home()
  1873. {
  1874.     FPOS tpos;
  1875.     undisplay_dollar();
  1876.     tpos = curwin->w_cursor;
  1877.     if ((mod_mask & MOD_MASK_CTRL))
  1878. curwin->w_cursor.lnum = 1;
  1879.     curwin->w_cursor.col = 0;
  1880.     curwin->w_curswant = 0;
  1881.     start_arrow(&tpos);
  1882. }
  1883.     static void
  1884. ins_end()
  1885. {
  1886.     FPOS tpos;
  1887.     undisplay_dollar();
  1888.     tpos = curwin->w_cursor;
  1889.     if ((mod_mask & MOD_MASK_CTRL))
  1890. curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  1891.     coladvance(MAXCOL);
  1892.     curwin->w_curswant = MAXCOL;
  1893.     start_arrow(&tpos);
  1894. }
  1895.     static void
  1896. ins_s_left()
  1897. {
  1898.     undisplay_dollar();
  1899.     if (curwin->w_cursor.lnum > 1 || curwin->w_cursor.col > 0)
  1900.     {
  1901. start_arrow(&curwin->w_cursor);
  1902. (void)bck_word(1L, 0, FALSE);
  1903.     }
  1904.     else
  1905. beep_flush();
  1906. }
  1907.     static void
  1908. ins_right()
  1909. {
  1910.     undisplay_dollar();
  1911.     if (gchar_cursor() != NUL)
  1912.     {
  1913. start_arrow(&curwin->w_cursor);
  1914. #ifdef MULTI_BYTE
  1915. if (is_dbcs)
  1916. {
  1917.     char_u *p = ml_get_pos(&curwin->w_cursor);
  1918.     if (IsLeadByte(p[0]) && p[1] != NUL)
  1919. ++curwin->w_cursor.col;
  1920. }
  1921. #endif
  1922. curwin->w_set_curswant = TRUE;
  1923. ++curwin->w_cursor.col;
  1924. #ifdef RIGHTLEFT
  1925. revins_legal++;
  1926. if (revins_chars)
  1927.     revins_chars--;
  1928. #endif
  1929.     }
  1930.     /* if 'whichwrap' set for cursor in insert mode, may move the
  1931.      * cursor to the next line */
  1932.     else if (vim_strchr(p_ww, ']') != NULL
  1933.     && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
  1934.     {
  1935. start_arrow(&curwin->w_cursor);
  1936. curwin->w_set_curswant = TRUE;
  1937. ++curwin->w_cursor.lnum;
  1938. curwin->w_cursor.col = 0;
  1939.     }
  1940.     else
  1941. beep_flush();
  1942. }
  1943.     static void
  1944. ins_s_right()
  1945. {
  1946.     undisplay_dollar();
  1947.     if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count
  1948.     || gchar_cursor() != NUL)
  1949.     {
  1950. start_arrow(&curwin->w_cursor);
  1951. (void)fwd_word(1L, 0, 0);
  1952.     }
  1953.     else
  1954. beep_flush();
  1955. }
  1956.     static void
  1957. ins_up()
  1958. {
  1959.     FPOS tpos;
  1960.     linenr_t old_topline;
  1961.     undisplay_dollar();
  1962.     tpos = curwin->w_cursor;
  1963.     old_topline = curwin->w_topline;
  1964.     if (cursor_up(1L, TRUE) == OK)
  1965.     {
  1966. if (old_topline != curwin->w_topline)
  1967.     update_screen(VALID);
  1968. start_arrow(&tpos);
  1969. #ifdef CINDENT
  1970. can_cindent = TRUE;
  1971. #endif
  1972.     }
  1973.     else
  1974. beep_flush();
  1975. }
  1976.     static void
  1977. ins_pageup()
  1978. {
  1979.     FPOS tpos;
  1980.     undisplay_dollar();
  1981.     tpos = curwin->w_cursor;
  1982.     if (onepage(BACKWARD, 1L) == OK)
  1983.     {
  1984. start_arrow(&tpos);
  1985. #ifdef CINDENT
  1986. can_cindent = TRUE;
  1987. #endif
  1988.     }
  1989.     else
  1990. beep_flush();
  1991. }
  1992.     static void
  1993. ins_down()
  1994. {
  1995.     FPOS tpos;
  1996.     linenr_t old_topline = curwin->w_topline;
  1997.     undisplay_dollar();
  1998.     tpos = curwin->w_cursor;
  1999.     if (cursor_down(1L, TRUE) == OK)
  2000.     {
  2001. if (old_topline != curwin->w_topline)
  2002.     update_screen(VALID);
  2003. start_arrow(&tpos);
  2004. #ifdef CINDENT
  2005. can_cindent = TRUE;
  2006. #endif
  2007.     }
  2008.     else
  2009. beep_flush();
  2010. }
  2011.     static void
  2012. ins_pagedown()
  2013. {
  2014.     FPOS tpos;
  2015.     undisplay_dollar();
  2016.     tpos = curwin->w_cursor;
  2017.     if (onepage(FORWARD, 1L) == OK)
  2018.     {
  2019. start_arrow(&tpos);
  2020. #ifdef CINDENT
  2021. can_cindent = TRUE;
  2022. #endif
  2023.     }
  2024.     else
  2025. beep_flush();
  2026. }
  2027. /*
  2028.  * Handle TAB in Insert or Replace mode.
  2029.  * Return TRUE when the TAB needs to be inserted like a normal character.
  2030.  */
  2031.     static int
  2032. ins_tab()
  2033. {
  2034.     int     i;
  2035.     int     temp;
  2036.     if (Insstart_blank_vcol == MAXCOL && curwin->w_cursor.lnum == Insstart.lnum)
  2037. Insstart_blank_vcol = get_nolist_virtcol();
  2038.     if (echeck_abbr(TAB + ABBR_OFF))
  2039. return FALSE;
  2040.     i = inindent(0);
  2041. #ifdef CINDENT
  2042.     if (i)
  2043. can_cindent = FALSE;
  2044. #endif
  2045.     /*
  2046.      * When nothing special, insert TAB like a normal character
  2047.      */
  2048.     if (!curbuf->b_p_et && !(p_sta && i) && !curbuf->b_p_sts)
  2049. return TRUE;
  2050.     stop_arrow();
  2051.     did_ai = FALSE;
  2052. #ifdef SMARTINDENT
  2053.     did_si = FALSE;
  2054.     can_si = FALSE;
  2055.     can_si_back = FALSE;
  2056. #endif
  2057.     AppendToRedobuff((char_u *)"t");
  2058.     if (p_sta && i)     /* insert tab in indent */
  2059.     {
  2060. if (State == REPLACE)     /* delete a char first */
  2061. {
  2062.     i = gchar_cursor();
  2063.     if (i)
  2064. del_char(FALSE);
  2065. }
  2066. change_indent(INDENT_INC, 0, TRUE, i);
  2067. return FALSE;
  2068.     }
  2069.     /*
  2070.      * p_et or p_sts is set: expand a tab into spaces
  2071.      */
  2072.     if (curbuf->b_p_sts)
  2073. temp = (int)curbuf->b_p_sts;
  2074.     else
  2075. temp = (int)curbuf->b_p_ts;
  2076.     temp -= get_nolist_virtcol() % temp;
  2077.     /*
  2078.      * Insert the first space with ins_char(). It will delete one char in
  2079.      * replace mode.  Insert the rest with ins_str(); it will not delete any
  2080.      * chars.
  2081.      */
  2082.     ins_char(' ');
  2083.     while (--temp)
  2084.     {
  2085. ins_str((char_u *)" ");
  2086. if (State == REPLACE)     /* no char replaced */
  2087.     replace_push(NUL);
  2088.     }
  2089.     /*
  2090.      * For 'softtabstop': Replace a number of spaces by a TAB, if possible.
  2091.      */
  2092.     if (curbuf->b_p_sts && !curbuf->b_p_et)
  2093.     {
  2094. char_u     *ptr;
  2095. FPOS     fpos;
  2096. colnr_t     want_vcol, vcol, tab_vcol;
  2097. int     did_change = FALSE;
  2098. int     ts = curbuf->b_p_ts;
  2099. /* find first white before the cursor */
  2100. ptr = ml_get_cursor();
  2101. fpos = curwin->w_cursor;
  2102. while (fpos.col > 0 && vim_iswhite(ptr[-1]))
  2103. {
  2104.     --fpos.col;
  2105.     --ptr;
  2106. }
  2107. /* In Replace mode, don't change characters before the insert point. */
  2108. if (State == REPLACE && fpos.lnum == Insstart.lnum
  2109.    && fpos.col < Insstart.col)
  2110. {
  2111.     ptr += Insstart.col - fpos.col;
  2112.     fpos.col = Insstart.col;
  2113. }
  2114. /* compute virtual column numbers of first white and cursor */
  2115. getvcol(curwin, &fpos, &vcol, NULL, NULL);
  2116. getvcol(curwin, &curwin->w_cursor, &want_vcol, NULL, NULL);
  2117. /* use as many TABs as possible */
  2118. tab_vcol = (want_vcol / ts) * ts;
  2119. while (vcol < tab_vcol)
  2120. {
  2121.     if (*ptr != TAB)
  2122.     {
  2123. *ptr = TAB;
  2124. did_change = TRUE;
  2125.     }
  2126.     ++fpos.col;
  2127.     ++ptr;
  2128.     vcol = ((vcol + ts) / ts) * ts;
  2129. }
  2130. if (did_change)
  2131. {
  2132.     /* may need to delete a number of the following spaces */
  2133.     i = want_vcol - vcol;
  2134.     ptr += i;
  2135.     fpos.col += i;
  2136.     i = curwin->w_cursor.col - fpos.col;
  2137.     if (i > 0)
  2138.     {
  2139. mch_memmove(ptr, ptr + i, STRLEN(ptr + i) + 1);
  2140. /* correct replace stack. */
  2141. if (State == REPLACE)
  2142.     for (temp = i; --temp >= 0; )
  2143. replace_join(want_vcol - vcol);
  2144.     }
  2145.     curwin->w_cursor.col -= i;
  2146. }
  2147.     }
  2148.     return FALSE;
  2149. }
  2150. /*
  2151.  * Handle CR or NL in insert mode.
  2152.  * Return TRUE when out of memory.
  2153.  */
  2154.     static int
  2155. ins_eol(c)
  2156.     int c;
  2157. {
  2158.     int     i;
  2159.     if (echeck_abbr(c + ABBR_OFF))
  2160. return FALSE;
  2161.     stop_arrow();
  2162.     /*
  2163.      * Strange Vi behaviour: In Replace mode, typing a NL will not delete the
  2164.      * character under the cursor.  Only push a NUL on the replace stack,
  2165.      * nothing to put back when the NL is deleted.
  2166.      */
  2167.     if (State == REPLACE)
  2168. replace_push(NUL);
  2169. #ifdef RIGHTLEFT
  2170. # ifdef FKMAP
  2171.     if (p_altkeymap && p_fkmap)
  2172. fkmap(NL);
  2173. # endif
  2174.     /* NL in reverse insert will allways start in the end of
  2175.      * current line. */
  2176.     if (revins_on)
  2177. while (gchar_cursor() != NUL)
  2178.     ++curwin->w_cursor.col;
  2179. #endif
  2180.     AppendToRedobuff(NL_STR);
  2181.     if (has_format_option(FO_RET_COMS))
  2182. fo_do_comments = TRUE;
  2183.     i = open_line(FORWARD, TRUE, FALSE, old_indent);
  2184.     old_indent = 0;
  2185.     fo_do_comments = FALSE;
  2186. #ifdef CINDENT
  2187.     can_cindent = TRUE;
  2188. #endif
  2189.     return (!i);
  2190. }
  2191. #ifdef DIGRAPHS
  2192. /*
  2193.  * Handle digraph in insert mode.
  2194.  * Returns character still to be inserted, or NUL when nothing remaining to be
  2195.  * done.
  2196.  */
  2197.     static int
  2198. ins_digraph()
  2199. {
  2200.     int     c;
  2201.     int     cc;
  2202.     if (redrawing() && !char_avail())
  2203.     {
  2204. edit_putchar('?', TRUE);
  2205. #ifdef SHOWCMD
  2206. add_to_showcmd_c(Ctrl('K'));
  2207. #endif
  2208.     }
  2209. #ifdef USE_GUI_WIN32
  2210.     dont_scroll = TRUE; /* disallow scrolling here */
  2211. #endif
  2212.     /* don't map the digraph chars. This also prevents the
  2213.      * mode message to be deleted when ESC is hit */
  2214.     ++no_mapping;
  2215.     ++allow_keys;
  2216.     c = vgetc();
  2217.     --no_mapping;
  2218.     --allow_keys;
  2219.     if (IS_SPECIAL(c) || mod_mask)     /* special key */
  2220.     {
  2221. #ifdef SHOWCMD
  2222. clear_showcmd();
  2223. #endif
  2224. insert_special(c, TRUE, FALSE);
  2225. return NUL;
  2226.     }
  2227.     if (c != ESC)
  2228.     {
  2229. if (redrawing() && !char_avail())
  2230. {
  2231.     if (charsize(c) == 1)
  2232. edit_putchar(c, TRUE);
  2233. #ifdef SHOWCMD
  2234.     add_to_showcmd_c(c);
  2235. #endif
  2236. }
  2237. ++no_mapping;
  2238. ++allow_keys;
  2239. cc = vgetc();
  2240. --no_mapping;
  2241. --allow_keys;
  2242. if (cc != ESC)
  2243. {
  2244.     AppendToRedobuff((char_u *)"26"); /* CTRL-V */
  2245.     c = getdigraph(c, cc, TRUE);
  2246. #ifdef SHOWCMD
  2247.     clear_showcmd();
  2248. #endif
  2249.     return c;
  2250. }
  2251.     }
  2252. #ifdef SHOWCMD
  2253.     clear_showcmd();
  2254. #endif
  2255.     return NUL;
  2256. }
  2257. #endif
  2258. /*
  2259.  * Handle CTRL-E and CTRL-Y in Insert mode: copy char from other line.
  2260.  * Returns the char to be inserted, or NUL if none found.
  2261.  */
  2262.     static int
  2263. ins_copychar(lnum)
  2264.     linenr_t lnum;
  2265. {
  2266.     int     c;
  2267.     int     temp;
  2268.     char_u  *ptr;
  2269.     if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count)
  2270.     {
  2271. beep_flush();
  2272. return NUL;
  2273.     }
  2274.     /* try to advance to the cursor column */
  2275.     temp = 0;
  2276.     ptr = ml_get(lnum);
  2277.     validate_virtcol();
  2278.     while ((colnr_t)temp < curwin->w_virtcol && *ptr)
  2279. temp += lbr_chartabsize(ptr++, (colnr_t)temp);
  2280.     if ((colnr_t)temp > curwin->w_virtcol)
  2281. --ptr;
  2282.     if ((c = *ptr) == NUL)
  2283. beep_flush();
  2284.     return c;
  2285. }
  2286. #ifdef SMARTINDENT
  2287. /*
  2288.  * Try to do some very smart auto-indenting.
  2289.  * Used when inserting a "normal" character.
  2290.  */
  2291.     static void
  2292. ins_try_si(c)
  2293.     int     c;
  2294. {
  2295.     FPOS *pos, old_pos;
  2296.     char_u *ptr;
  2297.     int i;
  2298.     int temp;
  2299.     /*
  2300.      * do some very smart indenting when entering '{' or '}'
  2301.      */
  2302.     if (((did_si || can_si_back) && c == '{') || (can_si && c == '}'))
  2303.     {
  2304. /*
  2305.  * for '}' set indent equal to indent of line containing matching '{'
  2306.  */
  2307. if (c == '}' && (pos = findmatch(NULL, '{')) != NULL)
  2308. {
  2309.     old_pos = curwin->w_cursor;
  2310.     /*
  2311.      * If the matching '{' has a ')' immediately before it (ignoring
  2312.      * white-space), then line up with the start of the line
  2313.      * containing the matching '(' if there is one.  This handles the
  2314.      * case where an "if (..n..) {" statement continues over multiple
  2315.      * lines -- webb
  2316.      */
  2317.     ptr = ml_get(pos->lnum);
  2318.     i = pos->col;
  2319.     if (i > 0) /* skip blanks before '{' */
  2320. while (--i > 0 && vim_iswhite(ptr[i]))
  2321.     ;
  2322.     curwin->w_cursor.lnum = pos->lnum;
  2323.     curwin->w_cursor.col = i;
  2324.     if (ptr[i] == ')' && (pos = findmatch(NULL, '(')) != NULL)
  2325. curwin->w_cursor = *pos;
  2326.     i = get_indent();
  2327.     curwin->w_cursor = old_pos;
  2328.     set_indent(i, TRUE);
  2329. }
  2330. else if (curwin->w_cursor.col > 0)
  2331. {
  2332.     /*
  2333.      * when inserting '{' after "O" reduce indent, but not
  2334.      * more than indent of previous line
  2335.      */
  2336.     temp = TRUE;
  2337.     if (c == '{' && can_si_back && curwin->w_cursor.lnum > 1)
  2338.     {
  2339. old_pos = curwin->w_cursor;
  2340. i = get_indent();
  2341. while (curwin->w_cursor.lnum > 1)
  2342. {
  2343.     ptr = skipwhite(ml_get(--(curwin->w_cursor.lnum)));
  2344.     /* ignore empty lines and lines starting with
  2345.      * '#'.
  2346.      */
  2347.     if (*ptr != '#' && *ptr != NUL)
  2348. break;
  2349. }
  2350. if (get_indent() >= i)
  2351.     temp = FALSE;
  2352. curwin->w_cursor = old_pos;
  2353.     }
  2354.     if (temp)
  2355. shift_line(TRUE, FALSE, 1);
  2356. }
  2357.     }
  2358.     /*
  2359.      * set indent of '#' always to 0
  2360.      */
  2361.     if (curwin->w_cursor.col > 0 && can_si && c == '#')
  2362.     {
  2363. /* remember current indent for next line */
  2364. old_indent = get_indent();
  2365. set_indent(0, TRUE);
  2366.     }
  2367. }
  2368. #endif
  2369. /*
  2370.  * Get the value that w_virtcol would have when 'list' is off.
  2371.  * Unless 'cpo' contains the 'L' flag.
  2372.  */
  2373.     static colnr_t
  2374. get_nolist_virtcol()
  2375. {
  2376.     colnr_t virtcol;
  2377.     if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL)
  2378.     {
  2379. curwin->w_p_list = FALSE;
  2380. getvcol(curwin, &curwin->w_cursor, NULL, &virtcol, NULL);
  2381. curwin->w_p_list = TRUE;
  2382. return virtcol;
  2383.     }
  2384.     validate_virtcol();
  2385.     return curwin->w_virtcol;
  2386. }