]> granicus.if.org Git - vim/commitdiff
patch 7.4.858 v7.4.858
authorBram Moolenaar <Bram@vim.org>
Tue, 8 Sep 2015 16:46:31 +0000 (18:46 +0200)
committerBram Moolenaar <Bram@vim.org>
Tue, 8 Sep 2015 16:46:31 +0000 (18:46 +0200)
Problem:    It's a bit clumsy to execute a command on a list of matches.
Solution:   Add the ":ldo", ":lfdo", ":cdo" and ":cfdo" commands. (Yegappan
            Lakshmanan)

19 files changed:
runtime/doc/cmdline.txt
runtime/doc/editing.txt
runtime/doc/index.txt
runtime/doc/tabpage.txt
runtime/doc/windows.txt
src/ex_cmds.h
src/ex_cmds2.c
src/ex_docmd.c
src/proto/quickfix.pro
src/quickfix.c
src/testdir/Make_amiga.mak
src/testdir/Make_dos.mak
src/testdir/Make_ming.mak
src/testdir/Make_os2.mak
src/testdir/Make_vms.mms
src/testdir/Makefile
src/testdir/test_cdo.in [new file with mode: 0644]
src/testdir/test_cdo.ok [new file with mode: 0644]
src/version.c

index 94fe977cc79cb5793b8cbede9b9566f0fdfc63d6..fe2ef76ef549968d0900fd96cda9e1f2ef305cc5 100644 (file)
@@ -511,6 +511,8 @@ followed by another Vim command:
     :argdo
     :autocmd
     :bufdo
+    :cdo
+    :cfdo
     :command
     :cscope
     :debug
@@ -521,6 +523,8 @@ followed by another Vim command:
     :help
     :helpfind
     :lcscope
+    :ldo
+    :lfdo
     :make
     :normal
     :perl
index 49a96f6a663a2400c31d88f2aaa5bc71b38017a3..5666e68b5a72f739febb5195989f6f6051113ba1 100644 (file)
@@ -868,7 +868,8 @@ USING THE ARGUMENT LIST
                        each file.
                        {not in Vi} {not available when compiled without the
                        |+listcmds| feature}
-                       Also see |:windo|, |:tabdo| and |:bufdo|.
+                       Also see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|,
+                       |:cfdo| and |:lfdo|
 
 Example: >
        :args *.c
index e8171a90e43cdd7ae14724ef2beca9c2d540287e..3949c2b5770db8425a8112949771ec309585a29d 100644 (file)
@@ -1138,6 +1138,8 @@ tag             command         action ~
 |:cc|          :cc             go to specific error
 |:cclose|      :ccl[ose]       close quickfix window
 |:cd|          :cd             change directory
+|:cdo|         :cdo            execute command in each valid error list entry
+|:cfdo|                :cfd[o]         execute command in each file in error list
 |:center|      :ce[nter]       format lines at the center
 |:cexpr|       :cex[pr]        read errors from expr and jump to first
 |:cfile|       :cf[ile]        read file with error messages and jump to first
@@ -1296,6 +1298,8 @@ tag             command         action ~
 |:lchdir|      :lch[dir]       change directory locally
 |:lclose|      :lcl[ose]       close location window
 |:lcscope|     :lcs[cope]      like ":cscope" but uses location list
+|:ldo|         :ld[o]          execute command in valid location list entries
+|:lfdo|                :lfd[o]         execute command in each file in location list
 |:left|                :le[ft]         left align lines
 |:leftabove|   :lefta[bove]    make split window appear left or above
 |:let|         :let            assign a value to a variable or option
index 46e0a8fde2eb568d2da61969b9233d20de219a99..b98c18b02cbfe31cb47c5c60d14f71fc61547eca 100644 (file)
@@ -248,7 +248,8 @@ LOOPING OVER TAB PAGES:
                {cmd} must not open or close tab pages or reorder them.
                {not in Vi} {not available when compiled without the
                |+listcmds| feature}
-               Also see |:windo|, |:argdo| and |:bufdo|.
+               Also see |:windo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo|
+               and |:lfdo|
 
 ==============================================================================
 3. Other items                                         *tab-page-other*
