On 22:41 Sat 06 Dec     , Bram Moolenaar wrote:
> 
> Marcin Szamotulski wrote:
> 
> > On 09:32 Thu 04 Dec     , Marcin Szamotulski wrote:
> > > On 14:31 Wed 03 Dec     , Matteo Cavalleri wrote:
> > > > I'm using the code I posted a while ago in this thread, I'm copying it 
> > > > here again :) (it was without the -buffer option, I'm adding it now)
> > > > 
> > > > create and source this file 
> > > > 
> > > > ------------------------ 
> > > > function! Test(f,l) 
> > > >         echom a:f." - ".a:l 
> > > > endfunction 
> > > > command! -buffer -range=% RangeTest call Test(<line1>, <line2>) 
> > > > ------------------------ 
> > > > 
> > > > then select a couple of lines and do: 
> > > > 
> > > > :'<,'>RangeTest 
> > > 
> > > I cannot reproduce it with the patch I sent.
> > > 
> > > Best regards,
> > > Marcin
> > 
> > Dear Bram,
> > 
> > The attached patch adds support for user commands.  For example this
> > patch makes it possible to define the following commands:
> >     com RangeLines :echo <line1>.' '.<line2>
> > which is the same as:
> >     com -addr=lines RangeLines :echo <line1>.' '.<line2>
> >     com -addr=arguments RangeArguments :echo <line1>.' '.<line2>
> >     com -addr=loaded_buffers RangeLoadedBuffers :echo <line1>.' '.<line2>
> >     com -addr=buffers RangeBuffers :echo <line1>.' '.<line2>
> >     com -addr=windows RangeWindows :echo <line1>.' '.<line2>
> >     com -addr=tabs RangeTabs :echo <line1>.' '.<line2>
> > 
> > The patch also includes a test, and it includes all the fixes
> > I published before in one place.
> 
> Thanks, I'll look into it soon.

Once again, now it does not break the tiny build.

I also include another patch (on top of that) which adds support for
counts in :argdo, :bufdo, :tabdo and :windo commands.

Best regards,
Marcin

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to vim_dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
diff --git a/runtime/doc/map.txt b/runtime/doc/map.txt
index 1be2827..ad21d64 100644
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1358,6 +1358,19 @@ Possible attributes are:
 Note that -range=N and -count=N are mutually exclusive - only one should be
 specified.
 
+					*E889* *:command-addr*
+It is possible that the special characters in the range like ., $ or % which
+by default correspond to the current line, last line and the whole buffer,
+relate to arguments, (loaded) buffers, windows or tab pages.
+
+Possible values are:
+	-addr=lines		Range of lines (this is the default)
+	-addr=arguments		Range for arguments
+	-addr=buffers		Range for (all) buffers
+	-addr=loaded_buffers	Range for only loaded buffers
+	-addr=windows		Range for windows
+	-addr=tabs		Range for tab pages
+
 Special cases				*:command-bang* *:command-bar*
 					*:command-register* *:command-buffer*
 There are some special cases as well:
diff --git a/src/Makefile b/src/Makefile
index 13fe70b..5a5518d 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1896,6 +1896,7 @@ test1 \
 	test_breakindent \
 	test_changelist \
 	test_close_count \
+	test_command_count \
 	test_eval \
 	test_insertcount \
 	test_listlbr \
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 5574ea7..fc6a8ac 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -63,7 +63,7 @@
 #define ADDR_WINDOWS		1
 #define ADDR_ARGUMENTS		2
 #define ADDR_LOADED_BUFFERS	3
-#define ADDR_UNLOADED_BUFFERS	4
+#define ADDR_BUFFERS	4
 #define ADDR_TABS		5
 
 #ifndef DO_DECLARE_EXCMD
@@ -161,7 +161,7 @@ EX(CMD_aunmenu,		"aunmenu",	ex_menu,
 			ADDR_LINES),
 EX(CMD_buffer,		"buffer",	ex_buffer,
 			BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR,
-			ADDR_UNLOADED_BUFFERS),
+			ADDR_BUFFERS),
 EX(CMD_bNext,		"bNext",	ex_bprevious,
 			BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
 			ADDR_LINES),
@@ -227,7 +227,7 @@ EX(CMD_bunload,		"bunload",	ex_bunload,
 			ADDR_LOADED_BUFFERS),
 EX(CMD_bwipeout,	"bwipeout",	ex_bunload,
 			BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR,
-			ADDR_UNLOADED_BUFFERS),
+			ADDR_BUFFERS),
 EX(CMD_change,		"change",	ex_change,
 			BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY,
 			ADDR_LINES),
