0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

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 |:caddbuffer| :cad[dbuffer] add errors from buffer
|:caddexpr| :cadde[xpr] add errors from expr |:caddexpr| :cadde[xpr] add errors from expr
|:caddfile| :caddf[ile] add error message to current quickfix list |: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 |:call| :cal[l] call a function
|:catch| :cat[ch] part of a :try command |: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 |:cbottom| :cbo[ttom] scroll to the bottom of the quickfix window
|:cbuffer| :cb[uffer] parse error messages and jump to first error |:cbuffer| :cb[uffer] parse error messages and jump to first error
|:cc| :cc go to specific error |:cc| :cc go to specific error
@@ -1356,10 +1358,12 @@ tag command action ~
|:laddexpr| :lad[dexpr] add locations from expr |:laddexpr| :lad[dexpr] add locations from expr
|:laddbuffer| :laddb[uffer] add locations from buffer |:laddbuffer| :laddb[uffer] add locations from buffer
|:laddfile| :laddf[ile] add locations to current location list |: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 |:last| :la[st] go to the last file in the argument list
|:language| :lan[guage] set the language (locale) |:language| :lan[guage] set the language (locale)
|:later| :lat[er] go to newer change, redo |: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 |:lbottom| :lbo[ttom] scroll to the bottom of the location window
|:lbuffer| :lb[uffer] parse locations and jump to first location |:lbuffer| :lb[uffer] parse locations and jump to first location
|:lcd| :lc[d] change directory locally |: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, exceeds the number of entries below the current line,
then the last error in the file is selected. then the last error in the file is selected.
*:lbe* *:lbelow* *:lbel* *:lbelow*
:[count]lbe[low] Same as ":cbelow", except the location list for the :[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. current window is used instead of the quickfix list.
*:cnf* *:cnfile* *:cnf* *:cnfile*

View File

@@ -8,29 +8,29 @@ static const unsigned short cmdidxs1[26] =
/* a */ 0, /* a */ 0,
/* b */ 19, /* b */ 19,
/* c */ 42, /* c */ 42,
/* d */ 105, /* d */ 107,
/* e */ 127, /* e */ 129,
/* f */ 147, /* f */ 149,
/* g */ 163, /* g */ 165,
/* h */ 169, /* h */ 171,
/* i */ 178, /* i */ 180,
/* j */ 196, /* j */ 198,
/* k */ 198, /* k */ 200,
/* l */ 203, /* l */ 205,
/* m */ 263, /* m */ 267,
/* n */ 281, /* n */ 285,
/* o */ 301, /* o */ 305,
/* p */ 313, /* p */ 317,
/* q */ 352, /* q */ 356,
/* r */ 355, /* r */ 359,
/* s */ 375, /* s */ 379,
/* t */ 443, /* t */ 447,
/* u */ 488, /* u */ 492,
/* v */ 499, /* v */ 503,
/* w */ 517, /* w */ 521,
/* x */ 531, /* x */ 535,
/* y */ 540, /* y */ 544,
/* z */ 541 /* 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 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 }, /* 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 } /* 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, EX(CMD_caddfile, "caddfile", ex_cfile,
TRLBAR|FILE1, TRLBAR|FILE1,
ADDR_NONE), ADDR_NONE),
EX(CMD_cafter, "cafter", ex_cbelow,
RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED),
EX(CMD_call, "call", ex_call, EX(CMD_call, "call", ex_call,
RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN, RANGE|NEEDARG|EXTRA|NOTRLCOM|SBOXOK|CMDWIN,
ADDR_LINES), ADDR_LINES),
@@ -275,6 +278,9 @@ EX(CMD_catch, "catch", ex_catch,
EX(CMD_cbuffer, "cbuffer", ex_cbuffer, EX(CMD_cbuffer, "cbuffer", ex_cbuffer,
BANG|RANGE|WORD1|TRLBAR, BANG|RANGE|WORD1|TRLBAR,
ADDR_OTHER), ADDR_OTHER),
EX(CMD_cbefore, "cbefore", ex_cbelow,
RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED),
EX(CMD_cbelow, "cbelow", ex_cbelow, EX(CMD_cbelow, "cbelow", ex_cbelow,
RANGE|COUNT|TRLBAR, RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED), ADDR_UNSIGNED),
@@ -749,12 +755,18 @@ EX(CMD_laddbuffer, "laddbuffer", ex_cbuffer,
EX(CMD_laddfile, "laddfile", ex_cfile, EX(CMD_laddfile, "laddfile", ex_cfile,
TRLBAR|FILE1, TRLBAR|FILE1,
ADDR_NONE), ADDR_NONE),
EX(CMD_lafter, "lafter", ex_cbelow,
RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED),
EX(CMD_later, "later", ex_later, EX(CMD_later, "later", ex_later,
TRLBAR|EXTRA|NOSPC|CMDWIN, TRLBAR|EXTRA|NOSPC|CMDWIN,
ADDR_NONE), ADDR_NONE),
EX(CMD_lbuffer, "lbuffer", ex_cbuffer, EX(CMD_lbuffer, "lbuffer", ex_cbuffer,
BANG|RANGE|WORD1|TRLBAR, BANG|RANGE|WORD1|TRLBAR,
ADDR_OTHER), ADDR_OTHER),
EX(CMD_lbefore, "lbefore", ex_cbelow,
RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED),
EX(CMD_lbelow, "lbelow", ex_cbelow, EX(CMD_lbelow, "lbelow", ex_cbelow,
RANGE|COUNT|TRLBAR, RANGE|COUNT|TRLBAR,
ADDR_UNSIGNED), 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 * 'qfp' points to the very first entry in the buffer and 'errornr' is the
* index of the very first entry in the quickfix list. * 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 * static qfline_T *
qf_find_entry_on_next_line( qf_find_entry_after_pos(
int bnr, int bnr,
linenr_T lnum, pos_T *pos,
int linewise,
qfline_T *qfp, qfline_T *qfp,
int *errornr) int *errornr)
{ {
if (qfp->qf_lnum > lnum) if (qf_entry_after_pos(qfp, pos, linewise))
// First entry is after line 'lnum' // First entry is after postion 'pos'
return qfp; 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 while (qfp->qf_next != NULL
&& qfp->qf_next->qf_fnum == bnr && 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; qfp = qfp->qf_next;
++*errornr; ++*errornr;
} }
if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr) if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr)
// No entries found after 'lnum' // No entries found after position 'pos'
return NULL; return NULL;
// Use the entry just after line 'lnum' // Use the entry just after position 'pos'
qfp = qfp->qf_next; qfp = qfp->qf_next;
++*errornr; ++*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 * 'qfp' points to the very first entry in the buffer and 'errornr' is the
* index of the very first entry in the quickfix list. * 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 * static qfline_T *
qf_find_entry_on_prev_line( qf_find_entry_before_pos(
int bnr, int bnr,
linenr_T lnum, pos_T *pos,
int linewise,
qfline_T *qfp, qfline_T *qfp,
int *errornr) int *errornr)
{ {
// Find the entry just before the line 'lnum' // Find the entry just before the position 'pos'
while (qfp->qf_next != NULL while (qfp->qf_next != NULL
&& qfp->qf_next->qf_fnum == bnr && 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; qfp = qfp->qf_next;
++*errornr; ++*errornr;
} }
if (qfp->qf_lnum >= lnum) // entry is after 'lnum' if (qf_entry_on_or_after_pos(qfp, pos, linewise))
return NULL; return NULL;
// If multiple entries are on the same line, then use the first entry if (linewise)
qfp = qf_find_first_entry_on_line(qfp, errornr); // If multiple entries are on the same line, then use the first entry
qfp = qf_find_first_entry_on_line(qfp, errornr);
return qfp; 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'. * the direction 'dir'.
*/ */
static qfline_T * static qfline_T *
qf_find_closest_entry( qf_find_closest_entry(
qf_list_T *qfl, qf_list_T *qfl,
int bnr, int bnr,
linenr_T lnum, pos_T *pos,
int dir, int dir,
int linewise,
int *errornr) int *errornr)
{ {
qfline_T *qfp; qfline_T *qfp;
@@ -5217,35 +5287,40 @@ qf_find_closest_entry(
return NULL; // no entry in this file return NULL; // no entry in this file
if (dir == FORWARD) 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 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; return qfp;
} }
/* /*
* Get the nth quickfix entry below the specified entry treating multiple * Get the nth quickfix entry below the specified entry. Searches forward in
* entries on a single line as one. Searches forward in the list. * the list. If linewise is TRUE, then treat multiple entries on a single line
* as one.
*/ */
static qfline_T * 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) while (n-- > 0 && !got_int)
{ {
qfline_T *first_entry = entry; qfline_T *first_entry = entry;
int first_errornr = *errornr; int first_errornr = *errornr;
// Treat all the entries on the same line in this file as one if (linewise)
entry = qf_find_last_entry_on_line(entry, 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 if (entry->qf_next == NULL
|| entry->qf_next->qf_fnum != entry->qf_fnum) || entry->qf_next->qf_fnum != entry->qf_fnum)
{ {
// If multiple entries are on the same line, then use the first if (linewise)
// entry {
entry = first_entry; // If multiple entries are on the same line, then use the first
*errornr = first_errornr; // entry
entry = first_entry;
*errornr = first_errornr;
}
break; 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 * Get the nth quickfix entry above the specified entry. Searches backwards in
* entries on a single line as one. Searches backwards in the list. * the list. If linewise is TRUE, then treat multiple entries on a single line
* as one.
*/ */
static qfline_T * 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) while (n-- > 0 && !got_int)
{ {
@@ -5273,25 +5349,32 @@ qf_get_nth_above_entry(qfline_T *entry, int *errornr, int n)
--*errornr; --*errornr;
// If multiple entries are on the same line, then use the first entry // 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; return entry;
} }
/* /*
* Find the n'th quickfix entry adjacent to line 'lnum' in buffer 'bnr' in the * Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in
* specified direction. * the specified direction. Returns the error number in the quickfix list or 0
* Returns the error number in the quickfix list or 0 if an entry is not found. * if an entry is not found.
*/ */
static int 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; qfline_T *adj_entry;
int errornr; int errornr;
// Find an entry closest to the specified line // Find an entry closest to the specified position
adj_entry = qf_find_closest_entry(qfl, bnr, lnum, dir, &errornr); adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr);
if (adj_entry == NULL) if (adj_entry == NULL)
return 0; 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 // Go to the n'th entry in the current buffer
if (dir == FORWARD) 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 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; return errornr;
} }
/* /*
* Jump to a quickfix entry in the current file nearest to the current line. * Jump to a quickfix entry in the current file nearest to the current line or
* ":cabove", ":cbelow", ":labove" and ":lbelow" commands * current line/col.
* ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore",
* ":lafter" and ":lbefore" commands
*/ */
void void
ex_cbelow(exarg_T *eap) ex_cbelow(exarg_T *eap)
@@ -5319,6 +5406,7 @@ ex_cbelow(exarg_T *eap)
int dir; int dir;
int buf_has_flag; int buf_has_flag;
int errornr = 0; int errornr = 0;
pos_T pos;
if (eap->addr_count > 0 && eap->line2 <= 0) 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 // 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; buf_has_flag = BUF_HAS_QF_ENTRY;
else else
buf_has_flag = BUF_HAS_LL_ENTRY; buf_has_flag = BUF_HAS_LL_ENTRY;
@@ -5348,13 +5437,25 @@ ex_cbelow(exarg_T *eap)
return; 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; dir = FORWARD;
else else
dir = BACKWARD; dir = BACKWARD;
errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, curwin->w_cursor.lnum, pos = curwin->w_cursor;
eap->addr_count > 0 ? eap->line2 : 0, dir); // 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) if (errornr > 0)
qf_jump(qi, 0, errornr, FALSE); 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! -nargs=0 -count Xcc <count>cc
command! -count=1 -nargs=0 Xbelow <mods><count>cbelow command! -count=1 -nargs=0 Xbelow <mods><count>cbelow
command! -count=1 -nargs=0 Xabove <mods><count>cabove 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:Xgetlist = function('getqflist')
let g:Xsetlist = function('setqflist') let g:Xsetlist = function('setqflist')
call setqflist([], 'f') call setqflist([], 'f')
@@ -74,6 +76,8 @@ func s:setup_commands(cchar)
command! -nargs=0 -count Xcc <count>ll command! -nargs=0 -count Xcc <count>ll
command! -count=1 -nargs=0 Xbelow <mods><count>lbelow command! -count=1 -nargs=0 Xbelow <mods><count>lbelow
command! -count=1 -nargs=0 Xabove <mods><count>labove 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:Xgetlist = function('getloclist', [0])
let g:Xsetlist = function('setloclist', [0]) let g:Xsetlist = function('setloclist', [0])
call setloclist(0, [], 'f') call setloclist(0, [], 'f')
@@ -4041,17 +4045,22 @@ func Test_empty_qfbuf()
endfunc endfunc
" Test for the :cbelow, :cabove, :lbelow and :labove commands. " Test for the :cbelow, :cabove, :lbelow and :labove commands.
" And for the :cafter, :cbefore, :lafter and :lbefore commands.
func Xtest_below(cchar) func Xtest_below(cchar)
call s:setup_commands(a:cchar) call s:setup_commands(a:cchar)
" No quickfix/location list " No quickfix/location list
call assert_fails('Xbelow', 'E42:') call assert_fails('Xbelow', 'E42:')
call assert_fails('Xabove', 'E42:') call assert_fails('Xabove', 'E42:')
call assert_fails('Xbefore', 'E42:')
call assert_fails('Xafter', 'E42:')
" Empty quickfix/location list " Empty quickfix/location list
call g:Xsetlist([]) call g:Xsetlist([])
call assert_fails('Xbelow', 'E42:') call assert_fails('Xbelow', 'E42:')
call assert_fails('Xabove', '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('X1')
call s:create_test_file('X2') call s:create_test_file('X2')
@@ -4065,39 +4074,74 @@ func Xtest_below(cchar)
call assert_fails('Xabove', 'E42:') call assert_fails('Xabove', 'E42:')
call assert_fails('3Xbelow', 'E42:') call assert_fails('3Xbelow', 'E42:')
call assert_fails('4Xabove', '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 " 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 edit +7 X2
Xabove Xabove
call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_equal(['X2', 5], [bufname(''), line('.')])
call assert_fails('Xabove', 'E553:') call assert_fails('Xabove', 'E553:')
normal 7G
Xbefore
call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
call assert_fails('Xbefore', 'E553:')
normal 2j normal 2j
Xbelow Xbelow
call assert_equal(['X2', 10], [bufname(''), line('.')]) call assert_equal(['X2', 10], [bufname(''), line('.')])
normal 7G
Xafter
call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
" Last error in this file " Last error in this file
Xbelow 99 Xbelow 99
call assert_equal(['X2', 15], [bufname(''), line('.')]) call assert_equal(['X2', 15], [bufname(''), line('.')])
call assert_fails('Xbelow', 'E553:') 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 " First error in this file
Xabove 99 Xabove 99
call assert_equal(['X2', 5], [bufname(''), line('.')]) call assert_equal(['X2', 5], [bufname(''), line('.')])
call assert_fails('Xabove', 'E553:') 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 normal gg
Xbelow 2 Xbelow 2
call assert_equal(['X2', 10], [bufname(''), line('.')]) call assert_equal(['X2', 10], [bufname(''), line('.')])
normal gg
Xafter 2
call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
normal G normal G
Xabove 2 Xabove 2
call assert_equal(['X2', 10], [bufname(''), line('.')]) call assert_equal(['X2', 10], [bufname(''), line('.')])
normal G
Xbefore 2
call assert_equal(['X2', 10, 3], [bufname(''), line('.'), col('.')])
edit X4 edit X4
call assert_fails('Xabove', 'E42:') call assert_fails('Xabove', 'E42:')
call assert_fails('Xbelow', 'E42:') call assert_fails('Xbelow', 'E42:')
call assert_fails('Xbefore', 'E42:')
call assert_fails('Xafter', 'E42:')
if a:cchar == 'l' if a:cchar == 'l'
" If a buffer has location list entries from some other window but not " If a buffer has location list entries from some other window but not
" from the current window, then the commands should fail. " from the current window, then the commands should fail.
edit X1 | split | call setloclist(0, [], 'f') edit X1 | split | call setloclist(0, [], 'f')
call assert_fails('Xabove', 'E776:') call assert_fails('Xabove', 'E776:')
call assert_fails('Xbelow', 'E776:') call assert_fails('Xbelow', 'E776:')
call assert_fails('Xbefore', 'E776:')
call assert_fails('Xafter', 'E776:')
close close
endif endif
@@ -4108,27 +4152,52 @@ func Xtest_below(cchar)
edit +1 X2 edit +1 X2
Xbelow 2 Xbelow 2
call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
normal 1G
Xafter 2
call assert_equal(['X2', 5, 2], [bufname(''), line('.'), col('.')])
normal gg normal gg
Xbelow 99 Xbelow 99
call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
normal gg
Xafter 99
call assert_equal(['X2', 15, 3], [bufname(''), line('.'), col('.')])
normal G normal G
Xabove 2 Xabove 2
call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 10, 1], [bufname(''), line('.'), col('.')])
normal G
Xbefore 2
call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
normal G normal G
Xabove 99 Xabove 99
call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
normal G
Xbefore 99
call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
normal 10G normal 10G
Xabove Xabove
call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 5, 1], [bufname(''), line('.'), col('.')])
normal 10G$
2Xbefore
call assert_equal(['X2', 10, 2], [bufname(''), line('.'), col('.')])
normal 10G normal 10G
Xbelow Xbelow
call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')]) call assert_equal(['X2', 15, 1], [bufname(''), line('.'), col('.')])
normal 9G
5Xafter
call assert_equal(['X2', 15, 2], [bufname(''), line('.'), col('.')])
" Invalid range " Invalid range
if a:cchar == 'c' if a:cchar == 'c'
call assert_fails('-2cbelow', 'E16:') call assert_fails('-2cbelow', 'E16:')
call assert_fails('-2cafter', 'E16:')
else else
call assert_fails('-2lbelow', 'E16:') call assert_fails('-2lbelow', 'E16:')
call assert_fails('-2lafter', 'E16:')
endif endif
call delete('X1') call delete('X1')

View File

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