index a7db69c52014ff6ed8ffe245687a05e64b6cc62e..4b947fc81b04e9c15aeabf4e504b4358d73ab0c1 100644 (file)
@@ -715,7 +715,8 @@ can also get to them with the buffer list commands, like ":bnext".
                        {cmd} must not open or close windows or reorder them.
                        {not in Vi} {not available when compiled without the
                        |+listcmds| feature}
-                       Also see |:tabdo|, |:argdo| and |:bufdo|.
+                       Also see |:tabdo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|,
+                       |:cfdo| and |:lfdo|
 
                                                        *:bufdo*
 :[range]bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list or if
@@ -743,7 +744,8 @@ can also get to them with the buffer list commands, like ":bnext".
                        each buffer.
                        {not in Vi} {not available when compiled without the
                        |+listcmds| feature}
-                       Also see |:tabdo|, |:argdo| and |:windo|.
+                       Also see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|,
+                       |:cfdo| and |:lfdo|
 
 Examples: >
 
index 794595697165b1d18614e9c28f67ca889a7ca2cf..874ac6ba0a48f3de01c672b275f9afd415d14583 100644 (file)
@@ -65,6 +65,7 @@
 #define ADDR_LOADED_BUFFERS    3
 #define ADDR_BUFFERS           4
 #define ADDR_TABS              5
+#define ADDR_QUICKFIX          6
 
 #ifndef DO_DECLARE_EXCMD
 typedef struct exarg exarg_T;
