changeset 16515:6e87a69b8e0c v8.1.1261

patch 8.1.1261: no error for quickfix commands with negative range commit https://github.com/vim/vim/commit/25190db225d63e185e77e043e694ef455b3cf304 Author: Bram Moolenaar <Bram@vim.org> Date: Sat May 4 15:05:28 2019 +0200 patch 8.1.1261: no error for quickfix commands with negative range Problem: No error for quickfix commands with negative range. Solution: Add ADDR_UNSIGNED and use it for quickfix commands. Make assert_fails() show the command if the error doesn't match.
author Bram Moolenaar <Bram@vim.org>
date Sat, 04 May 2019 15:15:05 +0200
parents 23780193686f
children c4a98e19390b
files runtime/doc/quickfix.txt src/eval.c src/ex_cmds.h src/ex_cmds2.c src/ex_docmd.c src/proto/quickfix.pro src/quickfix.c src/testdir/test_quickfix.vim src/version.c
diffstat 9 files changed, 177 insertions(+), 67 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -87,7 +87,7 @@ processing a quickfix or location list c
 
 							*: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.
@@ -96,10 +96,13 @@ processing a quickfix or location list c
 			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* *:cnext* *E553*
 :[count]cn[ext][!]	Display the [count] next error in the list that
--- a/src/eval.c
+++ b/src/eval.c
@@ -9595,14 +9595,27 @@ assert_beeps(typval_T *argvars)
     return ret;
 }
 
+    static void
+assert_append_cmd_or_arg(garray_T *gap, typval_T *argvars, char_u *cmd)
+{
+    char_u	*tofree;
+    char_u	numbuf[NUMBUFLEN];
+
+    if (argvars[1].v_type != VAR_UNKNOWN && argvars[2].v_type != VAR_UNKNOWN)
+    {
+	ga_concat(gap, echo_string(&argvars[2], &tofree, numbuf, 0));
+	vim_free(tofree);
+    }
+    else
+	ga_concat(gap, cmd);
+}
+
     int
 assert_fails(typval_T *argvars)
 {
     char_u	*cmd = tv_get_string_chk(&argvars[0]);
     garray_T	ga;
     int		ret = 0;
-    char_u	numbuf[NUMBUFLEN];
-    char_u	*tofree;
 
     called_emsg = FALSE;
     suppress_errthrow = TRUE;
@@ -9612,14 +9625,7 @@ assert_fails(typval_T *argvars)
     {
 	prepare_assert_error(&ga);
 	ga_concat(&ga, (char_u *)"command did not fail: ");
-	if (argvars[1].v_type != VAR_UNKNOWN
-					   && argvars[2].v_type != VAR_UNKNOWN)
-	{
-	    ga_concat(&ga, echo_string(&argvars[2], &tofree, numbuf, 0));
-	    vim_free(tofree);
-	}
-	else
-	    ga_concat(&ga, cmd);
+	assert_append_cmd_or_arg(&ga, argvars, cmd);
 	assert_error(&ga);
 	ga_clear(&ga);
 	ret = 1;
@@ -9635,6 +9641,8 @@ 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;
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -73,8 +73,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;
 #endif
@@ -92,7 +94,7 @@ typedef struct exarg exarg_T;
  * Not supported commands are included to avoid ambiguities.
  */
 #ifdef EX
-# undef EX	    /* just in case */
+# undef EX	    // just in case
 #endif
 #ifdef DO_DECLARE_EXCMD
 # define EX(a, b, c, d, e)  {(char_u *)b, c, (long_u)(d), e}
@@ -242,10 +244,10 @@ EX(CMD_change,		"change",	ex_change,
 			ADDR_LINES),
 EX(CMD_cNext,		"cNext",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cNfile,		"cNfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cabbrev,		"cabbrev",	ex_abbreviate,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
 			ADDR_NONE),
@@ -253,8 +255,8 @@ EX(CMD_cabclear,	"cabclear",	ex_abclear,
 			EXTRA|TRLBAR|CMDWIN,
 			ADDR_NONE),
 EX(CMD_cabove,		"cabove",	ex_cbelow,
-			RANGE|TRLBAR,
-			ADDR_OTHER),
+			RANGE|COUNT|TRLBAR,
+			ADDR_UNSIGNED),
 EX(CMD_caddbuffer,	"caddbuffer",	ex_cbuffer,
 			RANGE|WORD1|TRLBAR,
 			ADDR_OTHER),
@@ -274,14 +276,14 @@ EX(CMD_cbuffer,		"cbuffer",	ex_cbuffer,
 			BANG|RANGE|WORD1|TRLBAR,
 			ADDR_OTHER),
 EX(CMD_cbelow,		"cbelow",	ex_cbelow,
-			RANGE|TRLBAR,
-			ADDR_OTHER),
+			RANGE|COUNT|TRLBAR,
+			ADDR_UNSIGNED),
 EX(CMD_cbottom,		"cbottom",	ex_cbottom,
 			TRLBAR,
 			ADDR_NONE),
 EX(CMD_cc,		"cc",		ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_QUICKFIX),
 EX(CMD_cclose,		"cclose",	ex_cclose,
 			TRLBAR,
 			ADDR_NONE),
