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)

aa23b37942
This commit is contained in:
Florian Walch 2015-12-03 20:14:51 +01:00
parent 25eaacd10f
commit 7f99d210fd
14 changed files with 601 additions and 30 deletions

View File

@ -482,6 +482,8 @@ followed by another Vim command:
:argdo
:autocmd
:bufdo
:cdo
:cfdo
:command
:cscope
:debug
@ -492,6 +494,8 @@ followed by another Vim command:
:help
:helpfind
:lcscope
:ldo
:lfdo
:make
:normal
:promptfind

View File

@ -795,7 +795,8 @@ USING THE ARGUMENT LIST
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each file.
Also see |:windo|, |:tabdo| and |:bufdo|.
Also see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|,
|:cfdo| and |:lfdo|.
Example: >
:args *.c

View File

@ -1128,6 +1128,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| :cfdo 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
@ -1285,6 +1287,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

View File

@ -291,6 +291,100 @@ use this code: >
au QuickfixCmdPost make call QfMakeConv()
EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:
*:cdo*
:cdo[!] {cmd} Execute {cmd} in each valid entry in the quickfix list.
It works like doing this: >
:cfirst
:{cmd}
:cnext
:{cmd}
etc.
< When the current file can't be |abandon|ed and the [!]
is not present, the command fails.
When an error is detected on one buffer, further
buffers will not be visited.
The last buffer (or where an error occurred) becomes
the current buffer.
{cmd} can contain '|' to concatenate several commands.
Only valid entries in the quickfix list are used.
Note: While this command is executing, the Syntax
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each buffer.
Also see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,
|:ldo|, |:cfdo| and |:lfdo|.
*:cfdo*
:cfdo[!] {cmd} Execute {cmd} in each file in the quickfix list.
It works like doing this: >
:cfirst
:{cmd}
:cnfile
:{cmd}
etc.
< When the current file can't be |abandon|ed and the [!]
is not present, the command fails.
When an error is detected on one buffer, further
buffers will not be visited.
The last buffer (or where an error occurred) becomes
the current buffer.
{cmd} can contain '|' to concatenate several commands.
Only valid entries in the quickfix list are used.
Note: While this command is executing, the Syntax
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each buffer.
Also see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,
|:cdo|, |:ldo| and |:lfdo|.
*:ldo*
:ld[o][!] {cmd} Execute {cmd} in each valid entry in the location list
for the current window.
It works like doing this: >
:lfirst
:{cmd}
:lnext
:{cmd}
etc.
< When the current file can't be |abandon|ed and the [!]
is not present, the command fails.
When an error is detected on one buffer, further
buffers will not be visited.
The last buffer (or where an error occurred) becomes
the current buffer.
{cmd} can contain '|' to concatenate several commands.
Only valid entries in the location list are used.
Note: While this command is executing, the Syntax
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each buffer.
Also see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,
|:cdo|, |:cfdo| and |:lfdo|.
*:lfdo*
:lfdo[!] {cmd} Execute {cmd} in each file in the location list for
the current window.
It works like doing this: >
:lfirst
:{cmd}
:lnfile
:{cmd}
etc.
< When the current file can't be |abandon|ed and the [!]
is not present, the command fails.
When an error is detected on one buffer, further
buffers will not be visited.
The last buffer (or where an error occurred) becomes
the current buffer.
{cmd} can contain '|' to concatenate several commands.
Only valid entries in the location list are used.
Note: While this command is executing, the Syntax
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each buffer.
Also see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,
|:cdo|, |:ldo| and |:cfdo|.
=============================================================================
2. The error window *quickfix-window*

View File

@ -234,7 +234,8 @@ LOOPING OVER TAB PAGES:
current tab page.
{cmd} can contain '|' to concatenate several commands.
{cmd} must not open or close tab pages or reorder them.
Also see |:windo|, |:argdo| and |:bufdo|.
Also see |:windo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo|
and |:lfdo|.
==============================================================================
3. Other items *tab-page-other*

View File