@@ -270,6 +271,9 @@ EX(CMD_cclose,              "cclose",       ex_cclose,
 EX(CMD_cd,             "cd",           ex_cd,
                        BANG|FILE1|TRLBAR|CMDWIN,
                        ADDR_LINES),
+EX(CMD_cdo,            "cdo",          ex_listdo,
+                       BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+                       ADDR_QUICKFIX),
 EX(CMD_center,         "center",       ex_align,
                        TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
                        ADDR_LINES),
@@ -279,6 +283,9 @@ EX(CMD_cexpr,               "cexpr",        ex_cexpr,
 EX(CMD_cfile,          "cfile",        ex_cfile,
                        TRLBAR|FILE1|BANG,
                        ADDR_LINES),
+EX(CMD_cfdo,           "cfdo",         ex_listdo,
+                       BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+                       ADDR_QUICKFIX),
 EX(CMD_cfirst,         "cfirst",       ex_cc,
                        RANGE|NOTADR|COUNT|TRLBAR|BANG,
                        ADDR_LINES),
@@ -729,6 +736,9 @@ EX(CMD_lclose,              "lclose",       ex_cclose,
 EX(CMD_lcscope,                "lcscope",      do_cscope,
                        EXTRA|NOTRLCOM|XFILE,
                        ADDR_LINES),
+EX(CMD_ldo,            "ldo",          ex_listdo,
+                       BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+                       ADDR_QUICKFIX),
 EX(CMD_left,           "left",         ex_align,
                        TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
                        ADDR_LINES),
@@ -744,6 +754,9 @@ EX(CMD_lexpr,               "lexpr",        ex_cexpr,
 EX(CMD_lfile,          "lfile",        ex_cfile,
                        TRLBAR|FILE1|BANG,
                        ADDR_LINES),
+EX(CMD_lfdo,           "lfdo",         ex_listdo,
+                       BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+                       ADDR_QUICKFIX),
 EX(CMD_lfirst,         "lfirst",       ex_cc,
                        RANGE|NOTADR|COUNT|TRLBAR|BANG,
                        ADDR_LINES),
index eefd5d23771518ae3f931806e045cb11b441f19b..3cc2d45a716cc9b5591f058aa0ff397d1d8ff888 100644 (file)
@@ -2429,7 +2429,7 @@ ex_argdelete(eap)
 }
 
 /*
- * ":argdo", ":windo", ":bufdo", ":tabdo"
+ * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
  */
     void
 ex_listdo(eap)
@@ -2446,6 +2446,10 @@ ex_listdo(eap)
     char_u     *save_ei = NULL;
 #endif
     char_u     *p_shm_save;
+#ifdef FEAT_QUICKFIX
+    int                qf_size;
+    int                qf_idx;
+#endif
 
 #ifndef FEAT_WINDOWS
     if (eap->cmdidx == CMD_windo)
@@ -2498,18 +2502,37 @@ ex_listdo(eap)
        }
        /* set pcmark now */
        if (eap->cmdidx == CMD_bufdo)
-        {
+       {
            /* Advance to the first listed buffer after "eap->line1". */
-            for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
+           for (buf = firstbuf; buf != NULL && (buf->b_fnum < eap->line1
                                          || !buf->b_p_bl); buf = buf->b_next)
                if (buf->b_fnum > eap->line2)
                {
                    buf = NULL;
                    break;
                }
-            if (buf != NULL)
+           if (buf != NULL)
                goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
-        }
+       }
+#ifdef FEAT_QUICKFIX
+       else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+               || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+       {
+           qf_size = qf_get_size(eap);
+           if (qf_size <= 0 || eap->line1 > qf_size)
+               buf = NULL;
+           else
+           {
+               ex_cc(eap);
+
+               buf = curbuf;
+               i = eap->line1 - 1;
+               if (eap->addr_count <= 0)
+                   /* default is all the quickfix/location list entries */
+                   eap->line2 = qf_size;
+           }
+       }
+#endif
        else
            setpcmark();
        listcmd_busy = TRUE;        /* avoids setting pcmark below */
@@ -2595,11 +2618,28 @@ ex_listdo(eap)
                set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
                vim_free(p_shm_save);
 
-               /* If autocommands took us elsewhere, quit here */
+               /* If autocommands took us elsewhere, quit here. */
                if (curbuf->b_fnum != next_fnum)
                    break;
            }
 
+#ifdef FEAT_QUICKFIX
+           if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
+                   || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+           {
+               if (i >= qf_size || i >= eap->line2)
+                   break;
+
+               qf_idx = qf_get_cur_idx(eap);
+
+               ex_cnext(eap);
+
+               /* If jumping to the next quickfix entry fails, quit here */
+               if (qf_get_cur_idx(eap) == qf_idx)
+                   break;
+           }
+#endif
+
            if (eap->cmdidx == CMD_windo)
            {
                validate_cursor();      /* cursor may have moved */
index 7633d54200146d67202befafab9146077a5c5857..35b6637fdcd14c2d23be348a35f1c699071314cf 100644 (file)
@@ -135,7 +135,7 @@ static int  getargopt __ARGS((exarg_T *eap));
 #endif
 
 static int     check_more __ARGS((int, int));
-static linenr_T get_address __ARGS((char_u **, int addr_type, int skip, int to_other_file));
+static linenr_T get_address __ARGS((exarg_T *, char_u **, int addr_type, int skip, int to_other_file));
 static void    get_flags __ARGS((exarg_T *eap));
 #if !defined(FEAT_PERL) \
        || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \
@@ -2173,9 +2173,12 @@ do_one_cmd(cmdlinep, sourcing,
                lnum = CURRENT_TAB_NR;
                ea.line2 = lnum;
                break;
+           case ADDR_QUICKFIX:
+               ea.line2 = qf_get_cur_valid_idx(&ea);
+               break;
        }
        ea.cmd = skipwhite(ea.cmd);
-       lnum = get_address(&ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0);
+       lnum = get_address(&ea, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0);
        if (ea.cmd == NULL)                 /* error detected */
            goto doend;
        if (lnum == MAXLNUM)
@@ -2233,6 +2236,12 @@ do_one_cmd(cmdlinep, sourcing,
                            ea.line2 = ARGCOUNT;
                        }
                        break;
+                   case ADDR_QUICKFIX:
+                       ea.line1 = 1;
+                       ea.line2 = qf_get_size(&ea);
+                       if (ea.line2 == 0)
+                           ea.line2 = 1;
+                       break;
                }
                ++ea.addr_count;
            }
