{"action":"created","issue":{"url":"https://api.github.com/repos/neovim/neovim/issues/2927","labels_url":"https://api.github.com/repos/neovim/neovim/issues/2927/labels{/name}","comments_url":"https://api.github.com/repos/neovim/neovim/issues/2927/comments","events_url":"https://api.github.com/repos/neovim/neovim/issues/2927/events","html_url":"https://github.com/neovim/neovim/pull/2927","id":91860789,"number":2927,"title":"[RFC] vim-patch:7.4.858","user":{"login":"fwalch","id":339435,"avatar_url":"https://avatars.githubusercontent.com/u/339435?v=3","gravatar_id":"","url":"https://api.github.com/users/fwalch","html_url":"https://github.com/fwalch","followers_url":"https://api.github.com/users/fwalch/followers","following_url":"https://api.github.com/users/fwalch/following{/other_user}","gists_url":"https://api.github.com/users/fwalch/gists{/gist_id}","starred_url":"https://api.github.com/users/fwalch/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/fwalch/subscriptions","organizations_url":"https://api.github.com/users/fwalch/orgs","repos_url":"https://api.github.com/users/fwalch/repos","events_url":"https://api.github.com/users/fwalch/events{/privacy}","received_events_url":"https://api.github.com/users/fwalch/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/neovim/neovim/labels/enhancement","name":"enhancement","color":"bfe5bf"},{"url":"https://api.github.com/repos/neovim/neovim/labels/RFC","name":"RFC","color":"dfdfdf"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":18,"created_at":"2015-06-29T17:19:10Z","updated_at":"2015-12-07T07:46:33Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/neovim/neovim/pulls/2927","html_url":"https://github.com/neovim/neovim/pull/2927","diff_url":"https://github.com/neovim/neovim/pull/2927.diff","patch_url":"https://github.com/neovim/neovim/pull/2927.patch"},"body":"Port of the \":cdo patch\" from https://groups.google.com/forum/#!topic/vim_dev/dfyt-G6SMec.\r\n\r\nAdds `:cdo` and `:ldo` commands that behave like `:argdo` and `:bufdo`, but on quickfix/location list.\r\n\r\nHeard about this from @nelstrom on Twitter earlier today. I think these commands make a lot of sense, so I gave porting the patch to Neovim a shot. I also ported the original tests to a Lua spec.\r\n\r\nOn top of #2926, as that modifies some of the same code parts.\r\n\r\nOriginal patch (excluding Makefile/.proto changes):\r\n\r\n```diff\r\ndiff --git a/runtime/doc/cmdline.txt b/runtime/doc/cmdline.txt\r\n--- a/runtime/doc/cmdline.txt\r\n+++ b/runtime/doc/cmdline.txt\r\n@@ -511,6 +511,8 @@ followed by another Vim command:\r\n     :argdo\r\n     :autocmd\r\n     :bufdo\r\n+    :cdo\r\n+    :cfdo\r\n     :command\r\n     :cscope\r\n     :debug\r\n@@ -521,6 +523,8 @@ followed by another Vim command:\r\n     :help\r\n     :helpfind\r\n     :lcscope\r\n+    :ldo\r\n+    :lfdo\r\n     :make\r\n     :normal\r\n     :perl\r\ndiff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt\r\n--- a/runtime/doc/editing.txt\r\n+++ b/runtime/doc/editing.txt\r\n@@ -855,7 +855,8 @@ USING THE ARGUMENT LIST\r\n \t\t\teach file.\r\n \t\t\t{not in Vi} {not available when compiled without the\r\n \t\t\t|+listcmds| feature}\r\n-\t\t\tAlso see |:windo|, |:tabdo| and |:bufdo|.\r\n+\t\t\tAlso see |:windo|, |:tabdo|, |:bufdo|, |:cdo|, |:ldo|,\r\n+\t\t\t|:cfdo| and |:lfdo|\r\n \r\n Example: >\r\n \t:args *.c\r\ndiff --git a/runtime/doc/index.txt b/runtime/doc/index.txt\r\n--- a/runtime/doc/index.txt\r\n+++ b/runtime/doc/index.txt\r\n@@ -1138,6 +1138,8 @@ tag\t      command\t      action ~\r\n |:cc|\t\t:cc\t\tgo to specific error\r\n |:cclose|\t:ccl[ose]\tclose quickfix window\r\n |:cd|\t\t:cd\t\tchange directory\r\n+|:cdo|\t\t:cdo\t\texecute command in each valid error list entry\r\n+|:cfdo|\t\t:cfdo\t\texecute command in each file in error list\r\n |:center|\t:ce[nter]\tformat lines at the center\r\n |:cexpr|\t:cex[pr]\tread errors from expr and jump to first\r\n |:cfile|\t:cf[ile]\tread file with error messages and jump to first\r\n@@ -1296,6 +1298,8 @@ tag\t      command\t      action ~\r\n |:lchdir|\t:lch[dir]\tchange directory locally\r\n |:lclose|\t:lcl[ose]\tclose location window\r\n |:lcscope|\t:lcs[cope]      like \":cscope\" but uses location list\r\n+|:ldo|\t\t:ld[o]\t\texecute command in valid location list entries\r\n+|:lfdo|\t\t:lfd[o]\t\texecute command in each file in location list\r\n |:left|\t\t:le[ft]\t\tleft align lines\r\n |:leftabove|\t:lefta[bove]\tmake split window appear left or above\r\n |:let|\t\t:let\t\tassign a value to a variable or option\r\ndiff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt\r\n--- a/runtime/doc/quickfix.txt\r\n+++ b/runtime/doc/quickfix.txt\r\n@@ -298,6 +298,108 @@ use this code: >\r\n \r\n \tau QuickfixCmdPost make call QfMakeConv()\r\n \r\n+EXECUTE A COMMAND IN ALL THE BUFFERS IN QUICKFIX OR LOCATION LIST:\r\n+\t\t\t\t\t\t\t*:cdo*\r\n+:cdo[!] {cmd}\t\tExecute {cmd} in each valid entry in the quickfix list.\r\n+\t\t\tIt works like doing this: >\r\n+\t\t\t\t:cfirst\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\t:cnext\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\tetc.\r\n+<\t\t\tWhen the current file can't be |abandon|ed and the [!]\r\n+\t\t\tis not present, the command fails.\r\n+\t\t\tWhen an error is detected on one buffer, further\r\n+\t\t\tbuffers will not be visited.\r\n+\t\t\tThe last buffer (or where an error occurred) becomes\r\n+\t\t\tthe current buffer.\r\n+\t\t\t{cmd} can contain '|' to concatenate several commands.\r\n+\t\t\tOnly valid entries in the quickfix list are used.\r\n+\t\t\tNote: While this command is executing, the Syntax\r\n+\t\t\tautocommand event is disabled by adding it to\r\n+\t\t\t'eventignore'.  This considerably speeds up editing\r\n+\t\t\teach buffer.\r\n+\t\t\t{not in Vi} {not available when compiled without the\r\n+\t\t\t|+listcmds| feature}\r\n+\t\t\tAlso see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,\r\n+\t\t\t|:ldo|, |:cfdo| and |:lfdo|.\r\n+\r\n+\t\t\t\t\t\t\t*:cfdo*\r\n+:cfdo[!] {cmd}\t\tExecute {cmd} in each file in the quickfix list.\r\n+\t\t\tIt works like doing this: >\r\n+\t\t\t\t:cfirst\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\t:cnfile\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\tetc.\r\n+<\t\t\tWhen the current file can't be |abandon|ed and the [!]\r\n+\t\t\tis not present, the command fails.\r\n+\t\t\tWhen an error is detected on one buffer, further\r\n+\t\t\tbuffers will not be visited.\r\n+\t\t\tThe last buffer (or where an error occurred) becomes\r\n+\t\t\tthe current buffer.\r\n+\t\t\t{cmd} can contain '|' to concatenate several commands.\r\n+\t\t\tOnly valid entries in the quickfix list are used.\r\n+\t\t\tNote: While this command is executing, the Syntax\r\n+\t\t\tautocommand event is disabled by adding it to\r\n+\t\t\t'eventignore'.  This considerably speeds up editing\r\n+\t\t\teach buffer.\r\n+\t\t\t{not in Vi} {not available when compiled without the\r\n+\t\t\t|+listcmds| feature}\r\n+\t\t\tAlso see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,\r\n+\t\t\t|:cdo|, |:ldo| and |:lfdo|.\r\n+\r\n+\t\t\t\t\t\t\t*:ldo*\r\n+:ld[o][!] {cmd}\t\tExecute {cmd} in each entry in the location list for\r\n+\t\t\tthe current window.\r\n+\t\t\tIt works like doing this: >\r\n+\t\t\t\t:lfirst\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\t:lnext\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\tetc.\r\n+<\t\t\tWhen the current file can't be |abandon|ed and the [!]\r\n+\t\t\tis not present, the command fails.\r\n+\t\t\tWhen an error is detected on one buffer, further\r\n+\t\t\tbuffers will not be visited.\r\n+\t\t\tThe last buffer (or where an error occurred) becomes\r\n+\t\t\tthe current buffer.\r\n+\t\t\t{cmd} can contain '|' to concatenate several commands.\r\n+\t\t\tOnly valid entries in the location list are used.\r\n+\t\t\tNote: While this command is executing, the Syntax\r\n+\t\t\tautocommand event is disabled by adding it to\r\n+\t\t\t'eventignore'.  This considerably speeds up editing\r\n+\t\t\teach buffer.\r\n+\t\t\t{not in Vi} {not available when compiled without the\r\n+\t\t\t|+listcmds| feature}\r\n+\t\t\tAlso see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,\r\n+\t\t\t|:cdo|, |:cfdo| and |:lfdo|.\r\n+\r\n+\t\t\t\t\t\t\t*:lfdo*\r\n+:lfdo[!] {cmd}\t\tExecute {cmd} in each file in the location list for\r\n+\t\t\tthe current window.\r\n+\t\t\tIt works like doing this: >\r\n+\t\t\t\t:lfirst\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\t:lnfile\r\n+\t\t\t\t:{cmd}\r\n+\t\t\t\tetc.\r\n+<\t\t\tWhen the current file can't be |abandon|ed and the [!]\r\n+\t\t\tis not present, the command fails.\r\n+\t\t\tWhen an error is detected on one buffer, further\r\n+\t\t\tbuffers will not be visited.\r\n+\t\t\tThe last buffer (or where an error occurred) becomes\r\n+\t\t\tthe current buffer.\r\n+\t\t\t{cmd} can contain '|' to concatenate several commands.\r\n+\t\t\tOnly valid entries in the location list are used.\r\n+\t\t\tNote: While this command is executing, the Syntax\r\n+\t\t\tautocommand event is disabled by adding it to\r\n+\t\t\t'eventignore'.  This considerably speeds up editing\r\n+\t\t\teach buffer.\r\n+\t\t\t{not in Vi} {not available when compiled without the\r\n+\t\t\t|+listcmds| feature}\r\n+\t\t\tAlso see |:bufdo|, |:tabdo|, |:argdo|, |:windo|,\r\n+\t\t\t|:cdo|, |:ldo| and |:cfdo|.\r\n \r\n =============================================================================\r\n 2. The error window\t\t\t\t\t*quickfix-window*\r\ndiff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt\r\n--- a/runtime/doc/tabpage.txt\r\n+++ b/runtime/doc/tabpage.txt\r\n@@ -248,7 +248,8 @@ LOOPING OVER TAB PAGES:\r\n \t\t{cmd} must not open or close tab pages or reorder them.\r\n \t\t{not in Vi} {not available when compiled without the\r\n \t\t|+listcmds| feature}\r\n-\t\tAlso see |:windo|, |:argdo| and |:bufdo|.\r\n+\t\tAlso see |:windo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|, |:cfdo|\r\n+\t\tand |:lfdo|\r\n \r\n ==============================================================================\r\n 3. Other items\t\t\t\t\t\t*tab-page-other*\r\ndiff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt\r\n--- a/runtime/doc/windows.txt\r\n+++ b/runtime/doc/windows.txt\r\n@@ -715,7 +715,8 @@ 8. Do a command in all buffers or window\r\n \t\t\t{cmd} must not open or close windows or reorder them.\r\n \t\t\t{not in Vi} {not available when compiled without the\r\n \t\t\t|+listcmds| feature}\r\n-\t\t\tAlso see |:tabdo|, |:argdo| and |:bufdo|.\r\n+\t\t\tAlso see |:tabdo|, |:argdo|, |:bufdo|, |:cdo|, |:ldo|,\r\n+\t\t\t|:cfdo| and |:lfdo|\r\n \r\n \t\t\t\t\t\t\t*:bufdo*\r\n :[range]bufdo[!] {cmd}\tExecute {cmd} in each buffer in the buffer list or if\r\n@@ -743,7 +744,8 @@ 8. Do a command in all buffers or window\r\n \t\t\teach buffer.\r\n \t\t\t{not in Vi} {not available when compiled without the\r\n \t\t\t|+listcmds| feature}\r\n-\t\t\tAlso see |:tabdo|, |:argdo| and |:windo|.\r\n+\t\t\tAlso see |:tabdo|, |:argdo|, |:windo|, |:cdo|, |:ldo|,\r\n+\t\t\t|:cfdo| and |:lfdo|\r\n \r\n Examples: >\r\n \r\ndiff --git a/src/ex_cmds.h b/src/ex_cmds.h\r\n--- a/src/ex_cmds.h\r\n+++ b/src/ex_cmds.h\r\n@@ -270,12 +270,18 @@ EX(CMD_cclose,\t\t\"cclose\",\tex_cclose,\r\n EX(CMD_cd,\t\t\"cd\",\t\tex_cd,\r\n \t\t\tBANG|FILE1|TRLBAR|CMDWIN,\r\n \t\t\tADDR_LINES),\r\n+EX(CMD_cdo,\t\t\"cdo\",\t\tex_listdo,\r\n+\t\t\tBANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,\r\n+\t\t\tADDR_LINES),\r\n EX(CMD_center,\t\t\"center\",\tex_align,\r\n \t\t\tTRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,\r\n \t\t\tADDR_LINES),\r\n EX(CMD_cexpr,\t\t\"cexpr\",\tex_cexpr,\r\n \t\t\tNEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG,\r\n \t\t\tADDR_LINES),\r\n+EX(CMD_cfdo,\t\t\"cfdo\",\t\tex_listdo,\r\n+\t\t\tBANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,\r\n+\t\t\tADDR_LINES),\r\n EX(CMD_cfile,\t\t\"cfile\",\tex_cfile,\r\n \t\t\tTRLBAR|FILE1|BANG,\r\n \t\t\tADDR_LINES),\r\n@@ -729,6 +735,9 @@ EX(CMD_lclose,\t\t\"lclose\",\tex_cclose,\r\n EX(CMD_lcscope,\t\t\"lcscope\",\tdo_cscope,\r\n \t\t\tEXTRA|NOTRLCOM|XFILE,\r\n \t\t\tADDR_LINES),\r\n+EX(CMD_ldo,\t\t\"ldo\",\t\tex_listdo,\r\n+\t\t\tBANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,\r\n+\t\t\tADDR_LINES),\r\n EX(CMD_left,\t\t\"left\",\t\tex_align,\r\n \t\t\tTRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,\r\n \t\t\tADDR_LINES),\r\n@@ -741,6 +750,9 @@ EX(CMD_let,\t\t\"let\",\t\tex_let,\r\n EX(CMD_lexpr,\t\t\"lexpr\",\tex_cexpr,\r\n \t\t\tNEEDARG|WORD1|NOTRLCOM|TRLBAR|BANG,\r\n \t\t\tADDR_LINES),\r\n+EX(CMD_lfdo,\t\t\"lfdo\",\t\tex_listdo,\r\n+\t\t\tBANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,\r\n+\t\t\tADDR_LINES),\r\n EX(CMD_lfile,\t\t\"lfile\",\tex_cfile,\r\n \t\t\tTRLBAR|FILE1|BANG,\r\n \t\t\tADDR_LINES),\r\ndiff --git a/src/ex_cmds2.c b/src/ex_cmds2.c\r\n--- a/src/ex_cmds2.c\r\n+++ b/src/ex_cmds2.c\r\n@@ -2429,7 +2429,7 @@ ex_argdelete(eap)\r\n }\r\n \r\n /*\r\n- * \":argdo\", \":windo\", \":bufdo\", \":tabdo\"\r\n+ * \":argdo\", \":windo\", \":bufdo\", \":tabdo\", \":cdo\", \":ldo\", \":cfdo\" and \":lfdo\"\r\n  */\r\n     void\r\n ex_listdo(eap)\r\n@@ -2446,6 +2446,9 @@ ex_listdo(eap)\r\n     char_u\t*save_ei = NULL;\r\n #endif\r\n     char_u\t*p_shm_save;\r\n+#ifdef FEAT_QUICKFIX\r\n+    int\t\tqf_size;\r\n+#endif\r\n \r\n #ifndef FEAT_WINDOWS\r\n     if (eap->cmdidx == CMD_windo)\r\n@@ -2510,6 +2513,24 @@ ex_listdo(eap)\r\n             if (buf != NULL)\r\n \t\tgoto_buffer(eap, DOBUF_FIRST, FORWARD, buf->b_fnum);\r\n         }\r\n+#ifdef FEAT_QUICKFIX\r\n+\telse if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||\r\n+\t\teap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)\r\n+\t{\r\n+\t    qf_size = qf_get_size(eap);\r\n+\t    if (qf_size <= 0 || eap->line1 > qf_size)\r\n+\t\tbuf = NULL;\r\n+\t    else\r\n+\t    {\r\n+\t\tex_cc(eap);\r\n+\r\n+\t\tbuf = curbuf;\r\n+\t\ti = eap->line1 - 1;\r\n+\t\tif (eap->addr_count <= 0)\r\n+\t\t    eap->line2 = qf_size;   /* default is all the quickfix/location list entries */\r\n+\t    }\r\n+\t}\r\n+#endif\r\n \telse\r\n \t    setpcmark();\r\n \tlistcmd_busy = TRUE;\t    /* avoids setting pcmark below */\r\n@@ -2600,6 +2621,17 @@ ex_listdo(eap)\r\n \t\t    break;\r\n \t    }\r\n \r\n+#ifdef FEAT_QUICKFIX\r\n+\t    if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||\r\n+\t\t    eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)\r\n+\t    {\r\n+\t\tif (i >= qf_size || i >= eap->line2)\r\n+\t\t    break;\r\n+\r\n+\t\tex_cnext(eap);\r\n+\t    }\r\n+#endif\r\n+\r\n \t    if (eap->cmdidx == CMD_windo)\r\n \t    {\r\n \t\tvalidate_cursor();\t/* cursor may have moved */\r\ndiff --git a/src/ex_docmd.c b/src/ex_docmd.c\r\n--- a/src/ex_docmd.c\r\n+++ b/src/ex_docmd.c\r\n@@ -3838,6 +3838,8 @@ set_one_cmd_context(xp, buff)\r\n \tcase CMD_botright:\r\n \tcase CMD_browse:\r\n \tcase CMD_bufdo:\r\n+\tcase CMD_cdo:\r\n+\tcase CMD_cfdo:\r\n \tcase CMD_confirm:\r\n \tcase CMD_debug:\r\n \tcase CMD_folddoclosed:\r\n@@ -3847,7 +3849,9 @@ set_one_cmd_context(xp, buff)\r\n \tcase CMD_keepjumps:\r\n \tcase CMD_keepmarks:\r\n \tcase CMD_keeppatterns:\r\n+\tcase CMD_ldo:\r\n \tcase CMD_leftabove:\r\n+\tcase CMD_lfdo:\r\n \tcase CMD_lockmarks:\r\n \tcase CMD_noautocmd:\r\n \tcase CMD_noswapfile:\r\ndiff --git a/src/quickfix.c b/src/quickfix.c\r\n--- a/src/quickfix.c\r\n+++ b/src/quickfix.c\r\n@@ -2990,19 +2990,108 @@ get_mef_name()\r\n }\r\n \r\n /*\r\n+ * Returns the number of valid entries in the current quickfix/location list\r\n+ */\r\n+    int\r\n+qf_get_size(eap)\r\n+    exarg_T\t*eap;\r\n+{\r\n+    qf_info_T\t*qi = &ql_info;\r\n+    qfline_T\t*qfp;\r\n+    int\t\ti, sz = 0;\r\n+    int\t\tprev_fnum = 0;\r\n+\r\n+    if (eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo)\r\n+    {\r\n+\t/* Location list */\r\n+\tqi = GET_LOC_LIST(curwin);\r\n+\tif (qi == NULL)\r\n+\t    return 0;\r\n+    }\r\n+\r\n+    for (i = 0, qfp = qi->qf_lists[qi->qf_curlist].qf_start;\r\n+\t    (i < qi->qf_lists[qi->qf_curlist].qf_count) && (qfp != NULL);\r\n+\t    ++i, qfp = qfp->qf_next)\r\n+    {\r\n+\t    if (qfp->qf_valid)\r\n+\t\tif (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)\r\n+\t\t    sz++;\t/* Count all valid entries */\r\n+\t\telse if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)\r\n+\t\t{\r\n+\t\t    /* Count the number of files */\r\n+\t\t    sz++;\r\n+\t\t    prev_fnum = qfp->qf_fnum;\r\n+\t\t}\r\n+    }\r\n+\r\n+    return sz;\r\n+}\r\n+\r\n+/*\r\n+ * Get the 'n'th valid error entry in the quickfix or location list.\r\n+ * Used by :cdo, :ldo, :cfdo and :lfdo commands.\r\n+ * For :cdo and :ldo returns the 'n'th valid error entry.\r\n+ * For :cfdo and :lfdo returns the 'n'th valid file entry.\r\n+ */\r\n+    static int\r\n+qf_get_nth_valid_entry(qi, n, fdo)\r\n+    qf_info_T\t*qi;\r\n+    int\t\tn;\r\n+    int\t\tfdo;\r\n+{\r\n+    qf_list_T\t*qfl = &qi->qf_lists[qi->qf_curlist];\r\n+    qfline_T\t*qfp = qfl->qf_start;\r\n+    int\t\ti, eidx;\r\n+    int\t\tprev_fnum = 0;\r\n+\r\n+    /* check if the list has valid errors */\r\n+    if (qfl->qf_count <= 0 || qfl->qf_nonevalid)\r\n+\treturn 1;\r\n+\r\n+    for (i = 1, eidx = 0; i <= qfl->qf_count && qfp!= NULL;\r\n+\t    i++, qfp = qfp->qf_next)\r\n+    {\r\n+\tif (qfp->qf_valid)\r\n+\t    if (fdo)\r\n+\t    {\r\n+\t\tif (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)\r\n+\t\t{\r\n+\t\t    /* Count the number of files */\r\n+\t\t    eidx++;\r\n+\t\t    prev_fnum = qfp->qf_fnum;\r\n+\t\t}\r\n+\t    }\r\n+\t    else\r\n+\t\teidx++;\r\n+\r\n+\tif (eidx == n)\r\n+\t    break;\r\n+    }\r\n+\r\n+    if (i <= qfl->qf_count)\r\n+\treturn i;\r\n+    else\r\n+\treturn 1;\r\n+}\r\n+\r\n+/*\r\n  * \":cc\", \":crewind\", \":cfirst\" and \":clast\".\r\n  * \":ll\", \":lrewind\", \":lfirst\" and \":llast\".\r\n+ * \":cdo\", \":ldo\", \":cfdo\" and \":lfdo\"\r\n  */\r\n     void\r\n ex_cc(eap)\r\n     exarg_T\t*eap;\r\n {\r\n     qf_info_T\t*qi = &ql_info;\r\n+    int\t\terrornr;\r\n \r\n     if (eap->cmdidx == CMD_ll\r\n \t    || eap->cmdidx == CMD_lrewind\r\n \t    || eap->cmdidx == CMD_lfirst\r\n-\t    || eap->cmdidx == CMD_llast)\r\n+\t    || eap->cmdidx == CMD_llast\r\n+\t    || eap->cmdidx == CMD_ldo\r\n+\t    || eap->cmdidx == CMD_lfdo)\r\n     {\r\n \tqi = GET_LOC_LIST(curwin);\r\n \tif (qi == NULL)\r\n@@ -3012,34 +3101,51 @@ ex_cc(eap)\r\n \t}\r\n     }\r\n \r\n-    qf_jump(qi, 0,\r\n-\t    eap->addr_count > 0\r\n-\t    ? (int)eap->line2\r\n-\t    : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)\r\n-\t\t? 0\r\n-\t\t: (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind\r\n-\t\t   || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)\r\n-\t\t    ? 1\r\n-\t\t    : 32767,\r\n-\t    eap->forceit);\r\n+    if (eap->addr_count > 0)\r\n+\terrornr = (int)eap->line2;\r\n+    else\r\n+    {\r\n+\tif (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll)\r\n+\t    errornr = 0;\r\n+\telse if (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind\r\n+\t\t|| eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst)\r\n+\t    errornr = 1;\r\n+\telse\r\n+\t    errornr = 32767;\r\n+    }\r\n+\r\n+    /* For cdo and ldo commands, jump to the nth valid error.\r\n+     * For cfdo and lfdo commands, jump to the nth valid file entry.\r\n+     */\r\n+    if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo ||\r\n+\t    eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)\r\n+\terrornr = qf_get_nth_valid_entry(qi,\r\n+\t\teap->addr_count > 0 ? (int)eap->line1 : 1,\r\n+\t\teap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);\r\n+\r\n+    qf_jump(qi, 0, errornr, eap->forceit);\r\n }\r\n \r\n /*\r\n  * \":cnext\", \":cnfile\", \":cNext\" and \":cprevious\".\r\n  * \":lnext\", \":lNext\", \":lprevious\", \":lnfile\", \":lNfile\" and \":lpfile\".\r\n+ * Also, used by \":cdo\", \":ldo\", \":cfdo\" and \":lfdo\" commands.\r\n  */\r\n     void\r\n ex_cnext(eap)\r\n     exarg_T\t*eap;\r\n {\r\n     qf_info_T\t*qi = &ql_info;\r\n+    int\t\terrornr;\r\n \r\n     if (eap->cmdidx == CMD_lnext\r\n \t    || eap->cmdidx == CMD_lNext\r\n \t    || eap->cmdidx == CMD_lprevious\r\n \t    || eap->cmdidx == CMD_lnfile\r\n \t    || eap->cmdidx == CMD_lNfile\r\n-\t    || eap->cmdidx == CMD_lpfile)\r\n+\t    || eap->cmdidx == CMD_lpfile\r\n+\t    || eap->cmdidx == CMD_ldo\r\n+\t    || eap->cmdidx == CMD_lfdo)\r\n     {\r\n \tqi = GET_LOC_LIST(curwin);\r\n \tif (qi == NULL)\r\n@@ -3049,15 +3155,24 @@ ex_cnext(eap)\r\n \t}\r\n     }\r\n \r\n-    qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext)\r\n+    if (eap->addr_count > 0 &&\r\n+\t    (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo &&\r\n+\t     eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo))\r\n+\terrornr = (int)eap->line2;\r\n+    else\r\n+\terrornr = 1;\r\n+\r\n+    qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext\r\n+\t\t|| eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)\r\n \t    ? FORWARD\r\n-\t    : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile)\r\n+\t    : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile\r\n+\t\t|| eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)\r\n \t\t? FORWARD_FILE\r\n \t\t: (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile\r\n \t\t   || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile)\r\n \t\t    ? BACKWARD_FILE\r\n \t\t    : BACKWARD,\r\n-\t    eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit);\r\n+\t    errornr, eap->forceit);\r\n }\r\n \r\n /*\r\n```"},"comment":{"url":"https://api.github.com/repos/neovim/neovim/issues/comments/162439263","html_url":"https://github.com/neovim/neovim/pull/2927#issuecomment-162439263","issue_url":"https://api.github.com/repos/neovim/neovim/issues/2927","id":162439263,"user":{"login":"justinmk","id":1359421,"avatar_url":"https://avatars.githubusercontent.com/u/1359421?v=3","gravatar_id":"","url":"https://api.github.com/users/justinmk","html_url":"https://github.com/justinmk","followers_url":"https://api.github.com/users/justinmk/followers","following_url":"https://api.github.com/users/justinmk/following{/other_user}","gists_url":"https://api.github.com/users/justinmk/gists{/gist_id}","starred_url":"https://api.github.com/users/justinmk/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/justinmk/subscriptions","organizations_url":"https://api.github.com/users/justinmk/orgs","repos_url":"https://api.github.com/users/justinmk/repos","events_url":"https://api.github.com/users/justinmk/events{/privacy}","received_events_url":"https://api.github.com/users/justinmk/received_events","type":"User","site_admin":false},"created_at":"2015-12-07T07:46:33Z","updated_at":"2015-12-07T07:46:33Z","body":"I found [another way](https://github.com/neovim/neovim/pull/2927#discussion_r46790505) to avoid the hang, but it yields the same wrong results:\r\n\r\n```\r\nxLine1\r\nLine2\r\nLine3\r\n```\r\n\r\nThings get more strange:\r\n\r\n- Adding a call like `print('g:result='..helpers.eval('g:result'))` again causes a hang\r\n- The final two calls in the test aren't running at all. \r\n\r\nI don't see anything suspicious in this PR, but if things were this unreliable on master I can't see how the other tests would be passing...\r\n\r\n\r\n"}}