@@ -1184,7 +1184,7 @@ EX(CMD_saveas,		"saveas",	ex_write,
 			ADDR_LINES),
 EX(CMD_sbuffer,		"sbuffer",	ex_buffer,
 			BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR,
-			ADDR_UNLOADED_BUFFERS),
+			ADDR_BUFFERS),
 EX(CMD_sbNext,		"sbNext",	ex_bprevious,
 			RANGE|NOTADR|COUNT|EDITCMD|TRLBAR,
 			ADDR_LINES),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 607dbd9..a1401e4 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -27,6 +27,7 @@ typedef struct ucmd
     char_u	*uc_rep;	/* The command's replacement string */
     long	uc_def;		/* The default value for a range/count */
     int		uc_compl;	/* completion type */
+    int		uc_addr_type;	/* The command's address type */
 # ifdef FEAT_EVAL
     scid_T	uc_scriptID;	/* SID where the command was defined */
 #  ifdef FEAT_CMDL_COMPL
@@ -2136,7 +2137,11 @@ do_one_cmd(cmdlinep, sourcing,
        )
 	ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type;
     else
+#ifdef FEAT_USR_CMDS
+	if (ea.cmdidx != CMD_USER)
+#endif
 	ea.addr_type = ADDR_LINES;
+    /* ea.addr_type for user commands is set by find_ucmd */
     ea.cmd = cmd;
 
     /* repeat for all ',' or ';' separated addresses */
@@ -2157,7 +2162,7 @@ do_one_cmd(cmdlinep, sourcing,
 		ea.line2 = curwin->w_arg_idx + 1;
 		break;
 	    case ADDR_LOADED_BUFFERS:
-	    case ADDR_UNLOADED_BUFFERS:
+	    case ADDR_BUFFERS:
 		ea.line2 = curbuf->b_fnum;
 		break;
 	    case ADDR_TABS:
@@ -2191,18 +2196,50 @@ do_one_cmd(cmdlinep, sourcing,
 			    buf = buf->b_prev;
 			ea.line2 = buf->b_fnum;
 			break;
-		    case ADDR_UNLOADED_BUFFERS:
+		    case ADDR_BUFFERS:
 			ea.line1 = firstbuf->b_fnum;
 			ea.line2 = lastbuf->b_fnum;
 			break;
 		    case ADDR_WINDOWS:
+#ifdef FEAT_USR_CMDS
+			if (IS_USER_CMDIDX(ea.cmdidx))
+			{
+			    ea.line1 = 1;
+			    ea.line2 = LAST_WIN_NR;
+			}
+			else
+#endif
+			{
+			    /* there is no vim command which uses '%' and
+			     * ADDR_WINDOWS */
+			    errormsg = (char_u *)_(e_invrange);
+			    goto doend;
+			}
+			break;
 		    case ADDR_TABS:
-			errormsg = (char_u *)_(e_invrange);
-			goto doend;
+#ifdef FEAT_USR_CMDS
+			if (IS_USER_CMDIDX(ea.cmdidx))
+			{
+			    ea.line1 = 1;
+			    ea.line2 = LAST_TAB_NR;
+			}
+			else
+#endif
+			{
+			    /* there is no vim command which uses '%' and
+			     * ADDR_TABS */
+			    errormsg = (char_u *)_(e_invrange);
+			    goto doend;
+			}
 			break;
 		    case ADDR_ARGUMENTS:
-			ea.line1 = 1;
-			ea.line2 = ARGCOUNT;
+			if (!ARGCOUNT)
+			    ea.line1 = ea.line2 = 0;
+			else
+			{
+			    ea.line1 = 1;
+			    ea.line2 = ARGCOUNT;
+			}
 			break;
 		}
 		++ea.addr_count;
@@ -2629,8 +2666,45 @@ do_one_cmd(cmdlinep, sourcing,
 
     if ((ea.argt & DFLALL) && ea.addr_count == 0)
     {
-	ea.line1 = 1;
-	ea.line2 = curbuf->b_ml.ml_line_count;
+	buf_T	    *buf;
+	switch (ea.addr_type)
+	{
+	    case ADDR_LINES:
+		ea.line1 = 1;
+		ea.line2 = curbuf->b_ml.ml_line_count;
+		break;
+	    case ADDR_LOADED_BUFFERS:
+		buf = firstbuf;
+		while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL)
+		    buf = buf->b_next;
+		ea.line1 = buf->b_fnum;
+		buf = lastbuf;
+		while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL)
+		    buf = buf->b_prev;
+		ea.line2 = buf->b_fnum;
+		break;
+	    case ADDR_BUFFERS:
+		ea.line1 = firstbuf->b_fnum;
+		ea.line2 = lastbuf->b_fnum;
+		break;
+	    case ADDR_WINDOWS:
+		ea.line1 = 1;
+		ea.line2 = LAST_WIN_NR;
+		break;
+	    case ADDR_TABS:
+		ea.line1 = 1;
+		ea.line2 = LAST_TAB_NR;
+		break;
+	    case ADDR_ARGUMENTS:
+		if (!ARGCOUNT)
+		    ea.line1 = ea.line2 = 0;
+		else
+		{
+		    ea.line1 = 1;
+		    ea.line2 = ARGCOUNT;
+		}
+		break;
+	}
     }
 
     /* accept numbered register only when no count allowed (:put) */