@@ -2693,6 +2702,11 @@ do_one_cmd(cmdlinep, sourcing,
                else
                    ea.line2 = ARGCOUNT;
                break;
+           case ADDR_QUICKFIX:
+               ea.line2 = qf_get_size(&ea);
+               if (ea.line2 == 0)
+                   ea.line2 = 1;
+               break;
        }
     }
 
@@ -3839,6 +3853,8 @@ set_one_cmd_context(xp, buff)
        case CMD_botright:
        case CMD_browse:
        case CMD_bufdo:
+       case CMD_cdo:
+       case CMD_cfdo:
        case CMD_confirm:
        case CMD_debug:
        case CMD_folddoclosed:
@@ -3848,7 +3864,9 @@ set_one_cmd_context(xp, buff)
        case CMD_keepjumps:
        case CMD_keepmarks:
        case CMD_keeppatterns:
+       case CMD_ldo:
        case CMD_leftabove:
+       case CMD_lfdo:
        case CMD_lockmarks:
        case CMD_noautocmd:
        case CMD_noswapfile:
@@ -4321,7 +4339,8 @@ skip_range(cmd, ctx)
  * Return MAXLNUM when no Ex address was found.
  */
     static linenr_T
-get_address(ptr, addr_type, skip, to_other_file)
+get_address(eap, ptr, addr_type, skip, to_other_file)
+    exarg_T    *eap;
     char_u     **ptr;
     int                addr_type;  /* flag: one of ADDR_LINES, ... */
     int                skip;       /* only skip the address, don't use it */
@@ -4362,6 +4381,9 @@ get_address(ptr, addr_type, skip, to_other_file)
                    case ADDR_TABS:
                        lnum = CURRENT_TAB_NR;
                        break;
+                   case ADDR_QUICKFIX:
+                       lnum = qf_get_cur_valid_idx(eap);
+                       break;
                }
                break;
 
@@ -4394,6 +4416,11 @@ get_address(ptr, addr_type, skip, to_other_file)
                    case ADDR_TABS:
                        lnum = LAST_TAB_NR;
                        break;
+                   case ADDR_QUICKFIX:
+                       lnum = qf_get_size(eap);
+                       if (lnum == 0)
+                           lnum = 1;
+                       break;
                }
                break;
 
@@ -4569,6 +4596,9 @@ get_address(ptr, addr_type, skip, to_other_file)
                    case ADDR_TABS:
                        lnum = CURRENT_TAB_NR;
                        break;
+                   case ADDR_QUICKFIX:
+                       lnum = qf_get_cur_valid_idx(eap);
+                       break;
                }
            }
 
@@ -4707,6 +4737,10 @@ invalid_range(eap)
                if (eap->line2 > LAST_TAB_NR)
                    return (char_u *)_(e_invrange);
                break;
+           case ADDR_QUICKFIX:
+               if (eap->line2 != 1 && eap->line2 > qf_get_size(eap))
+                   return (char_u *)_(e_invrange);
+               break;
        }
     }
     return NULL;
@@ -5817,6 +5851,7 @@ static struct
     {ADDR_TABS, "tabs"},
     {ADDR_BUFFERS, "buffers"},
     {ADDR_WINDOWS, "windows"},
+    {ADDR_QUICKFIX, "quickfix"},
     {-1, NULL}
 };
 #endif
