home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 1 / 1708 / input.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-28  |  9.8 KB  |  507 lines

  1. /* input.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    16820 SW Tallac Way
  6.  *    Beaverton, OR 97006
  7.  *    kirkenda@jove.cs.pdx.edu, or ...uunet!tektronix!psueea!jove!kirkenda
  8.  */
  9.  
  10.  
  11. /* This file contains the input() function, which implements vi's INPUT mode.
  12.  * It also contains the code that supports digraphs.
  13.  */
  14.  
  15. #include <ctype.h>
  16. #include "config.h"
  17. #include "vi.h"
  18.  
  19.  
  20. #ifndef NO_DIGRAPH
  21. static struct
  22. {
  23.     char    key1;
  24.     char    key2;
  25.     char    dig;
  26. } digs[MAXDIGS];
  27.  
  28. static char digraph(key1, key2)
  29.     char    key1;    /* the first character (punctuation) */
  30.     char    key2;    /* the overtyped character (probably a letter) */
  31. {
  32.     int    i;
  33.  
  34.     /* can only be a digraph if key1 is punctuation */
  35.     if (!isascii(key1) || !ispunct(key1))
  36.     {
  37.         return key2;
  38.     }
  39.  
  40.     /* scan through the digraph chart */
  41.     for (i = 0;
  42.          i < MAXDIGS && (!digs[i].dig || digs[i].key1 != key1 || digs[i].key2 != key2);
  43.          i++)
  44.     {
  45.     }
  46.  
  47.     /* if this combination isn't in there, just use the new key */
  48.     if (i >= MAXDIGS)
  49.     {
  50.         return key2;
  51.     }
  52.  
  53.     /* else use the digraph key */
  54.     return digs[i].dig;
  55. }
  56.  
  57. do_digraph(bang, args)
  58.     int    bang;
  59.     char    args[];
  60. {
  61.     int    i;
  62.     int    dig;
  63.  
  64.     /* if no args, then display the existing digraphs */
  65.     if (*args < ' ')
  66.     {
  67.         for (i = 0; i < MAXDIGS; i++)
  68.         {
  69.             if (digs[i].dig)
  70.             {
  71.                 msg("digraph %c%c %c", digs[i].key1, digs[i].key2, digs[i].dig);
  72.             }
  73.         }
  74.         return;
  75.     }
  76.  
  77.     /* first character of a digraph must be punctuation */
  78.     if (!isascii(args[0]) || !ispunct(args[0]))
  79.     {
  80.         msg("The first character of a digraph must be punctuation");
  81.         return;
  82.     }
  83.     if (!args[1])
  84.     {
  85.         msg("Digraphs must be composed of two characters");
  86.         return;
  87.     }
  88.  
  89.     /* locate the new digraph character */
  90.     for (i = 2; args[i] == ' ' || args[i] == '\t'; i++)
  91.     {
  92.     }
  93.     dig = args[i];
  94.     if (!bang && dig)
  95.     {
  96.         dig |= 0x80;
  97.     }
  98.  
  99.     /* search for the digraph */
  100.     for (i = 0; i < MAXDIGS && (digs[i].key1 != args[0] || digs[i].key2 != args[1]); i++)
  101.     {
  102.     }
  103.     if (i >= MAXDIGS)
  104.     {
  105.         for (i = 0; i < MAXDIGS && digs[i].dig; i++)
  106.         {
  107.         }
  108.         if (i >= MAXDIGS)
  109.         {
  110.             msg("Out of space in the digraph table");
  111.             return;
  112.         }
  113.     }
  114.  
  115.     /* assign it the new digraph value */
  116.     digs[i].key1 = args[0];
  117.     digs[i].key2 = args[1];
  118.     digs[i].dig = dig;
  119. }
  120.  
  121. savedigs(fd)
  122.     int        fd;
  123. {
  124.     int        i;
  125.     static char    buf[] = "digraph! XX Y\n";
  126.  
  127.     for (i = 0; i < MAXDIGS; i++)
  128.     {
  129.         if (digs[i].dig)
  130.         {
  131.             buf[9] = digs[i].key1;
  132.             buf[10] = digs[i].key2;
  133.             buf[12] = digs[i].dig;
  134.             write(fd, buf, 14);
  135.         }
  136.     }
  137. }
  138. #endif
  139.  
  140.  
  141. /* This function allows the user to replace an existing (possibly zero-length)
  142.  * chunk of text with typed-in text.  It returns the MARK of the last character
  143.  * that the user typed in.
  144.  */
  145. MARK input(from, to, when)
  146.     MARK    from;    /* where to start inserting text */
  147.     MARK    to;    /* extent of text to delete */
  148.     int    when;    /* either WHEN_VIINP or WHEN_VIREP */
  149. {
  150.     char    key[2];    /* key char followed by '\0' char */
  151.     char    *build;    /* used in building a newline+indent string */
  152.     char    *scan;    /* used while looking at the indent chars of a line */
  153.     MARK    m;    /* some place in the text */
  154. #ifndef NO_EXTENSIONS
  155.     int    quit = FALSE;    /* boolean: are we exiting after this? */
  156. #endif
  157.  
  158. #ifdef DEBUG
  159.     /* if "from" and "to" are reversed, complain */
  160.     if (from > to)
  161.     {
  162.         msg("ERROR: input(%ld:%d, %ld:%d)",
  163.             markline(from), markidx(from),
  164.             markline(to), markidx(to));
  165.         return MARK_UNSET;
  166.     }
  167. #endif
  168.  
  169.     key[1] = 0;
  170.  
  171.     /* if we're replacing text with new text, save the old stuff */
  172.     /* (Alas, there is no easy way to save text for replace mode) */
  173.     if (from != to)
  174.     {
  175.         cut(from, to);
  176.     }
  177.  
  178.     ChangeText
  179.     {
  180.         /* if doing a dot command, then reuse the previous text */
  181.         if (doingdot)
  182.         {
  183.             /* delete the text that's there now */
  184.             if (from != to)
  185.             {
  186.                 delete(from, to);
  187.             }
  188.  
  189.             /* insert the previous text */
  190.             cutname('.');
  191.             cursor = paste(from, FALSE, TRUE) + 1L;
  192.             /* explicitly set preredraw and postredraw */
  193.             redrawafter = markline(from);
  194.             preredraw = markline(to);
  195.             postredraw = markline(cursor);
  196.         }
  197.         else /* interactive version */
  198.         {
  199.             /* if doing a change within the line... */
  200.             if (from != to && markline(from) == markline(to))
  201.             {
  202.                 /* mark the end of the text with a "$" */
  203.                 change(to - 1, to, "$");
  204.             }
  205.             else
  206.             {
  207.                 /* delete the old text right off */
  208.                 if (from != to)
  209.                 {
  210.                     delete(from, to);
  211.                 }
  212.                 to = from;
  213.             }
  214.  
  215.             /* handle autoindent of the first line, maybe */
  216.             cursor = from;
  217.             if (*o_autoindent && markline(cursor) > 1L && markidx(cursor) == 0)
  218.             {
  219.                 /* Only autoindent blank lines. */
  220.                 pfetch(markline(cursor));
  221.                 if (plen == 0)
  222.                 {
  223.                     /* Okay, we really want to autoindent */
  224.                     pfetch(markline(cursor) - 1L);
  225.                     for (scan = ptext, build = tmpblk.c;
  226.                          *scan == ' ' || *scan == '\t';
  227.                          )
  228.                     {
  229.                         *build++ = *scan++;
  230.                     }
  231.                     if (build > tmpblk.c)
  232.                     {
  233.                         *build = '\0';
  234.                         add(cursor, tmpblk.c);
  235.                         cursor += (build - tmpblk.c);
  236.                     }
  237.                 }
  238.             }
  239.  
  240.             /* repeatedly add characters from the user */
  241.             for (;;)
  242.             {
  243.                 /* Get a character */
  244.                 redraw(cursor, TRUE);
  245.                 key[0] = getkey(when);
  246.  
  247.                 /* if whitespace & wrapmargin is set & we're
  248.                 /* past the warpmargin, then change the
  249.                 /* whitespace character into a newline
  250.                  */
  251.                 if ((*key == ' ' || *key == '\t')
  252.                  && *o_wrapmargin != 0)
  253.                 {
  254.                     pfetch(markline(cursor));
  255.                     if (idx2col(cursor, ptext, TRUE) > COLS - (*o_wrapmargin & 0xff))
  256.                     {
  257.                         *key = '\n';
  258.                     }
  259.                 }
  260.  
  261.                 /* process it */
  262.                 switch (*key)
  263.                 {
  264. #ifndef NO_EXTENSIONS
  265.                   case 0: /* special movement mapped keys */
  266.                     *key = getkey(0);
  267.                     switch (*key)
  268.                     {
  269.                       case 'h':    m = m_left(cursor, 0L);        break;
  270.                       case 'j':    m = m_down(cursor, 0L);        break;
  271.                       case 'k':    m = m_up(cursor, 0L);        break;
  272.                       case 'l':    m = cursor + 1;                break;
  273.                       case 'b':    m = m_bword(cursor, 0L);    break;
  274.                       case 'w':    m = m_fword(cursor, 0L);    break;
  275.                       case '^':    m = m_front(cursor, 0L);    break;
  276.                       case '$':    m = m_rear(cursor, 0L);        break;
  277.                       case ctrl('B'):
  278.                       case ctrl('F'):
  279.                             m = m_scroll(cursor, 0L, *key); break;
  280.                       case 'x':    m = v_xchar(cursor, 0L);    break;
  281.                       case 'i':    m = to = from = cursor;        break;
  282.                       default:    m = MARK_UNSET;            break;
  283.                     }
  284.                     /* adjust the moved cursor */
  285.                     m = adjmove(cursor, m, (*key == 'j' || *key == 'k' ? 0x20 : 0));
  286.                     if (*key == '$' || (*key == 'l' && m <= cursor))
  287.                     {
  288.                         m++;
  289.                     }
  290.                     /* if the cursor is reasonable, use it */
  291.                     if (m == MARK_UNSET)
  292.                     {
  293.                         beep();
  294.                     }
  295.                     else
  296.                     {
  297.                         if (to > cursor)
  298.                         {
  299.                             delete(cursor, to);
  300.                             redraw(cursor, TRUE);
  301.                         }
  302.                         from = to = cursor = m;
  303.                     }
  304.                     break;
  305.  
  306.                   case ctrl('Z'):
  307.                     if (getkey(0) == ctrl('Z'))
  308.                     {
  309.                         quit = TRUE;
  310.                         goto BreakBreak;
  311.                     }
  312.                     break;
  313. #endif
  314.                   case ctrl('['):
  315.                     goto BreakBreak;
  316.  
  317.                   case ctrl('U'):
  318.                     if (markline(cursor) == markline(from))
  319.                     {
  320.                         cursor = from;
  321.                     }
  322.                     else
  323.                     {
  324.                         cursor &= ~(BLKSIZE - 1);
  325.                     }
  326.                     break;
  327.  
  328.                   case ctrl('D'):
  329.                   case ctrl('T'):
  330.                     mark[27] = cursor;
  331.                     cmd_shift(cursor, cursor, *key == ctrl('D') ? CMD_SHIFTL : CMD_SHIFTR, TRUE, "");
  332.                     if (mark[27])
  333.                     {
  334.                         cursor = mark[27];
  335.                     }
  336.                     else
  337.                     {
  338.                         cursor = m_front(cursor, 0L);
  339.                     }
  340.                     break;
  341.  
  342.                   case '\b':
  343.                     if (cursor <= from)
  344.                     {
  345.                         beep();
  346.                     }
  347.                     else if (markidx(cursor) == 0)
  348.                     {
  349.                         cursor -= BLKSIZE;
  350.                         pfetch(markline(cursor));
  351.                         cursor += plen;
  352.                     }
  353.                     else
  354.                     {
  355.                         cursor--;
  356.                     }
  357.                     break;
  358.  
  359.                   case ctrl('W'):
  360.                     m = m_bword(cursor, 1L);
  361.                     if (markline(m) == markline(cursor) && m >= from)
  362.                     {
  363.                         cursor = m;
  364.                         if (from > cursor)
  365.                         {
  366.                             from = cursor;
  367.                         }
  368.                     }
  369.                     else
  370.                     {
  371.                         beep();
  372.                     }
  373.                     break;
  374.  
  375.                   case '\n':
  376.                   case '\r':
  377.                     build = tmpblk.c;
  378.                     *build++ = '\n';
  379.                     if (*o_autoindent)
  380.                     {
  381.                         pfetch(markline(cursor));
  382.                         for (scan = ptext; *scan == ' ' || *scan == '\t'; )
  383.                         {
  384.                             *build++ = *scan++;
  385.                         }
  386.                     }
  387.                     *build = 0;
  388.                     if (cursor >= to && when != WHEN_VIREP)
  389.                     {
  390.                         add(cursor, tmpblk.c);
  391.                     }
  392.                     else
  393.                     {
  394.                         change(cursor, to, tmpblk.c);
  395.                     }
  396.                     redraw(cursor, TRUE);
  397.                     to = cursor = (cursor & ~(BLKSIZE - 1))
  398.                             + BLKSIZE
  399.                             + (int)(build - tmpblk.c) - 1;
  400.                     break;
  401.  
  402.                   case ctrl('A'):
  403.                   case ctrl('P'):
  404.                     if (cursor < to)
  405.                     {
  406.                         delete(cursor, to);
  407.                     }
  408.                     if (*key == ctrl('A'))
  409.                     {
  410.                         cutname('.');
  411.                     }
  412.                     to = cursor = paste(cursor, FALSE, TRUE) + 1L;
  413.                     break;
  414.  
  415.                   case ctrl('V'):
  416.                     if (cursor >= to && when != WHEN_VIREP)
  417.                     {
  418.                         add(cursor, "^");
  419.                     }
  420.                     else
  421.                     {
  422.                         change(cursor, to, "^");
  423.                     }
  424.                     redraw(cursor, TRUE);
  425.                     *key = getkey(0);
  426.                     if (*key == '\n')
  427.                     {
  428.                         /* '\n' too hard to handle */
  429.                         *key = '\r';
  430.                     }
  431.                     change(cursor, cursor + 1, key);
  432.                     cursor++;
  433.                     if (cursor > to)
  434.                     {
  435.                         to = cursor;
  436.                     }
  437.                     break;
  438.  
  439.                   case ctrl('L'):
  440.                   case ctrl('R'):
  441.                     redraw(MARK_UNSET, FALSE);
  442.                     break;
  443.  
  444.                   default:
  445.                     if (cursor >= to && when != WHEN_VIREP)
  446.                     {
  447.                         add(cursor, key);
  448.                         cursor++;
  449.                         to = cursor;
  450.                     }
  451.                     else
  452.                     {
  453.                         pfetch(markline(cursor));
  454.                         if (markidx(cursor) == plen)
  455.                         {
  456.                             add(cursor, key);
  457.                         }
  458.                         else
  459.                         {
  460. #ifndef NO_DIGRAPH
  461.                             *key = digraph(ptext[markidx(cursor)], *key);
  462. #endif
  463.                             change(cursor, cursor + 1, key);
  464.                         }
  465.                         cursor++;
  466.                     }
  467.                 } /* end switch(*key) */
  468.             } /* end for(;;) */
  469. BreakBreak:;
  470.  
  471.             /* delete any excess characters */
  472.             if (cursor < to)
  473.             {
  474.                 delete(cursor, to);
  475.             }
  476.  
  477.         } /* end if doingdot else */
  478.  
  479.     } /* end ChangeText */
  480.  
  481.     /* put the new text into a cut buffer for possible reuse */
  482.     if (!doingdot)
  483.     {
  484.         blksync();
  485.         cutname('.');
  486.         cut(from, cursor);
  487.     }
  488.  
  489.     /* move to last char that we inputted, unless it was newline */
  490.     if (markidx(cursor) != 0)
  491.     {
  492.         cursor--;
  493.     }
  494.     redraw(cursor, FALSE);
  495.  
  496. #ifndef NO_EXTENSIONS
  497.     if (quit)
  498.     {
  499.         refresh();
  500.         cursor = v_xit(cursor, 0L, 'Z');
  501.     }
  502. #endif
  503.  
  504.     rptlines = 0L;
  505.     return cursor;
  506. }
  507.