mirror of
https://github.com/neovim/neovim.git
synced 2024-12-29 14:41:06 -07:00
vim-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 vim/vim#4340)
cf6a55c4b0
This commit is contained in:
parent
5cf94effee
commit
d1608f7503
@ -1173,9 +1173,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] go 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
|
||||||
@ -1336,10 +1338,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
|
||||||
|
@ -128,8 +128,8 @@ processing a quickfix or location list command, it will be aborted.
|
|||||||
:[count]lab[ove] Same as ":cabove", except the location list for the
|
:[count]lab[ove] Same as ":cabove", except the location list for the
|
||||||
current window is used instead of the quickfix list.
|
current window is used instead of the quickfix list.
|
||||||
|
|
||||||
*:cbe* *:cbelow*
|
*:cbel* *:cbelow*
|
||||||
:[count]cbe[low] Go to the [count] error below the current line in the
|
:[count]cbel[ow] Go to the [count] error below the current line in the
|
||||||
current buffer. If [count] is omitted, then 1 is
|
current buffer. If [count] is omitted, then 1 is
|
||||||
used. If there are no errors, then an error message
|
used. If there are no errors, then an error message
|
||||||
is displayed. Assumes that the entries in a quickfix
|
is displayed. Assumes that the entries in a quickfix
|
||||||
@ -139,8 +139,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.
|
||||||
|
|
||||||
|
*:lbe* *:lbefore*
|
||||||
|
:[count]lbe[fore] 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*
|
||||||
|
@ -342,6 +342,12 @@ module.cmds = {
|
|||||||
addr_type='ADDR_NONE',
|
addr_type='ADDR_NONE',
|
||||||
func='ex_cfile',
|
func='ex_cfile',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command='cafter',
|
||||||
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
|
addr_type='ADDR_UNSIGNED',
|
||||||
|
func='ex_cbelow',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
command='call',
|
command='call',
|
||||||
flags=bit.bor(RANGE, NEEDARG, EXTRA, NOTRLCOM, SBOXOK, CMDWIN),
|
flags=bit.bor(RANGE, NEEDARG, EXTRA, NOTRLCOM, SBOXOK, CMDWIN),
|
||||||
@ -360,6 +366,12 @@ module.cmds = {
|
|||||||
addr_type='ADDR_OTHER',
|
addr_type='ADDR_OTHER',
|
||||||
func='ex_cbuffer',
|
func='ex_cbuffer',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command='cbefore',
|
||||||
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
|
addr_type='ADDR_UNSIGNED',
|
||||||
|
func='ex_cbelow',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
command='cbelow',
|
command='cbelow',
|
||||||
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
@ -1310,6 +1322,12 @@ module.cmds = {
|
|||||||
addr_type='ADDR_NONE',
|
addr_type='ADDR_NONE',
|
||||||
func='ex_cfile',
|
func='ex_cfile',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command='lafter',
|
||||||
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
|
addr_type='ADDR_UNSIGNED',
|
||||||
|
func='ex_cbelow',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
command='later',
|
command='later',
|
||||||
flags=bit.bor(TRLBAR, EXTRA, NOSPC, CMDWIN),
|
flags=bit.bor(TRLBAR, EXTRA, NOSPC, CMDWIN),
|
||||||
@ -1322,6 +1340,12 @@ module.cmds = {
|
|||||||
addr_type='ADDR_OTHER',
|
addr_type='ADDR_OTHER',
|
||||||
func='ex_cbuffer',
|
func='ex_cbuffer',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
command='lbefore',
|
||||||
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
|
addr_type='ADDR_UNSIGNED',
|
||||||
|
func='ex_cbelow',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
command='lbelow',
|
command='lbelow',
|
||||||
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
flags=bit.bor(RANGE, COUNT, TRLBAR),
|
||||||
|
@ -4573,74 +4573,150 @@ static qfline_T * qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
|
|||||||
return entry;
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 bool qf_entry_after_pos(const qfline_T *qfp, const pos_T *pos,
|
||||||
|
bool linewise)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
if (linewise) {
|
||||||
|
return qfp->qf_lnum > pos->lnum;
|
||||||
|
}
|
||||||
|
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 bool qf_entry_before_pos(const qfline_T *qfp, const pos_T *pos,
|
||||||
|
bool linewise)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
if (linewise) {
|
||||||
|
return qfp->qf_lnum < pos->lnum;
|
||||||
|
}
|
||||||
|
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 bool qf_entry_on_or_after_pos(const qfline_T *qfp, const pos_T *pos,
|
||||||
|
bool linewise)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
if (linewise) {
|
||||||
|
return qfp->qf_lnum >= pos->lnum;
|
||||||
|
}
|
||||||
|
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 bool qf_entry_on_or_before_pos(const qfline_T *qfp, const pos_T *pos,
|
||||||
|
bool linewise)
|
||||||
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
|
{
|
||||||
|
if (linewise) {
|
||||||
|
return qfp->qf_lnum <= pos->lnum;
|
||||||
|
}
|
||||||
|
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 *qf_find_entry_on_next_line(int bnr,
|
static qfline_T *qf_find_entry_after_pos(
|
||||||
linenr_T lnum,
|
int bnr,
|
||||||
|
const pos_T *pos,
|
||||||
|
bool linewise,
|
||||||
qfline_T *qfp,
|
qfline_T *qfp,
|
||||||
int *errornr)
|
int *errornr
|
||||||
|
)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
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)++;
|
||||||
|
|
||||||
return qfp;
|
return qfp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 *qf_find_entry_on_prev_line(int bnr,
|
static qfline_T *qf_find_entry_before_pos(
|
||||||
linenr_T lnum,
|
int bnr,
|
||||||
|
const pos_T *pos,
|
||||||
|
bool linewise,
|
||||||
qfline_T *qfp,
|
qfline_T *qfp,
|
||||||
int *errornr)
|
int *errornr
|
||||||
|
)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
// 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 (linewise) {
|
||||||
// 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
|
||||||
qfp = qf_find_first_entry_on_line(qfp, errornr);
|
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 *qf_find_closest_entry(qf_list_T *qfl,
|
static qfline_T *qf_find_closest_entry(
|
||||||
|
qf_list_T *qfl,
|
||||||
int bnr,
|
int bnr,
|
||||||
linenr_T lnum,
|
const pos_T *pos,
|
||||||
int dir,
|
Direction dir,
|
||||||
int *errornr)
|
bool linewise,
|
||||||
|
int *errornr
|
||||||
|
)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
qfline_T *qfp;
|
qfline_T *qfp;
|
||||||
|
|
||||||
@ -4653,33 +4729,38 @@ static qfline_T *qf_find_closest_entry(qf_list_T *qfl,
|
|||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
static void qf_get_nth_below_entry(qfline_T *entry,
|
/// as one.
|
||||||
int *errornr,
|
static void qf_get_nth_below_entry(qfline_T *entry, linenr_T n,
|
||||||
linenr_T n)
|
bool linewise, int *errornr)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
|
||||||
|
if (linewise) {
|
||||||
// Treat all the entries on the same line in this file as one
|
// Treat all the entries on the same line in this file as one
|
||||||
entry = qf_find_last_entry_on_line(entry, errornr);
|
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 (linewise) {
|
||||||
// If multiple entries are on the same line, then use the first
|
// If multiple entries are on the same line, then use the first
|
||||||
// entry
|
// entry
|
||||||
// entry = first_entry;
|
// entry = first_entry;
|
||||||
*errornr = first_errornr;
|
*errornr = first_errornr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4688,11 +4769,12 @@ static void qf_get_nth_below_entry(qfline_T *entry,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
static void qf_get_nth_above_entry(qfline_T *entry,
|
/// as one.
|
||||||
int *errornr,
|
static void qf_get_nth_above_entry(qfline_T *entry, linenr_T n,
|
||||||
linenr_T n)
|
bool linewise, int *errornr)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
while (n-- > 0 && !got_int) {
|
while (n-- > 0 && !got_int) {
|
||||||
if (entry->qf_prev == NULL
|
if (entry->qf_prev == NULL
|
||||||
@ -4703,25 +4785,30 @@ static void qf_get_nth_above_entry(qfline_T *entry,
|
|||||||
entry = entry->qf_prev;
|
entry = entry->qf_prev;
|
||||||
(*errornr)--;
|
(*errornr)--;
|
||||||
|
|
||||||
// If multiple entries are on the same line, then use the first entry
|
if (linewise) {
|
||||||
entry = qf_find_first_entry_on_line(entry, errornr);
|
entry = qf_find_first_entry_on_line(entry, errornr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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 qf_find_nth_adj_entry(qf_list_T *qfl,
|
static int qf_find_nth_adj_entry(
|
||||||
|
qf_list_T *qfl,
|
||||||
int bnr,
|
int bnr,
|
||||||
linenr_T lnum,
|
pos_T *pos,
|
||||||
linenr_T n,
|
linenr_T n,
|
||||||
int dir)
|
Direction dir,
|
||||||
|
bool linewise
|
||||||
|
)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
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);
|
qfline_T *const adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir,
|
||||||
|
linewise, &errornr);
|
||||||
if (adj_entry == NULL) {
|
if (adj_entry == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -4729,24 +4816,25 @@ static int qf_find_nth_adj_entry(qf_list_T *qfl,
|
|||||||
if (--n > 0) {
|
if (--n > 0) {
|
||||||
// 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) {
|
||||||
qf_get_nth_below_entry(adj_entry, &errornr, n);
|
qf_get_nth_below_entry(adj_entry, n, linewise, &errornr);
|
||||||
} else {
|
} else {
|
||||||
qf_get_nth_above_entry(adj_entry, &errornr, n);
|
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 ex_cbelow(exarg_T *eap)
|
void ex_cbelow(exarg_T *eap)
|
||||||
{
|
{
|
||||||
qf_info_T *qi;
|
qf_info_T *qi;
|
||||||
qf_list_T *qfl;
|
qf_list_T *qfl;
|
||||||
int dir;
|
int dir;
|
||||||
int buf_has_flag;
|
int buf_has_flag;
|
||||||
int errornr = 0;
|
|
||||||
|
|
||||||
if (eap->addr_count > 0 && eap->line2 <= 0) {
|
if (eap->addr_count > 0 && eap->line2 <= 0) {
|
||||||
EMSG(_(e_invrange));
|
EMSG(_(e_invrange));
|
||||||
@ -4754,7 +4842,8 @@ void 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;
|
||||||
@ -4775,14 +4864,30 @@ void 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_T 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++;
|
||||||
|
const int 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);
|
||||||
|
@ -40,6 +40,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')
|
||||||
@ -75,6 +77,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')
|
||||||
@ -4201,17 +4205,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')
|
||||||
@ -4225,39 +4234,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
|
||||||
|
|
||||||
@ -4268,27 +4312,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')
|
||||||
|
Loading…
Reference in New Issue
Block a user