@ -702,7 +702,8 @@ can also get to them with the buffer list commands, like ":bnext".
the current window.
{cmd} can contain '|' to concatenate several commands.
{cmd} must not open or close windows or reorder them.
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
@ -728,7 +729,8 @@ can also get to them with the buffer list commands, like ":bnext".
autocommand event is disabled by adding it to
'eventignore'. This considerably speeds up editing
each buffer.
Also see |:tabdo|, |:argdo| and |:windo|.
Also see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|,
|:cfdo| and |:lfdo|.
Examples: >

View File

@ -34,6 +34,7 @@ local ADDR_ARGUMENTS = 2
local ADDR_LOADED_BUFFERS = 3
local ADDR_BUFFERS = 4
local ADDR_TABS = 5
local ADDR_QUICKFIX = 6
-- The following table is described in ex_cmds_defs.h file.
return {
@ -373,6 +374,12 @@ return {
addr_type=ADDR_LINES,
func='ex_cd',
},
{
command='cdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL),
addr_type=ADDR_QUICKFIX,
func='ex_listdo',
},
{
command='center',
flags=bit.bor(TRLBAR, RANGE, WHOLEFOLD, EXTRA, CMDWIN, MODIFY),
@ -391,6 +398,14 @@ return {
addr_type=ADDR_LINES,
func='ex_cfile',
},
-- Even though 'cfdo' is alphabetically lower than 'cfile', it is after
-- 'cfile' in this cmd list to support the existing ":cf" abbreviation.
{
command='cfdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL),
addr_type=ADDR_QUICKFIX,
func='ex_listdo',
},
{
command='cfirst',
flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG),
@ -1285,6 +1300,12 @@ return {
addr_type=ADDR_LINES,
func='do_cscope',
},
{
command='ldo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL),
addr_type=ADDR_QUICKFIX,
func='ex_listdo',
},
{
command='left',
flags=bit.bor(TRLBAR, RANGE, WHOLEFOLD, EXTRA, CMDWIN, MODIFY),
@ -1315,6 +1336,14 @@ return {
addr_type=ADDR_LINES,
func='ex_cfile',
},
-- Even though 'lfdo' is alphabetically lower than 'lfile', it is after
-- 'lfile' in this cmd list to support the existing ":lf" abbreviation.
{
command='lfdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, NOTADR, DFLALL),
addr_type=ADDR_QUICKFIX,
func='ex_listdo',
},
{
command='lfirst',
flags=bit.bor(RANGE, NOTADR, COUNT, TRLBAR, BANG),

View File

@ -1868,7 +1868,7 @@ void ex_argdelete(exarg_T *eap)
}
/*
* ":argdo", ":windo", ":bufdo", ":tabdo"
* ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo"
*/
void ex_listdo(exarg_T *eap)
{
@ -1879,7 +1879,6 @@ void ex_listdo(exarg_T *eap)
char_u *save_ei = NULL;
char_u *p_shm_save;
if (eap->cmdidx != CMD_windo && eap->cmdidx != CMD_tabdo)
/* Don't do syntax HL autocommands. Skipping the syntax file is a
* great speed improvement. */
@ -1914,7 +1913,10 @@ void ex_listdo(exarg_T *eap)
default:
break;
}
buf_T *buf = curbuf;
size_t qf_size = 0;
/* set pcmark now */
if (eap->cmdidx == CMD_bufdo) {
/* Advance to the first listed buffer after "eap->line1". */
@ -1929,6 +1931,22 @@ void ex_listdo(exarg_T *eap)
if (buf != NULL) {
goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);
}
} else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
qf_size = qf_get_size(eap);
assert(eap->line1 >= 0);
if (qf_size == 0 || (size_t)eap->line1 > qf_size) {
buf = NULL;
} else {
ex_cc(eap);
buf = curbuf;
i = eap->line1 - 1;
if (eap->addr_count <= 0) {
// Default to all quickfix/location list entries.
eap->line2 = qf_size;
}
}
} else {
setpcmark();
}
@ -2009,9 +2027,27 @@ void ex_listdo(exarg_T *eap)
set_option_value((char_u *)"shm", 0L, p_shm_save, 0);
xfree(p_shm_save);
/* If autocommands took us elsewhere, quit here */
if (curbuf->b_fnum != next_fnum)
// If autocommands took us elsewhere, quit here.
if (curbuf->b_fnum != next_fnum) {
break;
}
}
if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||
eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
assert(i >= 0);
if ((size_t)i >= qf_size || i >= eap->line2) {
break;
}
size_t 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;
}
}
if (eap->cmdidx == CMD_windo) {

View File

@ -72,6 +72,7 @@
#define ADDR_LOADED_BUFFERS 3
#define ADDR_BUFFERS 4
#define ADDR_TABS 5
#define ADDR_QUICKFIX 6
typedef struct exarg exarg_T;

View File

@ -1531,9 +1531,12 @@ static char_u * do_one_cmd(char_u **cmdlinep,
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) {
@ -1582,6 +1585,13 @@ static char_u * do_one_cmd(char_u **cmdlinep,
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;
}
@ -1962,6 +1972,12 @@ static char_u * do_one_cmd(char_u **cmdlinep,
ea.line2 = ARGCOUNT;
}
break;
case ADDR_QUICKFIX:
ea.line2 = qf_get_size(&ea);
if (ea.line2 == 0) {
ea.line2 = 1;
}
break;
}
}
@ -2945,6 +2961,8 @@ set_one_cmd_context (
case CMD_botright:
case CMD_browse:
case CMD_bufdo:
case CMD_cdo:
case CMD_cfdo:
case CMD_confirm:
case CMD_debug:
case CMD_folddoclosed:
@ -2954,7 +2972,9 @@ set_one_cmd_context (
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:
@ -3367,7 +3387,8 @@ skip_range (
*
* Return MAXLNUM when no Ex address was found.
*/
static linenr_T get_address(char_u **ptr,
static linenr_T get_address(exarg_T *eap,
char_u **ptr,
int addr_type, // flag: one of ADDR_LINES, ...
int skip, // only skip the address, don't use it
int to_other_file // flag: may jump to other file
@ -3405,6 +3426,9 @@ static linenr_T get_address(char_u **ptr,
case ADDR_TABS:
lnum = CURRENT_TAB_NR;
break;
case ADDR_QUICKFIX:
lnum = qf_get_cur_valid_idx(eap);
break;
}
break;
@ -3436,6 +3460,12 @@ static linenr_T get_address(char_u **ptr,
case ADDR_TABS:
lnum = LAST_TAB_NR;
break;
case ADDR_QUICKFIX:
lnum = qf_get_size(eap);
if (lnum == 0) {
lnum = 1;
}
break;
}
break;
@ -3578,6 +3608,9 @@ static linenr_T get_address(char_u **ptr,
case ADDR_TABS:
lnum = CURRENT_TAB_NR;
break;
case ADDR_QUICKFIX:
lnum = qf_get_cur_valid_idx(eap);
break;
}
}
@ -3702,6 +3735,12 @@ static char_u *invalid_range(exarg_T *eap)
return (char_u *)_(e_invrange);
}
break;
case ADDR_QUICKFIX:
assert(eap->line2 >= 0);
if (eap->line2 != 1 && (size_t)eap->line2 > qf_get_size(eap)) {
return (char_u *)_(e_invrange);
}
break;
}
}
return NULL;
@ -4589,6 +4628,7 @@ static struct {
{ADDR_TABS, "tabs"},
{ADDR_BUFFERS, "buffers"},
{ADDR_WINDOWS, "windows"},
{ADDR_QUICKFIX, "quickfix"},
{-1, NULL}
};
@ -7013,9 +7053,7 @@ static void ex_put(exarg_T *eap)
*/
static void ex_copymove(exarg_T *eap)
{
long n;
n = get_address(&eap->arg, eap->addr_type, FALSE, FALSE);
long n = get_address(eap, &eap->arg, eap->addr_type, false, false);
if (eap->arg == NULL) { /* error detected */
eap->nextcmd = NULL;
return;

View File

@ -1202,7 +1202,7 @@ static void qf_clean_dir_stack(struct dir_stack_T **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?
@ -2571,9 +2571,159 @@ static char_u *get_mef_name(void)
return name;
}
/// Returns the number of valid entries in the current quickfix/location list.
size_t qf_get_size(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
{
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;
}
}
int prev_fnum = 0;
size_t sz = 0;
qfline_T *qfp;
size_t i;
assert(qi->qf_lists[qi->qf_curlist].qf_count >= 0);
for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start;
i < (size_t)qi->qf_lists[qi->qf_curlist].qf_count && qfp != NULL;
i++, qfp = qfp->qf_next) {
if (!qfp->qf_valid) {
continue;
}
if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo) {
// Count all valid entries.
sz++;
} 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.
size_t qf_get_cur_idx(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
{
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;
}
}
assert(qi->qf_lists[qi->qf_curlist].qf_index >= 0);
return (size_t)qi->qf_lists[qi->qf_curlist].qf_index;
}
/// Returns the current index in the quickfix/location list,
/// counting only valid entries.
/// Returns 1 if there are no valid entries.
int qf_get_cur_valid_idx(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
{
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 1;
}
}
qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
// Check if the list has valid errors.
if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
return 1;
}
int prev_fnum = 0;
int eidx = 0;
qfline_T *qfp;
size_t i;
assert(qfl->qf_index >= 0);
for (i = 1, qfp = qfl->qf_start;
i <= (size_t)qfl->qf_index && qfp != NULL;
i++, qfp = qfp->qf_next) {
if (!qfp->qf_valid) {
continue;
}
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 != 0 ? 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 size_t qf_get_nth_valid_entry(qf_info_T *qi, size_t n, bool fdo)
FUNC_ATTR_NONNULL_ALL
{
qf_list_T *qfl = &qi->qf_lists[qi->qf_curlist];
// Check if the list has valid errors.
if (qfl->qf_count <= 0 || qfl->qf_nonevalid) {
return 1;
}
int prev_fnum = 0;
size_t eidx = 0;
size_t i;
qfline_T *qfp;
assert(qfl->qf_count >= 0);
for (i = 1, qfp = qfl->qf_start;
i <= (size_t)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;
}
}
return i <= (size_t)qfl->qf_count ? i : 1;
}
/*
* ":cc", ":crewind", ":cfirst" and ":clast".
* ":ll", ":lrewind", ":lfirst" and ":llast".
* ":cdo", ":ldo", ":cfdo" and ":lfdo".
*/
void ex_cc(exarg_T *eap)
{
@ -2582,7 +2732,10 @@ void ex_cc(exarg_T *eap)
if (eap->cmdidx == CMD_ll
|| eap->cmdidx == CMD_lrewind
|| eap->cmdidx == CMD_lfirst
|| eap->cmdidx == CMD_llast) {
|| eap->cmdidx == CMD_llast
|| eap->cmdidx == CMD_llast
|| eap->cmdidx == CMD_ldo
|| eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
if (qi == NULL) {
EMSG(_(e_loclist));
@ -2590,21 +2743,42 @@ void ex_cc(exarg_T *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);
int errornr;
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) {
size_t n;
if (eap->addr_count > 0) {
assert(eap->line1 >= 0);
n = (size_t)eap->line1;
} else {
n = 1;
}
size_t valid_entry = qf_get_nth_valid_entry(qi, n,
eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
assert(valid_entry <= INT_MAX);
errornr = (int)valid_entry;
}
qf_jump(qi, 0, errornr, eap->forceit);
}
/*
* ":cnext", ":cnfile", ":cNext" and ":cprevious".
* ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
* ":cdo", ":ldo", ":cfdo" and ":lfdo".
*/
void ex_cnext(exarg_T *eap)
{
@ -2615,7 +2789,10 @@ void ex_cnext(exarg_T *eap)
|| eap->cmdidx == CMD_lprevious
|| eap->cmdidx == CMD_lnfile
|| eap->cmdidx == CMD_lNfile
|| eap->cmdidx == CMD_lpfile) {
|| eap->cmdidx == CMD_lpfile
|| eap->cmdidx == CMD_lpfile
|| eap->cmdidx == CMD_ldo
|| eap->cmdidx == CMD_lfdo) {
qi = GET_LOC_LIST(curwin);
if (qi == NULL) {
EMSG(_(e_loclist));
@ -2623,15 +2800,26 @@ void ex_cnext(exarg_T *eap)
}
}
qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext)
int errornr;
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);
}
/*

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

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

@ -135,7 +135,7 @@ static int included_patches[] = {
// 861 NA
// 860,
// 859,
// 858,
858,
// 857,
// 856,
// 855 NA