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)
This commit is contained in:
Bram Moolenaar
2019-05-05 15:02:30 +02:00
parent ce79353ace
commit cf6a55c4b0
7 changed files with 297 additions and 81 deletions

View File

@ -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

View File

@ -152,8 +152,36 @@ processing a quickfix or location list command, it will be aborted.
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*

View File

@ -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][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][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][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;

View File

@ -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_cbuffer,
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),

View File

@ -5128,36 +5128,100 @@ qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
}
/*
* 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, int *errornr, int n)
}
/*
* 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, int *errornr, int n)
--*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, int bnr, linenr_T lnum, int n, int dir)
{
// 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);

View File

@ -39,6 +39,8 @@ func s:setup_commands(cchar)
command! -nargs=0 -count Xcc <count>cc
command! -count=1 -nargs=0 Xbelow <mods><count>cbelow
command! -count=1 -nargs=0 Xabove <mods><count>cabove
command! -count=1 -nargs=0 Xbefore <mods><count>cbefore
command! -count=1 -nargs=0 Xafter <mods><count>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 <count>ll
command! -count=1 -nargs=0 Xbelow <mods><count>lbelow
command! -count=1 -nargs=0 Xabove <mods><count>labove
command! -count=1 -nargs=0 Xbefore <mods><count>lbefore
command! -count=1 -nargs=0 Xafter <mods><count>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')

View File

@ -767,6 +767,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1275,
/**/
1274,
/**/