@@ -3211,6 +3285,7 @@ find_ucmd(eap, p, full, xp, compl)
 			eap->cmdidx = CMD_USER_BUF;
 		    eap->argt = (long)uc->uc_argt;
 		    eap->useridx = j;
+		    eap->addr_type = uc->uc_addr_type;
 
 # ifdef FEAT_CMDL_COMPL
 		    if (compl != NULL)
@@ -3839,7 +3914,7 @@ set_one_cmd_context(xp, buff)
 			return NULL;
 		    }
 
-		    /* For the -complete and -nargs attributes, we complete
+		    /* For the -complete, -nargs and -addr attributes, we complete
 		     * their arguments as well.
 		     */
 		    if (STRNICMP(arg, "complete", p - arg) == 0)
@@ -3854,6 +3929,12 @@ set_one_cmd_context(xp, buff)
 			xp->xp_pattern = p + 1;
 			return NULL;
 		    }
+		    else if (STRNICMP(arg, "addr", p - arg) == 0)
+		    {
+			xp->xp_context = EXPAND_USER_ADDR_TYPE;
+			xp->xp_pattern = p + 1;
+			return NULL;
+		    }
 		    return NULL;
 		}
 		arg = skipwhite(p);
@@ -4264,6 +4345,7 @@ get_address(ptr, addr_type, skip, to_other_file)
     pos_T	pos;
     pos_T	*fp;
     linenr_T	lnum;
+    buf_T	*buf;
 
     cmd = skipwhite(*ptr);
     lnum = MAXLNUM;
@@ -4285,7 +4367,7 @@ get_address(ptr, addr_type, skip, to_other_file)
 			lnum = curwin->w_arg_idx + 1;
 			break;
 		    case ADDR_LOADED_BUFFERS:
-		    case ADDR_UNLOADED_BUFFERS:
+		    case ADDR_BUFFERS:
 			lnum = curbuf->b_fnum;
 			break;
 		    case ADDR_TABS:
@@ -4308,7 +4390,16 @@ get_address(ptr, addr_type, skip, to_other_file)
 			lnum = ARGCOUNT;
 			break;
 		    case ADDR_LOADED_BUFFERS:
-		    case ADDR_UNLOADED_BUFFERS:
+			buf = lastbuf;
+			while (buf->b_ml.ml_mfp == NULL)
+			{
+			    if (buf->b_prev == NULL)
+				break;
+			    buf = buf->b_prev;
+			}
+			lnum = buf->b_fnum;
+			break;
+		    case ADDR_BUFFERS:
 			lnum = lastbuf->b_fnum;
 			break;
 		    case ADDR_TABS:
@@ -4477,7 +4568,7 @@ get_address(ptr, addr_type, skip, to_other_file)
 			lnum = curwin->w_arg_idx + 1;
 			break;
 		    case ADDR_LOADED_BUFFERS:
-		    case ADDR_UNLOADED_BUFFERS:
+		    case ADDR_BUFFERS:
 			lnum = curbuf->b_fnum;
 			break;
 		    case ADDR_TABS:
@@ -4495,7 +4586,7 @@ get_address(ptr, addr_type, skip, to_other_file)
 	    else
 		n = getdigits(&cmd);
 	    if (addr_type == ADDR_LOADED_BUFFERS
-		    || addr_type == ADDR_UNLOADED_BUFFERS)
+		    || addr_type == ADDR_BUFFERS)
 		lnum = compute_buffer_local_count(addr_type, lnum, (i == '-') ? -1 * n : n);
 	    else if (i == '-')
 		lnum -= n;
