1
0
forked from aniani/vim

patch 7.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)
This commit is contained in:
Bram Moolenaar 2015-09-08 18:46:31 +02:00
parent 4a4b821085
commit aa23b37942
19 changed files with 506 additions and 31 deletions

View File

@ -511,6 +511,8 @@ followed by another Vim command:
:argdo :argdo
:autocmd :autocmd
:bufdo :bufdo
:cdo
:cfdo
:command :command
:cscope :cscope
:debug :debug
@ -521,6 +523,8 @@ followed by another Vim command:
:help :help
:helpfind :helpfind
:lcscope :lcscope
:ldo
:lfdo
:make :make
:normal :normal
:perl :perl

View File

@ -868,7 +868,8 @@ USING THE ARGUMENT LIST
each file. each file.
{not in Vi} {not available when compiled without the {not in Vi} {not available when compiled without the
|+listcmds| feature} |+listcmds| feature}
Also see |:windo|, |:tabdo| and |:bufdo|. Also see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|,
|:cfdo| and |:lfdo|
Example: > Example: >
:args *.c :args *.c

View File

@ -1138,6 +1138,8 @@ tag command action ~
|:cc| :cc go to specific error |:cc| :cc go to specific error
|:cclose| :ccl[ose] close quickfix window |:cclose| :ccl[ose] close quickfix window
|:cd| :cd change directory |: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 |:center| :ce[nter] format lines at the center
|:cexpr| :cex[pr] read errors from expr and jump to first |:cexpr| :cex[pr] read errors from expr and jump to first
|:cfile| :cf[ile] read file with error messages 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 |:lchdir| :lch[dir] change directory locally
|:lclose| :lcl[ose] close location window |:lclose| :lcl[ose] close location window
|:lcscope| :lcs[cope] like ":cscope" but uses location list |: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 |:left| :le[ft] left align lines
|:leftabove| :lefta[bove] make split window appear left or above |:leftabove| :lefta[bove] make split window appear left or above
|:let| :let assign a value to a variable or option |:let| :let assign a value to a variable or option

View File

@ -248,7 +248,8 @@ LOOPING OVER TAB PAGES:
{cmd} must not open or close tab pages or reorder them. {cmd} must not open or close tab pages or reorder them.
{not in Vi} {not available when compiled without the {not in Vi} {not available when compiled without the
|+listcmds| feature} |+listcmds| feature}
Also see |:windo|, |:argdo| and |:bufdo|. Also see |:windo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo|
and |:lfdo|
============================================================================== ==============================================================================
3. Other items *tab-page-other* 3. Other items *tab-page-other*

