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

  1. /* vcmd.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 functions that handle VI commands */
  12.  
  13.  
  14. #include "config.h"
  15. #include "vi.h"
  16. #if    MSDOS
  17. #include <process.h>
  18. #include <string.h>
  19. #endif
  20. #if    TOS
  21. #include <osbind.h>
  22. #include <string.h>
  23. #endif
  24.  
  25.  
  26. /* This function puts the editor in EX mode */
  27. MARK v_quit()
  28. {
  29.     mode = MODE_EX;
  30.     return cursor;
  31. }
  32.  
  33. /* This function causes the screen to be redrawn */
  34. MARK v_redraw()
  35. {
  36.     redraw(MARK_UNSET, FALSE);
  37.     return cursor;
  38. }
  39.  
  40. /* This function executes a single EX command, and waits for a user keystroke
  41.  * before returning to the VI screen.  If that keystroke is another ':', then
  42.  * another EX command is read and executed.
  43.  */
  44. /*ARGSUSED*/
  45. MARK v_1ex(m, text)
  46.     MARK    m;    /* the current line */
  47.     char    *text;    /* the first command to execute */
  48. {
  49.     /* scroll up, so we don't overwrite the command */
  50.     if (mode == MODE_COLON)
  51.     {
  52.         addch('\n');
  53.         refresh();
  54.     }
  55.  
  56.     /* run the command.  be careful about modes & output */
  57.     exwrote = (mode == MODE_COLON);
  58.     doexcmd(text);
  59.     exrefresh();
  60.  
  61.     /* if mode is no longer MODE_VI, then we should quit right away! */
  62.     if (mode != MODE_VI && mode != MODE_COLON)
  63.         return cursor;
  64.  
  65.     /* The command did some output.  Wait for a keystoke. */
  66.     if (exwrote)
  67.     {
  68.         mode = MODE_VI;    
  69.         msg("[Hit any key to continue]");
  70.         if (getkey(0) == ':')
  71.         {    mode = MODE_COLON;
  72.             addch('\n');
  73.         }
  74.         else
  75.             redraw(MARK_UNSET, FALSE);
  76.     }
  77.  
  78.     return cursor;
  79. }
  80.  
  81. /* This function undoes the last change */
  82. /*ARGSUSED*/
  83. MARK v_undo(m)
  84.     MARK    m;    /* (ignored) */
  85. {
  86.     undo();
  87.     redraw(MARK_UNSET, FALSE);
  88.     return cursor;
  89. }
  90.  
  91. /* This function deletes the character(s) that the cursor is on */
  92. MARK v_xchar(m, cnt)
  93.     MARK    m;    /* where to start deletions */
  94.     long    cnt;    /* number of chars to delete */
  95. {
  96.     DEFAULT(1);
  97.  
  98.     pfetch(markline(m));
  99.     if (markidx(m + cnt) > plen)
  100.     {
  101.         cnt = plen - markidx(m);
  102.     }
  103.     if (cnt == 0L)
  104.     {
  105.         return MARK_UNSET;
  106.     }
  107.     ChangeText
  108.     {
  109.         cut(m, m + cnt);
  110.         delete(m, m + cnt);
  111.     }
  112.     return m;
  113. }
  114.  
  115. /* This function deletes character to the left of the cursor */
  116. MARK v_Xchar(m, cnt)
  117.     MARK    m;    /* where deletions end */
  118.     long    cnt;    /* number of chars to delete */
  119. {
  120.     DEFAULT(1);
  121.  
  122.     /* if we're at the first char of the line, error! */
  123.     if (markidx(m) == 0)
  124.     {
  125.         return MARK_UNSET;
  126.     }
  127.  
  128.     /* make sure we don't try to delete more chars than there are */
  129.     if (cnt > markidx(m))
  130.     {
  131.         cnt = markidx(m);
  132.     }
  133.  
  134.     /* delete 'em */
  135.     ChangeText
  136.     {
  137.         cut(m - cnt, m);
  138.         delete(m - cnt, m);
  139.     }
  140.  
  141.     return m - cnt;
  142. }
  143.  
  144. /* This function defines a mark */
  145. /*ARGSUSED*/
  146. MARK v_mark(m, count, key)
  147.     MARK    m;    /* where the mark will be */
  148.     long    count;    /* (ignored) */
  149.     int    key;    /* the ASCII label of the mark */
  150. {
  151.     if (key < 'a' || key > 'z')
  152.     {
  153.         msg("Marks must be from a to z");
  154.     }
  155.     else
  156.     {
  157.         mark[key - 'a'] = m;
  158.     }
  159.     return m;
  160. }
  161.  
  162. /* This function toggles upper & lower case letters */
  163. MARK v_ulcase(m)
  164.     MARK    m;    /* where to make the change */
  165. {
  166.     char    new[2];
  167. #if    MSDOS || TOS
  168.     char    *pos;
  169.     char    *lower="\207\201\202\204\206\221\224\244";
  170.     char     *upper="\200\232\220\216\217\222\231\245";
  171. #endif
  172.  
  173.     /* extract the char that's there now */
  174.     pfetch(markline(m));
  175.     new[0] = ptext[markidx(m)];
  176.     new[1] = '\0';
  177.  
  178.     /* change it if necessary */
  179.     if (new[0] >= 'a' && new[0] <= 'z' || new[0] >= 'A' && new[0] <= 'Z')
  180.     {
  181.         new[0] ^= ('A' ^ 'a');
  182.         ChangeText
  183.         {
  184.             change(m, m + 1, new);
  185.         }
  186.     }
  187. #if    MSDOS || TOS
  188.     if ((pos=strchr(lower, new[0]))!=0)
  189.         new[0]=upper[(int)(pos-lower)];
  190.     else if ((pos=strchr(upper, new[0]))!=0)
  191.         new[0]=lower[(int)(pos-upper)];
  192.     else
  193.         goto nochange;        /* Urghh - GB */
  194.     ChangeText
  195.     {
  196.         change(m, m + 1, new);
  197.     }
  198. nochange:
  199. #endif
  200.     if (new[0] && ptext[markidx(m) + 1])
  201.     {
  202.         m++;
  203.     }
  204.     return m;
  205. }
  206.  
  207.  
  208. MARK v_replace(m, cnt, key)
  209.     MARK    m;    /* first char to be replaced */
  210.     long    cnt;    /* number of chars to replace */
  211.     int    key;    /* what to replace them with */
  212. {
  213.     register char    *text;
  214.     register int    i;
  215.     static int    samekey;
  216.  
  217.     DEFAULT(1);
  218.  
  219.     /* map ^M to '\n' */
  220.     if (key == '\r')
  221.     {
  222.         key = '\n';
  223.     }
  224.     else if (key == ctrl('V'))
  225.     {
  226.         if (doingdot)
  227.             key = samekey;
  228.         else
  229.             key = samekey = getkey(0);
  230.         if (key == 0)
  231.             return MARK_UNSET;
  232.     }
  233.     else if (!doingdot && key == ctrl('['))
  234.     {
  235.         samekey = 0;
  236.         return MARK_UNSET;
  237.     }
  238.  
  239.     /* make sure the resulting line isn't too long */
  240.     if (cnt > BLKSIZE - 2 - markidx(m))
  241.     {
  242.         cnt = BLKSIZE - 2 - markidx(m);
  243.     }
  244.  
  245.     /* build a string of the desired character with the desired length */
  246.     for (text = tmpblk.c, i = cnt; i > 0; i--)
  247.     {
  248.         *text++ = key;
  249.     }
  250.     *text = '\0';
  251.  
  252.     /* make sure cnt doesn't extend past EOL */
  253.     pfetch(markline(m));
  254.     key = markidx(m);
  255.     if (key + cnt > plen)
  256.     {
  257.         cnt = plen - key;
  258.     }
  259.  
  260.     /* do the replacement */
  261.     ChangeText
  262.     {
  263.         change(m, m + cnt, tmpblk.c);
  264.     }
  265.  
  266.     if (*tmpblk.c == '\n')
  267.     {
  268.         return (m & ~(BLKSIZE - 1)) + cnt * BLKSIZE;
  269.     }
  270.     else
  271.     {
  272.         return m + cnt - 1;
  273.     }
  274. }
  275.  
  276. MARK v_overtype(m)
  277.     MARK        m;    /* where to start overtyping */
  278. {
  279.     MARK        end;    /* end of a substitution */
  280.     static long    width;    /* width of a single-line replace */
  281.  
  282.     /* the "doingdot" version of replace is really a substitution */
  283.     if (doingdot)
  284.     {
  285.         /* was the last one really repeatable? */
  286.         if (width < 0)
  287.         {
  288.             msg("Can't repeat a multi-line overtype command");
  289.             return MARK_UNSET;
  290.         }
  291.  
  292.         /* replacing nothing by nothing?  Don't bother */
  293.         if (width == 0)
  294.         {
  295.             return m;
  296.         }
  297.  
  298.         /* replace some chars by repeated text */
  299.         return v_subst(m, width);
  300.     }
  301.  
  302.     /* Normally, we input starting here, in replace mode */
  303.     ChangeText
  304.     {
  305.         end = input(m, m, WHEN_VIREP);
  306.     }
  307.  
  308.     /* if we ended on the same line we started on, then this
  309.      * overtype is repeatable via the dot key.
  310.      */
  311.     if (markline(end) == markline(m) && end >= m - 1L)
  312.     {
  313.         width = end - m + 1L;
  314.     }
  315.     else /* it isn't repeatable */
  316.     {
  317.         width = -1L;
  318.     }
  319.  
  320.     return end;
  321. }
  322.  
  323.  
  324. /* This function selects which cut buffer to use */
  325. /*ARGSUSED*/
  326. MARK v_selcut(m, cnt, key)
  327.     MARK    m;
  328.     long    cnt;
  329.     int    key;
  330. {
  331.     cutname(key);
  332.     return m;
  333. }
  334.  
  335. /* This function pastes text from a cut buffer */
  336. /*ARGSUSED*/
  337. MARK v_paste(m, cnt, cmd)
  338.     MARK    m;    /* where to paste the text */
  339.     long    cnt;    /* (ignored) */
  340.     int    cmd;    /* either 'p' or 'P' */
  341. {
  342.     ChangeText
  343.     {
  344.         m = paste(m, cmd == 'p', FALSE);
  345.     }
  346.     return m;
  347. }
  348.  
  349. /* This function yanks text into a cut buffer */
  350. MARK v_yank(m, n)
  351.     MARK    m, n;    /* range of text to yank */
  352. {
  353.     cut(m, n);
  354.     return m;
  355. }
  356.  
  357. /* This function deletes a range of text */
  358. MARK v_delete(m, n)
  359.     MARK    m, n;    /* range of text to delete */
  360. {
  361.     /* illegal to try and delete nothing */
  362.     if (n <= m)
  363.     {
  364.         return MARK_UNSET;
  365.     }
  366.     /* Do it */
  367.     ChangeText
  368.     {
  369.         cut(m, n);
  370.         delete(m, n);
  371.     }
  372.     return m;
  373. }
  374.  
  375.  
  376. /* This starts input mode without deleting anything */
  377. MARK v_insert(m, cnt, key)
  378.     MARK    m;    /* where to start (sort of) */
  379.     long    cnt;    /* repeat how many times? */
  380.     int    key;    /* what command is this for? {a,A,i,I,o,O} */
  381. {
  382.     int    wasdot;
  383.     long    reps;
  384.  
  385.     DEFAULT(1);
  386.  
  387.     ChangeText
  388.     {
  389.         /* tweak the insertion point, based on command key */
  390.         switch (key)
  391.         {
  392.           case 'i':
  393.             break;
  394.  
  395.           case 'a':
  396.             pfetch(markline(m));
  397.             if (plen > 0)
  398.             {
  399.                 m++;
  400.             }
  401.             break;
  402.  
  403.           case 'I':
  404.             m = m_front(m, 1L);
  405.             break;
  406.  
  407.           case 'A':
  408.             pfetch(markline(m));
  409.             m = (m & ~(BLKSIZE - 1)) + plen;
  410.             break;
  411.  
  412.           case 'O':
  413.             m &= ~(BLKSIZE - 1);
  414.             add(m, "\n");
  415.             break;
  416.  
  417.           case 'o':
  418.             m = (m & ~(BLKSIZE - 1)) + BLKSIZE;
  419.             add(m, "\n");
  420.             break;
  421.         }
  422.  
  423.         /* insert the same text once or more */
  424.         for (reps = cnt, wasdot = doingdot; reps > 0; reps--, doingdot = TRUE)
  425.         {
  426.             m = input(m, m, WHEN_VIINP);
  427.         }
  428.  
  429.         /* compensate for inaccurate redraw clues from input() */
  430.         if ((key == 'O' || key == 'o') && wasdot)
  431.         {
  432.             redraw(MARK_UNSET);
  433.         }
  434.  
  435.         doingdot = FALSE;
  436.     }
  437.  
  438.     return m;
  439. }
  440.  
  441. /* This starts input mode with some text deleted */
  442. MARK v_change(m, n)
  443.     MARK    m, n;    /* the range of text to change */
  444. {
  445.     int    lnmode;    /* is this a line-mode change? */
  446.  
  447.     /* swap them if they're in reverse order */
  448.     if (m > n)
  449.     {
  450.         MARK    tmp;
  451.         tmp = m;
  452.         m = n;
  453.         n = tmp;
  454.     }
  455.  
  456.     /* for line mode, retain the last newline char */
  457.     lnmode = (markidx(m) == 0 && markidx(n) == 0 && m != n);
  458.     if (lnmode)
  459.     {
  460.         n -= BLKSIZE;
  461.         pfetch(markline(n));
  462.         n = (n & ~(BLKSIZE - 1)) + plen;
  463.     }
  464.  
  465.     ChangeText
  466.     {
  467.         cut(m, n);
  468.         m = input(m, n, WHEN_VIINP);
  469.     }
  470.  
  471.     /* compensate for inaccurate redraw clues from paste() */
  472.     if (doingdot)
  473.     {
  474.         preredraw = markline(n);
  475.         if (lnmode)
  476.         {
  477.             preredraw++;
  478.             postredraw++;
  479.         }
  480.     }
  481.  
  482.     return m;
  483. }
  484.  
  485. /* This function replaces a given number of characters with input */
  486. MARK v_subst(m, cnt)
  487.     MARK    m;    /* where substitutions start */
  488.     long    cnt;    /* number of chars to replace */
  489. {
  490.     DEFAULT(1);
  491.  
  492.     /* make sure we don't try replacing past EOL */
  493.     pfetch(markline(m));
  494.     if (markidx(m) + cnt > plen)
  495.     {
  496.         cnt = plen - markidx(m);
  497.     }
  498.  
  499.     /* Go for it! */
  500.     ChangeText
  501.     {
  502.         cut(m, m + cnt);
  503.         m = input(m, m + cnt, WHEN_VIINP);
  504.     }
  505.     return m;
  506. }
  507.  
  508. /* This calls the ex "join" command to join some lines together */
  509. MARK v_join(m, cnt)
  510.     MARK    m;    /* the first line to be joined */
  511.     long    cnt;    /* number of other lines to join */
  512. {
  513.     MARK    joint;    /* where the lines were joined */
  514.  
  515.     DEFAULT(1);
  516.  
  517.     /* figure out where the joint will be */
  518.     pfetch(markline(m));
  519.     joint = (m & ~(BLKSIZE - 1)) + plen;
  520.  
  521.     /* join the lines */
  522.     cmd_join(m, m + MARK_AT_LINE(cnt), CMD_JOIN, 0, "");
  523.     mustredraw = TRUE;
  524.  
  525.     /* the cursor should be left at the joint */
  526.     return joint;
  527. }
  528.  
  529. /* This calls the ex shifter command to shift some lines */
  530. static MARK shift_help(m, n, excmd)
  531.     MARK    m, n;    /* range of lines to shift */
  532.     CMD    excmd;    /* which way do we shift? */
  533. {
  534.     /* make sure our endpoints aren't in reverse order */
  535.     if (m > n)
  536.     {
  537.         MARK tmp;
  538.  
  539.         tmp = n;
  540.         n = m;
  541.         m = tmp;
  542.     }
  543.  
  544.     /* linemode? adjust for inclusive endmarks in ex */
  545.     if (markidx(m) == 0 && markidx(n) == 0)
  546.     {
  547.         n -= BLKSIZE;
  548.     }
  549.  
  550.     cmd_shift(m, n, excmd, 0, "");
  551.     return m;
  552. }
  553.  
  554. /* This calls the ex "<" command to shift some lines left */
  555. MARK v_lshift(m, n)
  556.     MARK    m, n;    /* range of lines to shift */
  557. {
  558.     return shift_help(m, n, CMD_SHIFTL);
  559. }
  560.  
  561. /* This calls the ex ">" command to shift some lines right */
  562. MARK v_rshift(m, n)
  563.     MARK    m, n;    /* range of lines to shift */
  564. {
  565.     return shift_help(m, n, CMD_SHIFTR);
  566. }
  567.  
  568. /* This runs some lines through a filter program */
  569. MARK v_filter(m, n)
  570.     MARK    m, n;    /* range of lines to shift */
  571. {
  572.     char    cmdln[100];    /* a shell command line */
  573.  
  574.     /* linemode? adjust for inclusive endmarks in ex */
  575.     if (markidx(m) == 0 && markidx(n) == 0)
  576.     {
  577.         n -= BLKSIZE;
  578.     }
  579.  
  580.     if (vgets('!', cmdln, sizeof(cmdln)) > 0)
  581.     {
  582.         filter(m, n, cmdln);
  583.     }
  584.  
  585.     redraw(MARK_UNSET, FALSE);
  586.     return m;
  587. }
  588.  
  589.  
  590. /* This function runs the ex "file" command to show the file's status */
  591. MARK v_status()
  592. {
  593.     cmd_file(cursor, cursor, CMD_FILE, 0, "");
  594.     return cursor;
  595. }
  596.  
  597. /* This function switches to the previous file, if possible */
  598. MARK v_switch()
  599. {
  600.     if (!*prevorig)
  601.         msg("No previous file");
  602.     else
  603.     {    strcpy(tmpblk.c, prevorig);
  604.         cmd_edit(cursor, cursor, CMD_EDIT, 0, tmpblk.c);
  605.     }
  606.     return cursor;
  607. }
  608.  
  609. /* This function does a tag search on a keyword */
  610. /*ARGSUSED*/
  611. MARK v_tag(keyword, m, cnt)
  612.     char    *keyword;
  613.     MARK    m;
  614.     long    cnt;
  615. {
  616.     /* remember the initial change level */
  617.     cnt = changes;
  618.  
  619.     /* move the cursor to the start of the tag name, where m is */
  620.     cursor = m;
  621.  
  622.     /* perform the tag search */
  623.     cmd_tag(cursor, cursor, CMD_TAG, 0, keyword);
  624.  
  625.     return cursor;
  626. }
  627.  
  628. #ifndef NO_EXTENSIONS
  629. /* This function looks up a keyword by calling the helpprog program */
  630. /*ARGSUSED*/
  631. MARK v_keyword(keyword, m, cnt)
  632.     char    *keyword;
  633.     MARK    m;
  634.     long    cnt;
  635. {
  636.     int    status;
  637. #if    TOS
  638.     char cmdline[130];
  639. #endif
  640.  
  641.     move(LINES - 1, 0);
  642.     addstr("---------------------------------------------------------\n");
  643.     clrtoeol();
  644.     refresh();
  645.     suspend_curses();
  646.  
  647. #if    ANY_UNIX
  648.  
  649.     switch (fork())
  650.     {
  651.       case -1:                        /* error */
  652.         break;
  653.  
  654.       case 0:                        /* child */
  655.         execl(o_keywordprg, o_keywordprg, keyword, (char *)0);
  656.         exit(2); /* if we get here, the exec failed */
  657.  
  658.       default:                        /* parent */
  659.         wait(&status);
  660.         if (status > 0)
  661.         {
  662.             write(2, "<<< failed >>>\n", 15);
  663.         }
  664.     }
  665.  
  666. #endif
  667. #if    MSDOS
  668.     if ((status=spawnlp(P_WAIT, o_keywordprg, o_keywordprg, keyword,
  669.                         (char *)0))==-1)
  670.         write(2, "<<< failed >>>\n", 15);
  671. #endif
  672. #if    TOS
  673.     strcpy(cmdline+1, keyword);
  674.     cmdline[0]=strlen(keyword);
  675.     if ((status=Pexec(0, o_keywordprg, cmdline, "\0"))<0)
  676.         write(2, "<<< failed >>>\n", 15);
  677. #endif
  678.  
  679.     resume_curses(FALSE); /* "resume, but not quietly" */
  680.     redraw(MARK_UNSET, FALSE);
  681.     return m;
  682. }
  683.  
  684.  
  685.  
  686. MARK v_increment(keyword, m, cnt)
  687.     char    *keyword;
  688.     MARK    m;
  689.     long    cnt;
  690. {
  691.     static    sign;
  692.     char    newval[12];
  693.     long    atol();
  694.  
  695.     DEFAULT(1);
  696.  
  697.     /* get one more keystroke, unless doingdot */
  698.     if (!doingdot)
  699.     {
  700.         sign = getkey(0);
  701.     }
  702.  
  703.     /* adjust the number, based on that second keystroke */
  704.     switch (sign)
  705.     {
  706.       case '+':
  707.       case '#':
  708.         cnt = atol(keyword) + cnt;
  709.         break;
  710.  
  711.       case '-':
  712.         cnt = atol(keyword) - cnt;
  713.         break;
  714.  
  715.       case '=':
  716.         break;
  717.  
  718.       default:
  719.         return MARK_UNSET;
  720.     }
  721.     sprintf(newval, "%ld", cnt);
  722.  
  723.     ChangeText
  724.     {
  725.         change(m, m + strlen(keyword), newval);
  726.     }
  727.  
  728.     return m;
  729. }
  730. #endif
  731.  
  732.  
  733. /* This function acts like the EX command "xit" */
  734. /*ARGSUSED*/
  735. MARK v_xit(m, cnt, key)
  736.     MARK    m;    /* ignored */
  737.     long    cnt;    /* ignored */
  738.     int    key;    /* must be a second 'Z' */
  739. {
  740.     /* if second char wasn't 'Z', fail */
  741.     if (key != 'Z')
  742.     {
  743.         return MARK_UNSET;
  744.     }
  745.  
  746.     /* move the physical cursor to the end of the screen */
  747.     move(LINES - 1, 0);
  748.     clrtoeol();
  749.     refresh();
  750.  
  751.     /* do the xit command */
  752.     cmd_xit(m, m, CMD_XIT, FALSE, "");
  753.  
  754.     /* if we're really going to quit, then scroll the screen up 1 line */
  755.     if (mode == MODE_QUIT)
  756.     {
  757.         addch('\n');
  758.         refresh();
  759.     }
  760.  
  761.     /* regardless of whether we succeeded or failed, return the cursor */
  762.     return m;
  763. }
  764.  
  765.  
  766. /* This function undoes changes to a single line, if possible */
  767. MARK v_undoline(m)
  768.     MARK    m;    /* where we hope to undo the change */
  769. {
  770.     if (markline(m) != U_line)
  771.     {
  772.         return MARK_UNSET;
  773.     }
  774.  
  775.     ChangeText
  776.     {
  777.         changeline(U_line, U_text);
  778.     }
  779.     return m & ~(BLKSIZE - 1);
  780. }
  781.