@@ -4531,7 +4622,7 @@ get_address(ptr, addr_type, skip, to_other_file)
 			lnum = LAST_WIN_NR;
 		    break;
 		case ADDR_LOADED_BUFFERS:
-		case ADDR_UNLOADED_BUFFERS:
+		case ADDR_BUFFERS:
 		    if (lnum < firstbuf->b_fnum)
 		    {
 			lnum = firstbuf->b_fnum;
@@ -5585,14 +5676,14 @@ get_command_name(xp, idx)
 #endif
 
 #if defined(FEAT_USR_CMDS) || defined(PROTO)
-static int	uc_add_command __ARGS((char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, char_u *compl_arg, int force));
+static int	uc_add_command __ARGS((char_u *name, size_t name_len, char_u *rep, long argt, long def, int flags, int compl, char_u *compl_arg, int addr_type, int force));
 static void	uc_list __ARGS((char_u *name, size_t name_len));
-static int	uc_scan_attr __ARGS((char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl, char_u **compl_arg));
+static int	uc_scan_attr __ARGS((char_u *attr, size_t len, long *argt, long *def, int *flags, int *compl, char_u **compl_arg, int* attr_type_arg));
 static char_u	*uc_split_args __ARGS((char_u *arg, size_t *lenp));
 static size_t	uc_check_code __ARGS((char_u *code, size_t len, char_u *buf, ucmd_T *cmd, exarg_T *eap, char_u **split_buf, size_t *split_len));
 
     static int
-uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, force)
+uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, addr_type, force)
     char_u	*name;
     size_t	name_len;
     char_u	*rep;
@@ -5601,6 +5692,7 @@ uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, force)
     int		flags;
     int		compl;
     char_u	*compl_arg;
+    int		addr_type;
     int		force;
 {
     ucmd_T	*cmd = NULL;
@@ -5695,6 +5787,7 @@ uc_add_command(name, name_len, rep, argt, def, flags, compl, compl_arg, force)
     cmd->uc_compl_arg = compl_arg;
 # endif
 #endif
+    cmd->uc_addr_type = addr_type;
 
     return OK;
 
@@ -5707,6 +5800,23 @@ fail:
 }
 #endif
 
+#if defined(FEAT_USR_CMDS)
+static struct
+{
+    int	    expand;
+    char    *name;
+} addr_type_complete[] =
+{
+    {ADDR_ARGUMENTS, "arguments"},
+    {ADDR_LINES, "lines"},
+    {ADDR_LOADED_BUFFERS, "loaded_buffers"},
+    {ADDR_TABS, "tabs"},
+    {ADDR_BUFFERS, "buffers"},
+    {ADDR_WINDOWS, "windows"},
+    {-1, NULL}
+};
+#endif
+
 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO)
 /*
  * List of names for completion for ":command" with the EXPAND_ flag.
@@ -5794,7 +5904,7 @@ uc_list(name, name_len)
 
 	    /* Put out the title first time */
 	    if (!found)
-		MSG_PUTS_TITLE(_("\n    Name        Args Range Complete  Definition"));
+		MSG_PUTS_TITLE(_("\n    Name        Args       Address   Complete  Definition"));
 	    found = TRUE;
 	    msg_putchar('\n');
 	    if (got_int)
@@ -5855,6 +5965,20 @@ uc_list(name, name_len)
 		IObuff[len++] = ' ';
 	    } while (len < 11);
 
+	    /* Address Type */
+	    for (j = 0; addr_type_complete[j].expand != -1; ++j)
+		if (addr_type_complete[j].expand != ADDR_LINES
+			&& addr_type_complete[j].expand == cmd->uc_addr_type)
+		{
+		    STRCPY(IObuff + len, addr_type_complete[j].name);
+		    len += (int)STRLEN(IObuff + len);
+		    break;
+		}
+
+	    do {
+		IObuff[len++] = ' ';
+	    } while (len < 21);
+
 	    /* Completion */
 	    for (j = 0; command_complete[j].expand != 0; ++j)
 		if (command_complete[j].expand == cmd->uc_compl)
@@ -5866,7 +5990,7 @@ uc_list(name, name_len)
 
 	    do {
 		IObuff[len++] = ' ';
-	    } while (len < 21);
+	    } while (len < 35);
 
 	    IObuff[len] = '\0';
 	    msg_outtrans(IObuff);
