home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / v / vim_src.zip / MISCCMDS.C < prev    next >
C/C++ Source or Header  |  1993-01-12  |  13KB  |  709 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMitation
  4.  *
  5.  * Code Contributions By:    Bram Moolenaar            mool@oce.nl
  6.  *                            Tim Thompson            twitch!tjt
  7.  *                            Tony Andrews            onecom!wldrdg!tony 
  8.  *                            G. R. (Fred) Walter        watmath!watcgl!grwalter 
  9.  */
  10.  
  11. /*
  12.  * misccmds.c: functions that didn't seem to fit elsewhere
  13.  */
  14.  
  15. #include "vim.h"
  16. #include "globals.h"
  17. #include "proto.h"
  18. #include "param.h"
  19.  
  20. static char *(si_tab[]) = {"if", "else", "while", "for", "do"};
  21.  
  22. /*
  23.  * count the size of the indent in the current line
  24.  */
  25.     int
  26. get_indent()
  27. {
  28.     register char *ptr;
  29.     register int count = 0;
  30.  
  31.     for (ptr = nr2ptr(Curpos.lnum); *ptr; ++ptr)
  32.     {
  33.         if (*ptr == TAB)    /* count a tab for what it is worth */
  34.             count += p_ts - (count % p_ts);
  35.         else if (*ptr == ' ')
  36.             ++count;            /* count a space for one */
  37.         else
  38.             break;
  39.     }
  40.     return (count);
  41. }
  42.  
  43. /*
  44.  * set the indent of the current line
  45.  * leaves the cursor on the first non-blank in the line
  46.  */
  47.     void
  48. set_indent(size, delete)
  49.     register int size;
  50.     int delete;
  51. {
  52.     int        oldstate = State;
  53.  
  54.     State = INSERT;        /* don't want REPLACE for State */
  55.     Curpos.col = 0;
  56.     if (delete)
  57.     {
  58.         while (isspace(gcharCurpos()))    /* delete old indent */
  59.             delchar(FALSE);
  60.     }
  61.     while (size >= p_ts)
  62.     {
  63.         inschar(TAB);
  64.         size -= p_ts;
  65.     }
  66.     while (size)
  67.     {
  68.         inschar(' ');
  69.         --size;
  70.     }
  71.     State = oldstate;
  72.     script_winsize_pp();
  73. }
  74.  
  75. /*
  76.  * Opencmd
  77.  *
  78.  * Add a blank line below or above the current line.
  79.  */
  80.  
  81.     int
  82. Opencmd(dir, redraw)
  83.     int         dir;
  84.     int            redraw;
  85. {
  86.     char   *l;
  87.     char   *ptr;
  88.     FPOS    oldCurpos;             /* old cursor position */
  89.     int        newcol = 0;            /* new cursor column */
  90.     int     newindent = 0;        /* auto-indent of the new line */
  91.     int     extra = 0;            /* number of bytes to be copied from current line */
  92.     int        n;
  93.     int        truncate = FALSE;    /* truncate current line afterwards */
  94.     int        no_si = FALSE;        /* reset did_si afterwards */
  95.  
  96.     ptr = nr2ptr(Curpos.lnum);
  97.     u_clearline();        /* cannot do "U" command when adding lines */
  98.     did_si = FALSE;
  99.     if (p_ai || p_si)
  100.     {
  101.         /*
  102.          * count white space on current line
  103.          */
  104.         newindent = get_indent();
  105.  
  106.                 /*
  107.                  * If we just did an auto-indent, then we didn't type anything on the
  108.                  * prior line, and it should be truncated.
  109.                  */
  110.         if (dir == FORWARD && did_ai)
  111.                 truncate = TRUE;
  112.         else if (p_si)
  113.         {
  114.             char    *p;
  115.             char    *pp;
  116.             int        i, save;
  117.  
  118.             p = ptr;
  119.             skipspace(&p);
  120.             if (dir == FORWARD)
  121.             {
  122.                 if (*p == '{')
  123.                 {
  124.                     did_si = TRUE;
  125.                     no_si = TRUE;
  126.                 }
  127.                 else
  128.                 {
  129.                     for (pp = p; islower(*pp); ++pp) ;
  130.                     if (!isidchar(*pp))
  131.                     {
  132.                         save = *pp;
  133.                         *pp = NUL;
  134.                         for (i = sizeof(si_tab)/sizeof(char *); --i >= 0; )
  135.                             if (strcmp(p, si_tab[i]) == 0)
  136.                             {
  137.                                 did_si = TRUE;
  138.                                 break;
  139.                             }
  140.                         *pp = save;
  141.                     }
  142.                 }
  143.             }
  144.             else
  145.             {
  146.                 if (*p == '}')
  147.                     did_si = TRUE;
  148.             }
  149.         }
  150.         did_ai = TRUE;
  151.         if (p_si)
  152.             can_si = TRUE;
  153.     }
  154.     if (State == INSERT || State == REPLACE)    /* only when dir == FORWARD */
  155.         extra = strlen(ptr + Curpos.col);
  156.     if ((l = alloc_line(extra)) == NULL)
  157.         return (FALSE);
  158.     if (extra)
  159.     {
  160.         strcpy(l, ptr + Curpos.col);
  161.         did_ai = FALSE;         /* don't trucate now */
  162.     }
  163.  
  164.     oldCurpos = Curpos;
  165.     if (dir == BACKWARD)
  166.         --Curpos.lnum;
  167.     if (appendline(Curpos.lnum, l) == FALSE)
  168.         return FALSE;
  169.     if (newindent || did_si)
  170.     {
  171.         ++Curpos.lnum;
  172.         if (did_si)
  173.         {
  174.             if (p_sr)
  175.                 newindent -= newindent % p_sw;
  176.             newindent += p_sw;
  177.         }
  178.         set_indent(newindent, FALSE);
  179.         newcol = Curpos.col;
  180.         if (no_si)
  181.             did_si = FALSE;
  182.     }
  183.     Curpos = oldCurpos;
  184.  
  185.     if (dir == FORWARD)
  186.     {
  187.         if (truncate)
  188.             *ptr = NUL;
  189.         else if (extra)
  190.         {
  191.             truncate = TRUE;
  192.             *(ptr + Curpos.col) = NUL;        /* truncate current line at cursor */
  193.         }
  194.         if (truncate)
  195.             canincrease(0);
  196.  
  197.         /*
  198.          * Get the cursor to the start of the line, so that 'Cursrow' gets
  199.          * set to the right physical line number for the stuff that
  200.          * follows...
  201.          */
  202.         Curpos.col = 0;
  203.  
  204.         if (redraw)
  205.         {
  206.             cursupdate();
  207.  
  208.             /*
  209.              * If we're doing an open on the last logical line, then go ahead and
  210.              * scroll the screen up. Otherwise, just insert a blank line at the
  211.              * right place. We use calls to plines() in case the cursor is
  212.              * resting on a long line.
  213.              */
  214.             n = Cursrow + plines(Curpos.lnum);
  215.             if (n == (Rows - 1))
  216.                 scrollup(1L);
  217.             else
  218.                 s_ins(n, 1, TRUE);
  219.         }
  220.         ++Curpos.lnum;    /* cursor moves down */
  221.     }
  222.     else if (redraw)
  223.         s_ins(Cursrow, 1, TRUE); /* insert physical line */
  224.  
  225.     Curpos.col = newcol;
  226.     if (redraw)
  227.     {
  228.         updateScreen(VALID_TO_CURSCHAR);
  229.         cursupdate();        /* update Cursrow */
  230.     }
  231.     CHANGED;
  232.  
  233.     return (TRUE);
  234. }
  235.  
  236. /*
  237.  * plines(p) - return the number of physical screen lines taken by line 'p'
  238.  */
  239.     int
  240. plines(p)
  241.     linenr_t p;
  242. {
  243.     register int    col = 0;
  244.     register u_char  *s;
  245.  
  246. #ifdef DEBUG
  247.     if (p == 0)
  248.     {
  249.         emsg("plines(0) ????");
  250.         return (0);
  251.     }
  252. #endif
  253.     s = (u_char *)nr2ptr(p);
  254.  
  255.     if (*s == NUL)                /* empty line */
  256.         return 1;
  257.  
  258.     while (*s != NUL)
  259.         col += chartabsize(*s++, col);
  260.  
  261.     /*
  262.      * If list mode is on, then the '$' at the end of the line takes up one
  263.      * extra column.
  264.      */
  265.     if (p_list)
  266.         col += 1;
  267.  
  268.     /*
  269.      * If 'number' mode is on, add another 8.
  270.      */
  271.     if (p_nu)
  272.         col += 8;
  273.  
  274.     return ((col + ((int)Columns - 1)) / (int)Columns);
  275. }
  276.  
  277. /*
  278.  * Count the physical lines (rows) for the lines "first" to "last" inclusive.
  279.  */
  280.     int
  281. plines_m(first, last)
  282.     linenr_t        first, last;
  283. {
  284.         int count = 0;
  285.  
  286.         while (first <= last)
  287.                 count += plines(first++);
  288.         return (count);
  289. }
  290.  
  291.     void
  292. fileinfo()
  293. {
  294.     if (bufempty())
  295.     {
  296.         msg("Buffer Empty");
  297.         return;
  298.     }
  299.     sprintf(IObuff, "\"%s\"%s line %ld of %ld -- %d %% --",
  300.             (Filename != NULL) ? Filename : "No File",
  301.             Changed ? " [Modified]" : "",
  302.             (long)Curpos.lnum,
  303.             (long)line_count,
  304.             (int)(((long)Curpos.lnum * 100L) / (long)line_count));
  305.  
  306.     if (numfiles > 1)
  307.         sprintf(IObuff + strlen(IObuff), " (file %d of %d)", curfile + 1, numfiles);
  308.     msg(IObuff);
  309. }
  310.  
  311.     void
  312. setfname(s)
  313.     char *s;
  314. {
  315.         if (Filename != NULL)
  316.                 free(Filename);
  317.         if (s == NULL || *s == NUL)
  318.                 Filename = NULL;
  319.         else
  320.         {
  321.                 FullName(s, IObuff, IOSIZE);
  322.                 Filename = (char *)strsave(IObuff);
  323.         }
  324. }
  325.  
  326. /*
  327.  * put filename in title bar of window
  328.  */
  329.     void
  330. maketitle()
  331. {
  332. #ifdef AMIGA
  333.         if (Filename == NULL)
  334.                 settitle("");
  335.         else
  336.         {
  337.             if (numfiles == 1)
  338.                 settitle(Filename);
  339.             else
  340.             {
  341.                     sprintf(IObuff, "%s (%d of %d)", Filename, curfile + 1, numfiles);
  342.                     settitle(IObuff);
  343.             }
  344.         }
  345. #endif
  346. }
  347.  
  348.     void
  349. inschar(c)
  350.     int            c;
  351. {
  352.     register char  *p;
  353.     register char  *pend;
  354.  
  355.     p = nr2ptr(Curpos.lnum);
  356.     pend = p + Curpos.col;
  357.     if (State != REPLACE || *pend == NUL)
  358.     {
  359.             /* make room for the new char. */
  360.             if (!canincrease(1))
  361.                 return;
  362.  
  363.             p = nr2ptr(Curpos.lnum);
  364.             pend = p + Curpos.col;
  365.             p += strlen(p) + 1;
  366.  
  367.             for (; p > pend; p--)
  368.                 *p = *(p - 1);
  369.     }
  370.     *pend = c;
  371.  
  372.     /*
  373.      * If we're in insert mode and showmatch mode is set, then check for
  374.      * right parens and braces. If there isn't a match, then beep. If there
  375.      * is a match AND it's on the screen, then flash to it briefly. If it
  376.      * isn't on the screen, don't do anything.
  377.      */
  378.     if (p_sm && State == INSERT && (c == ')' || c == '}' || c == ']'))
  379.     {
  380.         FPOS           *lpos, csave;
  381.  
  382.         if ((lpos = showmatch()) == NULL)        /* no match, so beep */
  383.             beep();
  384.         else if (lpos->lnum >= Topline)
  385.         {
  386.             updateScreen(VALID_TO_CURSCHAR); /* show the new char first */
  387.             csave = Curpos;
  388.             Curpos = *lpos;     /* move to matching char */
  389.             cursupdate();
  390.             setcursor();
  391.             flushbuf();
  392.             vim_delay();        /* brief pause */
  393.             Curpos = csave;     /* restore cursor position */
  394.             cursupdate();
  395.         }
  396.     }
  397.     ++Curpos.col;
  398.  
  399.     CHANGED;
  400. }
  401.  
  402.     void
  403. insstr(s)
  404.     register char  *s;
  405. {
  406.     register char  *p;
  407.     register char  *pend;
  408.     register int    n = strlen(s);
  409.  
  410.     /* Move everything in the file over to make */
  411.     /* room for the new string. */
  412.     if (!canincrease(n))
  413.         return;
  414.  
  415.     p = nr2ptr(Curpos.lnum);
  416.     pend = p + Curpos.col;
  417.     p += strlen(p) + n;
  418.  
  419.     for (; p > pend; p--)
  420.         *p = *(p - n);
  421.  
  422.     Curpos.col += n;
  423.     while (--n >= 0)
  424.         *p++ = *s++;
  425.  
  426.     CHANGED;
  427. }
  428.  
  429.     int
  430. delchar(fixpos)
  431.     int            fixpos;     /* if TRUE fix the cursor position when done */
  432. {
  433.     char        *ptr;
  434.     int            lastchar;
  435.  
  436.     ptr = pos2ptr(&Curpos);
  437.  
  438.     if (*ptr == NUL)    /* can't do anything */
  439.         return FALSE;
  440.  
  441.     lastchar = (*++ptr == NUL);
  442.     /* Delete the char. at Curpos by shifting everything in the line down. */
  443.     do
  444.         *(ptr - 1) = *ptr;
  445.     while (*ptr++);
  446.  
  447.     /*
  448.      * If we just took off the last character of a non-blank line, we don't
  449.      * want to end up positioned at the newline.
  450.      */
  451.     if (fixpos && Curpos.col > 0 && lastchar && State != INSERT)
  452.             --Curpos.col;
  453.  
  454.     (void)canincrease(0);
  455.     CHANGED;
  456.     return TRUE;
  457. }
  458.  
  459.     void
  460. dellines(nlines, can_update)
  461.     long             nlines;
  462.     int                can_update;
  463. {
  464.     int             doscreen;    /* if true, update the screen */
  465.     int             num_plines = 0;
  466.  
  467.     doscreen = can_update;
  468.     /*
  469.      * There's no point in keeping the screen updated if we're deleting more
  470.      * than a screen's worth of lines.
  471.      */
  472.     if (nlines > (Rows - 1) && can_update)
  473.     {
  474.         doscreen = FALSE;
  475.         /* flaky way to clear rest of screen */
  476.         s_del(Cursrow, (int)Rows - 1, TRUE);
  477.     }
  478.     while (nlines-- > 0)
  479.     {
  480.         if (bufempty())         /* nothing to delete */
  481.             break;
  482.  
  483.         /*
  484.          * Set up to delete the correct number of physical lines on the
  485.          * screen
  486.          */
  487.         if (doscreen)
  488.             num_plines += plines(Curpos.lnum);
  489.  
  490.         free_line(delsline(Curpos.lnum));
  491.  
  492.         CHANGED;
  493.  
  494.         /* If we delete the last line in the file, stop */
  495.         if (Curpos.lnum > line_count)
  496.         {
  497.             Curpos.lnum = line_count;
  498.             break;
  499.         }
  500.     }
  501.     Curpos.col = 0;
  502.     /*
  503.      * Delete the correct number of physical lines on the screen
  504.      */
  505.     if (doscreen && num_plines > 0)
  506.         s_del(Cursrow, num_plines, TRUE);
  507. }
  508.  
  509.     int
  510. gchar(pos)
  511.     FPOS *pos;
  512. {
  513.     return (int)(*(pos2ptr(pos)));
  514. }
  515.  
  516.     int
  517. gcharCurpos()
  518. {
  519.     return (int)(*(pos2ptr(&Curpos)));
  520. }
  521.  
  522. /*
  523.  * return TRUE if the cursor is before or on the first non-blank in the line
  524.  */
  525.     int
  526. inindent()
  527. {
  528.     register char *ptr;
  529.     register int col;
  530.  
  531.     for (col = 0, ptr = nr2ptr(Curpos.lnum); isspace(*ptr++); ++col)
  532.         ;
  533.     if (col >= Curpos.col)
  534.         return TRUE;
  535.     else
  536.         return FALSE;
  537. }
  538.  
  539. /*
  540.  * skipspace: skip over ' ' and '\t'.
  541.  *
  542.  * note: you must give a pointer to a char pointer!
  543.  */
  544.     void
  545. skipspace(pp)
  546.     char **pp;
  547. {
  548.     register char *p;
  549.     
  550.     for (p = *pp; *p == ' ' || *p == '\t'; ++p)    /* skip to next non-white */
  551.         ;
  552.     *pp = p;
  553. }
  554.  
  555. /*
  556.  * skiptospace: skip over text until ' ' or '\t'.
  557.  *
  558.  * note: you must give a pointer to a char pointer!
  559.  */
  560.     void
  561. skiptospace(pp)
  562.     char **pp;
  563. {
  564.     register char *p;
  565.  
  566.     for (p = *pp; *p != ' ' && *p != '\t' && *p != NUL; ++p)
  567.         ;
  568.     *pp = p;
  569. }
  570.  
  571. /*
  572.  * getdigits: get a number from a string and skip over it
  573.  *
  574.  * note: you must give a pointer to a char pointer!
  575.  */
  576.  
  577.     long
  578. getdigits(pp)
  579.     char **pp;
  580. {
  581.     register char *p;
  582.     long retval;
  583.     
  584.     p = *pp;
  585.     retval = atol(p);
  586.     while (isdigit(*p))    /* skip to next non-digit */
  587.         ++p;
  588.     *pp = p;
  589.     return retval;
  590. }
  591.  
  592.     char *
  593. plural(n)
  594.     long n;
  595. {
  596.     static char buf[2] = "s";
  597.  
  598.     if (n == 1)
  599.         return &(buf[1]);
  600.     return &(buf[0]);
  601. }
  602.  
  603. /*
  604.  * set_Changed is called whenever something in the file is changed
  605.  * If the file is readonly, give a warning message with the first change.
  606.  */
  607.     void
  608. set_Changed()
  609. {
  610.     if (Changed == 0 && p_ro)
  611.     {
  612.         emsg("Warning: Changing a readonly file");
  613.         sleep(2);        /* give the user some time to think about it */
  614.     }
  615.     Changed = 1;
  616.     Updated = 1;
  617. }
  618.  
  619.     int
  620. ask_yesno(str)
  621.     char *str;
  622. {
  623.     int r = ' ';
  624.  
  625.     while (r != 'y' && r != 'n')
  626.     {
  627.         smsg("%s (y/n)? ", str);
  628.         r = vgetc();
  629.         outchar(r);        /* show what you typed */
  630.         flushbuf();
  631.     }
  632.     return r;
  633. }
  634.  
  635.     void
  636. msgmore(n)
  637.     long n;
  638. {
  639.     long pn;
  640.  
  641.     if (n > 0)
  642.         pn = n;
  643.     else
  644.         pn = -n;
  645.  
  646.     if (pn > p_report)
  647.         smsg("%ld %s lines %s", pn, n > 0 ? "more" : "fewer", got_int ? "(Interrupted)" : "");
  648. }
  649.  
  650. /*
  651.  * give a warning for an error
  652.  */
  653.     void
  654. beep()
  655. {
  656.     flush_buffers();
  657.     if (p_vb)
  658.     {
  659.         if (T_VB && *T_VB)
  660.             outstr(T_VB);
  661.         else
  662.         {            /* very primitive visual bell */
  663.             msg("    ^G");
  664.             msg("     ^G");
  665.             msg("    ^G ");
  666.             msg("     ^G");
  667.             msg("       ");
  668.         }
  669.     }
  670.     else
  671.         outchar('\007');
  672. }
  673.  
  674. /* 
  675.  * Expand environment variable with path name.
  676.  * If anything fails no expansion is done and dst equals src.
  677.  */
  678.     void
  679. expand_env(src, dst, dstlen)
  680.     char    *src;            /* input string e.g. "$HOME/vim.hlp" */
  681.     char    *dst;            /* where to put the result */
  682.     int        dstlen;            /* maximum length of the result */
  683. {
  684.     char    *tail;
  685.     int        c;
  686.     char    *var;
  687.  
  688.     if (*src == '$')
  689.     {
  690.         for (tail = src + 1; *tail; ++tail)
  691.             if (*tail == PATHSEP)
  692.                 break;
  693.         c = *tail;
  694.         *tail = NUL;
  695.         var = getenv(src + 1);
  696.         *tail = c;
  697.         if (*tail)
  698.             ++tail;
  699.         if (var && strlen(var) + strlen(tail) + 1 < dstlen)
  700.         {
  701.             strcpy(dst, var);
  702.             strcat(dst, PATHSEPSTR);
  703.             strcat(dst, tail);
  704.             return;
  705.         }
  706.     }
  707.     strncpy(dst, src, (size_t)dstlen);
  708. }
  709.