To: vim_dev@googlegroups.com Subject: Patch 7.4.858 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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) Files: runtime/doc/cmdline.txt, runtime/doc/editing.txt, runtime/doc/index.txt, runtime/doc/quickfix.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, src/testdir/test_cdo.ok *** ../vim-7.4.857/runtime/doc/cmdline.txt 2014-02-23 23:38:58.812760280 +0100 --- runtime/doc/cmdline.txt 2015-09-08 18:07:42.256948348 +0200 *************** *** 511,516 **** --- 511,518 ---- :argdo :autocmd :bufdo + :cdo + :cfdo :command :cscope :debug *************** *** 521,526 **** --- 523,530 ---- :help :helpfind :lcscope + :ldo + :lfdo :make :normal :perl *** ../vim-7.4.857/runtime/doc/editing.txt 2015-01-07 16:52:53.506792420 +0100 --- runtime/doc/editing.txt 2015-09-08 18:07:42.256948348 +0200 *************** *** 854,860 **** each file. {not in Vi} {not available when compiled without the |+listcmds| feature} ! Also see |:windo|, |:tabdo| and |:bufdo|. Example: > :args *.c --- 868,875 ---- each file. {not in Vi} {not available when compiled without the |+listcmds| feature} ! Also see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|, ! |:cfdo| and |:lfdo| Example: > :args *.c *** ../vim-7.4.857/runtime/doc/index.txt 2014-09-19 19:39:30.762446025 +0200 --- runtime/doc/index.txt 2015-09-08 18:10:53.402969644 +0200 *************** *** 1133,1138 **** --- 1138,1145 ---- |: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 *************** *** 1290,1295 **** --- 1298,1305 ---- |: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 *** ../vim-7.4.857/runtime/doc/quickfix.txt 2014-02-23 23:38:58.820760280 +0100 --- runtime/doc/quickfix.txt 2015-09-08 18:27:53.564412123 +0200 *************** *** 299,321 **** au QuickfixCmdPost make call QfMakeConv() ============================================================================= 2. The error window *quickfix-window* *:cope* *:copen* *w:quickfix_title* :cope[n] [height] Open a window to show the current list of errors. When [height] is given, the window becomes that high ! (if there is room). Otherwise the window is made ten ! lines high. ! The window will contain a special buffer, with ! 'buftype' equal to "quickfix". Don't change this! If there already is a quickfix window, it will be made the current window. It is not possible to open a ! second quickfix window. The window will have the ! w:quickfix_title variable set which will indicate the ! command that produced the quickfix list. This can be ! used to compose a custom status line if the value of ! 'statusline' is adjusted properly. *:lop* *:lopen* :lop[en] [height] Open a window to show the location list for the --- 299,395 ---- 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 excecution stops. + 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. + A range can be used to select entries, e.g.: > + :10,$cdo cmd + < To skip entries 1 to 9. + + Note: While this command is executing, the Syntax + autocommand event is disabled by adding it to + 'eventignore'. This considerably speeds up editing + each buffer. + {not in Vi} {not available when compiled without the + |+listcmds| feature} + 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. + < Otherwise it works the same as `:cdo`. + {not in Vi} {not available when compiled without the + |+listcmds| feature} + + *: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. + < Only valid entries in the location list are used. + Otherwise it works the same as `:cdo`. + {not in Vi} {not available when compiled without the + |+listcmds| feature} + + *: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. + < Otherwise it works the same as `:ldo`. + {not in Vi} {not available when compiled without the + |+listcmds| feature} + ============================================================================= 2. The error window *quickfix-window* *:cope* *:copen* *w:quickfix_title* :cope[n] [height] Open a window to show the current list of errors. + When [height] is given, the window becomes that high ! (if there is room). When [height] is omitted the ! window is made ten lines high. ! If there already is a quickfix window, it will be made the current window. It is not possible to open a ! second quickfix window. If [height] is given the ! existing window will be resized to it. ! ! The window will contain a special buffer, with ! 'buftype' equal to "quickfix". Don't change this! ! The window will have the w:quickfix_title variable set ! which will indicate the command that produced the ! quickfix list. This can be used to compose a custom ! status line if the value of 'statusline' is adjusted ! properly. *:lop* *:lopen* :lop[en] [height] Open a window to show the location list for the *** ../vim-7.4.857/runtime/doc/tabpage.txt 2015-04-21 18:08:21.838719097 +0200 --- runtime/doc/tabpage.txt 2015-09-08 18:07:42.256948348 +0200 *************** *** 248,254 **** {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|. ============================================================================== 3. Other items *tab-page-other* --- 248,255 ---- {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|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo| ! and |:lfdo| ============================================================================== 3. Other items *tab-page-other* *** ../vim-7.4.857/runtime/doc/windows.txt 2015-07-21 15:03:00.691467213 +0200 --- runtime/doc/windows.txt 2015-09-08 18:07:42.256948348 +0200 *************** *** 715,721 **** {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|. *:bufdo* :[range]bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list or if --- 715,722 ---- {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|, |:bufdo|, |:cdo|, |:ldo|, ! |:cfdo| and |:lfdo| *:bufdo* :[range]bufdo[!] {cmd} Execute {cmd} in each buffer in the buffer list or if *************** *** 743,749 **** each buffer. {not in Vi} {not available when compiled without the |+listcmds| feature} ! Also see |:tabdo|, |:argdo| and |:windo|. Examples: > --- 744,751 ---- each buffer. {not in Vi} {not available when compiled without the |+listcmds| feature} ! Also see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|, ! |:cfdo| and |:lfdo| Examples: > *** ../vim-7.4.857/src/ex_cmds.h 2015-07-21 15:03:00.691467213 +0200 --- src/ex_cmds.h 2015-09-08 18:20:51.228782439 +0200 *************** *** 65,70 **** --- 65,71 ---- #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,275 **** --- 271,279 ---- 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,284 **** --- 283,291 ---- 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,734 **** --- 736,744 ---- 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,749 **** --- 754,762 ---- 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), *** ../vim-7.4.857/src/ex_cmds2.c 2015-08-11 19:13:55.134175736 +0200 --- src/ex_cmds2.c 2015-09-08 18:24:57.594233149 +0200 *************** *** 2429,2435 **** } /* ! * ":argdo", ":windo", ":bufdo", ":tabdo" */ void ex_listdo(eap) --- 2429,2435 ---- } /* ! * ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" */ void ex_listdo(eap) *************** *** 2446,2451 **** --- 2446,2455 ---- 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,2515 **** } /* 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 || !buf->b_p_bl); buf = buf->b_next) if (buf->b_fnum > eap->line2) { buf = NULL; break; } ! if (buf != NULL) goto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum); ! } else setpcmark(); listcmd_busy = TRUE; /* avoids setting pcmark below */ --- 2502,2538 ---- } /* 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 || !buf->b_p_bl); buf = buf->b_next) if (buf->b_fnum > eap->line2) { buf = NULL; break; } ! 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,2605 **** set_option_value((char_u *)"shm", 0L, p_shm_save, 0); vim_free(p_shm_save); ! /* If autocommands took us elsewhere, quit here */ if (curbuf->b_fnum != next_fnum) break; } if (eap->cmdidx == CMD_windo) { validate_cursor(); /* cursor may have moved */ --- 2618,2645 ---- set_option_value((char_u *)"shm", 0L, p_shm_save, 0); vim_free(p_shm_save); ! /* 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 */ *** ../vim-7.4.857/src/ex_docmd.c 2015-08-11 18:52:58.073121563 +0200 --- src/ex_docmd.c 2015-09-08 18:07:42.260948306 +0200 *************** *** 135,141 **** #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 void get_flags __ARGS((exarg_T *eap)); #if !defined(FEAT_PERL) \ || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \ --- 135,141 ---- #endif static int check_more __ARGS((int, int)); ! 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,2181 **** lnum = CURRENT_TAB_NR; ea.line2 = lnum; break; } ea.cmd = skipwhite(ea.cmd); ! lnum = get_address(&ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; if (lnum == MAXLNUM) --- 2173,2184 ---- 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, &ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; if (lnum == MAXLNUM) *************** *** 2233,2238 **** --- 2236,2247 ---- 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,2698 **** --- 2702,2712 ---- else ea.line2 = ARGCOUNT; break; + case ADDR_QUICKFIX: + ea.line2 = qf_get_size(&ea); + if (ea.line2 == 0) + ea.line2 = 1; + break; } } *************** *** 3839,3844 **** --- 3853,3860 ---- 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,3854 **** --- 3864,3872 ---- 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,4327 **** * Return MAXLNUM when no Ex address was found. */ static linenr_T ! get_address(ptr, addr_type, skip, to_other_file) char_u **ptr; int addr_type; /* flag: one of ADDR_LINES, ... */ int skip; /* only skip the address, don't use it */ --- 4339,4346 ---- * Return MAXLNUM when no Ex address was found. */ static linenr_T ! 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,4367 **** --- 4381,4389 ---- case ADDR_TABS: lnum = CURRENT_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_cur_valid_idx(eap); + break; } break; *************** *** 4394,4399 **** --- 4416,4426 ---- case ADDR_TABS: lnum = LAST_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_size(eap); + if (lnum == 0) + lnum = 1; + break; } break; *************** *** 4569,4574 **** --- 4596,4604 ---- case ADDR_TABS: lnum = CURRENT_TAB_NR; break; + case ADDR_QUICKFIX: + lnum = qf_get_cur_valid_idx(eap); + break; } } *************** *** 4707,4712 **** --- 4737,4746 ---- 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,5822 **** --- 5851,5857 ---- {ADDR_TABS, "tabs"}, {ADDR_BUFFERS, "buffers"}, {ADDR_WINDOWS, "windows"}, + {ADDR_QUICKFIX, "quickfix"}, {-1, NULL} }; #endif *************** *** 9224,9230 **** { long n; ! n = get_address(&eap->arg, eap->addr_type, FALSE, FALSE); if (eap->arg == NULL) /* error detected */ { eap->nextcmd = NULL; --- 9259,9265 ---- { long n; ! n = get_address(eap, &eap->arg, eap->addr_type, FALSE, FALSE); if (eap->arg == NULL) /* error detected */ { eap->nextcmd = NULL; *** ../vim-7.4.857/src/proto/quickfix.pro 2013-08-10 13:37:24.000000000 +0200 --- src/proto/quickfix.pro 2015-09-08 18:29:04.723675697 +0200 *************** *** 17,22 **** --- 17,25 ---- 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)); *** ../vim-7.4.857/src/quickfix.c 2015-06-19 18:35:29.683602295 +0200 --- src/quickfix.c 2015-09-08 18:30:09.711003127 +0200 *************** *** 1373,1379 **** /* * 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 * Cleans up intermediate directory entries. * * TODO: How to solve the following problem? --- 1373,1379 ---- /* * 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. * Cleans up intermediate directory entries. * * TODO: How to solve the following problem? *************** *** 2990,3008 **** } /* * ":cc", ":crewind", ":cfirst" and ":clast". * ":ll", ":lrewind", ":lfirst" and ":llast". */ void ex_cc(eap) exarg_T *eap; { qf_info_T *qi = &ql_info; if (eap->cmdidx == CMD_ll || eap->cmdidx == CMD_lrewind || eap->cmdidx == CMD_lfirst ! || eap->cmdidx == CMD_llast) { qi = GET_LOC_LIST(curwin); if (qi == NULL) --- 2990,3172 ---- } /* + * 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_ldo ! || eap->cmdidx == CMD_lfdo) { qi = GET_LOC_LIST(curwin); if (qi == NULL) *************** *** 3012,3045 **** } } ! 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); } /* * ":cnext", ":cnfile", ":cNext" and ":cprevious". * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". */ void ex_cnext(eap) exarg_T *eap; { qf_info_T *qi = &ql_info; 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) { qi = GET_LOC_LIST(curwin); if (qi == NULL) --- 3176,3226 ---- } } ! 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_ldo ! || eap->cmdidx == CMD_lfdo) { qi = GET_LOC_LIST(curwin); if (qi == NULL) *************** *** 3049,3063 **** } } ! qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext) ? FORWARD ! : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile) ? 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); } /* --- 3230,3253 ---- } } ! 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_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, ! errornr, eap->forceit); } /* *** ../vim-7.4.857/src/testdir/Make_amiga.mak 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Make_amiga.mak 2015-09-08 18:33:40.696822313 +0200 *************** *** 41,46 **** --- 41,47 ---- 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,200 **** --- 196,202 ---- 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 *** ../vim-7.4.857/src/testdir/Make_dos.mak 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Make_dos.mak 2015-09-08 18:33:24.828984002 +0200 *************** *** 40,45 **** --- 40,46 ---- test_autocmd_option.out \ test_autoformat_join.out \ test_breakindent.out \ + test_cdo.out \ test_changelist.out \ test_charsearch.out \ test_close_count.out \ *** ../vim-7.4.857/src/testdir/Make_ming.mak 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Make_ming.mak 2015-09-08 18:33:54.412682545 +0200 *************** *** 62,67 **** --- 62,68 ---- test_autocmd_option.out \ test_autoformat_join.out \ test_breakindent.out \ + test_cdo.out \ test_changelist.out \ test_charsearch.out \ test_close_count.out \ *** ../vim-7.4.857/src/testdir/Make_os2.mak 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Make_os2.mak 2015-09-08 18:34:06.004564414 +0200 *************** *** 42,47 **** --- 42,48 ---- test_autocmd_option.out \ test_autoformat_join.out \ test_breakindent.out \ + test_cdo.out \ test_changelist.out \ test_charsearch.out \ test_close_count.out \ *** ../vim-7.4.857/src/testdir/Make_vms.mms 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Make_vms.mms 2015-09-08 18:34:18.448437596 +0200 *************** *** 4,10 **** # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # ! # Last change: 2015 Sep 01 # # 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. --- 4,10 ---- # Authors: Zoltan Arpadffy, # Sandor Kopanyi, # ! # 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,106 **** --- 101,107 ---- test_autocmd_option.out \ test_autoformat_join.out \ test_breakindent.out \ + test_cdo.out \ test_changelist.out \ test_charsearch.out \ test_close_count.out \ *** ../vim-7.4.857/src/testdir/Makefile 2015-09-01 16:04:26.706472322 +0200 --- src/testdir/Makefile 2015-09-08 18:34:35.048268412 +0200 *************** *** 38,43 **** --- 38,44 ---- test_autocmd_option.out \ test_autoformat_join.out \ test_breakindent.out \ + test_cdo.out \ test_changelist.out \ test_charsearch.out \ test_close_count.out \ *** ../vim-7.4.857/src/testdir/test_cdo.in 2015-09-08 18:42:16.203563949 +0200 --- src/testdir/test_cdo.in 2015-09-08 18:07:42.260948306 +0200 *************** *** 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 + *** ../vim-7.4.857/src/testdir/test_cdo.ok 2015-09-08 18:42:16.207563908 +0200 --- src/testdir/test_cdo.ok 2015-09-08 18:07:42.260948306 +0200 *************** *** 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 + *** ../vim-7.4.857/src/version.c 2015-09-08 17:50:38.071546587 +0200 --- src/version.c 2015-09-08 18:07:17.353206130 +0200 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 858, /**/ -- Why I like vim: > I like VIM because, when I ask a question in this newsgroup, I get a > one-line answer. With xemacs, I get a 1Kb lisp script with bugs in it ;-) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///