home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / vim-2.0.lha / Vim-2.0 / src / edit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-15  |  21.6 KB  |  999 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * edit.c: functions for insert mode
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "param.h"
  19. #include "ops.h"    /* for operator */
  20.  
  21. extern u_char *get_inserted();
  22. static void start_arrow __ARGS((void));
  23. static void stop_arrow __ARGS((void));
  24. static void stop_insert __ARGS((void));
  25. static int echeck_abbr __ARGS((int));
  26.  
  27. int arrow_used;                /* Normally FALSE, set to TRUE after hitting
  28.                              * cursor key in insert mode. Used by vgetorpeek()
  29.                              * to decide when to call u_sync() */
  30. int restart_edit = 0;        /* call edit when next command finished */
  31. static u_char    *last_insert = NULL;
  32.                             /* the text of the previous insert */
  33. static int        last_insert_skip;
  34.                             /* number of chars in front of the previous insert */
  35. static int        new_insert_skip;
  36.                             /* number of chars in front of the current insert */
  37.  
  38.     void
  39. edit(count)
  40.     long count;
  41. {
  42.     u_char         c;
  43.     u_char         cc;
  44.     u_char        *ptr;
  45.     u_char        *saved_line = NULL;        /* saved line for replace mode */
  46.     linenr_t     saved_lnum = 0;        /* lnum of saved line */
  47.     int             saved_char = NUL;        /* char replaced by NL */
  48.     linenr_t     lnum;
  49.     int          temp = 0;
  50.     int             mode;
  51.     int             nextc = 0;
  52.     int             lastc = 0;
  53.     colnr_t         mincol;
  54.  
  55.     if (restart_edit)
  56.     {
  57.         arrow_used = TRUE;
  58.         restart_edit = 0;
  59.     }
  60.     else
  61.         arrow_used = FALSE;
  62.  
  63. #ifdef DIGRAPHS
  64.     dodigraph(-1);                    /* clear digraphs */
  65. #endif
  66.  
  67. /*
  68.  * Get the current length of the redo buffer, those characters have to be
  69.  * skipped if we want to get to the inserted characters.
  70.  */
  71.  
  72.     ptr = get_inserted();
  73.     new_insert_skip = strlen((char *)ptr);
  74.     free(ptr);
  75.  
  76.     old_indent = 0;
  77.  
  78.     for (;;)
  79.     {
  80.         if (arrow_used)        /* don't repeat insert when arrow key used */
  81.             count = 0;
  82.  
  83.         set_want_col = TRUE;    /* set Curswant in case of K_DARROW or K_UARROW */
  84.         cursupdate();        /* Figure out where the cursor is based on Curpos. */
  85.         showruler(0);
  86.         setcursor();
  87.         if (nextc)            /* character remaining from CTRL-V */
  88.         {
  89.             c = nextc;
  90.             nextc = 0;
  91.         }
  92.         else
  93.         {
  94.             c = vgetc();
  95.             if (c == Ctrl('C') && got_int)
  96.                 got_int = FALSE;
  97.         }
  98.         if (c != Ctrl('D'))            /* remember to detect ^^D and 0^D */
  99.             lastc = c;
  100.  
  101. /*
  102.  * In replace mode a backspace puts the original text back.
  103.  * We save the current line to be able to do that.
  104.  * If characters are appended to the line, they will be deleted.
  105.  * If we start a new line (with CR) the saved line will be empty, thus
  106.  * the characters will be deleted.
  107.  * If we backspace over the new line, that line will be saved.
  108.  */
  109.         if (State == REPLACE && saved_lnum != Curpos.lnum)
  110.         {
  111.             free(saved_line);
  112.             saved_line = (u_char *)strsave((char *)nr2ptr(Curpos.lnum));
  113.             saved_lnum = Curpos.lnum;
  114.         }
  115.  
  116. #ifdef DIGRAPHS
  117.         c = dodigraph(c);
  118. #endif /* DIGRAPHS */
  119.  
  120.         if (c == Ctrl('V'))
  121.         {
  122.             outchar('^');
  123.             AppendToRedobuff("\026");    /* CTRL-V */
  124.             cursupdate();
  125.             setcursor();
  126.  
  127.             c = get_literal(&nextc);
  128.  
  129.         /* erase the '^' */
  130.             if ((cc = gcharCurpos()) == NUL || (cc == TAB && !p_list))
  131.                 outchar(' ');
  132.             else
  133.                 outstrn(transchar(cc));
  134.  
  135.             if (isidchar(c) || !echeck_abbr(c))
  136.                 insertchar(c);
  137.             continue;
  138.         }
  139.         switch (c)        /* handle character in insert mode */
  140.         {
  141.               case Ctrl('O'):        /* execute one command */
  142.                 if (echeck_abbr(Ctrl('O') + 0x100))
  143.                     break;
  144.                   count = 0;
  145.                 if (State == INSERT)
  146.                     restart_edit = 'I';
  147.                 else
  148.                     restart_edit = 'R';
  149.                 goto doESCkey;
  150.  
  151.               case ESC:             /* an escape ends input mode */
  152.                 if (echeck_abbr(ESC + 0x100))
  153.                     break;
  154.                 /*FALLTHROUGH*/
  155.  
  156.               case Ctrl('C'):
  157. doESCkey:
  158.                 if (!arrow_used)
  159.                 {
  160.                     AppendToRedobuff(ESC_STR);
  161.  
  162.                     if (--count > 0)        /* repeat what was typed */
  163.                     {
  164.                             start_redo_ins();
  165.                             continue;
  166.                     }
  167.                     stop_insert();
  168.                 }
  169.                 set_want_col = TRUE;
  170.  
  171.                 /*
  172.                  * The cursor should end up on the last inserted character.
  173.                  */
  174.                 if (Curpos.col != 0 && (!restart_edit || gcharCurpos() == NUL) && !p_ri)
  175.                     decCurpos();
  176.                 if (extraspace)            /* did reverse replace in column 0 */
  177.                 {
  178.                     delchar(FALSE);
  179.                     updateline();
  180.                     extraspace = FALSE;
  181.                 }
  182.                 State = NORMAL;
  183.                 script_winsize_pp();    /* may need to put :winsize in script */
  184.                     /* inchar() may have deleted the "INSERT" message */
  185.                 if (Recording)
  186.                     showmode();
  187.                 else if (p_smd)
  188.                     msg("");
  189.                 free(saved_line);
  190.                 old_indent = 0;
  191.                 return;
  192.  
  193.                   /*
  194.                  * Insert the previously inserted text.
  195.                  * Last_insert actually is a copy of the redo buffer, so we
  196.                  * first have to remove the command.
  197.                  * For ^@ the trailing ESC will end the insert.
  198.                  */
  199.               case K_ZERO:
  200.               case Ctrl('A'):
  201.                 stuff_inserted(NUL, 1L, (c == Ctrl('A')));
  202.                 break;
  203.  
  204.                   /*
  205.                  * insert the contents of a register
  206.                  */
  207.               case Ctrl('R'):
  208.                   if (!insertbuf(vgetc()))
  209.                     beep();
  210.                 break;
  211.  
  212.               case Ctrl('P'):            /* toggle reverse insert mode */
  213.                   p_ri = !p_ri;
  214.                 showmode();
  215.                 break;
  216.  
  217.                 /*
  218.                  * If the cursor is on an indent, ^T/^D insert/delete one
  219.                  * shiftwidth. Otherwise ^T/^D behave like a TAB/backspace.
  220.                  * This isn't completely compatible with
  221.                  * vi, but the difference isn't very noticeable and now you can
  222.                  * mix ^D/backspace and ^T/TAB without thinking about which one
  223.                  * must be used.
  224.                  */
  225.               case Ctrl('T'):        /* make indent one shiftwidth greater */
  226.               case Ctrl('D'):         /* make indent one shiftwidth smaller */
  227.                 stop_arrow();
  228.                 AppendCharToRedobuff(c);
  229.                 if ((lastc == '0' || lastc == '^') && Curpos.col)
  230.                 {
  231.                     --Curpos.col;
  232.                     delchar(FALSE);            /* delete the '^' or '0' */
  233.                     if (lastc == '^')
  234.                         old_indent = get_indent();    /* remember current indent */
  235.  
  236.                         /* determine offset from first non-blank */
  237.                     temp = Curpos.col;
  238.                     beginline(TRUE);
  239.                     temp -= Curpos.col;
  240.                     set_indent(0, TRUE);    /* remove all indent */
  241.                 }
  242.                 else
  243.                 {
  244.                         /* determine offset from first non-blank */
  245.                     temp = Curpos.col;
  246.                     beginline(TRUE);
  247.                     temp -= Curpos.col;
  248.  
  249.                     shift_line(c == Ctrl('D'), TRUE);
  250.  
  251.                         /* try to put cursor on same character */
  252.                     temp += Curpos.col;
  253.                 }
  254.                 if (temp <= 0)
  255.                     Curpos.col = 0;
  256.                 else
  257.                     Curpos.col = temp;
  258.                 did_ai = FALSE;
  259.                 did_si = FALSE;
  260.                 can_si = FALSE;
  261.                   goto redraw;
  262.  
  263.               case BS:
  264.               case DEL:
  265. nextbs:
  266.                 mode = 0;
  267. dodel:
  268.                 /* can't delete anything in an empty file */
  269.                 /* can't backup past first character in buffer */
  270.                 /* can't backup past starting point unless 'backspace' > 1 */
  271.                 /* can backup to a previous line if 'backspace' == 0 */
  272.                 if (bufempty() || (!p_ri &&
  273.                         ((Curpos.lnum == 1 && Curpos.col <= 0) ||
  274.                         (p_bs < 2 && (arrow_used ||
  275.                             (Curpos.lnum == Insstart.lnum &&
  276.                             Curpos.col <= Insstart.col) ||
  277.                             (Curpos.col <= 0 && p_bs == 0))))))
  278.                 {
  279.                     beep();
  280.                     goto redraw;
  281.                 }
  282.  
  283.                 stop_arrow();
  284.                 if (p_ri)
  285.                     incCurpos();
  286.                 if (Curpos.col <= 0)        /* delete newline! */
  287.                 {
  288.                     lnum = Insstart.lnum;
  289.                     if (Curpos.lnum == Insstart.lnum || p_ri)
  290.                     {
  291.                         if (!u_save((linenr_t)(Curpos.lnum - 2), (linenr_t)(Curpos.lnum + 1)))
  292.                             goto redraw;
  293.                         --Insstart.lnum;
  294.                         Insstart.col = 0;
  295.                     }
  296.                 /* in replace mode, in the line we started replacing, we
  297.                                                         only move the cursor */
  298.                     if (State != REPLACE || Curpos.lnum > lnum)
  299.                     {
  300.                         temp = gcharCurpos();        /* remember current char */
  301.                         --Curpos.lnum;
  302.                         dojoin(FALSE, TRUE);
  303.                         if (temp == NUL && gcharCurpos() != NUL)
  304.                             ++Curpos.col;
  305.                         if (saved_char)                /* restore what NL replaced */
  306.                         {
  307.                             State = NORMAL;            /* no replace for this char */
  308.                             inschar(saved_char);    /* but no showmatch */
  309.                             State = REPLACE;
  310.                             saved_char = NUL;
  311.                             if (!p_ri)
  312.                                 decCurpos();
  313.                         }
  314.                         else if (p_ri)                /* in reverse mode */
  315.                             saved_lnum = 0;            /* save this line again */
  316.                     }
  317.                     else
  318.                         decCurpos();
  319.                     did_ai = FALSE;
  320.                 }
  321.                 else
  322.                 {
  323.                     if (p_ri && State != REPLACE)
  324.                         decCurpos();
  325.                     mincol = 0;
  326.                     if (mode == 3 && !p_ri && p_ai)    /* keep indent */
  327.                     {
  328.                         temp = Curpos.col;
  329.                         beginline(TRUE);
  330.                         if (Curpos.col < temp)
  331.                             mincol = Curpos.col;
  332.                         Curpos.col = temp;
  333.                     }
  334.  
  335.                     /* delete upto starting point, start of line or previous word */
  336.                     do
  337.                     {
  338.                         if (!p_ri)
  339.                             decCurpos();
  340.  
  341.                                 /* start of word? */
  342.                         if (mode == 1 && !isspace(gcharCurpos()))
  343.                         {
  344.                             mode = 2;
  345.                             temp = isidchar(gcharCurpos());
  346.                         }
  347.                                 /* end of word? */
  348.                         else if (mode == 2 && (isspace(cc = gcharCurpos()) || isidchar(cc) != temp))
  349.                         {
  350.                             if (!p_ri)
  351.                                 incCurpos();
  352.                             else if (State == REPLACE)
  353.                                 decCurpos();
  354.                             break;
  355.                         }
  356.                         if (State == REPLACE)
  357.                         {
  358.                             if (saved_line)
  359.                             {
  360.                                 if (extraspace)
  361.                                 {
  362.                                     if ((int)strlen(nr2ptr(Curpos.lnum)) - 1 > (int)strlen((char *)saved_line))
  363.                                         delchar(FALSE);
  364.                                     else
  365.                                     {
  366.                                         decCurpos();
  367.                                         delchar(FALSE);
  368.                                         extraspace = FALSE;
  369.                                         pcharCurpos(*saved_line);
  370.                                     }
  371.                                 }
  372.                                 else if (Curpos.col < strlen((char *)saved_line))
  373.                                     pcharCurpos(saved_line[Curpos.col]);
  374.                                 else if (!p_ri)
  375.                                     delchar(FALSE);
  376.                             }
  377.                         }
  378.                         else  /* State != REPLACE */
  379.                         {
  380.                             delchar(FALSE);
  381.                             if (p_ri && gcharCurpos() == NUL)
  382.                                 break;
  383.                         }
  384.                         if (mode == 0)        /* just a single backspace */
  385.                             break;
  386.                         if (p_ri && State == REPLACE && incCurpos())
  387.                             break;
  388.                     } while (p_ri || (Curpos.col > mincol && (Curpos.lnum != Insstart.lnum ||
  389.                             Curpos.col != Insstart.col)));
  390.                     if (extraspace)
  391.                         decCurpos();
  392.                 }
  393.                 did_si = FALSE;
  394.                 can_si = FALSE;
  395.                 if (Curpos.col <= 1)
  396.                     did_ai = FALSE;
  397.                 /*
  398.                  * It's a little strange to put backspaces into the redo
  399.                  * buffer, but it makes auto-indent a lot easier to deal
  400.                  * with.
  401.                  */
  402.                 AppendCharToRedobuff(c);
  403.                 if (vpeekc() == BS)
  404.                 {
  405.                         c = vgetc();
  406.                         goto nextbs;    /* speedup multiple backspaces */
  407.                 }
  408. redraw:
  409.                 cursupdate();
  410.                 updateline();
  411.                 break;
  412.  
  413.               case Ctrl('W'):        /* delete word before cursor */
  414.                   mode = 1;
  415.                   goto dodel;
  416.  
  417.               case Ctrl('U'):        /* delete inserted text in current line */
  418.                 mode = 3;
  419.                   goto dodel;
  420.  
  421.               case K_LARROW:
  422.                   if (oneleft())
  423.                     start_arrow();
  424.                 else
  425.                     beep();
  426.                 break;
  427.  
  428.               case K_SLARROW:
  429.                   if (Curpos.lnum > 1 || Curpos.col > 0)
  430.                 {
  431.                     bck_word(1L, 0);
  432.                     start_arrow();
  433.                 }
  434.                 else
  435.                     beep();
  436.                 break;
  437.  
  438.               case K_RARROW:
  439.                 if (gcharCurpos() != NUL)
  440.                 {
  441.                     set_want_col = TRUE;
  442.                     start_arrow();
  443.                     ++Curpos.col;
  444.                 }
  445.                 else
  446.                     beep();
  447.                 break;
  448.  
  449.               case K_SRARROW:
  450.                   if (Curpos.lnum < line_count || gcharCurpos() != NUL)
  451.                 {
  452.                     fwd_word(1L, 0, 0);
  453.                     start_arrow();
  454.                 }
  455.                 else
  456.                     beep();
  457.                 break;
  458.  
  459.               case K_UARROW:
  460.                   if (oneup(1L))
  461.                     start_arrow();
  462.                 else
  463.                     beep();
  464.                 break;
  465.  
  466.               case K_SUARROW:
  467.                   if (onepage(BACKWARD, 1L))
  468.                     start_arrow();
  469.                 else
  470.                     beep();
  471.                 break;
  472.  
  473.               case K_DARROW:
  474.                   if (onedown(1L))
  475.                     start_arrow();
  476.                 else
  477.                     beep();
  478.                 break;
  479.  
  480.               case K_SDARROW:
  481.                   if (onepage(FORWARD, 1L))
  482.                     start_arrow();
  483.                 else
  484.                     beep();
  485.                 break;
  486.  
  487.               case TAB:
  488.                 if (echeck_abbr(TAB + 0x100))
  489.                     break;
  490.                   if (!p_et || (p_ri && State == REPLACE))
  491.                     goto normalchar;
  492.                                         /* expand a tab into spaces */
  493.                 stop_arrow();
  494.                 did_ai = FALSE;
  495.                 did_si = FALSE;
  496.                 can_si = FALSE;
  497.                 temp = (int)p_ts - Curpos.col % (int)p_ts;
  498.                 inschar(' ');            /* delete one char in replace mode */
  499.                 while (--temp)
  500.                     insstr(" ");        /* insstr does not delete chars */
  501.                 AppendToRedobuff("\t");
  502.                 goto redraw;
  503.  
  504.               case CR:
  505.               case NL:
  506.                 if (echeck_abbr(c + 0x100))
  507.                     break;
  508.                 stop_arrow();
  509.                 if (State == REPLACE)
  510.                 {
  511.                     saved_char = gcharCurpos();
  512.                     delchar(FALSE);
  513.                 }
  514.                 AppendToRedobuff(NL_STR);
  515.                 if (!Opencmd(FORWARD, TRUE, State == INSERT))
  516.                     goto doESCkey;        /* out of memory */
  517.                 if (p_ri)
  518.                 {
  519.                     decCurpos();
  520.                     if (State == REPLACE && Curpos.col > 0)
  521.                         decCurpos();
  522.                 }
  523.                 break;
  524.  
  525. #ifdef DIGRAPHS
  526.               case Ctrl('K'):
  527.                 outchar('?');
  528.                 AppendToRedobuff("\026");    /* CTRL-V */
  529.                 setcursor();
  530.                   c = vgetc();
  531.                 outstrn(transchar(c));
  532.                 setcursor();
  533.                 c = getdigraph(c, vgetc());
  534.                 goto normalchar;
  535. #endif /* DIGRAPHS */
  536.  
  537.               case Ctrl('Y'):                /* copy from previous line */
  538.                 lnum = Curpos.lnum - 1;
  539.                 goto copychar;
  540.  
  541.               case Ctrl('E'):                /* copy from next line */
  542.                 lnum = Curpos.lnum + 1;
  543. copychar:
  544.                 if (lnum < 1 || lnum > line_count)
  545.                 {
  546.                     beep();
  547.                     break;
  548.                 }
  549.  
  550.                 /* try to advance to the cursor column */
  551.                 temp = 0;
  552.                 ptr = (u_char *)nr2ptr(lnum);
  553.                 while (temp < Cursvcol && *ptr)
  554.                         temp += chartabsize(*ptr++, temp);
  555.  
  556.                 if (temp > Cursvcol)
  557.                         --ptr;
  558.                 if ((c = *ptr) == NUL)
  559.                 {
  560.                     beep();
  561.                     break;
  562.                 }
  563.  
  564.                 /*FALLTHROUGH*/
  565.               default:
  566. normalchar:
  567.                 if (Curpos.col > 0 && ((can_si && c == '}') || (did_si && c == '{')))
  568.                     shift_line(TRUE, TRUE);
  569.  
  570.                 if (isidchar(c) || !echeck_abbr(c))
  571.                     insertchar(c);
  572.                 break;
  573.             }
  574.     }
  575. }
  576.  
  577. /*
  578.  * Next character is interpreted literally.
  579.  * A one, two or three digit decimal number is interpreted as its byte value.
  580.  * If one or two digits are entered, *nextc is set to the next character.
  581.  */
  582.     int
  583. get_literal(nextc)
  584.     int *nextc;
  585. {
  586.     u_char         cc;
  587.     u_char         nc;
  588.     int             oldstate;
  589.     int             i;
  590.  
  591.     oldstate = State;
  592.     State = NOMAPPING;        /* next characters not mapped */
  593.  
  594.     if (got_int)
  595.     {
  596.         *nextc = NUL;
  597.         return Ctrl('C');
  598.     }
  599.     cc = 0;
  600.     for (i = 0; i < 3; ++i)
  601.     {
  602.         nc = vgetc();
  603.         if (!isdigit(nc))
  604.             break;
  605.         cc = cc * 10 + nc - '0';
  606.         nc = 0;
  607.     }
  608.     if (i == 0)        /* no number entered */
  609.     {
  610.         cc = nc;
  611.         nc = 0;
  612.         if (cc == K_ZERO)    /* NUL is stored as NL */
  613.             cc = '\n';
  614.     }
  615.     else if (cc == 0)        /* NUL is stored as NL */
  616.         cc = '\n';
  617.  
  618.     State = oldstate;
  619.     *nextc = nc;
  620.     got_int = FALSE;        /* CTRL-C typed after CTRL-V is not an interrupt */
  621.     return cc;
  622. }
  623.  
  624. /*
  625.  * Special characters in this context are those that need processing other
  626.  * than the simple insertion that can be performed here. This includes ESC
  627.  * which terminates the insert, and CR/NL which need special processing to
  628.  * open up a new line. This routine tries to optimize insertions performed by
  629.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  630.  * stop and defer processing to the "normal" mechanism.
  631.  */
  632. #define ISSPECIAL(c)    ((c) < ' ' || (c) >= DEL)
  633.  
  634.     void
  635. insertchar(c)
  636.     unsigned    c;
  637. {
  638.     int        haveto_redraw = FALSE;
  639.  
  640.     stop_arrow();
  641.     /*
  642.      * If the cursor is past 'textwidth' and we are inserting a non-space,
  643.      * try to break the line in two or more pieces. If c == NUL then we have
  644.      * been called to do formatting only. If p_tw == 0 it does nothing.
  645.      */
  646.     if (c == NUL || !isspace(c))
  647.     {
  648.         while (p_tw && Cursvcol >= p_tw)
  649.         {
  650.             int        startcol;        /* Cursor column at entry */
  651.             int        wantcol;        /* column at textwidth border */
  652.             int        foundcol;        /* column for start of word */
  653.  
  654.             if ((startcol = Curpos.col) == 0)
  655.                 break;
  656.             coladvance((int)p_tw);            /* find column of textwidth border */
  657.             wantcol = Curpos.col;
  658.  
  659.             Curpos.col = startcol - 1;
  660.             foundcol = 0;
  661.             while (Curpos.col > 0)            /* find position to break at */
  662.             {
  663.                 if (isspace(gcharCurpos()))
  664.                 {
  665.                     while (Curpos.col > 0 && isspace(gcharCurpos()))
  666.                         --Curpos.col;
  667.                     if (Curpos.col == 0)    /* only spaces in front of text */
  668.                         break;
  669.                     foundcol = Curpos.col + 1;
  670.                     if (Curpos.col < wantcol)
  671.                         break;
  672.                 }
  673.                 --Curpos.col;
  674.             }
  675.  
  676.             if (foundcol == 0)            /* no spaces, cannot break line */
  677.             {
  678.                 Curpos.col = startcol;
  679.                 break;
  680.             }
  681.             Curpos.col = foundcol;        /* put cursor after pos. to break line */
  682.             startcol -= foundcol;
  683.             Opencmd(FORWARD, FALSE, FALSE);
  684.             while (isspace(gcharCurpos()) && startcol)        /* delete blanks */
  685.             {
  686.                 delchar(FALSE);
  687.                 --startcol;                /* adjust cursor pos. */
  688.             }
  689.             Curpos.col += startcol;
  690.             curs_columns(FALSE);        /* update Cursvcol */
  691.             haveto_redraw = TRUE;
  692.         }
  693.         if (c == NUL)                    /* formatting only */
  694.             return;
  695.         if (haveto_redraw)
  696.         {
  697.             /*
  698.              * If the cursor ended up just below the screen we scroll up here
  699.              * to avoid a redraw of the whole screen in the most common cases.
  700.              */
  701.              if (Curpos.lnum == Botline && !emptyrows)
  702.                 s_del(0, 1, TRUE);
  703.             updateScreen(CURSUPD);
  704.         }
  705.     }
  706.  
  707.     did_ai = FALSE;
  708.     did_si = FALSE;
  709.     can_si = FALSE;
  710.  
  711.     /*
  712.      * If there's any pending input, grab up to MAX_COLUMNS at once.
  713.      * This speeds up normal text input considerably.
  714.      */
  715.     if (vpeekc() != NUL && State != REPLACE && !p_ri)
  716.     {
  717.         char            p[MAX_COLUMNS + 1];
  718.         int             i;
  719.  
  720.         p[0] = c;
  721.         i = 1;
  722.         while ((c = vpeekc()) != NUL && !ISSPECIAL(c) && i < MAX_COLUMNS &&
  723.                     (!p_tw || (Cursvcol += charsize(p[i - 1])) < p_tw) &&
  724.                     !(!no_abbr && !isidchar(c) && isidchar(p[i - 1])))
  725.             p[i++] = vgetc();
  726.         p[i] = '\0';
  727.         insstr(p);
  728.         AppendToRedobuff(p);
  729.     }
  730.     else
  731.     {
  732.         inschar(c);
  733.         AppendCharToRedobuff(c);
  734.     }
  735.  
  736.     updateline();
  737. }
  738.  
  739.  
  740. /*
  741.  * start_arrow() is called when an arrow key is used in insert mode.
  742.  * It resembles hitting the <ESC> key.
  743.  */
  744.     static void
  745. start_arrow()
  746. {
  747.     if (!arrow_used)        /* something has been inserted */
  748.     {
  749.         AppendToRedobuff(ESC_STR);
  750.         arrow_used = TRUE;        /* this means we stopped the current insert */
  751.         stop_insert();
  752.     }
  753. }
  754.  
  755. /*
  756.  * stop_arrow() is called before a change is made in insert mode.
  757.  * If an arrow key has been used, start a new insertion.
  758.  */
  759.     static void
  760. stop_arrow()
  761. {
  762.     if (arrow_used)
  763.     {
  764.         u_saveCurpos();            /* errors are ignored! */
  765.         Insstart = Curpos;        /* new insertion starts here */
  766.         ResetRedobuff();
  767.         AppendToRedobuff("1i");    /* pretend we start an insertion */
  768.         arrow_used = FALSE;
  769.     }
  770. }
  771.  
  772. /*
  773.  * do a few things to stop inserting
  774.  */
  775.     static void
  776. stop_insert()
  777. {
  778.     stop_redo_ins();
  779.  
  780.     /*
  781.      * save the inserted text for later redo with ^@
  782.      */
  783.     free(last_insert);
  784.     last_insert = get_inserted();
  785.     last_insert_skip = new_insert_skip;
  786.  
  787.     /*
  788.      * If we just did an auto-indent, truncate the line, and put
  789.      * the cursor back.
  790.      */
  791.     if (did_ai && !arrow_used)
  792.     {
  793.         *nr2ptr(Curpos.lnum) = NUL;
  794.         canincrease(0);
  795.         Curpos.col = 0;
  796.         if (p_list)            /* the deletion is only seen in list mode */
  797.             updateline();
  798.     }
  799.     did_ai = FALSE;
  800.     did_si = FALSE;
  801.     can_si = FALSE;
  802. }
  803.  
  804. /*
  805.  * oneright oneleft onedown oneup
  806.  *
  807.  * Move one char {right,left,down,up}.    Return TRUE when sucessful, FALSE when
  808.  * we hit a boundary (of a line, or the file).
  809.  */
  810.  
  811.     int
  812. oneright()
  813. {
  814.     char *ptr;
  815.  
  816.     ptr = Curpos2ptr();
  817.     set_want_col = TRUE;
  818.  
  819.     if (*ptr++ == NUL || *ptr == NUL)
  820.         return FALSE;
  821.     ++Curpos.col;
  822.     return TRUE;
  823. }
  824.  
  825.     int
  826. oneleft()
  827. {
  828.     set_want_col = TRUE;
  829.  
  830.     if (Curpos.col == 0)
  831.         return FALSE;
  832.     --Curpos.col;
  833.     return TRUE;
  834. }
  835.  
  836.     void
  837. beginline(flag)
  838.     int            flag;
  839. {
  840.     Curpos.col = 0;
  841.     if (flag)
  842.     {
  843.         register char *ptr;
  844.  
  845.         for (ptr = nr2ptr(Curpos.lnum); isspace(*ptr); ++ptr)
  846.             ++Curpos.col;
  847.     }
  848.     set_want_col = TRUE;
  849. }
  850.  
  851.     int
  852. oneup(n)
  853.     long n;
  854. {
  855.     if (n != 0 && Curpos.lnum == 1)
  856.         return FALSE;
  857.     if (n >= Curpos.lnum)
  858.         Curpos.lnum = 1;
  859.     else
  860.         Curpos.lnum -= n;
  861.  
  862.     if (operator == NOP)
  863.         cursupdate();                /* make sure Topline is valid */
  864.  
  865.     /* try to advance to the column we want to be at */
  866.     coladvance(Curswant);
  867.     return TRUE;
  868. }
  869.  
  870.     int
  871. onedown(n)
  872.     long n;
  873. {
  874.     if (n != 0 && Curpos.lnum == line_count)
  875.         return FALSE;
  876.     Curpos.lnum += n;
  877.     if (Curpos.lnum > line_count)
  878.         Curpos.lnum = line_count;
  879.  
  880.     if (operator == NOP)
  881.         cursupdate();                /* make sure Topline is valid */
  882.  
  883.     /* try to advance to the column we want to be at */
  884.     coladvance(Curswant);
  885.     return TRUE;
  886. }
  887.  
  888.     int
  889. onepage(dir, count)
  890.     int        dir;
  891.     long    count;
  892. {
  893.     linenr_t        lp;
  894.     long            n;
  895.  
  896.     if (line_count == 1)    /* nothing to do */
  897.         return FALSE;
  898.     for ( ; count > 0; --count)
  899.     {
  900.         if (dir == FORWARD ? (Topline >= line_count - 1) : (Topline == 1))
  901.         {
  902.             beep();
  903.             return FALSE;
  904.         }
  905.         if (dir == FORWARD)
  906.         {
  907.             if (Botline > line_count)                /* at end of file */
  908.                 Topline = line_count;
  909.             else if (plines(Botline) >= Rows - 3 ||    /* next line is big */
  910.                     Botline - Topline <= 3)        /* just three lines on screen */
  911.                 Topline = Botline;
  912.             else
  913.                 Topline = Botline - 2;
  914.             Curpos.lnum = Topline;
  915.             if (count != 1)
  916.                 comp_Botline();
  917.         }
  918.         else    /* dir == BACKWARDS */
  919.         {
  920.             lp = Topline;
  921.             /*
  922.              * If the first two lines on the screen are not too big, we keep
  923.              * them on the screen.
  924.              */
  925.             if ((n = plines(lp)) > Rows / 2)
  926.                 --lp;
  927.             else if (lp < line_count && n + plines(lp + 1) < Rows / 2)
  928.                 ++lp;
  929.             Curpos.lnum = lp;
  930.             n = 0;
  931.             while (n <= Rows - 1 && lp >= 1)
  932.             {
  933.                 n += plines(lp);
  934.                 --lp;
  935.             }
  936.             if (n <= Rows - 1)                /* at begin of file */
  937.                 Topline = 1;
  938.             else if (lp >= Topline - 2)        /* happens with very long lines */
  939.             {
  940.                 --Topline;
  941.                 comp_Botline();
  942.                 Curpos.lnum = Botline - 1;
  943.             }
  944.             else
  945.                 Topline = lp + 2;
  946.         }
  947.     }
  948.     beginline(TRUE);
  949.     updateScreen(VALID);
  950.     return TRUE;
  951. }
  952.  
  953.     void
  954. stuff_inserted(c, count, no_esc)
  955.     int        c;
  956.     long    count;
  957.     int        no_esc;
  958. {
  959.     u_char        *esc_ptr = NULL;
  960.     u_char        *ptr;
  961.  
  962.     if (last_insert == NULL)
  963.     {
  964.         emsg("No inserted text yet");
  965.         return;
  966.     }
  967.     if (c)
  968.         stuffcharReadbuff(c);
  969.     if (no_esc && (esc_ptr = (u_char *)strrchr((char *)last_insert, 27)) != NULL)
  970.         *esc_ptr = NUL;        /* remove the ESC */
  971.  
  972.             /* skip the command */
  973.     ptr = last_insert + last_insert_skip;
  974.  
  975.     do
  976.         stuffReadbuff((char *)ptr);
  977.     while (--count > 0);
  978.  
  979.     if (no_esc && esc_ptr)
  980.         *esc_ptr = 27;        /* put the ESC back */
  981. }
  982.  
  983. /*
  984.  * Check the word in front of the cursor for an abbreviation.
  985.  * Called when the non-id character "c" has been entered.
  986.  * When an abbreviation is recognized it is removed from the text and
  987.  * the replacement string is inserted in typestr, followed by "c".
  988.  */
  989.     static int
  990. echeck_abbr(c)
  991.     int c;
  992. {
  993.     if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  994.         return FALSE;
  995.  
  996.     return check_abbr(c, nr2ptr(Curpos.lnum), Curpos.col,
  997.                 Curpos.lnum == Insstart.lnum ? Insstart.col : 0);
  998. }
  999.