aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/quickfix.txt7
-rw-r--r--src/nvim/eval.c24
-rw-r--r--src/nvim/ex_cmds.lua70
-rw-r--r--src/nvim/ex_cmds2.c2
-rw-r--r--src/nvim/ex_cmds_defs.h4
-rw-r--r--src/nvim/ex_docmd.c66
-rw-r--r--src/nvim/quickfix.c13
-rw-r--r--src/nvim/testdir/test_quickfix.vim48
8 files changed, 165 insertions, 69 deletions
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index d6ff3ea9ea..948b00c7c0 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -74,7 +74,7 @@ processing a quickfix or location list command, it will be aborted.
*:cc*
:cc[!] [nr] Display error [nr]. If [nr] is omitted, the same
- error is displayed again. Without [!] this doesn't
+:[nr]cc[!] error is displayed again. Without [!] this doesn't
work when jumping to another buffer, the current buffer
has been changed, there is the only window for the
buffer and both 'hidden' and 'autowrite' are off.
@@ -83,10 +83,13 @@ processing a quickfix or location list command, it will be aborted.
there is another window for this buffer.
The 'switchbuf' settings are respected when jumping
to a buffer.
+ When used in the quickfix window the line number can
+ be used, including "." for the current line and "$"
+ for the last line.
*:ll*
:ll[!] [nr] Same as ":cc", except the location list for the
- current window is used instead of the quickfix list.
+:[nr]ll[!] current window is used instead of the quickfix list.
*:cn* *:cne* *:cnext* *E553*
:[count]cn[ext][!] Display the [count] next error in the list that
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index f60504de5e..8a1556320c 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -5948,6 +5948,19 @@ int assert_exception(typval_T *argvars)
return 0;
}
+static void assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars,
+ const char *cmd)
+ FUNC_ATTR_NONNULL_ALL
+{
+ if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN) {
+ char *const tofree = encode_tv2echo(&argvars[2], NULL);
+ ga_concat(gap, (char_u *)tofree);
+ xfree(tofree);
+ } else {
+ ga_concat(gap, (char_u *)cmd);
+ }
+}
+
int assert_fails(typval_T *argvars)
FUNC_ATTR_NONNULL_ALL
{
@@ -5966,14 +5979,7 @@ int assert_fails(typval_T *argvars)
if (!called_emsg) {
prepare_assert_error(&ga);
ga_concat(&ga, (const char_u *)"command did not fail: ");
- if (argvars[1].v_type != VAR_UNKNOWN
- && argvars[2].v_type != VAR_UNKNOWN) {
- char *const tofree = encode_tv2echo(&argvars[2], NULL);
- ga_concat(&ga, (char_u *)tofree);
- xfree(tofree);
- } else {
- ga_concat(&ga, (const char_u *)cmd);
- }
+ assert_append_cmd_or_arg(&ga, argvars, cmd);
assert_error(&ga);
ga_clear(&ga);
ret = 1;
@@ -5986,6 +5992,8 @@ int assert_fails(typval_T *argvars)
prepare_assert_error(&ga);
fill_assert_error(&ga, &argvars[2], NULL, &argvars[1],
&vimvars[VV_ERRMSG].vv_tv, ASSERT_OTHER);
+ ga_concat(&ga, (char_u *)": ");
+ assert_append_cmd_or_arg(&ga, argvars, cmd);
assert_error(&ga);
ga_clear(&ga);
ret = 1;
diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua
index 1c2a66a0b9..60faae3268 100644
--- a/src/nvim/ex_cmds.lua
+++ b/src/nvim/ex_cmds.lua
@@ -297,13 +297,13 @@ module.cmds = {
{
command='cNext',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
command='cNfile',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -320,8 +320,8 @@ module.cmds = {
},
{
command='cabove',
- flags=bit.bor(RANGE, TRLBAR),
- addr_type='ADDR_OTHER',
+ flags=bit.bor(RANGE, COUNT, TRLBAR),
+ addr_type='ADDR_UNSIGNED',
func='ex_cbelow',
},
{
@@ -362,8 +362,8 @@ module.cmds = {
},
{
command='cbelow',
- flags=bit.bor(RANGE, TRLBAR),
- addr_type='ADDR_OTHER',
+ flags=bit.bor(RANGE, COUNT, TRLBAR),
+ addr_type='ADDR_UNSIGNED',
func='ex_cbelow',
},
{
@@ -375,7 +375,7 @@ module.cmds = {
{
command='cc',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_QUICKFIX',
func='ex_cc',
},
{
@@ -393,7 +393,7 @@ module.cmds = {
{
command='cdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL),
- addr_type='ADDR_QUICKFIX',
+ addr_type='ADDR_QUICKFIX_VALID',
func='ex_listdo',
},
{
@@ -419,13 +419,13 @@ module.cmds = {
{
command='cfdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL),
- addr_type='ADDR_QUICKFIX',
+ addr_type='ADDR_QUICKFIX_VALID',
func='ex_listdo',
},
{
command='cfirst',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
@@ -491,7 +491,7 @@ module.cmds = {
{
command='clast',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
@@ -527,19 +527,19 @@ module.cmds = {
{
command='cnext',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
command='cnewer',
flags=bit.bor(RANGE, COUNT, TRLBAR),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='qf_age',
},
{
command='cnfile',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -569,7 +569,7 @@ module.cmds = {
{
command='colder',
flags=bit.bor(RANGE, COUNT, TRLBAR),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='qf_age',
},
{
@@ -623,7 +623,7 @@ module.cmds = {
{
command='cprevious',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -635,13 +635,13 @@ module.cmds = {
{
command='cquit',
flags=bit.bor(RANGE, COUNT, ZEROR, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cquit',
},
{
command='crewind',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
@@ -1265,13 +1265,13 @@ module.cmds = {
{
command='lNext',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
command='lNfile',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -1282,8 +1282,8 @@ module.cmds = {
},
{
command='labove',
- flags=bit.bor(RANGE, TRLBAR),
- addr_type='ADDR_OTHER',
+ flags=bit.bor(RANGE, COUNT, TRLBAR),
+ addr_type='ADDR_UNSIGNED',
func='ex_cbelow',
},
{
@@ -1324,8 +1324,8 @@ module.cmds = {
},
{
command='lbelow',
- flags=bit.bor(RANGE, TRLBAR),
- addr_type='ADDR_OTHER',
+ flags=bit.bor(RANGE, COUNT, TRLBAR),
+ addr_type='ADDR_UNSIGNED',
func='ex_cbelow',
},
{
@@ -1361,7 +1361,7 @@ module.cmds = {
{
command='ldo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL),
- addr_type='ADDR_QUICKFIX',
+ addr_type='ADDR_QUICKFIX_VALID',
func='ex_listdo',
},
{
@@ -1399,13 +1399,13 @@ module.cmds = {
{
command='lfdo',
flags=bit.bor(BANG, NEEDARG, EXTRA, NOTRLCOM, RANGE, DFLALL),
- addr_type='ADDR_QUICKFIX',
+ addr_type='ADDR_QUICKFIX_VALID',
func='ex_listdo',
},
{
command='lfirst',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
@@ -1453,13 +1453,13 @@ module.cmds = {
{
command='ll',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_QUICKFIX',
func='ex_cc',
},
{
command='llast',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
@@ -1495,19 +1495,19 @@ module.cmds = {
{
command='lnext',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
command='lnewer',
flags=bit.bor(RANGE, COUNT, TRLBAR),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='qf_age',
},
{
command='lnfile',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -1537,7 +1537,7 @@ module.cmds = {
{
command='lolder',
flags=bit.bor(RANGE, COUNT, TRLBAR),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='qf_age',
},
{
@@ -1549,7 +1549,7 @@ module.cmds = {
{
command='lprevious',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cnext',
},
{
@@ -1561,7 +1561,7 @@ module.cmds = {
{
command='lrewind',
flags=bit.bor(RANGE, COUNT, TRLBAR, BANG),
- addr_type='ADDR_OTHER',
+ addr_type='ADDR_UNSIGNED',
func='ex_cc',
},
{
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index bde584d27e..c400975108 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -2113,7 +2113,7 @@ void ex_listdo(exarg_T *eap)
}
} else if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
|| eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo) {
- qf_size = qf_get_size(eap);
+ qf_size = qf_get_valid_size(eap);
assert(eap->line1 >= 0);
if (qf_size == 0 || (size_t)eap->line1 > qf_size) {
buf = NULL;
diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h
index 07a09e3a2e..4a16b914fd 100644
--- a/src/nvim/ex_cmds_defs.h
+++ b/src/nvim/ex_cmds_defs.h
@@ -74,8 +74,10 @@ typedef enum {
ADDR_BUFFERS, // buffer number
ADDR_TABS, // tab page number
ADDR_TABS_RELATIVE, // Tab page that only relative
+ ADDR_QUICKFIX_VALID, // quickfix list valid entry number
ADDR_QUICKFIX, // quickfix list entry number
- ADDR_OTHER, // something else
+ ADDR_UNSIGNED, // positive count or zero, defaults to 1
+ ADDR_OTHER, // something else, use line number for '$', '%', etc.
ADDR_NONE // no range used
} cmd_addr_T;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index d4764aa504..c5d64d2e25 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -1383,6 +1383,10 @@ static char_u * do_one_cmd(char_u **cmdlinep,
if (ea.cmdidx == CMD_wincmd && p != NULL) {
get_wincmd_addr_type(skipwhite(p), &ea);
}
+ // :.cc in quickfix window uses line number
+ if ((ea.cmdidx == CMD_cc || ea.cmdidx == CMD_ll) && bt_quickfix(curbuf)) {
+ ea.addr_type = ADDR_OTHER;
+ }
}
ea.cmd = cmd;
@@ -1730,14 +1734,17 @@ static char_u * do_one_cmd(char_u **cmdlinep,
ea.line2 = ARGCOUNT;
}
break;
- case ADDR_QUICKFIX:
- ea.line2 = qf_get_size(&ea);
+ case ADDR_QUICKFIX_VALID:
+ ea.line2 = qf_get_valid_size(&ea);
if (ea.line2 == 0) {
ea.line2 = 1;
}
break;
case ADDR_NONE:
- IEMSG(_("INTERNAL: Cannot use DFLALL with ADDR_NONE"));
+ case ADDR_UNSIGNED:
+ case ADDR_QUICKFIX:
+ IEMSG(_("INTERNAL: Cannot use DFLALL "
+ "with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX"));
break;
}
}
@@ -2347,9 +2354,13 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
eap->line2 = CURRENT_TAB_NR;
break;
case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
eap->line2 = 1;
break;
case ADDR_QUICKFIX:
+ eap->line2 = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
eap->line2 = qf_get_cur_valid_idx(eap);
break;
case ADDR_NONE:
@@ -2403,6 +2414,8 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
}
break;
case ADDR_TABS_RELATIVE:
+ case ADDR_UNSIGNED:
+ case ADDR_QUICKFIX:
*errormsg = (char_u *)_(e_invrange);
return FAIL;
case ADDR_ARGUMENTS:
@@ -2413,9 +2426,9 @@ int parse_cmd_address(exarg_T *eap, char_u **errormsg, bool silent)
eap->line2 = ARGCOUNT;
}
break;
- case ADDR_QUICKFIX:
+ case ADDR_QUICKFIX_VALID:
eap->line1 = 1;
- eap->line2 = qf_get_size(eap);
+ eap->line2 = qf_get_valid_size(eap);
if (eap->line2 == 0) {
eap->line2 = 1;
}
@@ -2524,14 +2537,13 @@ static void append_command(char_u *cmd)
*d = NUL;
}
-/*
- * Find an Ex command by its name, either built-in or user.
- * Start of the name can be found at eap->cmd.
- * Returns pointer to char after the command name.
- * "full" is set to TRUE if the whole command name matched.
- * Returns NULL for an ambiguous user command.
- */
+// Find an Ex command by its name, either built-in or user.
+// Start of the name can be found at eap->cmd.
+// Sets eap->cmdidx and returns a pointer to char after the command name.
+// "full" is set to TRUE if the whole command name matched.
+// Returns NULL for an ambiguous user command.
static char_u *find_command(exarg_T *eap, int *full)
+ FUNC_ATTR_NONNULL_ARG(1)
{
int len;
char_u *p;
@@ -3761,11 +3773,15 @@ static linenr_T get_address(exarg_T *eap,
break;
case ADDR_TABS_RELATIVE:
case ADDR_NONE:
+ case ADDR_UNSIGNED:
EMSG(_(e_invrange));
cmd = NULL;
goto error;
break;
case ADDR_QUICKFIX:
+ lnum = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
lnum = qf_get_cur_valid_idx(eap);
break;
}
@@ -3802,6 +3818,7 @@ static linenr_T get_address(exarg_T *eap,
break;
case ADDR_TABS_RELATIVE:
case ADDR_NONE:
+ case ADDR_UNSIGNED:
EMSG(_(e_invrange));
cmd = NULL;
goto error;
@@ -3812,6 +3829,12 @@ static linenr_T get_address(exarg_T *eap,
lnum = 1;
}
break;
+ case ADDR_QUICKFIX_VALID:
+ lnum = qf_get_valid_size(eap);
+ if (lnum == 0) {
+ lnum = 1;
+ }
+ break;
}
break;
@@ -3964,9 +3987,14 @@ static linenr_T get_address(exarg_T *eap,
lnum = 1;
break;
case ADDR_QUICKFIX:
+ lnum = qf_get_cur_idx(eap);
+ break;
+ case ADDR_QUICKFIX_VALID:
lnum = qf_get_cur_valid_idx(eap);
break;
case ADDR_NONE:
+ case ADDR_UNSIGNED:
+ lnum = 0;
break;
}
}
@@ -4115,7 +4143,19 @@ static char_u *invalid_range(exarg_T *eap)
break;
case ADDR_QUICKFIX:
assert(eap->line2 >= 0);
- if (eap->line2 != 1 && (size_t)eap->line2 > qf_get_size(eap)) {
+ // No error for value that is too big, will use the last entry.
+ if (eap->line2 <= 0) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_QUICKFIX_VALID:
+ if ((eap->line2 != 1 && (size_t)eap->line2 > qf_get_valid_size(eap))
+ || eap->line2 < 0) {
+ return (char_u *)_(e_invrange);
+ }
+ break;
+ case ADDR_UNSIGNED:
+ if (eap->line2 < 0) {
return (char_u *)_(e_invrange);
}
break;
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 2780553bdc..f72a5e0020 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -4269,11 +4269,22 @@ static char_u *get_mef_name(void)
return name;
}
-/// Returns the number of valid entries in the current quickfix/location list.
+/// Returns the number of entries in the current quickfix/location list.
size_t qf_get_size(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
{
qf_info_T *qi;
+
+ if ((qi = qf_cmd_get_stack(eap, false)) == NULL) {
+ return 0;
+ }
+ return (size_t)qf_get_curlist(qi)->qf_count;
+}
+
+/// Returns the number of valid entries in the current quickfix/location list.
+size_t qf_get_valid_size(exarg_T *eap)
+{
+ qf_info_T *qi;
qf_list_T *qfl;
if ((qi = qf_cmd_get_stack(eap, false)) == NULL) {
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 563dbd90d9..49d66d8c1f 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -29,7 +29,7 @@ func s:setup_commands(cchar)
command! -count -nargs=* -bang Xprev <mods><count>cprev<bang> <args>
command! -nargs=* -bang Xfirst <mods>cfirst<bang> <args>
command! -nargs=* -bang Xlast <mods>clast<bang> <args>
- command! -nargs=* -bang -range Xnfile <mods><count>cnfile<bang> <args>
+ command! -count -nargs=* -bang Xnfile <mods><count>cnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>cpfile<bang> <args>
command! -nargs=* Xexpr <mods>cexpr <args>
command! -range -nargs=* Xvimgrep <mods><count>vimgrep <args>
@@ -64,7 +64,7 @@ func s:setup_commands(cchar)
command! -count -nargs=* -bang Xprev <mods><count>lprev<bang> <args>
command! -nargs=* -bang Xfirst <mods>lfirst<bang> <args>
command! -nargs=* -bang Xlast <mods>llast<bang> <args>
- command! -nargs=* -bang -range Xnfile <mods><count>lnfile<bang> <args>
+ command! -count -nargs=* -bang Xnfile <mods><count>lnfile<bang> <args>
command! -nargs=* -bang Xpfile <mods>lpfile<bang> <args>
command! -nargs=* Xexpr <mods>lexpr <args>
command! -range -nargs=* Xvimgrep <mods><count>lvimgrep <args>
@@ -4286,13 +4286,9 @@ func Xtest_below(cchar)
" Invalid range
if a:cchar == 'c'
- call assert_fails('-2cbelow', 'E553:')
- " TODO: should go to first error in the current line?
- 0cabove
+ call assert_fails('-2cbelow', 'E16:')
else
- call assert_fails('-2lbelow', 'E553:')
- " TODO: should go to first error in the current line?
- 0labove
+ call assert_fails('-2lbelow', 'E16:')
endif
call delete('X1')
@@ -4306,6 +4302,42 @@ func Test_cbelow()
call Xtest_below('l')
endfunc
+func Test_quickfix_count()
+ let commands = [
+ \ 'cNext',
+ \ 'cNfile',
+ \ 'cabove',
+ \ 'cbelow',
+ \ 'cfirst',
+ \ 'clast',
+ \ 'cnewer',
+ \ 'cnext',
+ \ 'cnfile',
+ \ 'colder',
+ \ 'cprevious',
+ \ 'crewind',
+ \
+ \ 'lNext',
+ \ 'lNfile',
+ \ 'labove',
+ \ 'lbelow',
+ \ 'lfirst',
+ \ 'llast',
+ \ 'lnewer',
+ \ 'lnext',
+ \ 'lnfile',
+ \ 'lolder',
+ \ 'lprevious',
+ \ 'lrewind',
+ \ ]
+ for cmd in commands
+ call assert_fails('-1' .. cmd, 'E16:')
+ call assert_fails('.' .. cmd, 'E16:')
+ call assert_fails('%' .. cmd, 'E16:')
+ call assert_fails('$' .. cmd, 'E16:')
+ endfor
+endfunc
+
" Test for aborting quickfix commands using QuickFixCmdPre
func Xtest_qfcmd_abort(cchar)
call s:setup_commands(a:cchar)