# HG changeset patch # User Bram Moolenaar # Date 1557062104 -7200 # Node ID 1d2b3bb35414e0fe5642c47824eacb9f1a4b3eeb # Parent 5545614fe8e184ae04f55b780708fad55b25e761 patch 8.1.1275: cannot navigate to errors before/after the cursor commit https://github.com/vim/vim/commit/cf6a55c4b0cbf38b0c3fbed5ffd9a3fd0d2ede0e Author: Bram Moolenaar Date: Sun May 5 15:02:30 2019 +0200 patch 8.1.1275: cannot navigate to errors before/after the cursor Problem: Cannot navigate to errors before/after the cursor. Solution: Add the :cbefore and :cafter commands. (Yegappan Lakshmanan, closes #4340) diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt --- a/runtime/doc/index.txt +++ b/runtime/doc/index.txt @@ -1192,9 +1192,11 @@ tag command action ~ |:caddbuffer| :cad[dbuffer] add errors from buffer |:caddexpr| :cadde[xpr] add errors from expr |:caddfile| :caddf[ile] add error message to current quickfix list +|:cafter| :caf[ter] go to error after current cursor |:call| :cal[l] call a function |:catch| :cat[ch] part of a :try command -|:cbelow| :cbe[low] got to error below current line +|:cbefore| :cbef[ore] go to error before current cursor +|:cbelow| :cbel[ow] go 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 @@ -1356,10 +1358,12 @@ tag command action ~ |:laddexpr| :lad[dexpr] add locations from expr |:laddbuffer| :laddb[uffer] add locations from buffer |:laddfile| :laddf[ile] add locations to current location list +|:lafter| :laf[ter] go to location after current cursor |: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 +|:lbefore| :lbef[ore] go to location before current cursor +|:lbelow| :lbel[ow] 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 diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -152,8 +152,36 @@ processing a quickfix or location list c 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 + *:lbel* *:lbelow* +:[count]lbel[ow] Same as ":cbelow", except the location list for the + current window is used instead of the quickfix list. + + *:cbe* *:cbefore* +:[count]cbe[fore] Go to the [count] error before the current cursor + position 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, + line and column numbers. If [count] exceeds the + number of entries before the current position, then + the first error in the file is selected. + + *:lbef* *:lbefore* +:[count]lbef[ore] Same as ":cbefore", except the location list for the + current window is used instead of the quickfix list. + + *:caf* *:cafter* +:[count]caf[ter] Go to the [count] error after the current cursor + position 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, + line and column numbers. If [count] exceeds the + number of entries after the current position, then + the last error in the file is selected. + + *:laf* *:lafter* +:[count]laf[ter] Same as ":cafter", except the location list for the current window is used instead of the quickfix list. *:cnf* *:cnfile* diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h --- a/src/ex_cmdidxs.h +++ b/src/ex_cmdidxs.h @@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] /* 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 + /* d */ 107, + /* e */ 129, + /* f */ 149, + /* g */ 165, + /* h */ 171, + /* i */ 180, + /* j */ 198, + /* k */ 200, + /* l */ 205, + /* m */ 267, + /* n */ 285, + /* o */ 305, + /* p */ 317, + /* q */ 356, + /* r */ 359, + /* s */ 379, + /* t */ 447, + /* u */ 492, + /* v */ 503, + /* w */ 521, + /* x */ 535, + /* y */ 544, + /* z */ 545 }; /* @@ -43,7 +43,7 @@ static const unsigned char cmdidxs2[26][ { /* 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 }, + /* c */ { 3, 12, 16, 18, 20, 22, 25, 0, 0, 0, 0, 33, 37, 40, 46, 55, 57, 58, 59, 0, 61, 0, 64, 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,7 +52,7 @@ static const unsigned char cmdidxs2[26][ /* 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 }, + /* l */ { 3, 11, 15, 19, 20, 24, 27, 32, 0, 0, 0, 34, 37, 40, 44, 50, 0, 52, 61, 53, 54, 58, 60, 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,4 +69,4 @@ static const unsigned char cmdidxs2[26][ /* 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; +static const int command_count = 558; diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -266,6 +266,9 @@ EX(CMD_caddexpr, "caddexpr", ex_cexpr, EX(CMD_caddfile, "caddfile", ex_cfile, TRLBAR|FILE1, ADDR_NONE), +EX(CMD_cafter, "cafter", ex_cbelow, + RANGE|COUNT|TRLBAR, + ADDR_UNSIGNED), EX(CMD_call, "call", ex_call, RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN, ADDR_LINES), @@ -275,6 +278,9 @@ EX(CMD_catch, "catch", ex_catch, EX(CMD_cbuffer, "cbuffer", ex_cbuffer, BANG|RANGE|WORD1|TRLBAR, ADDR_OTHER), +EX(CMD_cbefore, "cbefore", ex_cbelow, + RANGE|COUNT|TRLBAR, + ADDR_UNSIGNED), EX(CMD_cbelow, "cbelow", ex_cbelow, RANGE|COUNT|TRLBAR, ADDR_UNSIGNED), @@ -749,12 +755,18 @@ EX(CMD_laddbuffer, "laddbuffer", ex_cbuf EX(CMD_laddfile, "laddfile", ex_cfile, TRLBAR|FILE1, ADDR_NONE), +EX(CMD_lafter, "lafter", ex_cbelow, + RANGE|COUNT|TRLBAR, + ADDR_UNSIGNED), EX(CMD_later, "later", ex_later, TRLBAR|EXTRA|NOSPC|CMDWIN, ADDR_NONE), EX(CMD_lbuffer, "lbuffer", ex_cbuffer, BANG|RANGE|WORD1|TRLBAR, ADDR_OTHER), +EX(CMD_lbefore, "lbefore", ex_cbelow, + RANGE|COUNT|TRLBAR, + ADDR_UNSIGNED), EX(CMD_lbelow, "lbelow", ex_cbelow, RANGE|COUNT|TRLBAR, ADDR_UNSIGNED), diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -5128,36 +5128,100 @@ qf_find_last_entry_on_line(qfline_T *ent } /* - * Find the first quickfix entry below line 'lnum' in buffer 'bnr'. + * Returns TRUE if the specified quickfix entry is + * after the given line (linewise is TRUE) + * or after the line and column. + */ + static int +qf_entry_after_pos(qfline_T *qfp, pos_T *pos, int linewise) +{ + if (linewise) + return qfp->qf_lnum > pos->lnum; + else + return (qfp->qf_lnum > pos->lnum || + (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col)); +} + +/* + * Returns TRUE if the specified quickfix entry is + * before the given line (linewise is TRUE) + * or before the line and column. + */ + static int +qf_entry_before_pos(qfline_T *qfp, pos_T *pos, int linewise) +{ + if (linewise) + return qfp->qf_lnum < pos->lnum; + else + return (qfp->qf_lnum < pos->lnum || + (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col)); +} + +/* + * Returns TRUE if the specified quickfix entry is + * on or after the given line (linewise is TRUE) + * or on or after the line and column. + */ + static int +qf_entry_on_or_after_pos(qfline_T *qfp, pos_T *pos, int linewise) +{ + if (linewise) + return qfp->qf_lnum >= pos->lnum; + else + return (qfp->qf_lnum > pos->lnum || + (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col)); +} + +/* + * Returns TRUE if the specified quickfix entry is + * on or before the given line (linewise is TRUE) + * or on or before the line and column. + */ + static int +qf_entry_on_or_before_pos(qfline_T *qfp, pos_T *pos, int linewise) +{ + if (linewise) + return qfp->qf_lnum <= pos->lnum; + else + return (qfp->qf_lnum < pos->lnum || + (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col)); +} + +/* + * Find the first quickfix entry after position 'pos' in buffer 'bnr'. + * If 'linewise' is TRUE, returns the entry after the specified line and treats + * multiple entries on a single line as one. Otherwise returns the entry after + * the specified line and column. * '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'. + * Returns NULL if an entry is not found after 'pos'. */ static qfline_T * -qf_find_entry_on_next_line( +qf_find_entry_after_pos( int bnr, - linenr_T lnum, + pos_T *pos, + int linewise, qfline_T *qfp, int *errornr) { - if (qfp->qf_lnum > lnum) - // First entry is after line 'lnum' + if (qf_entry_after_pos(qfp, pos, linewise)) + // First entry is after postion 'pos' return qfp; - // Find the entry just before or at the line 'lnum' + // Find the entry just before or at the position 'pos' while (qfp->qf_next != NULL && qfp->qf_next->qf_fnum == bnr - && qfp->qf_next->qf_lnum <= lnum) + && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise)) { qfp = qfp->qf_next; ++*errornr; } if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) - // No entries found after 'lnum' + // No entries found after position 'pos' return NULL; - // Use the entry just after line 'lnum' + // Use the entry just after position 'pos' qfp = qfp->qf_next; ++*errornr; @@ -5165,46 +5229,52 @@ qf_find_entry_on_next_line( } /* - * Find the first quickfix entry before line 'lnum' in buffer 'bnr'. + * Find the first quickfix entry before position 'pos' in buffer 'bnr'. + * If 'linewise' is TRUE, returns the entry before the specified line and + * treats multiple entries on a single line as one. Otherwise returns the entry + * before the specified line and column. * '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'. + * Returns NULL if an entry is not found before 'pos'. */ static qfline_T * -qf_find_entry_on_prev_line( +qf_find_entry_before_pos( int bnr, - linenr_T lnum, + pos_T *pos, + int linewise, qfline_T *qfp, int *errornr) { - // Find the entry just before the line 'lnum' + // Find the entry just before the position 'pos' while (qfp->qf_next != NULL && qfp->qf_next->qf_fnum == bnr - && qfp->qf_next->qf_lnum < lnum) + && qf_entry_before_pos(qfp->qf_next, pos, linewise)) { qfp = qfp->qf_next; ++*errornr; } - if (qfp->qf_lnum >= lnum) // entry is after 'lnum' + if (qf_entry_on_or_after_pos(qfp, pos, linewise)) return NULL; - // If multiple entries are on the same line, then use the first entry - qfp = qf_find_first_entry_on_line(qfp, errornr); + if (linewise) + // 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 + * Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in * the direction 'dir'. */ static qfline_T * qf_find_closest_entry( qf_list_T *qfl, int bnr, - linenr_T lnum, + pos_T *pos, int dir, + int linewise, int *errornr) { qfline_T *qfp; @@ -5217,35 +5287,40 @@ qf_find_closest_entry( return NULL; // no entry in this file if (dir == FORWARD) - qfp = qf_find_entry_on_next_line(bnr, lnum, qfp, errornr); + qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr); else - qfp = qf_find_entry_on_prev_line(bnr, lnum, qfp, errornr); + qfp = qf_find_entry_before_pos(bnr, pos, linewise, 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. + * Get the nth quickfix entry below the specified entry. Searches forward in + * the list. If linewise is TRUE, then treat multiple entries on a single line + * as one. */ static qfline_T * -qf_get_nth_below_entry(qfline_T *entry, int *errornr, int n) +qf_get_nth_below_entry(qfline_T *entry, int n, int linewise, int *errornr) { 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 (linewise) + // 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; + if (linewise) + { + // If multiple entries are on the same line, then use the first + // entry + entry = first_entry; + *errornr = first_errornr; + } break; } @@ -5257,11 +5332,12 @@ qf_get_nth_below_entry(qfline_T *entry, } /* - * Get the nth quickfix entry above the specified entry treating multiple - * entries on a single line as one. Searches backwards in the list. + * Get the nth quickfix entry above the specified entry. Searches backwards in + * the list. If linewise is TRUE, then treat multiple entries on a single line + * as one. */ static qfline_T * -qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n) +qf_get_nth_above_entry(qfline_T *entry, int n, int linewise, int *errornr) { while (n-- > 0 && !got_int) { @@ -5273,25 +5349,32 @@ qf_get_nth_above_entry(qfline_T *entry, --*errornr; // If multiple entries are on the same line, then use the first entry - entry = qf_find_first_entry_on_line(entry, errornr); + if (linewise) + 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. + * Find the n'th quickfix entry adjacent to position 'pos' 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) +qf_find_nth_adj_entry( + qf_list_T *qfl, + int bnr, + pos_T *pos, + int n, + int dir, + int linewise) { 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); + // Find an entry closest to the specified position + adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr); if (adj_entry == NULL) return 0; @@ -5299,17 +5382,21 @@ qf_find_nth_adj_entry(qf_list_T *qfl, in { // Go to the n'th entry in the current buffer if (dir == FORWARD) - adj_entry = qf_get_nth_below_entry(adj_entry, &errornr, n); + adj_entry = qf_get_nth_below_entry(adj_entry, n, linewise, + &errornr); else - adj_entry = qf_get_nth_above_entry(adj_entry, &errornr, n); + adj_entry = qf_get_nth_above_entry(adj_entry, n, linewise, + &errornr); } return errornr; } /* - * Jump to a quickfix entry in the current file nearest to the current line. - * ":cabove", ":cbelow", ":labove" and ":lbelow" commands + * Jump to a quickfix entry in the current file nearest to the current line or + * current line/col. + * ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore", + * ":lafter" and ":lbefore" commands */ void ex_cbelow(exarg_T *eap) @@ -5319,6 +5406,7 @@ ex_cbelow(exarg_T *eap) int dir; int buf_has_flag; int errornr = 0; + pos_T pos; if (eap->addr_count > 0 && eap->line2 <= 0) { @@ -5327,7 +5415,8 @@ ex_cbelow(exarg_T *eap) } // Check whether the current buffer has any quickfix entries - if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow) + if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter) buf_has_flag = BUF_HAS_QF_ENTRY; else buf_has_flag = BUF_HAS_LL_ENTRY; @@ -5348,13 +5437,25 @@ ex_cbelow(exarg_T *eap) return; } - if (eap->cmdidx == CMD_cbelow || eap->cmdidx == CMD_lbelow) + if (eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_lbelow + || eap->cmdidx == CMD_cafter + || eap->cmdidx == CMD_lafter) + // Forward motion commands 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); + pos = curwin->w_cursor; + // A quickfix entry column number is 1 based whereas cursor column + // number is 0 based. Adjust the column number. + pos.col++; + errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, &pos, + eap->addr_count > 0 ? eap->line2 : 0, dir, + eap->cmdidx == CMD_cbelow + || eap->cmdidx == CMD_lbelow + || eap->cmdidx == CMD_cabove + || eap->cmdidx == CMD_labove); if (errornr > 0) qf_jump(qi, 0, errornr, FALSE); diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -39,6 +39,8 @@ func s:setup_commands(cchar) command! -nargs=0 -count Xcc cc command! -count=1 -nargs=0 Xbelow cbelow command! -count=1 -nargs=0 Xabove cabove + command! -count=1 -nargs=0 Xbefore cbefore + command! -count=1 -nargs=0 Xafter cafter let g:Xgetlist = function('getqflist') let g:Xsetlist = function('setqflist') call setqflist([], 'f') @@ -74,6 +76,8 @@ func s:setup_commands(cchar) command! -nargs=0 -count Xcc ll command! -count=1 -nargs=0 Xbelow lbelow command! -count=1 -nargs=0 Xabove labove + command! -count=1 -nargs=0 Xbefore lbefore + command! -count=1 -nargs=0 Xafter lafter let g:Xgetlist = function('getloclist', [0]) let g:Xsetlist = function('setloclist', [0]) call setloclist(0, [], 'f') @@ -4041,17 +4045,22 @@ func Test_empty_qfbuf() endfunc " Test for the :cbelow, :cabove, :lbelow and :labove commands. +" And for the :cafter, :cbefore, :lafter and :lbefore 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:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') " Empty quickfix/location list call g:Xsetlist([]) call assert_fails('Xbelow', 'E42:') call assert_fails('Xabove', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') call s:create_test_file('X1') call s:create_test_file('X2') @@ -4065,39 +4074,74 @@ func Xtest_below(cchar) call assert_fails('Xabove', 'E42:') call assert_fails('3Xbelow', 'E42:') call assert_fails('4Xabove', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', 'E42:') + call assert_fails('3Xbefore', 'E42:') + call assert_fails('4Xafter', 'E42:') " Test the commands with various arguments - Xexpr ["X1:5:L5", "X2:5:L5", "X2:10:L10", "X2:15:L15", "X3:3:L3"] + Xexpr ["X1:5:3:L5", "X2:5:2:L5", "X2:10:3:L10", "X2:15:4:L15", "X3:3:5:L3"] edit +7 X2 Xabove call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_fails('Xabove', 'E553:') + normal 7G + Xbefore + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + call assert_fails('Xbefore', 'E553:') + normal 2j Xbelow call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal 7G + Xafter + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + " Last error in this file Xbelow 99 call assert_equal(['X2', 15], [bufname(''), line('.')]) call assert_fails('Xbelow', 'E553:') + normal gg + Xafter 99 + call assert_equal(['X2', 15, 4], [bufname(''), line('.'), col('.')]) + call assert_fails('Xafter', 'E553:') + " First error in this file Xabove 99 call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_fails('Xabove', 'E553:') + normal G + Xbefore 99 + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + call assert_fails('Xbefore', 'E553:') + normal gg Xbelow 2 call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal gg + Xafter 2 + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + normal G Xabove 2 call assert_equal(['X2', 10], [bufname(''), line('.')]) + normal G + Xbefore 2 + call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')]) + edit X4 call assert_fails('Xabove', 'E42:') call assert_fails('Xbelow', 'E42:') + call assert_fails('Xbefore', 'E42:') + call assert_fails('Xafter', '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:') + call assert_fails('Xbefore', 'E776:') + call assert_fails('Xafter', 'E776:') close endif @@ -4108,27 +4152,52 @@ func Xtest_below(cchar) edit +1 X2 Xbelow 2 call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) + normal 1G + Xafter 2 + call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')]) + normal gg Xbelow 99 call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + normal gg + Xafter 99 + call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')]) + normal G Xabove 2 call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) normal G + Xbefore 2 + call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')]) + + normal G Xabove 99 call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal G + Xbefore 99 + call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G Xabove call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) + normal 10G$ + 2Xbefore + call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')]) + normal 10G Xbelow call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) + normal 9G + 5Xafter + call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')]) " Invalid range if a:cchar == 'c' call assert_fails('-2cbelow', 'E16:') + call assert_fails('-2cafter', 'E16:') else call assert_fails('-2lbelow', 'E16:') + call assert_fails('-2lafter', 'E16:') endif call delete('X1') diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -768,6 +768,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1275, +/**/ 1274, /**/ 1273,