@@ -5906,7 +6030,7 @@ uc_fun_cmd()
 }
 
     static int
-uc_scan_attr(attr, len, argt, def, flags, compl, compl_arg)
+uc_scan_attr(attr, len, argt, def, flags, compl, compl_arg, addr_type_arg)
     char_u	*attr;
     size_t	len;
     long	*argt;
@@ -5914,6 +6038,7 @@ uc_scan_attr(attr, len, argt, def, flags, compl, compl_arg)
     int		*flags;
     int		*compl;
     char_u	**compl_arg;
+    int		*addr_type_arg;
 {
     char_u	*p;
 
@@ -6032,6 +6157,19 @@ invalid_count:
 								      == FAIL)
 		return FAIL;
 	}
+	else if (STRNICMP(attr, "addr", attrlen) == 0)
+	{
+	    *argt |= RANGE;
+	    if (val == NULL)
+	    {
+		EMSG(_("E179: argument required for -addr"));
+		return FAIL;
+	    }
+	    if (parse_addr_type_arg(val, (int)vallen, argt, addr_type_arg) == FAIL)
+		return FAIL;
+	    if (addr_type_arg != ADDR_LINES)
+		*argt |= (ZEROR | NOTADR) ;
+	}
 	else
 	{
 	    char_u ch = attr[len];
@@ -6060,6 +6198,7 @@ ex_command(eap)
     int	    flags = 0;
     int	    compl = EXPAND_NOTHING;
     char_u  *compl_arg = NULL;
+    int	    addr_type_arg = ADDR_LINES;
     int	    has_attr = (eap->arg[0] == '-');
     int	    name_len;
 
@@ -6070,7 +6209,7 @@ ex_command(eap)
     {
 	++p;
 	end = skiptowhite(p);
-	if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, &compl_arg)
+	if (uc_scan_attr(p, end - p, &argt, &def, &flags, &compl, &compl_arg, &addr_type_arg)
 		== FAIL)
 	    return;
 	p = skipwhite(end);
@@ -6111,7 +6250,7 @@ ex_command(eap)
     }
     else
 	uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg,
-								eap->forceit);
+								addr_type_arg, eap->forceit);
 }
 
 /*
@@ -6652,6 +6791,17 @@ get_user_commands(xp, idx)
 }
 
 /*
+ * Function given to ExpandGeneric() to obtain the list of user address type names.
+ */
+    char_u *
+get_user_cmd_addr_type(xp, idx)
+    expand_T	*xp UNUSED;
+    int		idx;
+{
+    return (char_u *)addr_type_complete[idx].name;
+}
+
+/*
  * Function given to ExpandGeneric() to obtain the list of user command
  * attributes.
  */
@@ -6661,8 +6811,8 @@ get_user_cmd_flags(xp, idx)
     int		idx;
 {
     static char *user_cmd_flags[] =
-	{"bang", "bar", "buffer", "complete", "count",
-	    "nargs", "range", "register"};
+	{"addr", "bang", "bar", "buffer", "complete",
+	    "count", "nargs", "range", "register"};
 
     if (idx >= (int)(sizeof(user_cmd_flags) / sizeof(user_cmd_flags[0])))
 	return NULL;
@@ -6696,6 +6846,43 @@ get_user_cmd_complete(xp, idx)
 }
 # endif /* FEAT_CMDL_COMPL */
 
+/*
+ * Parse address type argument
+ */
+    int
+parse_addr_type_arg(value, vallen, argt, addr_type_arg)
+    char_u	*value;
+    int		vallen;
+    long	*argt;
+    int		*addr_type_arg;
+{
+    int	    i, a, b;
+    for (i = 0; addr_type_complete[i].expand != -1; ++i)
+    {
+	a = (int)STRLEN(addr_type_complete[i].name) == vallen;
+	b = STRNCMP(value, addr_type_complete[i].name, vallen) == 0;
+	if (a && b)
+	{
+	    *addr_type_arg = addr_type_complete[i].expand;
+	    break;
+	}
+    }
+
+    if (addr_type_complete[i].expand == -1)
+    {
+	char_u	*err = value;
+	for (i=0; err[i] == NUL || !vim_iswhite(err[i]); i++);
+	err[i] = NUL;
+	EMSG2(_("E180: Invalid address type value: %s"), err);
+	return FAIL;
+    }
+
+    if (*addr_type_arg != ADDR_LINES)
+	*argt |= NOTADR;
+
+    return OK;
+}
+
 #endif	/* FEAT_USR_CMDS */
 
 #if defined(FEAT_USR_CMDS) || defined(FEAT_EVAL) || defined(PROTO)
