summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2015-09-08 18:46:31 +0200
committerBram Moolenaar <Bram@vim.org>2015-09-08 18:46:31 +0200
commitaa23b379421aa214e6543b06c974594a25799b09 (patch)
tree88d37433372978ab8248d916093d6bba639fe5b2
parent4a4b821085847651b71d8ad9fab9f180635cb453 (diff)
downloadvim-git-aa23b379421aa214e6543b06c974594a25799b09.tar.gz
patch 7.4.858v7.4.858
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)
-rw-r--r--runtime/doc/cmdline.txt4
-rw-r--r--runtime/doc/editing.txt3
-rw-r--r--runtime/doc/index.txt4
-rw-r--r--runtime/doc/tabpage.txt3
-rw-r--r--runtime/doc/windows.txt6
-rw-r--r--src/ex_cmds.h13
-rw-r--r--src/ex_cmds2.c52
-rw-r--r--src/ex_docmd.c43
-rw-r--r--src/proto/quickfix.pro3
-rw-r--r--src/quickfix.c222
-rw-r--r--src/testdir/Make_amiga.mak2
-rw-r--r--src/testdir/Make_dos.mak1
-rw-r--r--src/testdir/Make_ming.mak1
-rw-r--r--src/testdir/Make_os2.mak1
-rw-r--r--src/testdir/Make_vms.mms3
-rw-r--r--src/testdir/Makefile1
-rw-r--r--src/testdir/test_cdo.in107
-rw-r--r--src/testdir/test_cdo.ok66
-rw-r--r--src/version.c2
19 files changed, 506 insertions, 31 deletions
diff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt
index 94fe977cc..fe2ef76ef 100644
--- a/runtime/doc/cmdline.txt
+++ b/runtime/doc/cmdline.txt
@@ -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
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 49a96f6a6..5666e68b5 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -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
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index e8171a90e..3949c2b57 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -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
diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt
index 46e0a8fde..b98c18b02 100644
--- a/runtime/doc/tabpage.txt
+++ b/runtime/doc/tabpage.txt
@@ -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*
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index a7db69c52..4b947fc81 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -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: >
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 794595697..874ac6ba0 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -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),
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index eefd5d237..3cc2d45a7 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -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 */
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 7633d5420..35b6637fd 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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;
diff --git a/src/proto/quickfix.pro b/src/proto/quickfix.pro
index a5c690f64..c4e502e6d 100644
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -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));
diff --git a/src/quickfix.c b/src/quickfix.c
index 463056b56..7243a0cbc 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -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?
@@ -2990,19 +2990,183 @@ get_mef_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);
}
/*
diff --git a/src/testdir/Make_amiga.mak b/src/testdir/Make_amiga.mak
index 901a7c139..af27919e8 100644
--- a/src/testdir/Make_amiga.mak
+++ b/src/testdir/Make_amiga.mak
@@ -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
diff --git a/src/testdir/Make_dos.mak b/src/testdir/Make_dos.mak
index 603f4a411..abef95046 100644
--- a/src/testdir/Make_dos.mak
+++ b/src/testdir/Make_dos.mak
@@ -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 \
diff --git a/src/testdir/Make_ming.mak b/src/testdir/Make_ming.mak
index 1b76bcc98..aa59a014e 100644
--- a/src/testdir/Make_ming.mak
+++ b/src/testdir/Make_ming.mak
@@ -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 \
diff --git a/src/testdir/Make_os2.mak b/src/testdir/Make_os2.mak
index 08f78cb1e..9150af714 100644
--- a/src/testdir/Make_os2.mak
+++ b/src/testdir/Make_os2.mak
@@ -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 \
diff --git a/src/testdir/Make_vms.mms b/src/testdir/Make_vms.mms
index 6e7715388..a716d0361 100644
--- a/src/testdir/Make_vms.mms
+++ b/src/testdir/Make_vms.mms
@@ -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 \
diff --git a/src/testdir/Makefile b/src/testdir/Makefile
index f29ec8b45..39d8388ec 100644
--- a/src/testdir/Makefile
+++ b/src/testdir/Makefile
@@ -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
index 000000000..fb80ea116
--- /dev/null
+++ b/src/testdir/test_cdo.in
@@ -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
index 000000000..ddcff4bbb
--- /dev/null
+++ b/src/testdir/test_cdo.ok
@@ -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
+
diff --git a/src/version.c b/src/version.c
index 3fb4ad2fe..0e2e51e2e 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 858,
+/**/
857,
/**/
856,