home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d197 / stevie.lha / Stevie / edit.c < prev    next >
C/C++ Source or Header  |  1989-03-28  |  9KB  |  400 lines

  1. /*
  2.  * STEVIE - Simply Try this Editor for VI Enthusiasts
  3.  *
  4.  * Code Contributions By : Tim Thompson           twitch!tjt
  5.  *                         Tony Andrews           onecom!wldrdg!tony 
  6.  *                         G. R. (Fred) Walter    watmath!watcgl!grwalter 
  7.  */
  8.  
  9. #include "stevie.h"
  10.  
  11. /*
  12.  * This flag is used to make auto-indent work right on lines where only a
  13.  * <RETURN> or <ESC> is typed. It is set when an auto-indent is done, and
  14.  * reset when any other editting is done on the line. If an <ESC> or <RETURN>
  15.  * is received, and did_ai is TRUE, the line is truncated. 
  16.  */
  17. bool_t          did_ai = FALSE;
  18.  
  19. void
  20. edit()
  21. {
  22.     char            c;
  23.     bool_t          literal_next_flag = FALSE;
  24.  
  25.     Prenum = 0;
  26.  
  27.     /* position the display and the cursor at the top of the file. */
  28.     *Topchar = *Filemem;
  29.     *Curschar = *Filemem;
  30.     Cursrow = Curscol = 0;
  31.  
  32.     for (;;) {
  33.  
  34.     if (!RedrawingDisabled) {
  35.         cursupdate();    /* Figure out where the cursor is based on
  36.                  * Curschar. */
  37.         if (MustRedrawLine)
  38.         redrawline();
  39.  
  40.         if (MustRedrawScreen)
  41.         updateRealscreen();
  42.  
  43.         windgoto(Cursrow, Curscol);
  44.     }
  45.     c = vgetc();
  46.  
  47.     if (State == NORMAL) {
  48.         /* We're in the normal (non-insert) mode. */
  49.  
  50.         /* Pick up any leading digits and compute 'Prenum' */
  51.         if ((Prenum > 0 && isdigit(c)) || (isdigit(c) && c != '0')) {
  52.         Prenum = Prenum * 10 + (c - '0');
  53.         continue;
  54.         }
  55.         /* execute the command */
  56.         normal(c);
  57.         Prenum = 0;
  58.  
  59.     } else {
  60.         if (c == CTRL('V') && !literal_next_flag) {
  61.         literal_next_flag = TRUE;
  62.         outchar('^');
  63.         continue;
  64.         }
  65.         if (literal_next_flag) {
  66.         literal_next_flag = FALSE;
  67.         outchar('\b');
  68.         if (c != NL) {
  69.             did_ai = FALSE;
  70.             insertchar(c);
  71.             continue;
  72.         }
  73.         }
  74.         switch (c) {    /* We're in insert mode */
  75.  
  76.           case ESC:    /* an escape ends input mode */
  77.     doESCkey:
  78.         /*
  79.          * If we just did an auto-indent, truncate the line, and put
  80.          * the cursor back. 
  81.          */
  82.         if (did_ai) {
  83.             Curschar->linep->s[0] = NUL;
  84.             Curschar->index = 0;
  85.             did_ai = FALSE;
  86.         }
  87.         set_want_col = TRUE;
  88.  
  89.         /*
  90.          * The cursor should end up on the last inserted character.
  91.          * This is an attempt to match the real 'vi', but it may not
  92.          * be quite right yet. 
  93.          */
  94.         if (Curschar->index != 0) {
  95.             if (gchar(Curschar) == NUL)
  96.             dec(Curschar);
  97.             else if (Insbuffptr != NULL)
  98.             dec(Curschar);
  99.         }
  100.         State = NORMAL;
  101.         msg("");
  102.  
  103.         if (RedrawingDisabled) {
  104.             updateNextscreen(NOT_VALID);    /* Update LineSizes. */
  105.             cursupdate();    /* Update Topchar and Botchar. */
  106.         }
  107.         if (!UndoInProgress) {
  108.             int             n;
  109.             char           *p;
  110.  
  111.             if (last_command == 'o')
  112.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  113.  
  114.             if (Insbuffptr != NULL) {
  115.             if (last_command == 'O')
  116.                 AppendToUndobuff("0");
  117.             AppendToRedobuff(Insbuff);
  118.             AppendToUndoUndobuff(Insbuff);
  119.             n = 0;
  120.             for (p = Insbuff; *p != NUL; p++) {
  121.                 if (*p == NL) {
  122.                 if (n) {
  123.                     AppendNumberToUndobuff(n);
  124.                     AppendToUndobuff("dl");
  125.                     n = 0;
  126.                 }
  127.                 AppendToUndobuff(UNDO_SHIFTJ_STR);
  128.                 } else
  129.                 n++;
  130.             }
  131.             if (n) {
  132.                 AppendNumberToUndobuff(n);
  133.                 AppendToUndobuff("dl");
  134.             }
  135.             }
  136.             if (last_command == 'c') {
  137.             AppendToUndobuff(mkstr(last_command_char));
  138.             AppendToUndobuff(Yankbuff);
  139.             AppendToUndobuff(ESC_STR);
  140.             }
  141.             AppendToRedobuff(ESC_STR);
  142.             AppendToUndoUndobuff(ESC_STR);
  143.             if (last_command == 'O')
  144.             AppendToUndobuff(UNDO_SHIFTJ_STR);
  145.         }
  146.         break;
  147.  
  148.           case CTRL('D'):
  149.         /*
  150.          * Control-D is treated as a backspace in insert mode to make
  151.          * auto-indent easier. This isn't completely compatible with
  152.          * vi, but it's a lot easier than doing it exactly right, and
  153.          * the difference isn't very noticeable. 
  154.          */
  155.           case BS:
  156.         /* can't backup past starting point */
  157.         if (Curschar->linep == Insstart->linep &&
  158.             Curschar->index <= Insstart->index) {
  159.             beep();
  160.             break;
  161.         }
  162.         /* can't backup to a previous line */
  163.         if (Curschar->linep != Insstart->linep &&
  164.             Curschar->index <= 0) {
  165.             beep();
  166.             break;
  167.         }
  168.         did_ai = FALSE;
  169.         dec(Curschar);
  170.         delchar(TRUE, FALSE);
  171.         /*
  172.          * It's a little strange to put backspaces into the redo
  173.          * buffer, but it makes auto-indent a lot easier to deal
  174.          * with. 
  175.          */
  176.         AppendToInsbuff(BS_STR);
  177.         if (!RedrawingDisabled) {
  178.             cursupdate();
  179.             updateline();
  180.         }
  181.         break;
  182.  
  183.           case CR:
  184.           case NL:
  185.         AppendToInsbuff(NL_STR);
  186.         if (!OpenForward(!RedrawingDisabled))
  187.             goto doESCkey;    /* out of memory */
  188.  
  189.         if (!RedrawingDisabled)
  190.             windgoto(Cursrow, Curscol);
  191.         break;
  192.  
  193.           default:
  194.         did_ai = FALSE;
  195.         insertchar(c);
  196.         break;
  197.         }
  198.     }
  199.     }
  200. }
  201.  
  202. /*
  203.  * Special characters in this context are those that need processing other
  204.  * than the simple insertion that can be performed here. This includes ESC
  205.  * which terminates the insert, and CR/NL which need special processing to
  206.  * open up a new line. This routine tries to optimize insertions performed by
  207.  * the "redo", "undo" or "put" commands, so it needs to know when it should
  208.  * stop and defer processing to the "normal" mechanism. 
  209.  */
  210. #define    ISSPECIAL(c)    ((c) == BS || (c) == NL || (c) == CR || (c) == ESC)
  211.  
  212. void
  213. insertchar(c)
  214.     char            c;
  215. {
  216.     if (anyinput()) {        /* If there's any pending input, grab up to
  217.                  * MAX_COLUMNS at once. */
  218.     char            p[MAX_COLUMNS + 1];
  219.     int             i;
  220.  
  221.     p[0] = c;
  222.     i = 1;
  223.     c = vpeekc();
  224.     while (!ISSPECIAL(c) && anyinput() && (i < MAX_COLUMNS)) {
  225.         p[i++] = vgetc();
  226.         c = vpeekc();
  227.     }
  228.     p[i] = '\0';
  229.     insstr(p);
  230.     AppendToInsbuff(p);
  231.     } else {
  232.     inschar(c);
  233.     AppendToInsbuff(mkstr(c));
  234.     }
  235.  
  236.     if (!RedrawingDisabled)
  237.     updateline();
  238. }
  239.  
  240. void
  241. getout(r)
  242.     int             r;
  243. {
  244.     windgoto(Rows - 1, 0);
  245.     putchar('\r');
  246.     putchar('\n');
  247.     windexit(r);
  248. }
  249.  
  250. void
  251. scrolldown(nlines)
  252.     int             nlines;
  253. {
  254.     register LPtr  *p;
  255.     register int    done = 0;    /* total # of physical lines done */
  256.  
  257.     /* Scroll up 'nlines' lines. */
  258.     while (nlines--) {
  259.     if ((p = prevline(Topchar)) == NULL)
  260.         break;
  261.     done += plines(p);
  262.     *Topchar = *p;
  263.     if (Curschar->linep == Botchar->linep->prev)
  264.         *Curschar = *prevline(Curschar);
  265.     }
  266.     s_ins(0, done, Rows, Columns);
  267. }
  268.  
  269. void
  270. scrollup(nlines)
  271.     int             nlines;
  272. {
  273.     register LPtr  *p;
  274.     register int    done = 0;    /* total # of physical lines done */
  275.     register int    pl;        /* # of plines for the current line */
  276.  
  277.     /* Scroll down 'nlines' lines. */
  278.     while (nlines--) {
  279.     pl = plines(Topchar);
  280.     if ((p = nextline(Topchar)) == NULL)
  281.         break;
  282.     done += pl;
  283.     if (Curschar->linep == Topchar->linep)
  284.         *Curschar = *p;
  285.     *Topchar = *p;
  286.  
  287.     }
  288.     s_del(0, done, Rows, Columns);
  289. }
  290.  
  291. /*
  292.  * oneright oneleft onedown oneup 
  293.  *
  294.  * Move one char {right,left,down,up}.  Return TRUE when sucessful, FALSE when
  295.  * we hit a boundary (of a line, or the file). 
  296.  */
  297.  
  298. bool_t
  299. oneright()
  300. {
  301.     set_want_col = TRUE;
  302.  
  303.     switch (inc(Curschar)) {
  304.  
  305.       case 0:
  306.     return TRUE;
  307.  
  308.       case 1:
  309.     dec(Curschar);        /* crossed a line, so back up */
  310.     /* FALLTHROUGH */
  311.       case -1:
  312.     return FALSE;
  313.     }
  314.  
  315.     return FALSE;        /* PARANOIA: should never reach here */
  316. }
  317.  
  318. bool_t
  319. oneleft()
  320. {
  321.     set_want_col = TRUE;
  322.  
  323.     switch (dec(Curschar)) {
  324.  
  325.       case 0:
  326.     return TRUE;
  327.  
  328.       case 1:
  329.     inc(Curschar);        /* crossed a line, so back up */
  330.     /* FALLTHROUGH */
  331.       case -1:
  332.     return FALSE;
  333.     }
  334.  
  335.     return FALSE;        /* PARANOIA: should never reach here */
  336. }
  337.  
  338. void
  339. beginline(flag)
  340.     bool_t          flag;
  341. {
  342.     while (oneleft());
  343.     if (flag) {
  344.     while (isspace(gchar(Curschar)) && oneright());
  345.     }
  346.     set_want_col = TRUE;
  347. }
  348.  
  349. bool_t
  350. oneup(n)
  351. {
  352.     LPtr            p, *np;
  353.     int             k;
  354.  
  355.     p = *Curschar;
  356.     for (k = 0; k < n; k++) {
  357.     /* Look for the previous line */
  358.     if ((np = prevline(&p)) == NULL) {
  359.         /* If we've at least backed up a little .. */
  360.         if (k > 0)
  361.         break;        /* to update the cursor, etc. */
  362.         else
  363.         return FALSE;
  364.     }
  365.     p = *np;
  366.     }
  367.     *Curschar = p;
  368.  
  369.     cursupdate();        /* make sure Topchar is valid */
  370.  
  371.     /* try to advance to the column we want to be at */
  372.     *Curschar = *coladvance(&p, Curswant);
  373.     return TRUE;
  374. }
  375.  
  376. bool_t
  377. onedown(n)
  378. {
  379.     LPtr            p, *np;
  380.     int             k;
  381.  
  382.     p = *Curschar;
  383.     for (k = 0; k < n; k++) {
  384.     /* Look for the next line */
  385.     if ((np = nextline(&p)) == NULL) {
  386.         if (k > 0)
  387.         break;
  388.         else
  389.         return FALSE;
  390.     }
  391.     p = *np;
  392.     }
  393.  
  394.     cursupdate();        /* make sure Topchar is valid */
  395.  
  396.     /* try to advance to the column we want to be at */
  397.     *Curschar = *coladvance(&p, Curswant);
  398.     return TRUE;
  399. }
  400.