diff --git a/src/ex_getln.c b/src/ex_getln.c
index 8ebcc88..d8db15a 100644
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -4697,6 +4697,7 @@ ExpandFromContext(xp, pat, num_file, file, options)
 #endif
 #ifdef FEAT_USR_CMDS
 	    {EXPAND_USER_COMMANDS, get_user_commands, FALSE, TRUE},
+	    {EXPAND_USER_ADDR_TYPE, get_user_cmd_addr_type, FALSE, TRUE},
 	    {EXPAND_USER_CMD_FLAGS, get_user_cmd_flags, FALSE, TRUE},
 	    {EXPAND_USER_NARGS, get_user_cmd_nargs, FALSE, TRUE},
 	    {EXPAND_USER_COMPLETE, get_user_cmd_complete, FALSE, TRUE},
diff --git a/src/proto/ex_docmd.pro b/src/proto/ex_docmd.pro
index ebc54c9..d72ee76 100644
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -19,6 +19,7 @@ char_u *get_command_name __ARGS((expand_T *xp, int idx));
 void ex_comclear __ARGS((exarg_T *eap));
 void uc_clear __ARGS((garray_T *gap));
 char_u *get_user_commands __ARGS((expand_T *xp, int idx));
+char_u *get_user_cmd_addr_type __ARGS((expand_T *xp, int idx));
 char_u *get_user_cmd_flags __ARGS((expand_T *xp, int idx));
 char_u *get_user_cmd_nargs __ARGS((expand_T *xp, int idx));
 char_u *get_user_cmd_complete __ARGS((expand_T *xp, int idx));
diff --git a/src/testdir/test_command_count.in b/src/testdir/test_command_count.in
new file mode 100644
index 0000000..cca178e
--- /dev/null
+++ b/src/testdir/test_command_count.in
@@ -0,0 +1,50 @@
+Test for user command counts	    vim: set ft=vim :
+
+STARTTEST
+:let g:lines = []
+:so tiny.vim
+:com -range RangeLines :call add(g:lines, 'Rangeg:Lines '.<line1>.' '.<line2>)
+:com -range -addr=arguments RangeArguments :call add(g:lines, 'RangeArguments '.<line1>.' '.<line2>)
+:com -range=% -addr=arguments RangeArgumentsAll :call add(g:lines, 'RangeArgumentsAll '.<line1>.' '.<line2>)
+:com -range -addr=loaded_buffers RangeLoadedBuffers :call add(g:lines, 'RangeLoadedBuffers '.<line1>.' '.<line2>)
+:com -range=% -addr=loaded_buffers RangeLoadedBuffersAll :call add(g:lines, 'RangeLoadedBuffersAll '.<line1>.' '.<line2>)
+:com -range -addr=buffers RangeBuffers :call add(g:lines, 'RangeBuffers '.<line1>.' '.<line2>)
+:com -range=% -addr=buffers RangeBuffersAll :call add(g:lines, 'RangeBuffersAll '.<line1>.' '.<line2>)
+:com -range -addr=windows RangeWindows :call add(g:lines, 'RangeWindows '.<line1>.' '.<line2>)
+:com -range=% -addr=windows RangeWindowsAll :call add(g:lines, 'RangeWindowsAll '.<line1>.' '.<line2>)
+:com -range -addr=tabs RangeTabs :call add(g:lines, 'RangeTabs '.<line1>.' '.<line2>)
+:com -range=% -addr=tabs RangeTabsAll :call add(g:lines, 'RangeTabsAll '.<line1>.' '.<line2>)
+:set hidden
+:arga a b c d
+:argdo echo "loading buffers"
+:argu 3
+:.-,$-RangeArguments
+:%RangeArguments
+:RangeArgumentsAll
+:N
+:.RangeArguments
+:split|split|split|split
+:3wincmd w
+:.,$RangeWindows
+:%RangeWindows
+:RangeWindowsAll
+:only
+:blast|bd
+:.,$RangeLoadedBuffers
+:%RangeLoadedBuffers
+:RangeLoadedBuffersAll
+:.,$RangeBuffers
+:%RangeBuffers
+:RangeBuffersAll
+:tabe|tabe|tabe|tabe
+:normal 2gt
+:.,$RangeTabs
+:%RangeTabs
+:RangeTabsAll
+:1tabonly
+:e! test.out
+:call append(0, g:lines)
+:w|qa!
+ENDTEST
+
+
diff --git a/src/testdir/test_command_count.ok b/src/testdir/test_command_count.ok
new file mode 100644
index 0000000..11e88b3
--- /dev/null
+++ b/src/testdir/test_command_count.ok
@@ -0,0 +1,17 @@
+RangeArguments 2 4
+RangeArguments 1 5
+RangeArgumentsAll 1 5
+RangeArguments 2 2
+RangeWindows 3 5
+RangeWindows 1 5
+RangeWindowsAll 1 5
+RangeLoadedBuffers 2 4
+RangeLoadedBuffers 1 4
+RangeLoadedBuffersAll 1 4
+RangeBuffers 2 5
+RangeBuffers 1 5
+RangeBuffersAll 1 5
+RangeTabs 2 5
+RangeTabs 1 5
+RangeTabsAll 1 5
+
diff --git a/src/vim.h b/src/vim.h
index 7f3e393..ea53e00 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -798,6 +798,7 @@ extern char *(*dyn_libintl_textdomain)(const char *domainname);
 #define EXPAND_HISTORY		41
 #define EXPAND_USER		42
 #define EXPAND_SYNTIME		43
