From 86330fdd3f39a8975b25b7050a3d02b77a442057 Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Sat, 10 Jan 2015 20:27:17 -0300 Subject: vim-patch:7.4.530-531 Specify different kinds of counts for commands. Updated ex commands generator scripts. Includes fixes to comments from patch 7.4.531 Original message: Problem: Many commands take a count or range that is not using line numbers. Solution: For each command specify what kind of count it uses. For windows, buffers and arguments have "$" and "." have a relevant meaning. (Marcin Szamotulski) https://code.google.com/p/vim/source/detail?r=v7-4-530 https://code.google.com/p/vim/source/detail?r=v7-4-531 Add legacy tests for 7.4.530 https://code.google.com/p/vim/source/detail?r=1e6d87a36dcdca231721dde8cbbc26610fb3df27 --- src/nvim/ex_docmd.c | 371 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 334 insertions(+), 37 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 51010983bb..a1760f653c 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1065,6 +1065,33 @@ void * getline_cookie(LineGetter fgetline, return cp; } +/* + * Helper function to apply an offset for buffer commands, i.e. ":bdelete", + * ":bwipeout", etc. + * Returns the buffer number. + */ +static int compute_buffer_local_count(int addr_type, int lnum, int offset) +{ + buf_T *buf; + int count = offset; + + buf = firstbuf; + while (buf->b_next != NULL && buf->b_fnum < lnum) + buf = buf->b_next; + while (count != 0) { + count += (count < 0) ? 1 : -1; + if (buf->b_prev == NULL) + break; + buf = (count < 0) ? buf->b_prev : buf->b_next; + if (addr_type == ADDR_LOADED_BUFFERS) + /* skip over unloaded buffers */ + while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { + buf = (count < 0) ? buf->b_prev : buf->b_next; + } + } + return buf->b_fnum; +} + /* * Execute one Ex command. * @@ -1072,10 +1099,11 @@ void * getline_cookie(LineGetter fgetline, * * 1. skip comment lines and leading space * 2. handle command modifiers - * 3. parse range - * 4. parse command - * 5. parse arguments - * 6. switch on command name + * 3. skip over the range to find the command + * 4. parse the range + * 5. parse the command + * 6. parse arguments + * 7. switch on command name * * Note: "fgetline" can be NULL. * @@ -1100,6 +1128,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, int did_sandbox = FALSE; cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ + win_T *wp; + tabpage_T *tp; + char_u *cmd; memset(&ea, 0, sizeof(ea)); ea.line1 = 1; @@ -1132,7 +1163,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.cmd = *cmdlinep; for (;; ) { /* - * 1. skip comment lines and leading white space and colons + * 1. Skip comment lines and leading white space and colons. */ while (*ea.cmd == ' ' || *ea.cmd == '\t' || *ea.cmd == ':') ++ea.cmd; @@ -1155,7 +1186,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, } /* - * 2. handle command modifiers. + * 2. Handle command modifiers. */ p = ea.cmd; if (ascii_isdigit(*ea.cmd)) @@ -1319,8 +1350,18 @@ static char_u * do_one_cmd(char_u **cmdlinep, (void)do_intthrow(cstack); } + // 3. Skip over the range to find the command. Let "p" point to after it. + // + // We need the command to know what kind of range it uses. + + cmd = ea.cmd; + ea.cmd = skip_range(ea.cmd, NULL); + if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) + ea.cmd = skipwhite(ea.cmd + 1); + p = find_command(&ea, NULL); + /* - * 3. parse a range specifier of the form: addr [,addr] [;addr] .. + * 4. Parse a range specifier of the form: addr [,addr] [;addr] .. * * where 'addr' is: * @@ -1336,25 +1377,82 @@ static char_u * do_one_cmd(char_u **cmdlinep, * is equal to the lower. */ + if (ea.cmdidx != CMD_SIZE) { + ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; + } else { + ea.addr_type = ADDR_LINES; + } + ea.cmd = cmd; + /* repeat for all ',' or ';' separated addresses */ for (;; ) { ea.line1 = ea.line2; - ea.line2 = curwin->w_cursor.lnum; /* default is current line number */ + switch (ea.addr_type) { + case ADDR_LINES: + // default is current line number + ea.line2 = curwin->w_cursor.lnum; + break; + case ADDR_WINDOWS: + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) { + lnum++; + if (wp == curwin) + break; + } + ea.line2 = lnum; + break; + case ADDR_ARGUMENTS: + ea.line2 = curwin->w_arg_idx + 1; + break; + case ADDR_LOADED_BUFFERS: + case ADDR_UNLOADED_BUFFERS: + ea.line2 = curbuf->b_fnum; + break; + case ADDR_TABS: + lnum = 0; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + lnum++; + if (tp == curtab) + break; + } + ea.line2 = lnum; + break; + } ea.cmd = skipwhite(ea.cmd); - lnum = get_address(&ea.cmd, ea.skip, ea.addr_count == 0); + lnum = get_address(&ea.cmd, ea.addr_type, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; if (lnum == MAXLNUM) { if (*ea.cmd == '%') { /* '%' - all lines */ ++ea.cmd; - ea.line1 = 1; - ea.line2 = curbuf->b_ml.ml_line_count; + switch (ea.addr_type) { + case ADDR_LINES: + ea.line1 = 1; + ea.line2 = curbuf->b_ml.ml_line_count; + break; + case ADDR_WINDOWS: + case ADDR_LOADED_BUFFERS: + case ADDR_UNLOADED_BUFFERS: + case ADDR_TABS: + errormsg = (char_u *)_(e_invrange); + goto doend; + break; + case ADDR_ARGUMENTS: + ea.line1 = 1; + ea.line2 = ARGCOUNT; + break; + } ++ea.addr_count; } /* '*' - visual area */ else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) { pos_T *fp; + if (ea.addr_type != ADDR_LINES) { + errormsg = (char_u *)_(e_invrange); + goto doend; + } + ++ea.cmd; if (!ea.skip) { fp = getmark('<', FALSE); @@ -1392,7 +1490,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, check_cursor_lnum(); /* - * 4. parse command + * 5. Parse the command. */ /* @@ -1446,9 +1544,6 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; } - /* Find the command and let "p" point to after it. */ - p = find_command(&ea, NULL); - // If this looks like an undefined user command and there are CmdUndefined // autocommands defined, trigger the matching autocommands. if (p != NULL && ea.cmdidx == CMD_SIZE && !ea.skip @@ -1502,7 +1597,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.forceit = FALSE; /* - * 5. parse arguments + * 6. Parse arguments. */ if (!IS_USER_CMDIDX(ea.cmdidx)) { ea.argt = cmdnames[(int)ea.cmdidx].cmd_argt; @@ -1888,7 +1983,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, } /* - * 6. switch on command name + * 7. Switch on command name. * * The "ea" structure holds the arguments that can be used. */ @@ -3098,12 +3193,11 @@ skip_range ( * * Return MAXLNUM when no Ex address was found. */ -static linenr_T -get_address ( - char_u **ptr, - int skip, /* only skip the address, don't use it */ - int to_other_file /* flag: may jump to other file */ -) +static linenr_T get_address(char_u **ptr, + int addr_type, // flag: one of ADDR_LINES, ... + int skip, // only skip the address, don't use it + int to_other_file // flag: may jump to other file + ) { int c; int i; @@ -3112,6 +3206,9 @@ get_address ( pos_T pos; pos_T *fp; linenr_T lnum; + win_T *wp; + tabpage_T *tp; + buf_T *buf; cmd = skipwhite(*ptr); lnum = MAXLNUM; @@ -3119,12 +3216,68 @@ get_address ( switch (*cmd) { case '.': /* '.' - Cursor position */ ++cmd; - lnum = curwin->w_cursor.lnum; + switch (addr_type) { + case ADDR_LINES: + lnum = curwin->w_cursor.lnum; + break; + case ADDR_WINDOWS: + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) { + lnum++; + if (wp == curwin) + break; + } + break; + case ADDR_ARGUMENTS: + lnum = curwin->w_arg_idx + 1; + break; + case ADDR_LOADED_BUFFERS: + case ADDR_UNLOADED_BUFFERS: + lnum = curbuf->b_fnum; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + lnum++; + if (tp == curtab) + break; + } + break; + } break; case '$': /* '$' - last line */ ++cmd; - lnum = curbuf->b_ml.ml_line_count; + switch (addr_type) { + case ADDR_LINES: + lnum = curbuf->b_ml.ml_line_count; + break; + case ADDR_WINDOWS: + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) { + lnum++; + } + break; + case ADDR_ARGUMENTS: + lnum = ARGCOUNT; + break; + case ADDR_LOADED_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_UNLOADED_BUFFERS: + lnum = lastbuf->b_fnum; + break; + case ADDR_TABS: + lnum = 0; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + lnum++; + } + break; + } break; case '\'': /* ''' - mark */ @@ -3132,6 +3285,10 @@ get_address ( cmd = NULL; goto error; } + if (addr_type != ADDR_LINES) { + EMSG(_(e_invaddr)); + goto error; + } if (skip) ++cmd; else { @@ -3155,6 +3312,10 @@ get_address ( case '/': case '?': /* '/' or '?' - search */ c = *cmd++; + if (addr_type != ADDR_LINES) { + EMSG(_(e_invaddr)); + goto error; + } if (skip) { /* skip "/pat/" */ cmd = skip_regexp(cmd, c, p_magic, NULL); if (*cmd == c) @@ -3194,6 +3355,10 @@ get_address ( case '\\': /* "\?", "\/" or "\&", repeat search */ ++cmd; + if (addr_type != ADDR_LINES) { + EMSG(_(e_invaddr)); + goto error; + } if (*cmd == '&') i = RE_SUBST; else if (*cmd == '?' || *cmd == '/') @@ -3233,8 +3398,37 @@ get_address ( if (*cmd != '-' && *cmd != '+' && !ascii_isdigit(*cmd)) break; - if (lnum == MAXLNUM) - lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ + if (lnum == MAXLNUM) { + switch (addr_type) { + case ADDR_LINES: + lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ + break; + case ADDR_WINDOWS: + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) { + lnum++; + if (wp == curwin) + break; + } + break; + case ADDR_ARGUMENTS: + lnum = curwin->w_arg_idx + 1; + break; + case ADDR_LOADED_BUFFERS: + case ADDR_UNLOADED_BUFFERS: + lnum = curbuf->b_fnum; + break; + case ADDR_TABS: + lnum = 0; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { + lnum++; + if (tp == curtab) + break; + } + break; + } + } + if (ascii_isdigit(*cmd)) i = '+'; /* "number" is same as "+number" */ else @@ -3242,11 +3436,56 @@ get_address ( if (!ascii_isdigit(*cmd)) /* '+' is '+1', but '+0' is not '+1' */ n = 1; else - n = getdigits_long(&cmd); - if (i == '-') + n = getdigits(&cmd); + if (addr_type == ADDR_LOADED_BUFFERS || + addr_type == ADDR_UNLOADED_BUFFERS) + lnum = compute_buffer_local_count(addr_type, lnum, n); + else if (i == '-') lnum -= n; else lnum += n; + + switch (addr_type) { + case ADDR_LINES: + break; + case ADDR_ARGUMENTS: + if (lnum < 0) + lnum = 0; + else if (lnum >= ARGCOUNT) + lnum = ARGCOUNT; + break; + case ADDR_TABS: + if (lnum < 0) { + lnum = 0; + break; + } + c = 0; + for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) + c++; + if (lnum >= c) + lnum = c; + break; + case ADDR_WINDOWS: + if (lnum < 0) { + lnum = 0; + break; + } + c = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) + c++; + if (lnum > c) + lnum = c; + break; + case ADDR_LOADED_BUFFERS: + case ADDR_UNLOADED_BUFFERS: + if (lnum < firstbuf->b_fnum) { + lnum = firstbuf->b_fnum; + break; + } + if (lnum > lastbuf->b_fnum) + lnum = lastbuf->b_fnum; + break; + } } } while (*cmd == '/' || *cmd == '?'); @@ -5102,10 +5341,29 @@ static void ex_quit(exarg_T *eap) text_locked_msg(); return; } + + win_T *wp; + buf_T *buf; + int wnr; + + if (eap->addr_count > 0) { + wnr = eap->line2; + for (wp = firstwin; --wnr > 0;) { + if (wp->w_next == NULL) + break; + else + wp = wp->w_next; + } + buf = wp->w_buffer; + } else { + wp = curwin; + buf = curbuf; + } + apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); /* Refuse to quit when locked or when the buffer in the last window is * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_closing)) + if (curbuf_locked() || (buf->b_nwindows == 1 && curbuf->b_closing)) return; @@ -5127,7 +5385,7 @@ static void ex_quit(exarg_T *eap) getout(0); } /* close window; may free buffer */ - win_close(curwin, !P_HID(curwin->w_buffer) || eap->forceit); + win_close(wp, !P_HID(wp->w_buffer) || eap->forceit); } } @@ -5174,12 +5432,24 @@ static void ex_quit_all(exarg_T *eap) */ static void ex_close(exarg_T *eap) { + win_T *win; + int winnr = 0; if (cmdwin_type != 0) cmdwin_result = Ctrl_C; - else if (!text_locked() - && !curbuf_locked() - ) - ex_win_close(eap->forceit, curwin, NULL); + else if (!text_locked() && !curbuf_locked()) { + if (eap->addr_count == 0) + ex_win_close(eap->forceit, curwin, NULL); + else { + for (win = firstwin; win != NULL; win = win->w_next) { + winnr++; + if (winnr == eap->line2) + break; + } + if (win == NULL) + win = lastwin; + ex_win_close(eap->forceit, win, NULL); + } + } } /* @@ -5271,6 +5541,8 @@ static void ex_tabonly(exarg_T *eap) else if (first_tabpage->tp_next == NULL) MSG(_("Already only one tab page")); else { + if (eap->addr_count > 0) + goto_tabpage(eap->line2); /* Repeat this up to a 1000 times, because autocommands may mess * up the lists. */ for (int done = 0; done < 1000; ++done) { @@ -5341,6 +5613,18 @@ void tabpage_close_other(tabpage_T *tp, int forceit) */ static void ex_only(exarg_T *eap) { + win_T *wp; + int wnr; + if (eap->addr_count > 0) { + wnr = eap->line2; + for (wp = firstwin; --wnr > 0;) { + if (wp->w_next == NULL) + break; + else + wp = wp->w_next; + } + win_goto(wp); + } close_others(TRUE, eap->forceit); } @@ -5357,13 +5641,26 @@ void ex_all(exarg_T *eap) static void ex_hide(exarg_T *eap) { + win_T *win; + int winnr = 0; if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) eap->errmsg = e_invarg; else { /* ":hide" or ":hide | cmd": hide current window */ eap->nextcmd = check_nextcmd(eap->arg); if (!eap->skip) { - win_close(curwin, FALSE); /* don't free buffer */ + if (eap->addr_count == 0) + win_close(curwin, FALSE); /* don't free buffer */ + else { + for (win = firstwin; win != NULL; win = win->w_next) { + winnr++; + if (winnr == eap->line2) + break; + } + if (win == NULL) + win = lastwin; + win_close(win, FALSE); + } } } } @@ -6518,7 +6815,7 @@ static void ex_copymove(exarg_T *eap) { long n; - n = get_address(&eap->arg, FALSE, FALSE); + n = get_address(&eap->arg, eap->addr_type, FALSE, FALSE); if (eap->arg == NULL) { /* error detected */ eap->nextcmd = NULL; return; -- cgit From f6c55022ff9c5bc1c1be882498b1d4c44b032acb Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Thu, 15 Jan 2015 17:48:14 -0300 Subject: vim-patch:7.4.535 Patch 7.4.535 (after 7.4.530) Problem: Can't build with tiny features. Solution: Add #ifdefs and skip a test. https://code.google.com/p/vim/source/detail?name=v7-4-535 This is also a refactor of some code in 7.4.530. --- src/nvim/ex_docmd.c | 117 +++++++++++++++++++++++----------------------------- 1 file changed, 51 insertions(+), 66 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index a1760f653c..7f42fb5665 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1092,6 +1092,35 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset) return buf->b_fnum; } +static int current_win_nr(win_T *win) +{ + int nr = 0; + + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + ++nr; + if (wp == win) + break; + } + return nr; +} + +static int current_tab_nr(tabpage_T *tab) +{ + int nr = 0; + + FOR_ALL_TABS(tp) { + ++nr; + if (tp == tab) + break; + } + return nr; +} + +#define CURRENT_WIN_NR current_win_nr(curwin) +#define LAST_WIN_NR current_win_nr(NULL) +#define CURRENT_TAB_NR current_tab_nr(curtab) +#define LAST_TAB_NR current_tab_nr(NULL) + /* * Execute one Ex command. * @@ -1128,8 +1157,6 @@ static char_u * do_one_cmd(char_u **cmdlinep, int did_sandbox = FALSE; cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ - win_T *wp; - tabpage_T *tp; char_u *cmd; memset(&ea, 0, sizeof(ea)); @@ -1393,12 +1420,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: - lnum = 0; - for (wp = firstwin; wp != NULL; wp = wp->w_next) { - lnum++; - if (wp == curwin) - break; - } + lnum = CURRENT_WIN_NR; ea.line2 = lnum; break; case ADDR_ARGUMENTS: @@ -1409,12 +1431,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.line2 = curbuf->b_fnum; break; case ADDR_TABS: - lnum = 0; - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - lnum++; - if (tp == curtab) - break; - } + lnum = CURRENT_TAB_NR; ea.line2 = lnum; break; } @@ -3206,8 +3223,6 @@ static linenr_T get_address(char_u **ptr, pos_T pos; pos_T *fp; linenr_T lnum; - win_T *wp; - tabpage_T *tp; buf_T *buf; cmd = skipwhite(*ptr); @@ -3221,12 +3236,7 @@ static linenr_T get_address(char_u **ptr, lnum = curwin->w_cursor.lnum; break; case ADDR_WINDOWS: - lnum = 0; - for (wp = firstwin; wp != NULL; wp = wp->w_next) { - lnum++; - if (wp == curwin) - break; - } + lnum = CURRENT_WIN_NR; break; case ADDR_ARGUMENTS: lnum = curwin->w_arg_idx + 1; @@ -3234,11 +3244,9 @@ static linenr_T get_address(char_u **ptr, case ADDR_LOADED_BUFFERS: case ADDR_UNLOADED_BUFFERS: lnum = curbuf->b_fnum; - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - lnum++; - if (tp == curtab) - break; - } + break; + case ADDR_TABS: + lnum = CURRENT_TAB_NR; break; } break; @@ -3250,10 +3258,7 @@ static linenr_T get_address(char_u **ptr, lnum = curbuf->b_ml.ml_line_count; break; case ADDR_WINDOWS: - lnum = 0; - for (wp = firstwin; wp != NULL; wp = wp->w_next) { - lnum++; - } + lnum = LAST_WIN_NR; break; case ADDR_ARGUMENTS: lnum = ARGCOUNT; @@ -3272,10 +3277,7 @@ static linenr_T get_address(char_u **ptr, lnum = lastbuf->b_fnum; break; case ADDR_TABS: - lnum = 0; - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - lnum++; - } + lnum = LAST_TAB_NR; break; } break; @@ -3404,12 +3406,7 @@ static linenr_T get_address(char_u **ptr, lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ break; case ADDR_WINDOWS: - lnum = 0; - for (wp = firstwin; wp != NULL; wp = wp->w_next) { - lnum++; - if (wp == curwin) - break; - } + lnum = CURRENT_WIN_NR; break; case ADDR_ARGUMENTS: lnum = curwin->w_arg_idx + 1; @@ -3419,12 +3416,7 @@ static linenr_T get_address(char_u **ptr, lnum = curbuf->b_fnum; break; case ADDR_TABS: - lnum = 0; - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - lnum++; - if (tp == curtab) - break; - } + lnum = CURRENT_TAB_NR; break; } } @@ -3459,9 +3451,7 @@ static linenr_T get_address(char_u **ptr, lnum = 0; break; } - c = 0; - for (tp = first_tabpage; tp != NULL; tp = tp->tp_next) - c++; + c = LAST_TAB_NR; if (lnum >= c) lnum = c; break; @@ -3470,9 +3460,7 @@ static linenr_T get_address(char_u **ptr, lnum = 0; break; } - c = 0; - for (wp = firstwin; wp != NULL; wp = wp->w_next) - c++; + c = LAST_WIN_NR; if (lnum > c) lnum = c; break; @@ -5328,7 +5316,7 @@ void not_exiting(void) } /* - * ":quit": quit current window, quit Vim if closed the last window. + * ":quit": quit current window, quit Vim if the last window is closed. */ static void ex_quit(exarg_T *eap) { @@ -5343,27 +5331,23 @@ static void ex_quit(exarg_T *eap) } win_T *wp; - buf_T *buf; - int wnr; if (eap->addr_count > 0) { - wnr = eap->line2; - for (wp = firstwin; --wnr > 0;) { - if (wp->w_next == NULL) + int wnr = eap->line2; + + for (wp = firstwin; wp->w_next != NULL; wp = wp->w_next) { + if (--wnr <= 0) break; - else - wp = wp->w_next; } - buf = wp->w_buffer; } else { wp = curwin; - buf = curbuf; } apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf); /* Refuse to quit when locked or when the buffer in the last window is * being closed (can only happen in autocommands). */ - if (curbuf_locked() || (buf->b_nwindows == 1 && curbuf->b_closing)) + if (curbuf_locked() || + (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_closing)) return; @@ -5641,8 +5625,6 @@ void ex_all(exarg_T *eap) static void ex_hide(exarg_T *eap) { - win_T *win; - int winnr = 0; if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) eap->errmsg = e_invarg; else { @@ -5652,6 +5634,9 @@ static void ex_hide(exarg_T *eap) if (eap->addr_count == 0) win_close(curwin, FALSE); /* don't free buffer */ else { + int winnr = 0; + win_T *win; + for (win = firstwin; win != NULL; win = win->w_next) { winnr++; if (winnr == eap->line2) -- cgit From c5250857733e70d116ccec2cffe08d49772adcdd Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Thu, 15 Jan 2015 17:11:43 -0300 Subject: vim-patch:7.4.539 Patch 7.4.539 (after 7.4.530) Problem: Crash when computing buffer count. Problem with range for user commands. Line range wrong in Visual area. Solution: Avoid segfault in compute_buffer_local_count(). Check for CMD_USER when checking type of range. (Marcin Szamotulski) https://code.google.com/p/vim/source/detail?name=v7-4-539 --- src/nvim/ex_docmd.c | 50 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 37 insertions(+), 13 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7f42fb5665..521aa99b58 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1073,6 +1073,7 @@ void * getline_cookie(LineGetter fgetline, static int compute_buffer_local_count(int addr_type, int lnum, int offset) { buf_T *buf; + buf_T *nextbuf; int count = offset; buf = firstbuf; @@ -1080,15 +1081,29 @@ static int compute_buffer_local_count(int addr_type, int lnum, int offset) buf = buf->b_next; while (count != 0) { count += (count < 0) ? 1 : -1; - if (buf->b_prev == NULL) + nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; + if (nextbuf == NULL) break; - buf = (count < 0) ? buf->b_prev : buf->b_next; + buf = nextbuf; if (addr_type == ADDR_LOADED_BUFFERS) /* skip over unloaded buffers */ - while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) { - buf = (count < 0) ? buf->b_prev : buf->b_next; + while (buf->b_ml.ml_mfp == NULL) { + nextbuf = (offset < 0) ? buf->b_prev : buf->b_next; + if (nextbuf == NULL) { + break; + } + buf = nextbuf; } } + // we might have gone too far, last buffer is not loaded + if (addr_type == ADDR_LOADED_BUFFERS) { + while (buf->b_ml.ml_mfp == NULL) { + nextbuf = (offset >= 0) ? buf->b_prev : buf->b_next; + if (nextbuf == NULL) + break; + buf = nextbuf; + } + } return buf->b_fnum; } @@ -1404,7 +1419,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, * is equal to the lower. */ - if (ea.cmdidx != CMD_SIZE) { + if (ea.cmdidx != CMD_USER && ea.cmdidx != CMD_SIZE) { ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; } else { ea.addr_type = ADDR_LINES; @@ -1441,15 +1456,25 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; if (lnum == MAXLNUM) { if (*ea.cmd == '%') { /* '%' - all lines */ + buf_T *buf; ++ea.cmd; switch (ea.addr_type) { case ADDR_LINES: ea.line1 = 1; ea.line2 = curbuf->b_ml.ml_line_count; break; - case ADDR_WINDOWS: case ADDR_LOADED_BUFFERS: + buf = firstbuf; + while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) { + buf = buf->b_prev; + } + ea.line2 = buf->b_fnum; + break; case ADDR_UNLOADED_BUFFERS: + ea.line1 = firstbuf->b_fnum; + ea.line2 = lastbuf->b_fnum; + break; + case ADDR_WINDOWS: case ADDR_TABS: errormsg = (char_u *)_(e_invrange); goto doend; @@ -3431,7 +3456,8 @@ static linenr_T get_address(char_u **ptr, n = getdigits(&cmd); if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_UNLOADED_BUFFERS) - lnum = compute_buffer_local_count(addr_type, lnum, n); + lnum = compute_buffer_local_count(addr_type, lnum, + (i == '-') ? -1 * n : n); else if (i == '-') lnum -= n; else @@ -3451,18 +3477,16 @@ static linenr_T get_address(char_u **ptr, lnum = 0; break; } - c = LAST_TAB_NR; - if (lnum >= c) - lnum = c; + if (lnum >= LAST_TAB_NR) + lnum = LAST_TAB_NR; break; case ADDR_WINDOWS: if (lnum < 0) { lnum = 0; break; } - c = LAST_WIN_NR; - if (lnum > c) - lnum = c; + if (lnum > LAST_WIN_NR) + lnum = LAST_WIN_NR; break; case ADDR_LOADED_BUFFERS: case ADDR_UNLOADED_BUFFERS: -- cgit From 7fc952ab67afdfef5ba2a90cb277b30ce573333c Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Thu, 15 Jan 2015 20:18:15 -0300 Subject: vim-patch:7.4.542 Problem: Using a range for window and buffer commands has a few problems. Cannot specify the type of range for a user command. Solution: Add the -addr argument for user commands. Fix problems. (Marcin Szamotulski https://code.google.com/p/vim/source/detail?name=v7-4-542 --- src/nvim/ex_docmd.c | 197 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 164 insertions(+), 33 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 521aa99b58..75d324b421 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -85,6 +85,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 */ scid_T uc_scriptID; /* SID where the command was defined */ char_u *uc_compl_arg; /* completion argument if any */ } ucmd_T; @@ -1422,7 +1423,10 @@ static char_u * do_one_cmd(char_u **cmdlinep, if (ea.cmdidx != CMD_USER && ea.cmdidx != CMD_SIZE) { ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; } else { - ea.addr_type = ADDR_LINES; + if (ea.cmdidx != CMD_USER) { + ea.addr_type = ADDR_LINES; + // ea.addr_type for user commands is set by find_ucmd + } } ea.cmd = cmd; @@ -1442,7 +1446,7 @@ static char_u * do_one_cmd(char_u **cmdlinep, 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: @@ -1470,18 +1474,30 @@ static char_u * do_one_cmd(char_u **cmdlinep, } 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: case ADDR_TABS: - errormsg = (char_u *)_(e_invrange); - goto doend; + if (IS_USER_CMDIDX(ea.cmdidx)) { + ea.line1 = 1; + ea.line2 = + ea.addr_type == ADDR_WINDOWS ? LAST_WIN_NR : LAST_TAB_NR; + } else { + // there is no Vim command which uses '%' and + // ADDR_WINDOWS or ADDR_TABS + errormsg = (char_u *)_(e_invrange); + goto doend; + } break; case ADDR_ARGUMENTS: - ea.line1 = 1; - ea.line2 = ARGCOUNT; + if (ARGCOUNT == 0) { + ea.line1 = ea.line2 = 0; + } else { + ea.line1 = 1; + ea.line2 = ARGCOUNT; + } break; } ++ea.addr_count; @@ -1832,8 +1848,43 @@ static char_u * do_one_cmd(char_u **cmdlinep, } if ((ea.argt & DFLALL) && ea.addr_count == 0) { + buf_T *buf; + ea.line1 = 1; - ea.line2 = curbuf->b_ml.ml_line_count; + switch (ea.addr_type) { + case ADDR_LINES: + 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.line2 = LAST_WIN_NR; + break; + case ADDR_TABS: + ea.line2 = LAST_TAB_NR; + break; + case ADDR_ARGUMENTS: + if (ARGCOUNT == 0) { + ea.line1 = ea.line2 = 0; + } else { + ea.line2 = ARGCOUNT; + } + break; + } } /* accept numbered register only when no count allowed (:put) */ @@ -2332,6 +2383,7 @@ find_ucmd ( eap->cmdidx = CMD_USER_BUF; eap->argt = uc->uc_argt; eap->useridx = j; + eap->addr_type = uc->uc_addr_type; if (compl != NULL) *compl = uc->uc_compl; @@ -2871,9 +2923,8 @@ set_one_cmd_context ( return NULL; } - /* For the -complete and -nargs attributes, we complete - * their arguments as well. - */ + // For the -complete, -nargs and -addr attributes, we complete + // their arguments as well. if (STRNICMP(arg, "complete", p - arg) == 0) { xp->xp_context = EXPAND_USER_COMPLETE; xp->xp_pattern = p + 1; @@ -2882,6 +2933,10 @@ set_one_cmd_context ( xp->xp_context = EXPAND_USER_NARGS; 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; } @@ -3267,7 +3322,7 @@ static linenr_T get_address(char_u **ptr, 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: @@ -3298,7 +3353,7 @@ static linenr_T get_address(char_u **ptr, } lnum = buf->b_fnum; break; - case ADDR_UNLOADED_BUFFERS: + case ADDR_BUFFERS: lnum = lastbuf->b_fnum; break; case ADDR_TABS: @@ -3437,7 +3492,7 @@ static linenr_T get_address(char_u **ptr, 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: @@ -3454,10 +3509,8 @@ static linenr_T get_address(char_u **ptr, n = 1; else n = getdigits(&cmd); - if (addr_type == ADDR_LOADED_BUFFERS || - addr_type == ADDR_UNLOADED_BUFFERS) - lnum = compute_buffer_local_count(addr_type, lnum, - (i == '-') ? -1 * n : n); + if (addr_type == ADDR_LOADED_BUFFERS || addr_type == ADDR_BUFFERS) + lnum = compute_buffer_local_count(addr_type, lnum, (i == '-') ? -1 * n : n); else if (i == '-') lnum -= n; else @@ -3489,13 +3542,11 @@ static linenr_T get_address(char_u **ptr, 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; break; } - if (lnum > lastbuf->b_fnum) - lnum = lastbuf->b_fnum; break; } } @@ -4342,10 +4393,9 @@ char_u *get_command_name(expand_T *xp, int idx) return cmdnames[idx].cmd_name; } - static int uc_add_command(char_u *name, size_t name_len, char_u *rep, uint32_t argt, long def, int flags, int compl, - char_u *compl_arg, int force) + char_u *compl_arg, int addr_type, int force) { ucmd_T *cmd = NULL; char_u *p; @@ -4420,6 +4470,7 @@ static int uc_add_command(char_u *name, size_t name_len, char_u *rep, cmd->uc_compl = compl; cmd->uc_scriptID = current_SID; cmd->uc_compl_arg = compl_arg; + cmd->uc_addr_type = addr_type; return OK; @@ -4429,6 +4480,21 @@ fail: return FAIL; } + +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} +}; + /* * List of names for completion for ":command" with the EXPAND_ flag. * Must be alphabetical for completion. @@ -4477,6 +4543,7 @@ static struct { static void uc_list(char_u *name, size_t name_len) { + int i, j; int found = FALSE; ucmd_T *cmd; int len; @@ -4485,7 +4552,6 @@ static void uc_list(char_u *name, size_t name_len) gap = &curbuf->b_ucmds; for (;; ) { - int i; for (i = 0; i < gap->ga_len; ++i) { cmd = USER_CMD_GA(gap, i); a = cmd->uc_argt; @@ -4496,7 +4562,7 @@ static void uc_list(char_u *name, size_t 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) @@ -4551,8 +4617,21 @@ static void uc_list(char_u *name, size_t 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 (int j = 0; command_complete[j].expand != 0; ++j) + for (j = 0; command_complete[j].expand != 0; ++j) if (command_complete[j].expand == cmd->uc_compl) { STRCPY(IObuff + len, command_complete[j].name); len += (int)STRLEN(IObuff + len); @@ -4561,7 +4640,7 @@ static void uc_list(char_u *name, size_t name_len) do { IObuff[len++] = ' '; - } while (len < 21); + } while (len < 35); IObuff[len] = '\0'; msg_outtrans(IObuff); @@ -4597,7 +4676,9 @@ static char_u *uc_fun_cmd(void) return IObuff; } -static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, int *flags, int *compl, char_u **compl_arg) +static int uc_scan_attr(char_u *attr, size_t len, uint32_t *argt, long *def, + int *flags, int * compl, char_u **compl_arg, + int *addr_type_arg) { char_u *p; @@ -4696,6 +4777,18 @@ invalid_count: if (parse_compl_arg(val, (int)vallen, compl, argt, compl_arg) == 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]; attr[len] = '\0'; @@ -4721,6 +4814,7 @@ static void ex_command(exarg_T *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; @@ -4730,7 +4824,7 @@ static void ex_command(exarg_T *eap) while (*p == '-') { ++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); @@ -4764,7 +4858,7 @@ static void ex_command(exarg_T *eap) return; } else uc_add_command(name, end - name, p, argt, def, flags, compl, compl_arg, - eap->forceit); + addr_type_arg, eap->forceit); } /* @@ -5192,6 +5286,13 @@ static char_u *get_user_command_name(int idx) { return get_user_commands(NULL, idx - (int)CMD_SIZE); } +/* + * Function given to ExpandGeneric() to obtain the list of user address type names. + */ +char_u *get_user_cmd_addr_type(expand_T *xp, int idx) +{ + return (char_u *)addr_type_complete[idx].name; +} /* * Function given to ExpandGeneric() to obtain the list of user command names. @@ -5212,9 +5313,9 @@ char_u *get_user_commands(expand_T *xp, int idx) */ char_u *get_user_cmd_flags(expand_T *xp, int idx) { - static char *user_cmd_flags[] = - {"bang", "bar", "buffer", "complete", "count", - "nargs", "range", "register"}; + static char *user_cmd_flags[] = {"addr", "bang", "bar", + "buffer", "complete", "count", + "nargs", "range", "register"}; if (idx >= (int)ARRAY_SIZE(user_cmd_flags)) return NULL; @@ -5241,6 +5342,36 @@ char_u *get_user_cmd_complete(expand_T *xp, int idx) return (char_u *)command_complete[idx].name; } +/* + * Parse address type argument + */ +int parse_addr_type_arg(char_u *value, int vallen, uint32_t *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 || !ascii_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; +} /* * Parse a completion argument "value[vallen]". -- cgit From d2ad709a1e8eb9674e2744015cb609e941ea78f1 Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Thu, 15 Jan 2015 18:33:02 -0300 Subject: vim-patch:7.4.561 Patch 7.4.561 Problem: Ex range handling is wrong for buffer-local user commands. Solution: Check for CMD_USER_BUF. (Marcin Szamotulski) https://code.google.com/p/vim/source/detail?name=v7-4-561 --- src/nvim/ex_docmd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 75d324b421..6beb8b3523 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1420,10 +1420,12 @@ static char_u * do_one_cmd(char_u **cmdlinep, * is equal to the lower. */ - if (ea.cmdidx != CMD_USER && ea.cmdidx != CMD_SIZE) { + if (ea.cmdidx != CMD_SIZE + && ea.cmdidx != CMD_USER + && ea.cmdidx != CMD_USER_BUF) { ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; } else { - if (ea.cmdidx != CMD_USER) { + if (ea.cmdidx != CMD_USER && ea.cmdidx != CMD_USER_BUF) { ea.addr_type = ADDR_LINES; // ea.addr_type for user commands is set by find_ucmd } -- cgit From ca883df007d7644a0ff4986d564ee8524f88c86b Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Tue, 20 Jan 2015 00:28:37 -0300 Subject: vim-patch:7.4.565 Problem: Ranges for arguments, buffers, tabs, etc. are not checked to be valid but limited to the maximum. This can cause the wrong thing to happen. Solution: Give an error for an invalid value. (Marcin Szamotulski) Use windows range for ":wincmd". https://code.google.com/p/vim/source/detail?r=v7-4-565 --- src/nvim/ex_docmd.c | 105 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 43 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 6beb8b3523..78bfaad959 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1446,6 +1446,9 @@ static char_u * do_one_cmd(char_u **cmdlinep, break; case ADDR_ARGUMENTS: ea.line2 = curwin->w_arg_idx + 1; + if (ea.line2 > ARGCOUNT) { + ea.line2 = ARGCOUNT; + } break; case ADDR_LOADED_BUFFERS: case ADDR_BUFFERS: @@ -2247,7 +2250,7 @@ static char_u *find_command(exarg_T *eap, int *full) * Exceptions: * - the 'k' command can directly be followed by any character. * - the 's' command can be followed directly by 'c', 'g', 'i', 'I' or 'r' - * but :sre[wind] is another command, as are :scrip[tnames], + * but :sre[wind] is another command, as are :scr[iptnames], * :scs[cope], :sim[alt], :sig[ns] and :sil[ent]. * - the "d" command can directly be followed by 'l' or 'p' flag. */ @@ -3517,40 +3520,6 @@ static linenr_T get_address(char_u **ptr, lnum -= n; else lnum += n; - - switch (addr_type) { - case ADDR_LINES: - break; - case ADDR_ARGUMENTS: - if (lnum < 0) - lnum = 0; - else if (lnum >= ARGCOUNT) - lnum = ARGCOUNT; - break; - case ADDR_TABS: - if (lnum < 0) { - lnum = 0; - break; - } - if (lnum >= LAST_TAB_NR) - lnum = LAST_TAB_NR; - break; - case ADDR_WINDOWS: - if (lnum < 0) { - lnum = 0; - break; - } - if (lnum > LAST_WIN_NR) - lnum = LAST_WIN_NR; - break; - case ADDR_LOADED_BUFFERS: - case ADDR_BUFFERS: - if (lnum < firstbuf->b_fnum) { - lnum = firstbuf->b_fnum; - break; - } - break; - } } } while (*cmd == '/' || *cmd == '?'); @@ -3599,15 +3568,65 @@ static void ex_script_ni(exarg_T *eap) */ static char_u *invalid_range(exarg_T *eap) { - if ( eap->line1 < 0 - || eap->line2 < 0 - || eap->line1 > eap->line2 - || ((eap->argt & RANGE) - && !(eap->argt & NOTADR) - && eap->line2 > curbuf->b_ml.ml_line_count - + (eap->cmdidx == CMD_diffget) - )) + buf_T *buf; + if (eap->line1 < 0 || eap->line2 < 0 || eap->line1 > eap->line2) { return (char_u *)_(e_invrange); + } + + if (eap->argt & RANGE) { + switch (eap->addr_type) { + case ADDR_LINES: + if (!(eap->argt & NOTADR) && + eap->line2 > + curbuf->b_ml.ml_line_count + (eap->cmdidx == CMD_diffget)) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_ARGUMENTS: + if (eap->line2 > ARGCOUNT + (!ARGCOUNT)) { // add 1 if ARGCOUNT is 0 + return (char_u *)_(e_invrange); + } + break; + case ADDR_BUFFERS: + if (eap->line1 < firstbuf->b_fnum || eap->line2 > lastbuf->b_fnum) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_LOADED_BUFFERS: + buf = firstbuf; + while (buf->b_ml.ml_mfp == NULL) { + if (buf->b_next == NULL) { + return (char_u *)_(e_invrange); + } + buf = buf->b_next; + } + if (eap->line1 < buf->b_fnum) { + return (char_u *)_(e_invrange); + } + buf = lastbuf; + while (buf->b_ml.ml_mfp == NULL) { + if (buf->b_prev == NULL) { + return (char_u *)_(e_invrange); + } + buf = buf->b_prev; + } + if (eap->line2 > buf->b_fnum) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_WINDOWS: + if (eap->line1 < 1 + || eap->line2 > LAST_WIN_NR) { + return (char_u *)_(e_invrange); + } + break; + case ADDR_TABS: + if (eap->line2 > LAST_TAB_NR) { + return (char_u *)_(e_invrange); + } + break; + } + } return NULL; } -- cgit From e42b00dc3b7fb86a3f6ca2a91c0b9cd6569bed60 Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Tue, 20 Jan 2015 01:17:37 -0300 Subject: vim-patch:7.4.568 Problem: Giving an error for ":0wincmd w" is a problem for some plugins. Solution: Allow the zero in the range. (Marcin Szamotulski) https://code.google.com/p/vim/source/detail?r=v7-4-568 --- src/nvim/ex_docmd.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 78bfaad959..5dd744834e 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -3574,11 +3574,11 @@ static char_u *invalid_range(exarg_T *eap) } if (eap->argt & RANGE) { - switch (eap->addr_type) { + switch(eap->addr_type) { case ADDR_LINES: - if (!(eap->argt & NOTADR) && - eap->line2 > - curbuf->b_ml.ml_line_count + (eap->cmdidx == CMD_diffget)) { + if (!(eap->argt & NOTADR) + && eap->line2 > curbuf->b_ml.ml_line_count + + (eap->cmdidx == CMD_diffget)) { return (char_u *)_(e_invrange); } break; @@ -3588,11 +3588,12 @@ static char_u *invalid_range(exarg_T *eap) } break; case ADDR_BUFFERS: - if (eap->line1 < firstbuf->b_fnum || eap->line2 > lastbuf->b_fnum) { + if (eap->line1 < firstbuf->b_fnum + || eap->line2 > lastbuf->b_fnum) { return (char_u *)_(e_invrange); } break; - case ADDR_LOADED_BUFFERS: + case ADDR_LOADED_BUFFERS: buf = firstbuf; while (buf->b_ml.ml_mfp == NULL) { if (buf->b_next == NULL) { -- cgit From e01ebf245ee05b0efb05f739b60cbc830876bc3c Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Sat, 25 Apr 2015 15:08:48 -0300 Subject: vim-patch:7.4.572 Problem: Address type of :wincmd depends on the argument. Solution: Check the argument. https://code.google.com/p/vim/source/detail?r=v7-4-572 --- src/nvim/ex_docmd.c | 122 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 13 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 5dd744834e..8c293efd58 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1137,6 +1137,96 @@ static int current_tab_nr(tabpage_T *tab) #define CURRENT_TAB_NR current_tab_nr(curtab) #define LAST_TAB_NR current_tab_nr(NULL) +/* +* Figure out the address type for ":wincmd". +*/ +static void get_wincmd_addr_type(char_u *arg, exarg_T *eap) +{ + switch (*arg) { + case 'S': + case Ctrl_S: + case 's': + case Ctrl_N: + case 'n': + case 'j': + case Ctrl_J: + case 'k': + case Ctrl_K: + case 'T': + case Ctrl_R: + case 'r': + case 'R': + case 'K': + case 'J': + case '+': + case '-': + case Ctrl__: + case '_': + case '|': + case ']': + case Ctrl_RSB: + case 'g': + case Ctrl_G: + case Ctrl_V: + case 'v': + case 'h': + case Ctrl_H: + case 'l': + case Ctrl_L: + case 'H': + case 'L': + case '>': + case '<': + case '}': + case 'f': + case 'F': + case Ctrl_F: + case 'i': + case Ctrl_I: + case 'd': + case Ctrl_D: + /* window size or any count */ + eap->addr_type = ADDR_LINES; + break; + + case Ctrl_HAT: + case '^': + /* buffer number */ + eap->addr_type = ADDR_BUFFERS; + break; + + case Ctrl_Q: + case 'q': + case Ctrl_C: + case 'c': + case Ctrl_O: + case 'o': + case Ctrl_W: + case 'w': + case 'W': + case 'x': + case Ctrl_X: + /* window number */ + eap->addr_type = ADDR_WINDOWS; + break; + + case Ctrl_Z: + case 'z': + case 'P': + case 't': + case Ctrl_T: + case 'b': + case Ctrl_B: + case 'p': + case Ctrl_P: + case '=': + case CAR: + /* no count */ + eap->addr_type = 0; + break; + } +} + /* * Execute one Ex command. * @@ -1420,19 +1510,21 @@ static char_u * do_one_cmd(char_u **cmdlinep, * is equal to the lower. */ - if (ea.cmdidx != CMD_SIZE - && ea.cmdidx != CMD_USER - && ea.cmdidx != CMD_USER_BUF) { - ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; - } else { - if (ea.cmdidx != CMD_USER && ea.cmdidx != CMD_USER_BUF) { + // ea.addr_type for user commands is set by find_ucmd + if (!IS_USER_CMDIDX(ea.cmdidx)) { + if (ea.cmdidx != CMD_SIZE) { + ea.addr_type = cmdnames[(int)ea.cmdidx].cmd_addr_type; + } else { ea.addr_type = ADDR_LINES; - // ea.addr_type for user commands is set by find_ucmd + } + // :wincmd range depends on the argument + if (ea.cmdidx == CMD_wincmd) { + get_wincmd_addr_type(p, &ea); } } - ea.cmd = cmd; /* repeat for all ',' or ';' separated addresses */ + ea.cmd = cmd; for (;; ) { ea.line1 = ea.line2; switch (ea.addr_type) { @@ -1465,20 +1557,25 @@ static char_u * do_one_cmd(char_u **cmdlinep, goto doend; if (lnum == MAXLNUM) { if (*ea.cmd == '%') { /* '%' - all lines */ - buf_T *buf; ++ea.cmd; 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; + case ADDR_LOADED_BUFFERS: { + buf_T *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; @@ -3616,8 +3713,7 @@ static char_u *invalid_range(exarg_T *eap) } break; case ADDR_WINDOWS: - if (eap->line1 < 1 - || eap->line2 > LAST_WIN_NR) { + if (eap->line2 > LAST_WIN_NR) { return (char_u *)_(e_invrange); } break; -- cgit From 838c9aa31d7ad996206dc7879b18c13b2f8c5555 Mon Sep 17 00:00:00 2001 From: Felipe Morales Date: Sun, 19 Apr 2015 20:14:01 -0300 Subject: vim-patch:7.4.580 Problem: ":52wincmd v" still gives an invalid range error. (Charles Campbell) Solution: Skip over white space. https://code.google.com/p/vim/source/detail?name=v7-4-580 --- src/nvim/ex_docmd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/ex_docmd.c') diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 8c293efd58..646d64f9f8 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -1518,8 +1518,8 @@ static char_u * do_one_cmd(char_u **cmdlinep, ea.addr_type = ADDR_LINES; } // :wincmd range depends on the argument - if (ea.cmdidx == CMD_wincmd) { - get_wincmd_addr_type(p, &ea); + if (ea.cmdidx == CMD_wincmd && p != NULL) { + get_wincmd_addr_type(skipwhite(p), &ea); } } -- cgit