@@ -9224,7 +9259,7 @@ ex_copymove(eap)
 {
     long       n;
 
-    n = get_address(&eap->arg, eap->addr_type, FALSE, FALSE);
+    n = get_address(eap, &eap->arg, eap->addr_type, FALSE, FALSE);
     if (eap->arg == NULL)          /* error detected */
     {
        eap->nextcmd = NULL;
index a5c690f646b9cab8b86fbbfb0cc17929c46d1eaa..c4e502e6d80bc3614764e5ac6b5c5a17eed5ad4c 100644 (file)
@@ -17,6 +17,9 @@ int bt_dontwrite_msg __ARGS((buf_T *buf));
 int buf_hide __ARGS((buf_T *buf));
 int grep_internal __ARGS((cmdidx_T cmdidx));
 void ex_make __ARGS((exarg_T *eap));
+int qf_get_size __ARGS((exarg_T *eap));
+int qf_get_cur_idx __ARGS((exarg_T *eap));
+int qf_get_cur_valid_idx __ARGS((exarg_T *eap));
 void ex_cc __ARGS((exarg_T *eap));
 void ex_cnext __ARGS((exarg_T *eap));
 void ex_cfile __ARGS((exarg_T *eap));
index 463056b56513c66399f6759a01100a949a830a71..7243a0cbc4635128caa614a94c59993acda3c498 100644 (file)
@@ -1373,7 +1373,7 @@ qf_clean_dir_stack(stackptr)
 /*
  * Check in which directory of the directory stack the given file can be
  * found.
- * Returns a pointer to the directory name or NULL if not found
+ * Returns a pointer to the directory name or NULL if not found.
  * Cleans up intermediate directory entries.
  *
  * TODO: How to solve the following problem?
@@ -2989,20 +2989,184 @@ get_mef_name()
     return name;
 }
 
+/*
+ * Returns the number of valid entries in the current quickfix/location list.
+ */
+    int
+qf_get_size(eap)
+    exarg_T    *eap;
+{
+    qf_info_T  *qi = &ql_info;
+    qfline_T   *qfp;
+    int                i, sz = 0;
+    int                prev_fnum = 0;
+
+    if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo)
+    {
+       /* Location list */
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+           return 0;
+    }
+
+    for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start;
+           (i < qi->qf_lists[qi->qf_curlist].qf_count) && (qfp != NULL);
+           ++i, qfp = qfp->qf_next)
+    {
+       if (qfp->qf_valid)
+       {
+           if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
+               sz++;   /* Count all valid entries */
+           else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+           {
+               /* Count the number of files */
+               sz++;
+               prev_fnum = qfp->qf_fnum;
+           }
+       }
+    }
+
+    return sz;
+}
+
+/*
+ * Returns the current index of the quickfix/location list.
+ * Returns 0 if there is an error.
+ */
+    int
+qf_get_cur_idx(eap)
+    exarg_T    *eap;
+{
+    qf_info_T  *qi = &ql_info;
+
+    if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo)
+    {
+       /* Location list */
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+           return 0;
+    }
+
+    return qi->qf_lists[qi->qf_curlist].qf_index;
+}
+
+/*
+ * Returns the current index in the quickfix/location list (counting only valid
+ * entries). If no valid entries are in the list, then returns 1.
+ */
+    int
+qf_get_cur_valid_idx(eap)
+    exarg_T    *eap;
+{
+    qf_info_T  *qi = &ql_info;
+    qf_list_T  *qfl;
+    qfline_T   *qfp;
+    int                i, eidx = 0;
+    int                prev_fnum = 0;
+
+    if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo)
+    {
+       /* Location list */
+       qi = GET_LOC_LIST(curwin);
+       if (qi == NULL)
+           return 1;
+    }
+
+    qfl = &qi->qf_lists[qi->qf_curlist];
+    qfp = qfl->qf_start;
+
+    /* check if the list has valid errors */
+    if (qfl->qf_count <= 0 || qfl->qf_nonevalid)
+       return 1;
+
+    for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next)
+    {
+       if (qfp->qf_valid)
+       {
+           if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+           {
+               if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+               {
+                   /* Count the number of files */
+                   eidx++;
+                   prev_fnum = qfp->qf_fnum;
+               }
+           }
+           else
+               eidx++;
+       }
+    }
+
+    return eidx ? eidx : 1;
+}
+
+/*
+ * Get the 'n'th valid error entry in the quickfix or location list.
+ * Used by :cdo, :ldo, :cfdo and :lfdo commands.
+ * For :cdo and :ldo returns the 'n'th valid error entry.
+ * For :cfdo and :lfdo returns the 'n'th valid file entry.
+ */
+    static int
+qf_get_nth_valid_entry(qi, n, fdo)
+    qf_info_T  *qi;
+    int                n;
+    int                fdo;
+{
+    qf_list_T  *qfl = &qi->qf_lists[qi->qf_curlist];
+    qfline_T   *qfp = qfl->qf_start;
+    int                i, eidx;
+    int                prev_fnum = 0;
+
+    /* check if the list has valid errors */
+    if (qfl->qf_count <= 0 || qfl->qf_nonevalid)
+       return 1;
+
+    for (i = 1, eidx = 0; i <= qfl->qf_count && qfp!= NULL;
+           i++, qfp = qfp->qf_next)
+    {
+       if (qfp->qf_valid)
+       {
+           if (fdo)
+           {
+               if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
+               {
+                   /* Count the number of files */
+                   eidx++;
+                   prev_fnum = qfp->qf_fnum;
+               }
+           }
+           else
+               eidx++;
+       }
+
+       if (eidx == n)
+           break;
+    }
+
+    if (i <= qfl->qf_count)
+       return i;
+    else
+       return 1;
+}
+
 /*
  * ":cc", ":crewind", ":cfirst" and ":clast".
  * ":ll", ":lrewind", ":lfirst" and ":llast".
+ * ":cdo", ":ldo", ":cfdo" and ":lfdo"
  */
     void
 ex_cc(eap)
     exarg_T    *eap;
 {
     qf_info_T  *qi = &ql_info;
+    int                errornr;
 
     if (eap->cmdidx == CMD_ll
            || eap->cmdidx == CMD_lrewind
            || eap->cmdidx == CMD_lfirst
-           || eap->cmdidx == CMD_llast)
+           || eap->cmdidx == CMD_llast
+           || eap->cmdidx == CMD_ldo
+           || eap->cmdidx == CMD_lfdo)
     {
        qi = GET_LOC_LIST(curwin);
        if (qi == NULL)
@@ -3012,34 +3176,51 @@ ex_cc(eap)
        }
     }
 