+#define EXPAND_USER_ADDR_TYPE	44
 
 /* Values for exmode_active (0 is no exmode) */
 #define EXMODE_NORMAL		1
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index a71cbc0..d5f4225 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -823,8 +823,9 @@ current window.  The two windows then share this list, until one of them uses
 USING THE ARGUMENT LIST
 
 						*:argdo*
-:argdo[!] {cmd}		Execute {cmd} for each file in the argument list.
-			It works like doing this: >
+:[range]argdo[!] {cmd}	Execute {cmd} for each file in the argument list or
+			if [range] is specified only for arguments in that
+			range.  It works like doing this: >
 				:rewind
 				:{cmd}
 				:next
diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt
index b795dbe..e74cb5a 100644
--- a/runtime/doc/tabpage.txt
+++ b/runtime/doc/tabpage.txt
@@ -224,8 +224,10 @@ clarification what +N means in this context see |[range]|.
 LOOPING OVER TAB PAGES:
 
 							*:tabd* *:tabdo*
-:tabd[o] {cmd}	Execute {cmd} in each tab page.
-		It works like doing this: >
+:[range]tabd[o] {cmd}
+		Execute {cmd} in each tab page or if [range] is given only in
+		tab pages which tab page number is in the [range].  It works
+		like doing this: >
 			:tabfirst
 			:{cmd}
 			:tabnext
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index 2830a04..01d81c1 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -697,8 +697,9 @@ can also get to them with the buffer list commands, like ":bnext".
 8. Do a command in all buffers or windows			*list-repeat*
 
 							*:windo*
-:windo {cmd}		Execute {cmd} in each window.
-			It works like doing this: >
+:[range]windo {cmd}	Execute {cmd} in each window or if [range] is given
+			only in windows for which the window number lies in
+			the [range].  It works like doing this: >
 				CTRL-W t
 				:{cmd}
 				CTRL-W w
@@ -716,8 +717,10 @@ can also get to them with the buffer list commands, like ":bnext".
 			Also see |:tabdo|, |:argdo| and |:bufdo|.
 
 							*:bufdo*
-:bufdo[!] {cmd}		Execute {cmd} in each buffer in the buffer list.
-			It works like doing this: >
+:[range]bufdo[!] {cmd}	Execute {cmd} in each buffer in the buffer list or if
+			[range] is given only for buffers for which their
+			buffer numer is in the [range].  It works like doing
+			this: >
 				:bfirst
 				:{cmd}
 				:bnext
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index fc6a8ac..e165070 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -133,8 +133,8 @@ EX(CMD_argdelete,	"argdelete",	ex_argdelete,
 			BANG|RANGE|NOTADR|FILES|TRLBAR,
 			ADDR_ARGUMENTS),
 EX(CMD_argdo,		"argdo",	ex_listdo,
-			BANG|NEEDARG|EXTRA|NOTRLCOM,
-			ADDR_LINES),
+			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+			ADDR_ARGUMENTS),
 EX(CMD_argedit,		"argedit",	ex_argedit,
 			BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR,
 			ADDR_ARGUMENTS),
