home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / STVI369G.ZIP / EDIT.C < prev    next >
C/C++ Source or Header  |  1990-05-01  |  7KB  |  356 lines

  1. /* $Header: /nw/tony/src/stevie/src/RCS/edit.c,v 1.11 89/08/02 19:57:12 tony Exp $
  2.  *
  3.  * The main edit loop as well as some other simple cursor movement routines.
  4.  */
  5.  
  6. #include "stevie.h"
  7.  
  8. /*
  9.  * This flag is used to make auto-indent work right on lines where only
  10.  * a <RETURN> or <ESC> is typed. It is set when an auto-indent is done,
  11.  * and reset when any other editting is done on the line. If an <ESC>
  12.  * or <RETURN> is received, and did_ai is TRUE, the line is truncated.
  13.  */
  14. bool_t    did_ai = FALSE;
  15.  
  16. void
  17. edit()
  18. {
  19.     extern    bool_t    need_redraw;
  20.     int    c;
  21.     register char    *p, *q;
  22.  
  23.     Prenum = 0;
  24.  
  25.     /* position the display and the cursor at the top of the file. */
  26.     *Topchar = *Filemem;
  27.     *Curschar = *Filemem;
  28.     Cursrow = Curscol = 0;
  29.  
  30.     do_mlines();        /* check for mode lines before starting */
  31.  
  32.     updatescreen();
  33.  
  34.     for ( ;; ) {
  35.  
  36.     /* Figure out where the cursor is based on Curschar. */
  37.     cursupdate();
  38.  
  39.     if (need_redraw && !anyinput()) {
  40.         updatescreen();
  41.         need_redraw = FALSE;
  42.     }
  43.  
  44.     if (!anyinput())
  45.         windgoto(Cursrow,Curscol);
  46.  
  47.  
  48.     c = vgetc();
  49.  
  50.     if (State == NORMAL) {
  51.  
  52.         /* We're in the normal (non-insert) mode. */
  53.  
  54.         /* Pick up any leading digits and compute 'Prenum' */
  55.         if ( (Prenum>0 && isdigit(c)) || (isdigit(c) && c!='0') ){
  56.             Prenum = Prenum*10 + (c-'0');
  57.             continue;
  58.         }
  59.         /* execute the command */
  60.         normal(c);
  61.         Prenum = 0;
  62.  
  63.     } else {
  64.  
  65.         /*
  66.          * Insert or Replace mode.
  67.          */
  68.         switch (c) {
  69.  
  70.         case ESC:    /* an escape ends input mode */
  71.  
  72.             /*
  73.              * If we just did an auto-indent, truncate the
  74.              * line, and put the cursor back.
  75.              */
  76.             if (did_ai) {
  77.                 Curschar->linep->s[0] = NUL;
  78.                 Curschar->index = 0;
  79.                 did_ai = FALSE;
  80.             }
  81.  
  82.             set_want_col = TRUE;
  83.  
  84.             /* Don't end up on a '\n' if you can help it. */
  85.             if (gchar(Curschar) == NUL && Curschar->index != 0)
  86.                 dec(Curschar);
  87.  
  88.             /*
  89.              * The cursor should end up on the last inserted
  90.              * character. This is an attempt to match the real
  91.              * 'vi', but it may not be quite right yet.
  92.              */
  93.             if (Curschar->index != 0 && !endofline(Curschar))
  94.                 dec(Curschar);
  95.  
  96.             State = NORMAL;
  97.             msg("");
  98.  
  99.             /* construct the Redo buffer */
  100.             p=Redobuff;
  101.             q=Insbuff;
  102.             while ( q < Insptr )
  103.                 *p++ = *q++;
  104.             *p++ = ESC;
  105.             *p = NUL;
  106.             updatescreen();
  107.             break;
  108.  
  109.         case CTRL('D'):
  110.             /*
  111.              * Control-D is treated as a backspace in insert
  112.              * mode to make auto-indent easier. This isn't
  113.              * completely compatible with vi, but it's a lot
  114.              * easier than doing it exactly right, and the
  115.              * difference isn't very noticeable.
  116.              */
  117.         case BS:
  118.             /* can't backup past starting point */
  119.             if (Curschar->linep == Insstart->linep &&
  120.                 Curschar->index <= Insstart->index) {
  121.                 beep();
  122.                 break;
  123.             }
  124.  
  125.             /* can't backup to a previous line */
  126.             if (Curschar->linep != Insstart->linep &&
  127.                 Curschar->index <= 0) {
  128.                 beep();
  129.                 break;
  130.             }
  131.  
  132.             did_ai = FALSE;
  133.             dec(Curschar);
  134.             if (State == INSERT)
  135.                 delchar(TRUE);
  136.             /*
  137.              * It's a little strange to put backspaces into
  138.              * the redo buffer, but it makes auto-indent a
  139.              * lot easier to deal with.
  140.              */
  141.             *Insptr++ = BS;
  142.             Ninsert++;
  143.             cursupdate();
  144.             updateline();
  145.             break;
  146.  
  147.         case CR:
  148.         case NL:
  149.             if (State == REPLACE)        /* DMT added, 12/89 */
  150.                 delchar(FALSE);
  151.             *Insptr++ = NL;
  152.             Ninsert++;
  153.             opencmd(FORWARD, TRUE);        /* open a new line */
  154.             break;
  155.  
  156.         default:
  157.             did_ai = FALSE;
  158.             insertchar(c);
  159.             break;
  160.         }
  161.     }
  162.     }
  163. }
  164.  
  165. void
  166. insertchar(c)
  167. int    c;
  168. {
  169.     inschar(c);
  170.     *Insptr++ = c;
  171.     Ninsert++;
  172.     /*
  173.      * The following kludge avoids overflowing the statically
  174.      * allocated insert buffer. Just dump the user back into
  175.      * command mode, and print a message.
  176.      */
  177.     if (Insptr+10 >= &Insbuff[1024]) {
  178.         stuffin(mkstr(ESC));
  179.         emsg("No buffer space - returning to command mode");
  180.         sleep(2);
  181.     }
  182.     updateline();
  183. }
  184.  
  185. void
  186. getout()
  187. {
  188.     windgoto(Rows-1,0);
  189.     putchar('\r');
  190.     putchar('\n');
  191.     windexit(0);
  192. }
  193.  
  194. void
  195. scrolldown(nlines)
  196. int    nlines;
  197. {
  198.     register LPTR    *p;
  199.     register int    done = 0;    /* total # of physical lines done */
  200.  
  201.     /* Scroll up 'nlines' lines. */
  202.     while (nlines--) {
  203.         if ((p = prevline(Topchar)) == NULL)
  204.             break;
  205.         done += plines(p);
  206.         *Topchar = *p;
  207.         /*
  208.          * If the cursor is on the bottom line, we need to
  209.          * make sure it gets moved up the appropriate number
  210.          * of lines so it stays on the screen.
  211.          */
  212.         if (Curschar->linep == Botchar->linep->prev) {
  213.             int    i = 0;
  214.             while (i < done) {
  215.                 i += plines(Curschar);
  216.                 *Curschar = *prevline(Curschar);
  217.             }
  218.         }
  219.     }
  220.     s_ins(0, done);
  221. }
  222.  
  223. void
  224. scrollup(nlines)
  225. int    nlines;
  226. {
  227.     register LPTR    *p;
  228.     register int    done = 0;    /* total # of physical lines done */
  229.     register int    pl;        /* # of plines for the current line */
  230.  
  231.     /* Scroll down 'nlines' lines. */
  232.     while (nlines--) {
  233.         pl = plines(Topchar);
  234.         if ((p = nextline(Topchar)) == NULL)
  235.             break;
  236.         done += pl;
  237.         if (Curschar->linep == Topchar->linep)
  238.             *Curschar = *p;
  239.         *Topchar = *p;
  240.  
  241.     }
  242.     s_del(0, done);
  243. }
  244.  
  245. /*
  246.  * oneright
  247.  * oneleft
  248.  * onedown
  249.  * oneup
  250.  *
  251.  * Move one char {right,left,down,up}.  Return TRUE when
  252.  * sucessful, FALSE when we hit a boundary (of a line, or the file).
  253.  */
  254.  
  255. bool_t
  256. oneright()
  257. {
  258.     set_want_col = TRUE;
  259.  
  260.     switch (inc(Curschar)) {
  261.  
  262.     case 0:
  263.         return TRUE;
  264.  
  265.     case 1:
  266.         dec(Curschar);        /* crossed a line, so back up */
  267.         /* fall through */
  268.     case -1:
  269.         return FALSE;
  270.     }
  271.     /*NOTREACHED*/
  272. }
  273.  
  274. bool_t
  275. oneleft()
  276. {
  277.     set_want_col = TRUE;
  278.  
  279.     switch (dec(Curschar)) {
  280.  
  281.     case 0:
  282.         return TRUE;
  283.  
  284.     case 1:
  285.         inc(Curschar);        /* crossed a line, so back up */
  286.         /* fall through */
  287.     case -1:
  288.         return FALSE;
  289.     }
  290.     /*NOTREACHED*/
  291. }
  292.  
  293. void
  294. beginline(flag)
  295. bool_t    flag;
  296. {
  297.     while ( oneleft() )
  298.         ;
  299.     if (flag) {
  300.         while (isspace(gchar(Curschar)) && oneright())
  301.             ;
  302.     }
  303.     set_want_col = TRUE;
  304. }
  305.  
  306. bool_t
  307. oneup(n)
  308. int    n;
  309. {
  310.     LPTR    p, *np;
  311.     register int    k;
  312.  
  313.     p = *Curschar;
  314.     for ( k=0; k<n; k++ ) {
  315.         /* Look for the previous line */
  316.         if ( (np=prevline(&p)) == NULL ) {
  317.             /* If we've at least backed up a little .. */
  318.             if ( k > 0 )
  319.                 break;    /* to update the cursor, etc. */
  320.             else
  321.                 return FALSE;
  322.         }
  323.         p = *np;
  324.     }
  325.     *Curschar = p;
  326.     /* This makes sure Topchar gets updated so the complete line */
  327.     /* is one the screen. */
  328.     cursupdate();
  329.     /* try to advance to the column we want to be at */
  330.     *Curschar = *coladvance(&p, Curswant);
  331.     return TRUE;
  332. }
  333.  
  334. bool_t
  335. onedown(n)
  336. int    n;
  337. {
  338.     LPTR    p, *np;
  339.     register int    k;
  340.  
  341.     p = *Curschar;
  342.     for ( k=0; k<n; k++ ) {
  343.         /* Look for the next line */
  344.         if ( (np=nextline(&p)) == NULL ) {
  345.             if ( k > 0 )
  346.                 break;
  347.             else
  348.                 return FALSE;
  349.         }
  350.         p = *np;
  351.     }
  352.     /* try to advance to the column we want to be at */
  353.     *Curschar = *coladvance(&p, Curswant);
  354.     return TRUE;
  355. }
  356.