-    qf_jump(qi, 0,
-           eap->addr_count > 0
-           ? (int)eap->line2
-           : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)
-               ? 0
-               : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
-                  || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)
-                   ? 1
-                   : 32767,
-           eap->forceit);
+    if (eap->addr_count > 0)
+       errornr = (int)eap->line2;
+    else
+    {
+       if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)
+           errornr = 0;
+       else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
+               || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)
+           errornr = 1;
+       else
+           errornr = 32767;
+    }
+
+    /* For cdo and ldo commands, jump to the nth valid error.
+     * For cfdo and lfdo commands, jump to the nth valid file entry.
+     */
+    if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
+           eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
+       errornr = qf_get_nth_valid_entry(qi,
+               eap->addr_count > 0 ? (int)eap->line1 : 1,
+               eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
+
+    qf_jump(qi, 0, errornr, eap->forceit);
 }
 
 /*
  * ":cnext", ":cnfile", ":cNext" and ":cprevious".
  * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
+ * Also, used by ":cdo", ":ldo", ":cfdo" and ":lfdo" commands.
  */
     void
 ex_cnext(eap)
     exarg_T    *eap;
 {
     qf_info_T  *qi = &ql_info;
+    int                errornr;
 
     if (eap->cmdidx == CMD_lnext
            || eap->cmdidx == CMD_lNext
            || eap->cmdidx == CMD_lprevious
            || eap->cmdidx == CMD_lnfile
            || eap->cmdidx == CMD_lNfile
-           || eap->cmdidx == CMD_lpfile)
+           || eap->cmdidx == CMD_lpfile
+           || eap->cmdidx == CMD_ldo
+           || eap->cmdidx == CMD_lfdo)
     {
        qi = GET_LOC_LIST(curwin);
        if (qi == NULL)
@@ -3049,15 +3230,24 @@ ex_cnext(eap)
        }
     }
 
-    qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext)
+    if (eap->addr_count > 0 &&
+           (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo &&
+            eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo))
+       errornr = (int)eap->line2;
+    else
+       errornr = 1;
+
+    qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext
+               || eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
            ? FORWARD
