To: vim_dev@googlegroups.com Subject: Patch 8.1.1256 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.1256 Problem: Cannot navigate through errors relative to the cursor. Solution: Add :cabove, :cbelow, :labove and :lbelow. (Yegappan Lakshmanan, closes #4316) Files: runtime/doc/index.txt, runtime/doc/quickfix.txt, src/ex_cmdidxs.h, src/ex_cmds.h, src/ex_docmd.c, src/proto/quickfix.pro, src/quickfix.c, src/testdir/test_quickfix.vim *** ../vim-8.1.1255/runtime/doc/index.txt 2019-04-27 20:36:52.526303597 +0200 --- runtime/doc/index.txt 2019-05-03 21:35:09.162087906 +0200 *************** *** 1140,1150 **** --- 1192,1204 ---- |:cNfile| :cNf[ile] go to last error in previous file |:cabbrev| :ca[bbrev] like ":abbreviate" but for Command-line mode |:cabclear| :cabc[lear] clear all abbreviations for Command-line mode + |:cabove| :cabo[ve] go to error above current line |:caddbuffer| :cad[dbuffer] add errors from buffer |:caddexpr| :cadde[xpr] add errors from expr |:caddfile| :caddf[ile] add error message to current quickfix list |:call| :cal[l] call a function |:catch| :cat[ch] part of a :try command + |:cbelow| :cbe[low] got to error below current line |:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window |:cbuffer| :cb[uffer] parse error messages and jump to first error |:cc| :cc go to specific error *************** *** 1302,1313 **** --- 1356,1369 ---- |:lNext| :lN[ext] go to previous entry in location list |:lNfile| :lNf[ile] go to last entry in previous file |:list| :l[ist] print lines + |:labove| :lab[ove] go to location above current line |:laddexpr| :lad[dexpr] add locations from expr |:laddbuffer| :laddb[uffer] add locations from buffer |:laddfile| :laddf[ile] add locations to current location list |:last| :la[st] go to the last file in the argument list |:language| :lan[guage] set the language (locale) |:later| :lat[er] go to newer change, redo + |:lbelow| :lbe[low] go to location below current line |:lbottom| :lbo[ttom] scroll to the bottom of the location window |:lbuffer| :lb[uffer] parse locations and jump to first location |:lcd| :lc[d] change directory locally --- 1703,1708 ---- *** ../vim-8.1.1255/runtime/doc/quickfix.txt 2019-03-17 16:39:01.566006172 +0100 --- runtime/doc/quickfix.txt 2019-05-03 21:35:09.166087887 +0200 *************** *** 123,128 **** --- 123,158 ---- list for the current window is used instead of the quickfix list. + *:cabo* *:cabove* + :[count]cabo[ve] Go to the [count] error above the current line in the + current buffer. If [count] is omitted, then 1 is + used. If there are no errors, then an error message + is displayed. Assumes that the entries in a quickfix + list are sorted by their buffer number and line + number. If there are multiple errors on the same line, + then only the first entry is used. If [count] exceeds + the number of entries above the current line, then the + first error in the file is selected. + + *:lab* *:labove* + :[count]lab[ove] Same as ":cabove", except the location list for the + current window is used instead of the quickfix list. + + *:cbe* *:cbelow* + :[count]cbe[low] Go to the [count] error below the current line in the + current buffer. If [count] is omitted, then 1 is + used. If there are no errors, then an error message + is displayed. Assumes that the entries in a quickfix + list are sorted by their buffer number and line + number. If there are multiple errors on the same + line, then only the first entry is used. If [count] + exceeds the number of entries below the current line, + then the last error in the file is selected. + + *:lbe* *:lbelow* + :[count]lbe[low] Same as ":cbelow", except the location list for the + current window is used instead of the quickfix list. + *:cnf* *:cnfile* :[count]cnf[ile][!] Display the first error in the [count] next file in the list that includes a file name. If there are no *** ../vim-8.1.1255/src/ex_cmdidxs.h 2019-04-27 20:36:52.530303581 +0200 --- src/ex_cmdidxs.h 2019-05-03 21:42:06.720008024 +0200 *************** *** 8,36 **** /* a */ 0, /* b */ 19, /* c */ 42, ! /* d */ 103, ! /* e */ 125, ! /* f */ 145, ! /* g */ 161, ! /* h */ 167, ! /* i */ 176, ! /* j */ 194, ! /* k */ 196, ! /* l */ 201, ! /* m */ 259, ! /* n */ 277, ! /* o */ 297, ! /* p */ 309, ! /* q */ 348, ! /* r */ 351, ! /* s */ 371, ! /* t */ 439, ! /* u */ 484, ! /* v */ 495, ! /* w */ 513, ! /* x */ 527, ! /* y */ 536, ! /* z */ 537 }; /* --- 8,36 ---- /* a */ 0, /* b */ 19, /* c */ 42, ! /* d */ 105, ! /* e */ 127, ! /* f */ 147, ! /* g */ 163, ! /* h */ 169, ! /* i */ 178, ! /* j */ 196, ! /* k */ 198, ! /* l */ 203, ! /* m */ 263, ! /* n */ 281, ! /* o */ 301, ! /* p */ 313, ! /* q */ 352, ! /* r */ 355, ! /* s */ 375, ! /* t */ 443, ! /* u */ 488, ! /* v */ 499, ! /* w */ 517, ! /* x */ 531, ! /* y */ 540, ! /* z */ 541 }; /* *************** *** 43,49 **** { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 }, ! /* c */ { 3, 10, 12, 14, 16, 18, 21, 0, 0, 0, 0, 29, 33, 36, 42, 51, 53, 54, 55, 0, 57, 0, 60, 0, 0, 0 }, /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 }, /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 }, --- 43,49 ---- { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ /* a */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0, 7, 15, 0, 16, 0, 0, 0, 0, 0 }, /* b */ { 2, 0, 0, 4, 5, 7, 0, 0, 0, 0, 0, 8, 9, 10, 11, 12, 0, 13, 0, 0, 0, 0, 22, 0, 0, 0 }, ! /* c */ { 3, 11, 14, 16, 18, 20, 23, 0, 0, 0, 0, 31, 35, 38, 44, 53, 55, 56, 57, 0, 59, 0, 62, 0, 0, 0 }, /* d */ { 0, 0, 0, 0, 0, 0, 0, 0, 6, 15, 0, 16, 0, 0, 17, 0, 0, 19, 20, 0, 0, 0, 0, 0, 0, 0 }, /* e */ { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 7, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0 }, /* f */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0 }, *************** *** 52,58 **** /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 13, 0, 15, 0, 0, 0, 0, 0 }, /* j */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* k */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ! /* l */ { 3, 9, 11, 15, 16, 20, 23, 28, 0, 0, 0, 30, 33, 36, 40, 46, 0, 48, 57, 49, 50, 54, 56, 0, 0, 0 }, /* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 }, /* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 }, /* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 }, --- 52,58 ---- /* i */ { 1, 0, 0, 0, 0, 3, 0, 0, 0, 4, 0, 5, 6, 0, 0, 0, 0, 0, 13, 0, 15, 0, 0, 0, 0, 0 }, /* j */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, /* k */ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, ! /* l */ { 3, 10, 13, 17, 18, 22, 25, 30, 0, 0, 0, 32, 35, 38, 42, 48, 0, 50, 59, 51, 52, 56, 58, 0, 0, 0 }, /* m */ { 1, 0, 0, 0, 7, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16 }, /* n */ { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 8, 10, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0 }, /* o */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 5, 0, 0, 0, 0, 0, 0, 9, 0, 11, 0, 0, 0 }, *************** *** 69,72 **** /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; ! static const int command_count = 550; --- 69,72 ---- /* z */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; ! static const int command_count = 554; *** ../vim-8.1.1255/src/ex_cmds.h 2019-05-01 18:08:38.263237252 +0200 --- src/ex_cmds.h 2019-05-03 21:43:59.707432410 +0200 *************** *** 252,257 **** --- 252,260 ---- EX(CMD_cabclear, "cabclear", ex_abclear, EXTRA|TRLBAR|CMDWIN, ADDR_NONE), + EX(CMD_cabove, "cabove", ex_cbelow, + RANGE|TRLBAR, + ADDR_OTHER), EX(CMD_caddbuffer, "caddbuffer", ex_cbuffer, RANGE|WORD1|TRLBAR, ADDR_OTHER), *************** *** 270,275 **** --- 273,281 ---- EX(CMD_cbuffer, "cbuffer", ex_cbuffer, BANG|RANGE|WORD1|TRLBAR, ADDR_OTHER), + EX(CMD_cbelow, "cbelow", ex_cbelow, + RANGE|TRLBAR, + ADDR_OTHER), EX(CMD_cbottom, "cbottom", ex_cbottom, TRLBAR, ADDR_NONE), *************** *** 726,731 **** --- 732,740 ---- EX(CMD_last, "last", ex_last, EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR, ADDR_NONE), + EX(CMD_labove, "labove", ex_cbelow, + RANGE|TRLBAR, + ADDR_OTHER), EX(CMD_language, "language", ex_language, EXTRA|TRLBAR|CMDWIN, ADDR_NONE), *************** *** 744,749 **** --- 753,761 ---- EX(CMD_lbuffer, "lbuffer", ex_cbuffer, BANG|RANGE|WORD1|TRLBAR, ADDR_OTHER), + EX(CMD_lbelow, "lbelow", ex_cbelow, + RANGE|TRLBAR, + ADDR_OTHER), EX(CMD_lbottom, "lbottom", ex_cbottom, TRLBAR, ADDR_NONE), *** ../vim-8.1.1255/src/ex_docmd.c 2019-05-01 21:43:39.076257243 +0200 --- src/ex_docmd.c 2019-05-03 21:35:09.166087887 +0200 *************** *** 56,61 **** --- 56,62 ---- # define ex_cbuffer ex_ni # define ex_cc ex_ni # define ex_cnext ex_ni + # define ex_cbelow ex_ni # define ex_cfile ex_ni # define qf_list ex_ni # define qf_age ex_ni *** ../vim-8.1.1255/src/proto/quickfix.pro 2019-02-05 21:23:00.600559169 +0100 --- src/proto/quickfix.pro 2019-05-03 21:35:09.166087887 +0200 *************** *** 23,28 **** --- 23,29 ---- int qf_get_cur_valid_idx(exarg_T *eap); void ex_cc(exarg_T *eap); void ex_cnext(exarg_T *eap); + void ex_cbelow(exarg_T *eap); void ex_cfile(exarg_T *eap); void ex_vimgrep(exarg_T *eap); int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list); *** ../vim-8.1.1255/src/quickfix.c 2019-05-02 20:17:29.318924421 +0200 --- src/quickfix.c 2019-05-03 21:35:09.166087887 +0200 *************** *** 177,182 **** --- 177,183 ---- static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start); static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start); static qf_info_T *ll_get_or_alloc_list(win_T *); + static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); // Quickfix window check helper macro #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) *************** *** 1494,1499 **** --- 1495,1510 ---- } /* + * Returns TRUE if the specified quickfix/location list is not empty and + * has valid entries. + */ + static int + qf_list_has_valid_entries(qf_list_T *qfl) + { + return !qf_list_empty(qfl) && !qfl->qf_nonevalid; + } + + /* * Return a pointer to a list in the specified quickfix stack */ static qf_list_T * *************** *** 2700,2706 **** int qf_idx = qfl->qf_index; qfline_T *prev_qf_ptr; int prev_index; - static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); char_u *err = e_no_more_items; while (errornr--) --- 2711,2716 ---- *************** *** 4886,4892 **** 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) --- 4896,4902 ---- qfp = qfl->qf_start; // check if the list has valid errors ! if (!qf_list_has_valid_entries(qfl)) return 1; for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next) *************** *** 4924,4930 **** int prev_fnum = 0; // check if the list has valid errors ! if (qfl->qf_count <= 0 || qfl->qf_nonevalid) return 1; eidx = 0; --- 4934,4940 ---- int prev_fnum = 0; // check if the list has valid errors ! if (!qf_list_has_valid_entries(qfl)) return 1; eidx = 0; *************** *** 5045,5050 **** --- 5055,5355 ---- } /* + * Find the first entry in the quickfix list 'qfl' from buffer 'bnr'. + * The index of the entry is stored in 'errornr'. + * Returns NULL if an entry is not found. + */ + static qfline_T * + qf_find_first_entry_in_buf(qf_list_T *qfl, int bnr, int *errornr) + { + qfline_T *qfp = NULL; + int idx = 0; + + // Find the first entry in this file + FOR_ALL_QFL_ITEMS(qfl, qfp, idx) + if (qfp->qf_fnum == bnr) + break; + + *errornr = idx; + return qfp; + } + + /* + * Find the first quickfix entry on the same line as 'entry'. Updates 'errornr' + * with the error number for the first entry. Assumes the entries are sorted in + * the quickfix list by line number. + */ + static qfline_T * + qf_find_first_entry_on_line(qfline_T *entry, int *errornr) + { + while (!got_int + && entry->qf_prev != NULL + && entry->qf_fnum == entry->qf_prev->qf_fnum + && entry->qf_lnum == entry->qf_prev->qf_lnum) + { + entry = entry->qf_prev; + --*errornr; + } + + return entry; + } + + /* + * Find the last quickfix entry on the same line as 'entry'. Updates 'errornr' + * with the error number for the last entry. Assumes the entries are sorted in + * the quickfix list by line number. + */ + static qfline_T * + qf_find_last_entry_on_line(qfline_T *entry, int *errornr) + { + while (!got_int && + entry->qf_next != NULL + && entry->qf_fnum == entry->qf_next->qf_fnum + && entry->qf_lnum == entry->qf_next->qf_lnum) + { + entry = entry->qf_next; + ++*errornr; + } + + return entry; + } + + /* + * Find the first quickfix entry below line 'lnum' in buffer 'bnr'. + * 'qfp' points to the very first entry in the buffer and 'errornr' is the + * index of the very first entry in the quickfix list. + * Returns NULL if an entry is not found after 'lnum'. + */ + static qfline_T * + qf_find_entry_on_next_line( + int bnr, + linenr_T lnum, + qfline_T *qfp, + int *errornr) + { + if (qfp->qf_lnum > lnum) + // First entry is after line 'lnum' + return qfp; + + // Find the entry just before or at the line 'lnum' + while (qfp->qf_next != NULL + && qfp->qf_next->qf_fnum == bnr + && qfp->qf_next->qf_lnum <= lnum) + { + qfp = qfp->qf_next; + ++*errornr; + } + + if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) + // No entries found after 'lnum' + return NULL; + + // Use the entry just after line 'lnum' + qfp = qfp->qf_next; + ++*errornr; + + return qfp; + } + + /* + * Find the first quickfix entry before line 'lnum' in buffer 'bnr'. + * 'qfp' points to the very first entry in the buffer and 'errornr' is the + * index of the very first entry in the quickfix list. + * Returns NULL if an entry is not found before 'lnum'. + */ + static qfline_T * + qf_find_entry_on_prev_line( + int bnr, + linenr_T lnum, + qfline_T *qfp, + int *errornr) + { + // Find the entry just before the line 'lnum' + while (qfp->qf_next != NULL + && qfp->qf_next->qf_fnum == bnr + && qfp->qf_next->qf_lnum < lnum) + { + qfp = qfp->qf_next; + ++*errornr; + } + + if (qfp->qf_lnum >= lnum) // entry is after 'lnum' + return NULL; + + // If multiple entries are on the same line, then use the first entry + qfp = qf_find_first_entry_on_line(qfp, errornr); + + return qfp; + } + + /* + * Find a quickfix entry in 'qfl' closest to line 'lnum' in buffer 'bnr' in + * the direction 'dir'. + */ + static qfline_T * + qf_find_closest_entry( + qf_list_T *qfl, + int bnr, + linenr_T lnum, + int dir, + int *errornr) + { + qfline_T *qfp; + + *errornr = 0; + + // Find the first entry in this file + qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr); + if (qfp == NULL) + return NULL; // no entry in this file + + if (dir == FORWARD) + qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr); + else + qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr); + + return qfp; + } + + /* + * Get the nth quickfix entry below the specified entry treating multiple + * entries on a single line as one. Searches forward in the list. + */ + static qfline_T * + qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n) + { + while (n-- > 0 && !got_int) + { + qfline_T *first_entry = entry; + int first_errornr = *errornr; + + // Treat all the entries on the same line in this file as one + entry = qf_find_last_entry_on_line(entry, errornr); + + if (entry->qf_next == NULL + || entry->qf_next->qf_fnum != entry->qf_fnum) + { + // If multiple entries are on the same line, then use the first + // entry + entry = first_entry; + *errornr = first_errornr; + break; + } + + entry = entry->qf_next; + ++*errornr; + } + + return entry; + } + + /* + * Get the nth quickfix entry above the specified entry treating multiple + * entries on a single line as one. Searches backwards in the list. + */ + static qfline_T * + qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n) + { + while (n-- > 0 && !got_int) + { + if (entry->qf_prev == NULL + || entry->qf_prev->qf_fnum != entry->qf_fnum) + break; + + entry = entry->qf_prev; + --*errornr; + + // If multiple entries are on the same line, then use the first entry + entry = qf_find_first_entry_on_line(entry, errornr); + } + + return entry; + } + + /* + * Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the + * specified direction. + * Returns the error number in the quickfix list or 0 if an entry is not found. + */ + static int + qf_find_nth_adj_entry(qf_list_T *qfl, int bnr, linenr_T lnum, int n, int dir) + { + qfline_T *adj_entry; + int errornr; + + // Find an entry closest to the specified line + adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr); + if (adj_entry == NULL) + return 0; + + if (--n > 0) + { + // Go to the n'th entry in the current buffer + if (dir == FORWARD) + adj_entry = qf_get_nth_below_entry(adj_entry, &errornr, n); + else + adj_entry = qf_get_nth_above_entry(adj_entry, &errornr, n); + } + + return errornr; + } + + /* + * Jump to a quickfix entry in the current file nearest to the current line. + * ":cabove", ":cbelow", ":labove" and ":lbelow" commands + */ + void + ex_cbelow(exarg_T *eap) + { + qf_info_T *qi; + qf_list_T *qfl; + int dir; + int buf_has_flag; + int errornr = 0; + + if (eap->addr_count > 0 && eap->line2 <= 0) + { + emsg(_(e_invrange)); + return; + } + + // Check whether the current buffer has any quickfix entries + if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow) + buf_has_flag = BUF_HAS_QF_ENTRY; + else + buf_has_flag = BUF_HAS_LL_ENTRY; + if (!(curbuf->b_has_qf_entry & buf_has_flag)) + { + emsg(_(e_quickfix)); + return; + } + + if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL) + return; + + qfl = qf_get_curlist(qi); + // check if the list has valid errors + if (!qf_list_has_valid_entries(qfl)) + { + emsg(_(e_quickfix)); + return; + } + + if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow) + dir = FORWARD; + else + dir = BACKWARD; + + errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum, + eap->addr_count > 0 ? eap->line2 : 0, dir); + + if (errornr > 0) + qf_jump(qi, 0, errornr, FALSE); + else + emsg(_(e_no_more_items)); + } + + /* * Return the autocmd name for the :cfile Ex commands */ static char_u * *** ../vim-8.1.1255/src/testdir/test_quickfix.vim 2019-05-02 20:17:29.322924398 +0200 --- src/testdir/test_quickfix.vim 2019-05-03 21:48:52.249927300 +0200 *************** *** 37,42 **** --- 37,44 ---- command! -nargs=* Xgrepadd grepadd command! -nargs=* Xhelpgrep helpgrep command! -nargs=0 -count Xcc cc + command! -count=1 -nargs=0 Xbelow cbelow + command! -count=1 -nargs=0 Xabove cabove let g:Xgetlist = function('getqflist') let g:Xsetlist = function('setqflist') call setqflist([], 'f') *************** *** 70,75 **** --- 72,79 ---- command! -nargs=* Xgrepadd lgrepadd command! -nargs=* Xhelpgrep lhelpgrep command! -nargs=0 -count Xcc ll + command! -count=1 -nargs=0 Xbelow lbelow + command! -count=1 -nargs=0 Xabove labove let g:Xgetlist = function('getloclist', [0]) let g:Xsetlist = function('setloclist', [0]) call setloclist(0, [], 'f') *************** *** 4035,4037 **** --- 4039,4147 ---- enew call delete('Xfile1') endfunc + + " Test for the :cbelow, :cabove, :lbelow and :labove commands. + func Xtest_below(cchar) + call s:setup_commands(a:cchar) + + " No quickfix/location list + call assert_fails('Xbelow', 'E42:') + call assert_fails('Xabove', 'E42:') + + " Empty quickfix/location list + call g:Xsetlist([]) + call assert_fails('Xbelow', 'E42:') + call assert_fails('Xabove', 'E42:') + + call s:create_test_file('X1') + call s:create_test_file('X2') + call s:create_test_file('X3') + call s:create_test_file('X4') + + " Invalid entries + edit X1 + call g:Xsetlist(["E1", "E2"]) + call assert_fails('Xbelow', 'E42:') + call assert_fails('Xabove', 'E42:') + call assert_fails('3Xbelow', 'E42:') + call assert_fails('4Xabove', 'E42:') + + " Test the commands with various arguments + Xexpr ["X1:5:L5", "X2:5:L5", "X2:10:L10", "X2:15:L15", "X3:3:L3"] + edit +7 X2 + Xabove + call assert_equal(['X2', 5], [bufname(''), line('.')]) + call assert_fails('Xabove', 'E553:') + normal 2j + Xbelow + call assert_equal(['X2', 10], [bufname(''), line('.')]) + " Last error in this file + Xbelow 99 + call assert_equal(['X2', 15], [bufname(''), line('.')]) + call assert_fails('Xbelow', 'E553:') + " First error in this file + Xabove 99 + call assert_equal(['X2', 5], [bufname(''), line('.')]) + call assert_fails('Xabove', 'E553:') + normal gg + Xbelow 2 + call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal G + Xabove 2 + call assert_equal(['X2', 10], [bufname(''), line('.')]) + edit X4 + call assert_fails('Xabove', 'E42:') + call assert_fails('Xbelow', 'E42:') + if a:cchar == 'l' + " If a buffer has location list entries from some other window but not + " from the current window, then the commands should fail. + edit X1 | split | call setloclist(0, [], 'f') + call assert_fails('Xabove', 'E776:') + call assert_fails('Xbelow', 'E776:') + close + endif + + " Test for lines with multiple quickfix entries + Xexpr ["X1:5:L5", "X2:5:1:L5_1", "X2:5:2:L5_2", "X2:5:3:L5_3", + \ "X2:10:1:L10_1", "X2:10:2:L10_2", "X2:10:3:L10_3", + \ "X2:15:1:L15_1", "X2:15:2:L15_2", "X2:15:3:L15_3", "X3:3:L3"] + edit +1 X2 + Xbelow 2 + call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) + normal gg + Xbelow 99 + call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + normal G + Xabove 2 + call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) + normal G + Xabove 99 + call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G + Xabove + call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G + Xbelow + call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + + " Invalid range + if a:cchar == 'c' + call assert_fails('-2cbelow', 'E553:') + " TODO: should go to first error in the current line? + 0cabove + else + call assert_fails('-2lbelow', 'E553:') + " TODO: should go to first error in the current line? + 0labove + endif + + call delete('X1') + call delete('X2') + call delete('X3') + call delete('X4') + endfunc + + func Test_cbelow() + call Xtest_below('c') + call Xtest_below('l') + endfunc *** ../vim-8.1.1255/src/version.c 2019-05-03 21:19:58.926404208 +0200 --- src/version.c 2019-05-03 21:35:46.089908080 +0200 *************** *** 769,770 **** --- 769,772 ---- { /* Add new patch number below this line */ + /**/ + 1256, /**/ -- A hamburger walks into a bar, and the bartender says: "I'm sorry, but we don't serve food here." /// 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 ///