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; }
signature.asc
Description: Digital signature