View 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. {cmd} must not open or close windows or reorder them.
{not in Vi} {not available when compiled without the {not in Vi} {not available when compiled without the
|+listcmds| feature} |+listcmds| feature}
Also see |:tabdo|, |:argdo| and |:bufdo|. Also see |:tabdo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|,
|:cfdo| and |:lfdo|
*:bufdo* *:bufdo*
:[range]bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list or if :[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. each buffer.
{not in Vi} {not available when compiled without the {not in Vi} {not available when compiled without the
|+listcmds| feature} |+listcmds| feature}
Also see |:tabdo|, |:argdo| and |:windo|. Also see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|,
|:cfdo| and |:lfdo|
Examples: > Examples: >

View File

@ -65,6 +65,7 @@
#define ADDR_LOADED_BUFFERS 3 #define ADDR_LOADED_BUFFERS 3
#define ADDR_BUFFERS 4 #define ADDR_BUFFERS 4
#define ADDR_TABS 5 #define ADDR_TABS 5
#define ADDR_QUICKFIX 6
#ifndef DO_DECLARE_EXCMD #ifndef DO_DECLARE_EXCMD
typedef struct exarg exarg_T; typedef struct exarg exarg_T;
@ -270,6 +271,9 @@ EX(CMD_cclose, "cclose", ex_cclose,
EX(CMD_cd, "cd", ex_cd, EX(CMD_cd, "cd", ex_cd,
BANG|FILE1|TRLBAR|CMDWIN, BANG|FILE1|TRLBAR|CMDWIN,
ADDR_LINES), ADDR_LINES),
EX(CMD_cdo, "cdo", ex_listdo,
BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
ADDR_QUICKFIX),
EX(CMD_center, "center", ex_align, EX(CMD_center, "center", ex_align,
TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY, TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
ADDR_LINES), ADDR_LINES),
@ -279,6 +283,9 @@ EX(CMD_cexpr, "cexpr", ex_cexpr,
EX(CMD_cfile, "cfile", ex_cfile, EX(CMD_cfile, "cfile", ex_cfile,
TRLBAR|FILE1|BANG, TRLBAR|FILE1|BANG,
ADDR_LINES), ADDR_LINES),
EX(CMD_cfdo, "cfdo", ex_listdo,
BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
ADDR_QUICKFIX),
EX(CMD_cfirst, "cfirst", ex_cc, EX(CMD_cfirst, "cfirst", ex_cc,
RANGE|NOTADR|COUNT|TRLBAR|BANG, RANGE|NOTADR|COUNT|TRLBAR|BANG,
ADDR_LINES), ADDR_LINES),
@ -729,6 +736,9 @@ EX(CMD_lclose, "lclose", ex_cclose,
EX(CMD_lcscope, "lcscope", do_cscope, EX(CMD_lcscope, "lcscope", do_cscope,
EXTRA|NOTRLCOM|XFILE, EXTRA|NOTRLCOM|XFILE,
ADDR_LINES), ADDR_LINES),
EX(CMD_ldo, "ldo", ex_listdo,
BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
ADDR_QUICKFIX),
EX(CMD_left, "left", ex_align, EX(CMD_left, "left", ex_align,
TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY, TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
ADDR_LINES), ADDR_LINES),
@ -744,6 +754,9 @@ EX(CMD_lexpr, "lexpr", ex_cexpr,
EX(CMD_lfile, "lfile", ex_cfile, EX(CMD_lfile, "lfile", ex_cfile,
TRLBAR|FILE1|BANG, TRLBAR|FILE1|BANG,
ADDR_LINES), ADDR_LINES),
EX(CMD_lfdo, "lfdo", ex_listdo,
BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
ADDR_QUICKFIX),
EX(CMD_lfirst, "lfirst", ex_cc, EX(CMD_lfirst, "lfirst", ex_cc,
RANGE|NOTADR|COUNT|TRLBAR|BANG, RANGE|NOTADR|COUNT|TRLBAR|BANG,
ADDR_LINES), ADDR_LINES),

View File

@ -2429,7 +2429,7 @@ ex_argdelete(eap)
} }
/* /*
* ":argdo", ":windo", ":bufdo", ":tabdo" * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
*/ */
void void
ex_listdo(eap) ex_listdo(eap)
@ -2446,6 +2446,10 @@ ex_listdo(eap)
char_u *save_ei = NULL; char_u *save_ei = NULL;
#endif #endif
char_u *p_shm_save; char_u *p_shm_save;
#ifdef FEAT_QUICKFIX
int qf_size;
int qf_idx;
#endif
#ifndef FEAT_WINDOWS #ifndef FEAT_WINDOWS
if (eap->cmdidx == CMD_windo) if (eap->cmdidx == CMD_windo)
@ -2510,6 +2514,25 @@ ex_listdo(eap)
if (buf != NULL) if (buf != NULL)
goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); 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 else
setpcmark(); setpcmark();
listcmd_busy = TRUE; /* avoids setting pcmark below */ 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); set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
vim_free(p_shm_save); 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) if (curbuf->b_fnum != next_fnum)
break; 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) if (eap->cmdidx == CMD_windo)
{ {
validate_cursor(); /* cursor may have moved */ validate_cursor(); /* cursor may have moved */

View File

@ -135,7 +135,7 @@ static int getargopt __ARGS((exarg_T *eap));
#endif #endif
static int check_more __ARGS((int, int)); 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)); static void get_flags __ARGS((exarg_T *eap));
#if !defined(FEAT_PERL) \ #if !defined(FEAT_PERL) \
|| !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \ || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \
@ -2173,9 +2173,12 @@ do_one_cmd(cmdlinep, sourcing,
lnum = CURRENT_TAB_NR; lnum = CURRENT_TAB_NR;
ea.line2 = lnum; ea.line2 = lnum;
break; break;
case ADDR_QUICKFIX:
ea.line2 = qf_get_cur_valid_idx(&ea);
break;
} }
ea.cmd = skipwhite(ea.cmd); 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 */ if (ea.cmd == NULL) /* error detected */
goto doend; goto doend;
if (lnum == MAXLNUM) if (lnum == MAXLNUM)
@ -2233,6 +2236,12 @@ do_one_cmd(cmdlinep, sourcing,
ea.line2 = ARGCOUNT; ea.line2 = ARGCOUNT;
} }
break; break;
case ADDR_QUICKFIX:
ea.line1 = 1;
ea.line2 = qf_get_size(&ea);
if (ea.line2 == 0)
ea.line2 = 1;
break;
} }
++ea.addr_count; ++ea.addr_count;
} }
@ -2693,6 +2702,11 @@ do_one_cmd(cmdlinep, sourcing,
else else
ea.line2 = ARGCOUNT; ea.line2 = ARGCOUNT;
break; 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_botright:
case CMD_browse: case CMD_browse:
case CMD_bufdo: case CMD_bufdo:
case CMD_cdo:
case CMD_cfdo:
case CMD_confirm: case CMD_confirm:
case CMD_debug: case CMD_debug:
case CMD_folddoclosed: case CMD_folddoclosed:
@ -3848,7 +3864,9 @@ set_one_cmd_context(xp, buff)
case CMD_keepjumps: case CMD_keepjumps:
case CMD_keepmarks: case CMD_keepmarks:
case CMD_keeppatterns: case CMD_keeppatterns:
case CMD_ldo:
case CMD_leftabove: case CMD_leftabove:
case CMD_lfdo:
case CMD_lockmarks: case CMD_lockmarks:
case CMD_noautocmd: case CMD_noautocmd:
case CMD_noswapfile: case CMD_noswapfile:
@ -4321,7 +4339,8 @@ skip_range(cmd, ctx)
* Return MAXLNUM when no Ex address was found. * Return MAXLNUM when no Ex address was found.
*/ */
static linenr_T 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; char_u **ptr;
int addr_type; /* flag: one of ADDR_LINES, ... */ int addr_type; /* flag: one of ADDR_LINES, ... */
int skip; /* only skip the address, don't use it */ 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: case ADDR_TABS:
lnum = CURRENT_TAB_NR; lnum = CURRENT_TAB_NR;
break; break;
case ADDR_QUICKFIX:
lnum = qf_get_cur_valid_idx(eap);
break;
} }
break; break;
@ -4394,6 +4416,11 @@ get_address(ptr, addr_type, skip, to_other_file)
case ADDR_TABS: case ADDR_TABS:
lnum = LAST_TAB_NR; lnum = LAST_TAB_NR;
break; break;
case ADDR_QUICKFIX:
lnum = qf_get_size(eap);
if (lnum == 0)
lnum = 1;
break;
} }
break; break;
@ -4569,6 +4596,9 @@ get_address(ptr, addr_type, skip, to_other_file)
case ADDR_TABS: case ADDR_TABS:
lnum = CURRENT_TAB_NR; lnum = CURRENT_TAB_NR;
break; 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) if (eap->line2 > LAST_TAB_NR)
return (char_u *)_(e_invrange); return (char_u *)_(e_invrange);
break; break;
case ADDR_QUICKFIX:
if (eap->line2 != 1 && eap->line2 > qf_get_size(eap))
return (char_u *)_(e_invrange);
break;
} }
} }
return NULL; return NULL;
@ -5817,6 +5851,7 @@ static struct
{ADDR_TABS, "tabs"}, {ADDR_TABS, "tabs"},
{ADDR_BUFFERS, "buffers"}, {ADDR_BUFFERS, "buffers"},
{ADDR_WINDOWS, "windows"}, {ADDR_WINDOWS, "windows"},
{ADDR_QUICKFIX, "quickfix"},
{-1, NULL} {-1, NULL}
}; };
#endif #endif
@ -9224,7 +9259,7 @@ ex_copymove(eap)
{ {
long n; 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 */ if (eap->arg == NULL) /* error detected */
{ {
eap->nextcmd = NULL; eap->nextcmd = NULL;

View File

@ -17,6 +17,9 @@ int bt_dontwrite_msg __ARGS((buf_T *buf));
int buf_hide __ARGS((buf_T *buf)); int buf_hide __ARGS((buf_T *buf));
int grep_internal __ARGS((cmdidx_T cmdidx)); int grep_internal __ARGS((cmdidx_T cmdidx));
void ex_make __ARGS((exarg_T *eap)); 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_cc __ARGS((exarg_T *eap));
void ex_cnext __ARGS((exarg_T *eap)); void ex_cnext __ARGS((exarg_T *eap));
void ex_cfile __ARGS((exarg_T *eap)); void ex_cfile __ARGS((exarg_T *eap));

View File

@ -1373,7 +1373,7 @@ qf_clean_dir_stack(stackptr)
/* /*
* Check in which directory of the directory stack the given file can be * Check in which directory of the directory stack the given file can be
* found. * 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. * Cleans up intermediate directory entries.
* *
* TODO: How to solve the following problem? * TODO: How to solve the following problem?
@ -2989,20 +2989,184 @@ get_mef_name()
return 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". * ":cc", ":crewind", ":cfirst" and ":clast".
* ":ll", ":lrewind", ":lfirst" and ":llast". * ":ll", ":lrewind", ":lfirst" and ":llast".
* ":cdo", ":ldo", ":cfdo" and ":lfdo"
*/ */
void void
ex_cc(eap) ex_cc(eap)
exarg_T *eap; exarg_T *eap;
{ {
qf_info_T *qi = &ql_info; qf_info_T *qi = &ql_info;
int errornr;
if (eap->cmdidx == CMD_ll if (eap->cmdidx == CMD_ll
|| eap->cmdidx == CMD_lrewind || eap->cmdidx == CMD_lrewind
|| eap->cmdidx == CMD_lfirst || 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); qi = GET_LOC_LIST(curwin);
if (qi == NULL) if (qi == NULL)
@ -3012,34 +3176,51 @@ ex_cc(eap)
} }
} }
qf_jump(qi, 0, if (eap->addr_count > 0)
eap->addr_count > 0 errornr = (int)eap->line2;
? (int)eap->line2 else
: (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) {
? 0 if (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)
: (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind errornr = 0;
else if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind
|| eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)
? 1 errornr = 1;
: 32767, else
eap->forceit); 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". * ":cnext", ":cnfile", ":cNext" and ":cprevious".
* ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
* Also, used by ":cdo", ":ldo", ":cfdo" and ":lfdo" commands.
*/ */
void void
ex_cnext(eap) ex_cnext(eap)
exarg_T *eap; exarg_T *eap;
{ {
qf_info_T *qi = &ql_info; qf_info_T *qi = &ql_info;
int errornr;
if (eap->cmdidx == CMD_lnext if (eap->cmdidx == CMD_lnext
|| eap->cmdidx == CMD_lNext || eap->cmdidx == CMD_lNext
|| eap->cmdidx == CMD_lprevious || eap->cmdidx == CMD_lprevious
|| eap->cmdidx == CMD_lnfile || eap->cmdidx == CMD_lnfile
|| 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); qi = GET_LOC_LIST(curwin);
if (qi == NULL) 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 ? 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 ? FORWARD_FILE
: (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile
|| eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile) || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)
? BACKWARD_FILE ? BACKWARD_FILE
: BACKWARD, : BACKWARD,
eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); errornr, eap->forceit);
} }
/* /*

View File

@ -41,6 +41,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
test_autocmd_option.out \ test_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.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_autocmd_option.out: test_autocmd_option.in
test_autoformat_join.out: test_autoformat_join.in test_autoformat_join.out: test_autoformat_join.in
test_breakindent.out: test_breakindent.in test_breakindent.out: test_breakindent.in
test_cdo.out: test_cdo.in
test_changelist.out: test_changelist.in test_changelist.out: test_changelist.in
test_charsearch.out: test_charsearch.in test_charsearch.out: test_charsearch.in
test_close_count.out: test_close_count.in test_close_count.out: test_close_count.in

View File

@ -40,6 +40,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
test_autocmd_option.out \ test_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \

View File

@ -62,6 +62,7 @@ SCRIPTS = test3.out test4.out test5.out test6.out test7.out \
test_autocmd_option.out \ test_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \

View File

@ -42,6 +42,7 @@ SCRIPTS = test1.out test3.out test4.out test5.out test6.out \
test_autocmd_option.out \ test_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \

View File

@ -4,7 +4,7 @@
# Authors: Zoltan Arpadffy, <arpadffy@polarhome.com> # Authors: Zoltan Arpadffy, <arpadffy@polarhome.com>
# Sandor Kopanyi, <sandor.kopanyi@mailbox.hu> # 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. # 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. # 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_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \

View File

@ -38,6 +38,7 @@ SCRIPTS = test1.out test2.out test3.out test4.out test5.out test6.out \
test_autocmd_option.out \ test_autocmd_option.out \
test_autoformat_join.out \ test_autoformat_join.out \
test_breakindent.out \ test_breakindent.out \
test_cdo.out \
test_changelist.out \ test_changelist.out \
test_charsearch.out \ test_charsearch.out \
test_close_count.out \ test_close_count.out \

107
src/testdir/test_cdo.in Normal file
View File

@ -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

66
src/testdir/test_cdo.ok Normal file
View File

@ -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

View File

@ -741,6 +741,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
858,
/**/ /**/
857, 857,
/**/ /**/