@@ -290,7 +292,7 @@ EX(CMD_cd,		"cd",		ex_cd,
 			ADDR_NONE),
 EX(CMD_cdo,		"cdo",		ex_listdo,
 			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|DFLALL,
-			ADDR_QUICKFIX),
+			ADDR_QUICKFIX_VALID),
 EX(CMD_center,		"center",	ex_align,
 			TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
 			ADDR_LINES),
@@ -302,10 +304,10 @@ EX(CMD_cfile,		"cfile",	ex_cfile,
 			ADDR_NONE),
 EX(CMD_cfdo,		"cfdo",		ex_listdo,
 			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|DFLALL,
-			ADDR_QUICKFIX),
+			ADDR_QUICKFIX_VALID),
 EX(CMD_cfirst,		"cfirst",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cgetfile,	"cgetfile",	ex_cfile,
 			TRLBAR|FILE1,
 			ADDR_NONE),
@@ -335,7 +337,7 @@ EX(CMD_clist,		"clist",	qf_list,
 			ADDR_NONE),
 EX(CMD_clast,		"clast",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_close,		"close",	ex_close,
 			BANG|RANGE|COUNT|TRLBAR|CMDWIN,
 			ADDR_WINDOWS),
@@ -353,13 +355,13 @@ EX(CMD_cmenu,		"cmenu",	ex_menu,
 			ADDR_OTHER),
 EX(CMD_cnext,		"cnext",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cnewer,		"cnewer",	qf_age,
 			RANGE|COUNT|TRLBAR,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cnfile,		"cnfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cnoremap,	"cnoremap",	ex_map,
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
 			ADDR_NONE),
@@ -374,7 +376,7 @@ EX(CMD_copy,		"copy",		ex_copymove,
 			ADDR_LINES),
 EX(CMD_colder,		"colder",	qf_age,
 			RANGE|COUNT|TRLBAR,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_colorscheme,	"colorscheme",	ex_colorscheme,
 			WORD1|TRLBAR|CMDWIN,
 			ADDR_NONE),
@@ -398,7 +400,7 @@ EX(CMD_copen,		"copen",	ex_copen,
 			ADDR_OTHER),
 EX(CMD_cprevious,	"cprevious",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cpfile,		"cpfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
 			ADDR_OTHER),
@@ -407,7 +409,7 @@ EX(CMD_cquit,		"cquit",	ex_cquit,
 			ADDR_NONE),
 EX(CMD_crewind,		"crewind",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_cscope,		"cscope",	ex_cscope,
 			EXTRA|NOTRLCOM|XFILE,
 			ADDR_NONE),