-           : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile)
+           : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile
+               || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
                ? FORWARD_FILE
                : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile
                   || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)
                    ? BACKWARD_FILE
                    : BACKWARD,
-           eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit);
+           errornr, eap->forceit);
 }
 
 /*
index 901a7c139a2437b04c952e8b61398c16becb1715..af27919e8d6a879097f344fb3844020de50f9c55 100644 (file)
@@ -41,6 +41,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
                test_autocmd_option.out \
                test_autoformat_join.out \
                test_breakindent.out \
+               test_cdo.out \
                test_changelist.out \
                test_charsearch.out \
                test_close_count.out \
@@ -195,6 +196,7 @@ test_argument_count.out: test_argument_count.in
 test_autocmd_option.out: test_autocmd_option.in
 test_autoformat_join.out: test_autoformat_join.in
 test_breakindent.out: test_breakindent.in
+test_cdo.out: test_cdo.in
 test_changelist.out: test_changelist.in
 test_charsearch.out: test_charsearch.in
 test_close_count.out: test_close_count.in
index 603f4a4118f1ae419eeb280a8d0a369f4a6ba25f..abef950468bdc91f37c39ce65ac1291b94367529 100644 (file)
@@ -40,6 +40,7 @@ SCRIPTS =     test3.out test4.out test5.out test6.out test7.out \
                test_autocmd_option.out \
                test_autoformat_join.out \
                test_breakindent.out \
+               test_cdo.out \
                test_changelist.out \
                test_charsearch.out \
                test_close_count.out \
index 1b76bcc980e48d1ff9185d6218ebe1d5188443c9..aa59a014ecfd4a8e19da014c92d427d19cabcdee 100644 (file)
@@ -62,6 +62,7 @@ SCRIPTS =     test3.out test4.out test5.out test6.out test7.out \
                test_autocmd_option.out \
                test_autoformat_join.out \
                test_breakindent.out \
+               test_cdo.out \
                test_changelist.out \
                test_charsearch.out \
                test_close_count.out \
index 08f78cb1e855289060b880aef4987e82b54767ee..9150af7149f8460a9bbeeb1ab088919ebf76f0db 100644 (file)
@@ -42,6 +42,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
                test_autocmd_option.out \
                test_autoformat_join.out \
                test_breakindent.out \
+               test_cdo.out \
                test_changelist.out \
                test_charsearch.out \
                test_close_count.out \
index 6e77153883d19e962c7fcc003ae58b7c891f62b2..a716d0361d13d734e72cf377d0387d6b5db41c6f 100644 (file)
@@ -4,7 +4,7 @@
 # Authors:     Zoltan Arpadffy, <arpadffy@polarhome.com>
 #              Sandor Kopanyi,  <sandor.kopanyi@mailbox.hu>
 #
-# Last change:  2015 Sep 01
+# Last change:  2015 Sep 08
 #
 # This has been tested on VMS 6.2 to 8.3 on DEC Alpha, VAX and IA64.
 # Edit the lines in the Configuration section below to select.
@@ -101,6 +101,7 @@ SCRIPT = test1.out  test2.out  test3.out  test4.out  test5.out  \
         test_autocmd_option.out \
         test_autoformat_join.out \
         test_breakindent.out \
+        test_cdo.out \
         test_changelist.out \
         test_charsearch.out \
         test_close_count.out \
index f29ec8b45558d16606fb8bcc02911639909962e7..39d8388ecb3202f8341462910c5d5059856c8ac5 100644 (file)
@@ -38,6 +38,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
                test_autocmd_option.out \
                test_autoformat_join.out \
                test_breakindent.out \
+               test_cdo.out \
                test_changelist.out \
                test_charsearch.out \
                test_close_count.out \
diff --git a/src/testdir/test_cdo.in b/src/testdir/test_cdo.in
new file mode 100644 (file)
index 0000000..fb80ea1
--- /dev/null
@@ -0,0 +1,107 @@
+Tests for the :cdo, :cfdo, :ldo and :lfdo commands
+
+STARTTEST
+:so small.vim
+:if !has('quickfix') | e! test.ok | wq! test.out | endif
+
+:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile1')
+:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile2')
+:call writefile(["Line1", "Line2", "Line3"], 'Xtestfile3')
+
+:function RunTests(cchar)
+:  let nl="\n"
+
+:  enew
+:  " Try with an empty list
+:  exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " Populate the list and then try
+:  exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:3:1:Line3']"
+:  exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " Run command only on selected error lines
+:  enew
+:  exe "2,3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  " Boundary condition tests
+:  enew
+:  exe "1,1" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  enew
+:  exe "3" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  " Range test commands
+:  enew
+:  exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  enew
+:  exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  enew
+:  exe a:cchar . 'prev'
+:  exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  " Invalid error lines test
+:  enew
+:  exe "27" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "4,5" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " Run commands from an unsaved buffer
+:  let v:errmsg=''
+:  enew
+:  setlocal modified
+:  exe "2,2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  if v:errmsg =~# 'No write since last change'
+:     let g:result .= 'Unsaved file change test passed' . nl
+:  else
+:     let g:result .= 'Unsaved file change test failed' . nl
+:  endif
+
+:  " If the executed command fails, then the operation should be aborted
+:  enew!
+:  let subst_count = 0
+:  exe a:cchar . "do s/Line/xLine/ | let subst_count += 1"
+:  if subst_count == 1 && getline('.') == 'xLine1'
+:     let g:result .= 'Abort command on error test passed' . nl
+:  else
+:     let g:result .= 'Abort command on error test failed' . nl
+:  endif
+
+:  exe "2,2" . a:cchar . "do! let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " List with no valid error entries
+:  edit! +2 Xtestfile1
+:  exe a:cchar . "getexpr ['non-error 1', 'non-error 2', 'non-error 3']"
+:  exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "2" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  let v:errmsg=''
+:  exe "%" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "1,$" . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "." . a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  let g:result .= v:errmsg
+
+:  " List with only one valid entry
+:  exe a:cchar . "getexpr ['Xtestfile3:3:1:Line3']"
+:  exe a:cchar . "do let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " Tests for :cfdo and :lfdo commands
+:  exe a:cchar . "getexpr ['non-error 1', 'Xtestfile1:1:3:Line1', 'Xtestfile1:2:1:Line2', 'non-error 2', 'Xtestfile2:2:2:Line2', 'non-error 3', 'Xtestfile3:2:3:Line2', 'Xtestfile3:3:1:Line3']"
+:  exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "2,3" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "%" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe "1,$" . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:  exe a:cchar . 'pfile'
+:  exe "." . a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+
+:  " List with only one valid entry
+:  exe a:cchar . "getexpr ['Xtestfile2:2:5:Line2']"
+:  exe a:cchar . "fdo let g:result .= expand('%') . ' ' . line('.') . 'L' . ' ' . col('.') . 'C' . nl"
+:endfunction
+
+:let result=''
+:" Tests for the :cdo quickfix list command
+:call RunTests('c')
+:let result .= "\n"
+:" Tests for the :ldo location list command
+:call RunTests('l')
+
+:edit! test.out
+:0put =result
+:wq!
+ENDTEST
+
diff --git a/src/testdir/test_cdo.ok b/src/testdir/test_cdo.ok
new file mode 100644 (file)
index 0000000..ddcff4b
--- /dev/null
@@ -0,0 +1,66 @@
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile2 2L 2C
+Unsaved file change test passed
+Abort command on error test passed
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile3 2L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile2 2L 2C
+Xtestfile2 2L 5C
+
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile2 2L 2C
+Unsaved file change test passed
+Abort command on error test passed
+Xtestfile2 2L 2C
+Xtestfile3 3L 1C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile3 2L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile1 1L 3C
+Xtestfile2 2L 2C
+Xtestfile3 2L 3C
+Xtestfile2 2L 2C
+Xtestfile2 2L 5C
+
index 3fb4ad2fe2fb62b4a1674e76951caba7669ac516..0e2e51e2edd218ba28bc0c5e354440abbcb08088 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    858,
 /**/
     857,
 /**/