@@ -220,8 +220,8 @@ EX(CMD_buffers,		"buffers",	buflist_list,
 			BANG|TRLBAR|CMDWIN,
 			ADDR_LINES),
 EX(CMD_bufdo,		"bufdo",	ex_listdo,
-			BANG|NEEDARG|EXTRA|NOTRLCOM,
-			ADDR_LINES),
+			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+			ADDR_BUFFERS),
 EX(CMD_bunload,		"bunload",	ex_bunload,
 			BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR,
 			ADDR_LOADED_BUFFERS),
@@ -1384,8 +1384,8 @@ EX(CMD_tabclose,	"tabclose",	ex_tabclose,
 			RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN,
 			ADDR_TABS),
 EX(CMD_tabdo,		"tabdo",	ex_listdo,
-			NEEDARG|EXTRA|NOTRLCOM,
-			ADDR_LINES),
+			NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+			ADDR_TABS),
 EX(CMD_tabedit,		"tabedit",	ex_splitview,
 			BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR,
 			ADDR_TABS),
@@ -1576,8 +1576,8 @@ EX(CMD_wincmd,		"wincmd",	ex_wincmd,
 			NEEDARG|WORD1|RANGE|NOTADR,
 			ADDR_LINES),
 EX(CMD_windo,		"windo",	ex_listdo,
-			BANG|NEEDARG|EXTRA|NOTRLCOM,
-			ADDR_LINES),
+			BANG|NEEDARG|EXTRA|NOTRLCOM|RANGE|NOTADR|DFLALL,
+			ADDR_WINDOWS),
 EX(CMD_winpos,		"winpos",	ex_winpos,
 			EXTRA|TRLBAR|CMDWIN,
 			ADDR_LINES),
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 4614dea..3fac506 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -2472,15 +2472,34 @@ ex_listdo(eap)
 				    | (eap->forceit ? CCGD_FORCEIT : 0)
 				    | CCGD_EXCMD))
     {
-	/* start at the first argument/window/buffer */
 	i = 0;
+	/* start at the eap->line1 argument/window/buffer */
 #ifdef FEAT_WINDOWS
 	wp = firstwin;
 	tp = first_tabpage;
 #endif
+	switch (eap->cmdidx)
+	{
+#ifdef FEAT_WINDOWS
+	    case CMD_windo:
+		for (wp; wp != NULL && i+1 < eap->line1; wp = wp->w_next)
+		    i++;
+		break;
+	    case CMD_tabdo:
+		for(tp; tp != NULL && i+1 < eap->line1; tp = tp->tp_next)
+		    i++;
+		break;
+#endif
+	    case CMD_argdo:
+		i = eap->line1 - 1;
+		break;
+	    case CMD_bufdo:
+		i = eap->line1;
+		break;
+	}
 	/* set pcmark now */
 	if (eap->cmdidx == CMD_bufdo)
-	    goto_buffer(eap, DOBUF_FIRST, FORWARD, 0);
+	    goto_buffer(eap, DOBUF_FIRST, FORWARD, i);
 	else
 	    setpcmark();
 	listcmd_busy = TRUE;	    /* avoids setting pcmark below */
@@ -2506,7 +2525,6 @@ ex_listdo(eap)
 		}
 		if (curwin->w_arg_idx != i)
 		    break;
-		++i;
 	    }
 #ifdef FEAT_WINDOWS
 	    else if (eap->cmdidx == CMD_windo)
@@ -2541,6 +2559,8 @@ ex_listdo(eap)
 		    }
 	    }
 
+	    ++i;
+
 	    /* execute the command */
 	    do_cmdline(eap->arg, eap->getline, eap->cookie,
 						DOCMD_VERBOSE + DOCMD_NOWAIT);
@@ -2548,7 +2568,7 @@ ex_listdo(eap)
 	    if (eap->cmdidx == CMD_bufdo)
 	    {
 		/* Done? */
-		if (next_fnum < 0)
+		if (next_fnum < 0 || next_fnum > eap->line2)
 		    break;
 		/* Check if the buffer still exists. */
 		for (buf = firstbuf; buf != NULL; buf = buf->b_next)
@@ -2579,6 +2599,14 @@ ex_listdo(eap)
 		    do_check_scrollbind(TRUE);
 #endif
 	    }
+
+#ifdef FEAT_WINDOWS
+	    if (eap->cmdidx == CMD_windo || eap->cmdidx == CMD_tabdo)
+		if (i+1 > eap->line2)
+		    break;
+#endif
+	    if (eap->cmdidx == CMD_argdo && i >= eap->line2)
+		break;
 	}
 	listcmd_busy = FALSE;
     }

Attachment: signature.asc
Description: Digital signature

Reply via email to