@@ -725,16 +727,16 @@ EX(CMD_list,		"list",		ex_print,
 			ADDR_LINES),
 EX(CMD_lNext,		"lNext",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lNfile,		"lNfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_last,		"last",		ex_last,
 			EXTRA|BANG|EDITCMD|ARGOPT|TRLBAR,
 			ADDR_NONE),
 EX(CMD_labove,		"labove",	ex_cbelow,
-			RANGE|TRLBAR,
-			ADDR_OTHER),
+			RANGE|COUNT|TRLBAR,
+			ADDR_UNSIGNED),
 EX(CMD_language,	"language",	ex_language,
 			EXTRA|TRLBAR|CMDWIN,
 			ADDR_NONE),
@@ -754,8 +756,8 @@ EX(CMD_lbuffer,		"lbuffer",	ex_cbuffer,
 			BANG|RANGE|WORD1|TRLBAR,
 			ADDR_OTHER),
 EX(CMD_lbelow,		"lbelow",	ex_cbelow,
-			RANGE|TRLBAR,
-			ADDR_OTHER),
+			RANGE|COUNT|TRLBAR,
+			ADDR_UNSIGNED),
 EX(CMD_lbottom,		"lbottom",	ex_cbottom,
 			TRLBAR,
 			ADDR_NONE),
@@ -773,7 +775,7 @@ EX(CMD_lcscope,		"lcscope",	ex_cscope,
 			ADDR_NONE),
 EX(CMD_ldo,		"ldo",		ex_listdo,
 			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|DFLALL,
-			ADDR_QUICKFIX),
+			ADDR_QUICKFIX_VALID),
 EX(CMD_left,		"left",		ex_align,
 			TRLBAR|RANGE|WHOLEFOLD|EXTRA|CMDWIN|MODIFY,
 			ADDR_LINES),
@@ -791,10 +793,10 @@ EX(CMD_lfile,		"lfile",	ex_cfile,
 			ADDR_NONE),
 EX(CMD_lfdo,		"lfdo",		ex_listdo,
 			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|DFLALL,
-			ADDR_QUICKFIX),
+			ADDR_QUICKFIX_VALID),
 EX(CMD_lfirst,		"lfirst",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lgetfile,	"lgetfile",	ex_cfile,
 			TRLBAR|FILE1,
 			ADDR_NONE),
@@ -818,10 +820,10 @@ EX(CMD_lhistory,	"lhistory",	qf_history,
 			ADDR_NONE),
 EX(CMD_ll,		"ll",		ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_QUICKFIX),
 EX(CMD_llast,		"llast",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_llist,		"llist",	qf_list,
 			BANG|EXTRA|TRLBAR|CMDWIN,
 			ADDR_NONE),
@@ -839,13 +841,13 @@ EX(CMD_lnoremap,	"lnoremap",	ex_map,
 			ADDR_NONE),
 EX(CMD_lnext,		"lnext",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lnewer,		"lnewer",	qf_age,
 			RANGE|COUNT|TRLBAR,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lnfile,		"lnfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_loadview,	"loadview",	ex_loadview,
 			FILE1|TRLBAR,
 			ADDR_NONE),
