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