home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 313_01 / edit.c < prev    next >
C/C++ Source or Header  |  1990-04-22  |  7KB  |  354 lines

  1. /* $Header: /nw2/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.             *Insptr++ = NL;
  150.             Ninsert++;
  151.             opencmd(FORWARD, TRUE);        /* open a new line */
  152.             break;
  153.  
  154.         default:
  155.             did_ai = FALSE;
  156.             insertchar(c);
  157.             break;
  158.         }
  159.     }
  160.     }
  161. }
  162.  
  163. void
  164. insertchar(c)
  165. int    c;
  166. {
  167.     inschar(c);
  168.     *Insptr++ = c;
  169.     Ninsert++;
  170.     /*
  171.      * The following kludge avoids overflowing the statically
  172.      * allocated insert buffer. Just dump the user back into
  173.      * command mode, and print a message.
  174.      */
  175.     if (Insptr+10 >= &Insbuff[1024]) {
  176.         stuffin(mkstr(ESC));
  177.         emsg("No buffer space - returning to command mode");
  178.         sleep(2);
  179.     }
  180.     updateline();
  181. }
  182.  
  183. void
  184. getout()
  185. {
  186.     windgoto(Rows-1,0);
  187.     putchar('\r');
  188.     putchar('\n');
  189.     windexit(0);
  190. }
  191.  
  192. void
  193. scrolldown(nlines)
  194. int    nlines;
  195. {
  196.     register LPTR    *p;
  197.     register int    done = 0;    /* total # of physical lines done */
  198.  
  199.     /* Scroll up 'nlines' lines. */
  200.     while (nlines--) {
  201.         if ((p = prevline(Topchar)) == NULL)
  202.             break;
  203.         done += plines(p);
  204.         *Topchar = *p;
  205.         /*
  206.          * If the cursor is on the bottom line, we need to
  207.          * make sure it gets moved up the appropriate number
  208.          * of lines so it stays on the screen.
  209.          */
  210.         if (Curschar->linep == Botchar->linep->prev) {
  211.             int    i = 0;
  212.             while (i < done) {
  213.                 i += plines(Curschar);
  214.                 *Curschar = *prevline(Curschar);
  215.             }
  216.         }
  217.     }
  218.     s_ins(0, done);
  219. }
  220.  
  221. void
  222. scrollup(nlines)
  223. int    nlines;
  224. {
  225.     register LPTR    *p;
  226.     register int    done = 0;    /* total # of physical lines done */
  227.     register int    pl;        /* # of plines for the current line */
  228.  
  229.     /* Scroll down 'nlines' lines. */
  230.     while (nlines--) {
  231.         pl = plines(Topchar);
  232.         if ((p = nextline(Topchar)) == NULL)
  233.             break;
  234.         done += pl;
  235.         if (Curschar->linep == Topchar->linep)
  236.             *Curschar = *p;
  237.         *Topchar = *p;
  238.  
  239.     }
  240.     s_del(0, done);
  241. }
  242.  
  243. /*
  244.  * oneright
  245.  * oneleft
  246.  * onedown
  247.  * oneup
  248.  *
  249.  * Move one char {right,left,down,up}.  Return TRUE when
  250.  * sucessful, FALSE when we hit a boundary (of a line, or the file).
  251.  */
  252.  
  253. bool_t
  254. oneright()
  255. {
  256.     set_want_col = TRUE;
  257.  
  258.     switch (inc(Curschar)) {
  259.  
  260.     case 0:
  261.         return TRUE;
  262.  
  263.     case 1:
  264.         dec(Curschar);        /* crossed a line, so back up */
  265.         /* fall through */
  266.     case -1:
  267.         return FALSE;
  268.     }
  269.     /*NOTREACHED*/
  270. }
  271.  
  272. bool_t
  273. oneleft()
  274. {
  275.     set_want_col = TRUE;
  276.  
  277.     switch (dec(Curschar)) {
  278.  
  279.     case 0:
  280.         return TRUE;
  281.  
  282.     case 1:
  283.         inc(Curschar);        /* crossed a line, so back up */
  284.         /* fall through */
  285.     case -1:
  286.         return FALSE;
  287.     }
  288.     /*NOTREACHED*/
  289. }
  290.  
  291. void
  292. beginline(flag)
  293. bool_t    flag;
  294. {
  295.     while ( oneleft() )
  296.         ;
  297.     if (flag) {
  298.         while (isspace(gchar(Curschar)) && oneright())
  299.             ;
  300.     }
  301.     set_want_col = TRUE;
  302. }
  303.  
  304. bool_t
  305. oneup(n)
  306. int    n;
  307. {
  308.     LPTR    p, *np;
  309.     register int    k;
  310.  
  311.     p = *Curschar;
  312.     for ( k=0; k<n; k++ ) {
  313.         /* Look for the previous line */
  314.         if ( (np=prevline(&p)) == NULL ) {
  315.             /* If we've at least backed up a little .. */
  316.             if ( k > 0 )
  317.                 break;    /* to update the cursor, etc. */
  318.             else
  319.                 return FALSE;
  320.         }
  321.         p = *np;
  322.     }
  323.     *Curschar = p;
  324.     /* This makes sure Topchar gets updated so the complete line */
  325.     /* is one the screen. */
  326.     cursupdate();
  327.     /* try to advance to the column we want to be at */
  328.     *Curschar = *coladvance(&p, Curswant);
  329.     return TRUE;
  330. }
  331.  
  332. bool_t
  333. onedown(n)
  334. int    n;
  335. {
  336.     LPTR    p, *np;
  337.     register int    k;
  338.  
  339.     p = *Curschar;
  340.     for ( k=0; k<n; k++ ) {
  341.         /* Look for the next line */
  342.         if ( (np=nextline(&p)) == NULL ) {
  343.             if ( k > 0 )
  344.                 break;
  345.             else
  346.                 return FALSE;
  347.         }
  348.         p = *np;
  349.     }
  350.     /* try to advance to the column we want to be at */
  351.     *Curschar = *coladvance(&p, Curswant);
  352.     return TRUE;
  353. }
  354.