@@ -860,19 +862,19 @@ EX(CMD_lockvar,		"lockvar",	ex_lockvar,
 			ADDR_NONE),
 EX(CMD_lolder,		"lolder",	qf_age,
 			RANGE|COUNT|TRLBAR,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lopen,		"lopen",	ex_copen,
 			RANGE|COUNT|TRLBAR,
 			ADDR_OTHER),
 EX(CMD_lprevious,	"lprevious",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_lpfile,		"lpfile",	ex_cnext,
 			RANGE|COUNT|TRLBAR|BANG,
 			ADDR_OTHER),
 EX(CMD_lrewind,		"lrewind",	ex_cc,
 			RANGE|COUNT|TRLBAR|BANG,
-			ADDR_OTHER),
+			ADDR_UNSIGNED),
 EX(CMD_ltag,		"ltag",	ex_tag,
 			TRLBAR|BANG|WORD1,
 			ADDR_NONE),
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2132,7 +2132,7 @@ 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);
 	    if (qf_size <= 0 || eap->line1 > qf_size)
 		buf = NULL;
 	    else
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1786,7 +1786,7 @@ do_one_cmd(
  * is equal to the lower.
  */
 
-    /* ea.addr_type for user commands is set by find_ucmd */
+    // ea.addr_type for user commands is set by find_ucmd
     if (!IS_USER_CMDIDX(ea.cmdidx))
     {
 	if (ea.cmdidx != CMD_SIZE)
@@ -1794,9 +1794,14 @@ do_one_cmd(
 	else
 	    ea.addr_type = ADDR_LINES;
 
-	/* :wincmd range depends on the argument. */
+	// :wincmd range depends on the argument.
 	if (ea.cmdidx == CMD_wincmd && p != NULL)
 	    get_wincmd_addr_type(skipwhite(p), &ea);
+#ifdef FEAT_QUICKFIX
+	// :.cc in quickfix window uses line number
+	if ((ea.cmdidx == CMD_cc || ea.cmdidx == CMD_ll) && bt_quickfix(curbuf))
+	    ea.addr_type = ADDR_OTHER;
+#endif
     }
 
     ea.cmd = cmd;
@@ -2229,15 +2234,17 @@ do_one_cmd(
 		else
 		    ea.line2 = ARGCOUNT;
 		break;
-	    case ADDR_QUICKFIX:
+	    case ADDR_QUICKFIX_VALID:
 #ifdef FEAT_QUICKFIX
-		ea.line2 = qf_get_size(&ea);
+		ea.line2 = qf_get_valid_size(&ea);
 		if (ea.line2 == 0)
 		    ea.line2 = 1;
 #endif
 		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;
 	}
     }
@@ -2905,10 +2912,16 @@ parse_cmd_address(exarg_T *eap, char **e
 		eap->line2 = CURRENT_TAB_NR;
 		break;
 	    case ADDR_TABS_RELATIVE:
+	    case ADDR_UNSIGNED:
 		eap->line2 = 1;
 		break;
 	    case ADDR_QUICKFIX:
 #ifdef FEAT_QUICKFIX
+		eap->line2 = qf_get_cur_idx(eap);
+#endif
+		break;
+	    case ADDR_QUICKFIX_VALID:
+#ifdef FEAT_QUICKFIX
 		eap->line2 = qf_get_cur_valid_idx(eap);
 #endif
 		break;
@@ -2969,6 +2982,8 @@ parse_cmd_address(exarg_T *eap, char **e
 			}
 			break;
 		    case ADDR_TABS_RELATIVE:
+		    case ADDR_UNSIGNED:
+		    case ADDR_QUICKFIX:
 			*errormsg = _(e_invrange);
 			return FAIL;
 		    case ADDR_ARGUMENTS:
@@ -2980,10 +2995,10 @@ parse_cmd_address(exarg_T *eap, char **e
 			    eap->line2 = ARGCOUNT;
 			}
 			break;
-		    case ADDR_QUICKFIX:
+		    case ADDR_QUICKFIX_VALID:
 #ifdef FEAT_QUICKFIX
 			eap->line1 = 1;
-			eap->line2 = qf_get_size(eap);
+			eap->line2 = qf_get_valid_size(eap);
 			if (eap->line2 == 0)
 			    eap->line2 = 1;
 #endif
@@ -3102,7 +3117,7 @@ append_command(char_u *cmd)
 /*
  * 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.
+ * 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.
  */
@@ -4268,12 +4283,18 @@ get_address(
 			break;
 		    case ADDR_TABS_RELATIVE:
 		    case ADDR_NONE:
+		    case ADDR_UNSIGNED:
 			emsg(_(e_invrange));
 			cmd = NULL;
 			goto error;
 			break;
 		    case ADDR_QUICKFIX:
 #ifdef FEAT_QUICKFIX
+			lnum = qf_get_cur_idx(eap);
+#endif
+			break;
+		    case ADDR_QUICKFIX_VALID:
+#ifdef FEAT_QUICKFIX
 			lnum = qf_get_cur_valid_idx(eap);
 #endif
 			break;
@@ -4312,6 +4333,7 @@ get_address(
 			break;
 		    case ADDR_TABS_RELATIVE:
 		    case ADDR_NONE:
+		    case ADDR_UNSIGNED:
 			emsg(_(e_invrange));
 			cmd = NULL;
 			goto error;
@@ -4323,6 +4345,13 @@ get_address(
 			    lnum = 1;
 #endif
 			break;
+		    case ADDR_QUICKFIX_VALID:
+#ifdef FEAT_QUICKFIX
+			lnum = qf_get_valid_size(eap);
+			if (lnum == 0)
+			    lnum = 1;
+#endif
+			break;
 		}
 		break;
 
@@ -4503,10 +4532,17 @@ get_address(
 			break;
 		    case ADDR_QUICKFIX:
 #ifdef FEAT_QUICKFIX
+			lnum = qf_get_cur_idx(eap);
+#endif
+			break;
+		    case ADDR_QUICKFIX_VALID:
+#ifdef FEAT_QUICKFIX
 			lnum = qf_get_cur_valid_idx(eap);
 #endif
 			break;
 		    case ADDR_NONE:
+		    case ADDR_UNSIGNED:
+			lnum = 0;
 			break;
 		}
 	    }
@@ -4603,6 +4639,7 @@ ex_script_ni(exarg_T *eap)
 invalid_range(exarg_T *eap)
 {
     buf_T	*buf;
+
     if (       eap->line1 < 0
 	    || eap->line2 < 0
 	    || eap->line1 > eap->line2)
@@ -4664,10 +4701,22 @@ invalid_range(exarg_T *eap)
 		break;
 	    case ADDR_QUICKFIX:
 #ifdef FEAT_QUICKFIX
-		if (eap->line2 != 1 && eap->line2 > qf_get_size(eap))
+		// No error for value that is too big, will use the last entry.
+		if (eap->line2 <= 0)
 		    return _(e_invrange);
 #endif
 		break;
+	    case ADDR_QUICKFIX_VALID:
+#ifdef FEAT_QUICKFIX
+		if ((eap->line2 != 1 && eap->line2 > qf_get_valid_size(eap))
+			|| eap->line2 < 0)
+		    return _(e_invrange);
+#endif
+		break;
+	    case ADDR_UNSIGNED:
+		if (eap->line2 < 0)
+		    return _(e_invrange);
+		break;
 	    case ADDR_NONE:
 		// Will give an error elsewhere.
 		break;
--- a/src/proto/quickfix.pro
+++ b/src/proto/quickfix.pro
@@ -19,6 +19,7 @@ linenr_T qf_current_entry(win_T *wp);
 int grep_internal(cmdidx_T cmdidx);
 void ex_make(exarg_T *eap);
 int qf_get_size(exarg_T *eap);
+int qf_get_valid_size(exarg_T *eap);
 int qf_get_cur_idx(exarg_T *eap);
 int qf_get_cur_valid_idx(exarg_T *eap);
 void ex_cc(exarg_T *eap);
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -4828,10 +4828,23 @@ cleanup:
 }
 
 /*
+ * Returns the number of entries in the current quickfix/location list.
+ */
+    int
+qf_get_size(exarg_T *eap)
+{
+    qf_info_T	*qi;
+
+    if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
+	return 0;
+    return qf_get_curlist(qi)->qf_count;
+}
+
+/*
  * Returns the number of valid entries in the current quickfix/location list.
  */
     int
-qf_get_size(exarg_T *eap)
+qf_get_valid_size(exarg_T *eap)
 {
     qf_info_T	*qi;
     qf_list_T	*qfl;
--- a/src/testdir/test_quickfix.vim
+++ b/src/testdir/test_quickfix.vim
@@ -28,7 +28,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>
@@ -63,7 +63,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>
@@ -4126,13 +4126,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')
@@ -4145,3 +4141,39 @@ func Test_cbelow()
   call Xtest_below('c')
   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
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1261,
+/**/
     1260,
 /**/
     1259,