> I had a look at the count patch. I don't like the solution much. > > I think it would work better to add a flag similar to NOTADD that > specifies the kind of count: window number, buffer number, etc. That > way there is no need to pass information from where the counts are > parsed to where there is a switch on the command. Can use > compute_count() directly. First computing counts based on line numbers > and then redoing that for something else doesn't seem right. > > The code that computes the counts looks much too complicated. > > Please give the tests a name, we stopped using numbers recently.
I slightly improved the patch, I added NOTLNR to command's flags and now the count is not computed twice. I also refactored the code so it's simpler and I think easier to follow. Best regards, Marcin
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt index add3bb0..1c9c6d1 100644 --- a/runtime/doc/editing.txt +++ b/runtime/doc/editing.txt @@ -622,7 +622,8 @@ list of the current window. :argadd x a b x c :0argadd x x a b c :1argadd x a x b c - :99argadd x a b c x + :$argadd x a b c x + :+2aradd y a b c x y There is no check for duplicates, it is possible to add a file to the argument list twice. The currently edited file is not changed. @@ -644,11 +645,19 @@ list of the current window. < {not in Vi} {not available when compiled without the |+listcmds| feature} -:{range}argd[elete] Delete the {range} files from the argument list. +:[count]argd[elete] +:[range]argd[elete] Delete the {range} files from the argument list. When the last number in the range is too high, up to the last argument is deleted. Example: > - :10,1000argdel -< Deletes arguments 10 and further, keeping 1-9. + :10,$argdel +< Deletes arguments 10 and further, keeping 1-9. > + :$argd +< Deletes just the last one. > + :argd + :.argd +< Deletes the current argument. > + :%argd +< Removes all the files from the arglist. {not in Vi} {not available when compiled without the |+listcmds| feature} diff --git a/runtime/doc/tabpage.txt b/runtime/doc/tabpage.txt index 3c7ad9f..b8726ae 100644 --- a/runtime/doc/tabpage.txt +++ b/runtime/doc/tabpage.txt @@ -61,16 +61,25 @@ In the GUI tab pages line you can use the right mouse button to open menu. :[count]tabe[dit] *:tabe* *:tabedit* *:tabnew* :[count]tabnew Open a new tab page with an empty window, after the current - tab page. For [count] see |:tab| below. + tab page. If [count] is given the new tab page appears after + the tab page [count] otherwise the new tab page will appear + after the current one. > + :tabnew " opens tabpage after the current one + :.tabnew " as above + :+tabnew " opens tabpage after the next tab page + " note: it is one further than :tabnew + :-tabnew " opens tabpage before the current one + :0tabnew " opens tabpage before the first one + :$tabnew " opens tabpage after the last one :[count]tabe[dit] [++opt] [+cmd] {file} :[count]tabnew [++opt] [+cmd] {file} Open a new tab page and edit {file}, like with |:edit|. - For [count] see |:tab| below. + For [count] see |:tabnew| above. :[count]tabf[ind] [++opt] [+cmd] {file} *:tabf* *:tabfind* Open a new tab page and edit {file} in 'path', like with - |:find|. For [count] see |:tab| below. + |:find|. For [count] see |:tabnew| above. {not available when the |+file_in_path| feature was disabled at compile time} @@ -104,27 +113,42 @@ the top right to close the current tab page. A custom |'tabline'| may show something else. *:tabc* *:tabclose* -:tabc[lose][!] Close current tab page. +:[N]tabc[lose][!] + Close current tab page or if [N] is given close [N]th tab page. This command fails when: - There is only one tab page on the screen. *E784* - When 'hidden' is not set, [!] is not used, a buffer has changes, and there is no other window on this buffer. Changes to the buffer are not written and won't get lost, so - this is a "safe" command. + this is a "safe" command. > + :tabclose " close the current tab page + :-tabclose " close the previous tab page + :+tabclose " close the next tab page + :1tabclose " close the first tab page + :$tabclose " close the last tab page :tabc[lose][!] {count} - Close tab page {count}. Fails in the same way as `:tabclose` + Close tab page {count}. Fails in the same way as |:tabclose| above. *:tabo* *:tabonly* -:tabo[nly][!] Close all other tab pages. +:[N]tabo[nly][!] + Close all tab pages except the current one or the [N]th one if + [N] is given. When the 'hidden' option is set, all buffers in closed windows become hidden. When 'hidden' is not set, and the 'autowrite' option is set, modified buffers are written. Otherwise, windows that have buffers that are modified are not removed, unless the [!] is given, then they become hidden. But modified buffers are - never abandoned, so changes cannot get lost. + never abandoned, so changes cannot get lost. > + :tabonly " close all tab pages except the current + :.tabonly " one + :-tabonly " close all tab pages except the previous + " one + :+tabonly " close all tab pages except the next one + :1tabonly " close all tab pages except the first one + :$tabonly " close all tab pages except the last one SWITCHING TO ANOTHER TAB PAGE: @@ -176,7 +200,15 @@ REORDERING TAB PAGES: :[N]tabm[ove] Move the current tab page to after tab page N. Use zero to make the current tab page the first one. Without N the tab - page is made the last one. + page is made the last one. > + :-tabmove " move the tab page to the left + :tabmove " move the tab page to the right + :.tabmove " as above + :+tabmove " as above + :0tabmove " move the tab page to the begining of the tab + " list + :$tabmove " move the tab page to the end of the tab list +< :tabm[ove] +[N] :tabm[ove] -[N] diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt index 0098e3e..ace1e52 100644 --- a/runtime/doc/windows.txt +++ b/runtime/doc/windows.txt @@ -265,26 +265,40 @@ Closing a window CTRL-W q *CTRL-W_q* CTRL-W CTRL-Q *CTRL-W_CTRL-Q* -:q[uit] Quit current window. When quitting the last window (not - counting a help window), exit Vim. - When 'hidden' is set, and there is only one window for the - current buffer, it becomes hidden. - When 'hidden' is not set, and there is only one window for the - current buffer, and the buffer was changed, the command fails. - (Note: CTRL-Q does not work on all terminals) - -:q[uit]! Quit current window. If this was the last window for a buffer, +:[count]q[uit] Quit current window if [count] is not given, otherwise close + window with window number equal to [count]. When quitting the + last window (not counting a help window), exit Vim. When + 'hidden' is set, and there is only one window for the current + buffer, it becomes hidden. When 'hidden' is not set, and + there is only one window for the current buffer, and the + buffer was changed, the command fails. (Note: CTRL-Q does not + work on all terminals). If [count] is greater than + the last window number the last window will be closed: > + :1quit " quit the first window + :$quit " quit the last window + :9quit " quit the last window + " if there are less than 9 windows opened + :-quit " quit the previews window + :+quit " quit the next window + :+2quit " will also work as expected +< +:[count]q[uit]! Quit current window, unless [count] is given. For [count] see + |:quit| command. If this was the last window for a buffer, any changes to that buffer are lost. When quitting the last window (not counting help windows), exit Vim. The contents of the buffer are lost, even when 'hidden' is set. CTRL-W c *CTRL-W_c* *:clo* *:close* -:clo[se][!] Close current window. When the 'hidden' option is set, or - when the buffer was changed and the [!] is used, the buffer - becomes hidden (unless there is another window editing it). - When there is only one window in the current tab page and - there is another tab page, this closes the current tab page. +:[count]clo[se][!] + Close current window if [count] is not given, otherwise close + window with window number equal to [count]. For [count] see + |:quit| command. When the 'hidden' option is set, or when the + buffer was changed and the [!] is used, the buffer becomes + hidden (unless there is another window editing it). When + there is only one window in the current tab page and there is + another tab page, this closes the current tab page. |tab-page|. + This command fails when: *E444* - There is only one window on the screen. - When 'hidden' is not set, [!] is not used, the buffer has @@ -298,14 +312,14 @@ CTRL-W CTRL-C *CTRL-W_CTRL-C* command. *:hide* -:hid[e] Quit current window, unless it is the last window on the - screen. The buffer becomes hidden (unless there is another - window editing it or 'bufhidden' is "unload" or "delete"). - If the window is the last one in the current tab page the tab - page is closed. |tab-page| - The value of 'hidden' is irrelevant for this command. - Changes to the buffer are not written and won't get lost, so - this is a "safe" command. +:[count]hid[e] Quit current window, unless it is the last window on the + screen. For [count] see |:quit| command. The buffer becomes + hidden (unless there is another window editing it or + 'bufhidden' is "unload" or "delete"). If the window is the + last one in the current tab page the tab page is closed. + |tab-page| The value of 'hidden' is irrelevant for this + command. Changes to the buffer are not written and won't get + lost, so this is a "safe" command. :hid[e] {cmd} Execute {cmd} with 'hidden' is set. The previous value of 'hidden' is restored after {cmd} has been executed. @@ -316,15 +330,16 @@ CTRL-W CTRL-C *CTRL-W_CTRL-C* CTRL-W o *CTRL-W_o* *E445* CTRL-W CTRL-O *CTRL-W_CTRL-O* *:on* *:only* -:on[ly][!] Make the current window the only one on the screen. All other - windows are closed. - When the 'hidden' option is set, all buffers in closed windows - become hidden. - When 'hidden' is not set, and the 'autowrite' option is set, - modified buffers are written. Otherwise, windows that have - buffers that are modified are not removed, unless the [!] is - given, then they become hidden. But modified buffers are - never abandoned, so changes cannot get lost. +:[count]on[ly][!] + Make the current window the only one on the screen. All other + windows are closed. For [count] see |:quit| command. When + the 'hidden' option is set, all buffers in closed windows + become hidden. When 'hidden' is not set, and the 'autowrite' + option is set, modified buffers are written. Otherwise, + windows that have buffers that are modified are not removed, + unless the [!] is given, then they become hidden. But + modified buffers are never abandoned, so changes cannot get + lost. ============================================================================== 4. Moving cursor to other windows *window-move-cursor* diff --git a/src/Makefile b/src/Makefile index 64691a3..144fbc7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1898,6 +1898,8 @@ test1 test2 test3 test4 test5 test6 test7 test8 test9 \ test_listlbr_utf8 \ test_options \ test_qf_title \ + test_argument_count \ + test_close_count \ test10 test11 test12 test13 test14 test15 test16 test17 test18 test19 \ test20 test21 test22 test23 test24 test25 test26 test27 test28 test29 \ test30 test31 test32 test33 test34 test35 test36 test37 test38 test39 \ @@ -1907,7 +1909,7 @@ test1 test2 test3 test4 test5 test6 test7 test8 test9 \ test70 test71 test72 test73 test74 test75 test76 test77 test78 test79 \ test80 test81 test82 test83 test84 test85 test86 test87 test88 test89 \ test90 test91 test92 test93 test94 test95 test96 test97 test98 test99 \ - test100 test101 test102 test103 test104 test105 test106 test107: + test100 test101 test102 test103 test104 test105 test106 test107 : cd testdir; rm $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) testclean: diff --git a/src/ex_cmds.h b/src/ex_cmds.h index 93c7776..4f5b531 100644 --- a/src/ex_cmds.h +++ b/src/ex_cmds.h @@ -54,6 +54,7 @@ #define CMDWIN 0x100000L /* allowed in cmdline window */ #define MODIFY 0x200000L /* forbidden in non-'modifiable' buffer */ #define EXFLAGS 0x400000L /* allow flags after count in argument */ +#define NOTLNR 0x800000L /* count is not a line number */ #define FILES (XFILE | EXTRA) /* multiple extra files allowed */ #define WORD1 (EXTRA | NOSPC) /* one extra word allowed */ #define FILE1 (FILES | NOSPC) /* 1 file allowed, defaults to current file */ @@ -110,19 +111,19 @@ EX(CMD_anoremenu, "anoremenu", ex_menu, EX(CMD_args, "args", ex_args, BANG|FILES|EDITCMD|ARGOPT|TRLBAR), EX(CMD_argadd, "argadd", ex_argadd, - BANG|NEEDARG|RANGE|NOTADR|ZEROR|FILES|TRLBAR), + BANG|NEEDARG|RANGE|NOTADR|NOTLNR|ZEROR|FILES|TRLBAR), EX(CMD_argdelete, "argdelete", ex_argdelete, BANG|RANGE|NOTADR|FILES|TRLBAR), EX(CMD_argdo, "argdo", ex_listdo, BANG|NEEDARG|EXTRA|NOTRLCOM), EX(CMD_argedit, "argedit", ex_argedit, - BANG|NEEDARG|RANGE|NOTADR|FILE1|EDITCMD|ARGOPT|TRLBAR), + BANG|NEEDARG|RANGE|NOTADR|NOTLNR|FILE1|EDITCMD|ARGOPT|TRLBAR), EX(CMD_argglobal, "argglobal", ex_args, BANG|FILES|EDITCMD|ARGOPT|TRLBAR), EX(CMD_arglocal, "arglocal", ex_args, BANG|FILES|EDITCMD|ARGOPT|TRLBAR), EX(CMD_argument, "argument", ex_argument, - BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), + BANG|RANGE|NOTADR|COUNT|NOTLNR|EXTRA|EDITCMD|ARGOPT|TRLBAR), EX(CMD_ascii, "ascii", do_ascii, TRLBAR|SBOXOK|CMDWIN), EX(CMD_autocmd, "autocmd", ex_autocmd, @@ -132,7 +133,7 @@ EX(CMD_augroup, "augroup", ex_autocmd, EX(CMD_aunmenu, "aunmenu", ex_menu, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_buffer, "buffer", ex_buffer, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR), + BANG|RANGE|NOTADR|NOTLNR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR), EX(CMD_bNext, "bNext", ex_bprevious, BANG|RANGE|NOTADR|COUNT|EDITCMD|TRLBAR), EX(CMD_ball, "ball", ex_buffer_all, @@ -140,7 +141,7 @@ EX(CMD_ball, "ball", ex_buffer_all, EX(CMD_badd, "badd", ex_edit, NEEDARG|FILE1|EDITCMD|TRLBAR|CMDWIN), EX(CMD_bdelete, "bdelete", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), + BANG|RANGE|NOTADR|BUFNAME|COUNT|NOTLNR|EXTRA|TRLBAR), EX(CMD_behave, "behave", ex_behave, NEEDARG|WORD1|TRLBAR|CMDWIN), EX(CMD_belowright, "belowright", ex_wrongmodifier, @@ -174,9 +175,9 @@ EX(CMD_buffers, "buffers", buflist_list, EX(CMD_bufdo, "bufdo", ex_listdo, BANG|NEEDARG|EXTRA|NOTRLCOM), EX(CMD_bunload, "bunload", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|COUNT|EXTRA|TRLBAR), + BANG|RANGE|NOTADR|BUFNAME|COUNT|NOTLNR|EXTRA|TRLBAR), EX(CMD_bwipeout, "bwipeout", ex_bunload, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|TRLBAR), + BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|NOTLNR|EXTRA|TRLBAR), EX(CMD_change, "change", ex_change, BANG|WHOLEFOLD|RANGE|COUNT|TRLBAR|CMDWIN|MODIFY), EX(CMD_cNext, "cNext", ex_cnext, @@ -232,7 +233,7 @@ EX(CMD_clist, "clist", qf_list, EX(CMD_clast, "clast", ex_cc, RANGE|NOTADR|COUNT|TRLBAR|BANG), EX(CMD_close, "close", ex_close, - BANG|TRLBAR|CMDWIN), + BANG|RANGE|NOTADR|COUNT|NOTLNR|TRLBAR|CMDWIN), EX(CMD_cmap, "cmap", ex_map, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_cmapclear, "cmapclear", ex_mapclear, @@ -430,7 +431,7 @@ EX(CMD_hardcopy, "hardcopy", ex_hardcopy, EX(CMD_highlight, "highlight", ex_highlight, BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN), EX(CMD_hide, "hide", ex_hide, - BANG|EXTRA|NOTRLCOM), + BANG|RANGE|NOTADR|COUNT|NOTLNR|EXTRA|NOTRLCOM), EX(CMD_history, "history", ex_history, EXTRA|TRLBAR|CMDWIN), EX(CMD_insert, "insert", ex_append, @@ -678,7 +679,7 @@ EX(CMD_omapclear, "omapclear", ex_mapclear, EX(CMD_omenu, "omenu", ex_menu, RANGE|NOTADR|ZEROR|EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_only, "only", ex_only, - BANG|TRLBAR), + BANG|NOTADR|RANGE|COUNT|NOTLNR|TRLBAR), EX(CMD_onoremap, "onoremap", ex_map, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_onoremenu, "onoremenu", ex_menu, @@ -758,7 +759,7 @@ EX(CMD_python3, "python3", ex_py3, EX(CMD_py3file, "py3file", ex_py3file, RANGE|FILE1|NEEDARG|CMDWIN), EX(CMD_quit, "quit", ex_quit, - BANG|TRLBAR|CMDWIN), + BANG|RANGE|COUNT|NOTLNR|NOTADR|TRLBAR|CMDWIN), EX(CMD_quitall, "quitall", ex_quit_all, BANG|TRLBAR), EX(CMD_qall, "qall", ex_quit_all, @@ -806,7 +807,7 @@ EX(CMD_substitute, "substitute", do_sub, EX(CMD_sNext, "sNext", ex_previous, EXTRA|RANGE|NOTADR|COUNT|BANG|EDITCMD|ARGOPT|TRLBAR), EX(CMD_sargument, "sargument", ex_argument, - BANG|RANGE|NOTADR|COUNT|EXTRA|EDITCMD|ARGOPT|TRLBAR), + BANG|RANGE|NOTADR|COUNT|NOTLNR|EXTRA|EDITCMD|ARGOPT|TRLBAR), EX(CMD_sall, "sall", ex_all, BANG|RANGE|NOTADR|COUNT|TRLBAR), EX(CMD_sandbox, "sandbox", ex_wrongmodifier, @@ -814,7 +815,7 @@ EX(CMD_sandbox, "sandbox", ex_wrongmodifier, EX(CMD_saveas, "saveas", ex_write, BANG|DFLALL|FILE1|ARGOPT|CMDWIN|TRLBAR), EX(CMD_sbuffer, "sbuffer", ex_buffer, - BANG|RANGE|NOTADR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR), + BANG|RANGE|NOTADR|NOTLNR|BUFNAME|BUFUNL|COUNT|EXTRA|EDITCMD|TRLBAR), EX(CMD_sbNext, "sbNext", ex_bprevious, RANGE|NOTADR|COUNT|EDITCMD|TRLBAR), EX(CMD_sball, "sball", ex_buffer_all, @@ -946,25 +947,25 @@ EX(CMD_tags, "tags", do_tags, EX(CMD_tab, "tab", ex_wrongmodifier, NEEDARG|EXTRA|NOTRLCOM), EX(CMD_tabclose, "tabclose", ex_tabclose, - RANGE|NOTADR|COUNT|BANG|TRLBAR|CMDWIN), + RANGE|NOTADR|COUNT|NOTLNR|BANG|TRLBAR|CMDWIN), EX(CMD_tabdo, "tabdo", ex_listdo, NEEDARG|EXTRA|NOTRLCOM), EX(CMD_tabedit, "tabedit", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), + BANG|FILE1|RANGE|NOTADR|NOTLNR|ZEROR|EDITCMD|ARGOPT|TRLBAR), EX(CMD_tabfind, "tabfind", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR), + BANG|FILE1|RANGE|NOTADR|NOTLNR|ZEROR|EDITCMD|ARGOPT|NEEDARG|TRLBAR), EX(CMD_tabfirst, "tabfirst", ex_tabnext, TRLBAR), EX(CMD_tabmove, "tabmove", ex_tabmove, - RANGE|NOTADR|ZEROR|EXTRA|NOSPC|TRLBAR), + RANGE|NOTADR|NOTLNR|ZEROR|EXTRA|NOSPC|TRLBAR), EX(CMD_tablast, "tablast", ex_tabnext, TRLBAR), EX(CMD_tabnext, "tabnext", ex_tabnext, RANGE|NOTADR|COUNT|TRLBAR), EX(CMD_tabnew, "tabnew", ex_splitview, - BANG|FILE1|RANGE|NOTADR|ZEROR|EDITCMD|ARGOPT|TRLBAR), + BANG|FILE1|RANGE|NOTADR|NOTLNR|ZEROR|EDITCMD|ARGOPT|TRLBAR), EX(CMD_tabonly, "tabonly", ex_tabonly, - BANG|TRLBAR|CMDWIN), + BANG|RANGE|NOTADR|NOTLNR|TRLBAR|CMDWIN), EX(CMD_tabprevious, "tabprevious", ex_tabnext, RANGE|NOTADR|COUNT|TRLBAR), EX(CMD_tabNext, "tabNext", ex_tabnext, @@ -1206,3 +1207,13 @@ struct exarg #define EXFLAG_PRINT 0x04 /* 'p': print */ #endif + +#define ADDRT_ABSOLUTE 0x001 /* number */ +#define ADDRT_CURPOS 0x002 /* '.' */ +#define ADDRT_LAST 0x004 /* '$' */ +#define ADDRT_MARK 0x010 /* "'" */ +#define ADDRT_SEARCH 0x020 /* '/' or '?' */ +#define ADDRT_REPEAT 0x040 /* "\?", "\/" or "\&" */ +#define ADDRT_LOCAL 0x100 /* '+[linenr], or -[linenr]' */ +#define ADDRT_ALL 0x200 /* '%' */ +#define ADDRT_VISUAL 0x400 /* '*' */ diff --git a/src/ex_docmd.c b/src/ex_docmd.c index 15ce342..55fc63e 100644 --- a/src/ex_docmd.c +++ b/src/ex_docmd.c @@ -60,6 +60,7 @@ static char_u *get_user_command_name __ARGS((int idx)); # define IS_USER_CMDIDX(idx) (FALSE) #endif +static int compute_count(addr_T *, linenr_T, linenr_T, linenr_T, int); #ifdef FEAT_EVAL static char_u *do_one_cmd __ARGS((char_u **, int, struct condstack *, char_u *(*fgetline)(int, void *, int), void *cookie)); #else @@ -133,7 +134,7 @@ static int getargopt __ARGS((exarg_T *eap)); #endif static int check_more __ARGS((int, int)); -static linenr_T get_address __ARGS((char_u **, int skip, int to_other_file)); +static addr_T get_address __ARGS((char_u **, int skip, int to_other_file)); static void get_flags __ARGS((exarg_T *eap)); #if !defined(FEAT_PERL) \ || !defined(FEAT_PYTHON) || !defined(FEAT_PYTHON3) \ @@ -1681,6 +1682,94 @@ getline_cookie(fgetline, cookie) #endif /* + * Compute count for a command, depending on `addr->type`. + */ + static int +compute_count(addr, first, current, last, addr_all) + addr_T *addr; + linenr_T first; + linenr_T current; + linenr_T last; + int addr_all; +{ + if (addr->type & ADDRT_MARK || + addr->type & ADDRT_SEARCH || + addr->type & ADDRT_REPEAT || + addr->type & ADDRT_VISUAL || + addr->type & ADDRT_ALL && !addr_all) + return 0; + else if (addr->type & ADDRT_ALL && addr_all) + { + addr->lnum = (last > 0) ? last : 1; + return 2; + } + else if (addr->type & ADDRT_LAST) + addr->lnum = last; + else if (!(addr->type & ADDRT_ABSOLUTE)) + addr->lnum = current; + + if (addr->type & ADDRT_LOCAL) + { + addr->lnum += addr->local; + /* avoid E16 if address is negative */ + if (addr->lnum < first) + addr->lnum = first; + if (addr->lnum > last) + addr->lnum = last; + } + return 1; +} + + +/* + * Helper function to compute local count for buffer commands, i.e. ":bdelete", + * ":bwipeout", etc. + */ + void +compute_buffer_local_count(addr, ea) + addr_T *addr; + exarg_T ea; +{ + buf_T *buf; + + buf = firstbuf; + while (buf->b_next != NULL + && buf->b_fnum < addr->lnum) + buf = buf->b_next; + while (addr->local != 0) + { + if (addr->local < 0) + { + addr->local += 1; + if (buf->b_prev == NULL) + break; + buf = buf->b_prev; + if (ea.cmdidx != CMD_bwipeout + && ea.cmdidx != CMD_buffer + && ea.cmdidx != CMD_sbuffer) + /* skip over unloaded buffers */ + while (buf->b_prev != NULL && buf->b_ml.ml_mfp == NULL) + buf = buf->b_prev; + } + else + { + addr->local -= 1; + if (buf->b_next == NULL) + break; + buf = buf->b_next; + if (ea.cmdidx != CMD_bwipeout + && ea.cmdidx != CMD_buffer + && ea.cmdidx != CMD_sbuffer) + /* skip over unloaded buffers */ + while (buf->b_next != NULL && buf->b_ml.ml_mfp == NULL) + buf = buf->b_next; + } + } + addr->lnum = buf->b_fnum; +} + + +/* * Execute one Ex command. * * If 'sourcing' is TRUE, the command will be included in the error message. @@ -1717,6 +1806,7 @@ do_one_cmd(cmdlinep, sourcing, void *cookie; /* argument for fgetline() */ { char_u *p; + addr_T addr1, addr2; linenr_T lnum; long n; char_u *errormsg = NULL; /* error message */ @@ -1730,6 +1820,9 @@ do_one_cmd(cmdlinep, sourcing, #endif cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ + win_T *wp; + buf_T *buf; + char_u c; vim_memset(&ea, 0, sizeof(ea)); ea.line1 = 1; @@ -2022,43 +2115,48 @@ do_one_cmd(cmdlinep, sourcing, /* repeat for all ',' or ';' separated addresses */ for (;;) { - ea.line1 = ea.line2; - ea.line2 = curwin->w_cursor.lnum; /* default is current line number */ ea.cmd = skipwhite(ea.cmd); - lnum = get_address(&ea.cmd, ea.skip, ea.addr_count == 0); + addr1 = addr2; + addr2 = get_address(&ea.cmd, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; - if (lnum == MAXLNUM) + if (!(ea.argt & NOTLNR)) { - if (*ea.cmd == '%') /* '%' - all lines */ - { - ++ea.cmd; - ea.line1 = 1; - ea.line2 = curbuf->b_ml.ml_line_count; - ++ea.addr_count; - } - /* '*' - visual area */ - else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) + ea.line1 = ea.line2; + ea.line2 = curwin->w_cursor.lnum; /* default is current line number */ + if (addr2.lnum == MAXLNUM) { - pos_T *fp; - - ++ea.cmd; - if (!ea.skip) + if (*ea.cmd == '%') /* '%' - all lines */ { - fp = getmark('<', FALSE); - if (check_mark(fp) == FAIL) - goto doend; - ea.line1 = fp->lnum; - fp = getmark('>', FALSE); - if (check_mark(fp) == FAIL) - goto doend; - ea.line2 = fp->lnum; + ++ea.cmd; + ea.line1 = 1; + ea.line2 = curbuf->b_ml.ml_line_count; ++ea.addr_count; + addr2.type |= ADDRT_ALL; + } + /* '*' - visual area */ + else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) + { + pos_T *fp; + + ++ea.cmd; + if (!ea.skip) + { + fp = getmark('<', FALSE); + if (check_mark(fp) == FAIL) + goto doend; + ea.line1 = fp->lnum; + fp = getmark('>', FALSE); + if (check_mark(fp) == FAIL) + goto doend; + ea.line2 = fp->lnum; + ++ea.addr_count; + } } } + else + ea.line2 = addr2.lnum; } - else - ea.line2 = lnum; ea.addr_count++; if (*ea.cmd == ';') @@ -2071,15 +2169,6 @@ do_one_cmd(cmdlinep, sourcing, ++ea.cmd; } - /* One address given: set start and end lines */ - if (ea.addr_count == 1) - { - ea.line1 = ea.line2; - /* ... but only implicit: really no address given */ - if (lnum == MAXLNUM) - ea.addr_count = 0; - } - /* Don't leave the cursor on an illegal line (caused by ';') */ check_cursor_lnum(); @@ -2195,8 +2284,194 @@ do_one_cmd(cmdlinep, sourcing, goto doend; } - ni = (!IS_USER_CMDIDX(ea.cmdidx) - && (cmdnames[ea.cmdidx].cmd_func == ex_ni + /* + * For some commands addr might be used not as a line number + */ +#ifdef FEAT_USR_CMDS + if (!IS_USER_CMDIDX(ea.cmdidx)) +#endif + ea.argt = (long)cmdnames[(int)ea.cmdidx].cmd_argt; + + if (ea.argt & NOTLNR) + { + int current_idx; + int last_idx; + + switch(ea.cmdidx) + { + case CMD_close: + case CMD_hide: + case CMD_only: + case CMD_quit: + if (ea.addr_count == 0) + break; + last_idx = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) + { + last_idx++; + if (wp == curwin) + current_idx = last_idx; + } + if (compute_count(&addr2, 0, + current_idx, last_idx, FALSE) == 0) + { + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + } + else + ea.line1 = ea.line2 = addr2.lnum; + break; + case CMD_argument: + case CMD_sargument: + case CMD_argadd: + case CMD_argedit: + if (ea.addr_count == 0) + break; + if (compute_count(&addr2, 0, + curwin->w_arg_idx + 1, ARGCOUNT, FALSE) == 0) + { + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + } + else + ea.line1 = ea.line2 = addr2.lnum; + break; + case CMD_argdelete: + if (ea.addr_count > 1) + { + if (compute_count(&addr1, 1, + curwin->w_arg_idx + 1, ARGCOUNT, FALSE) == 0) + { + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + } + else + ea.line1 = addr1.lnum; + } + + c = skipwhite(p)[0]; + if (ea.addr_count > 0) + { + switch (compute_count(&addr2, 1, + curwin->w_arg_idx + 1, ARGCOUNT, TRUE)) + { + case 2: + ea.line1 = 1; + default: + case 1: + ea.line2 = addr2.lnum; + break; + case 0: + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + break; + }; + } + else if (c == '\0' || c == '|') /* expand :argdelete to :.argdelete */ + { + ea.line2 = addr2.lnum = curwin->w_arg_idx + 1; + ea.addr_count = 1; + } + + if (ea.addr_count <= 1) /* expand :Nargdelete to :N,Nargdelete */ + { + addr1 = addr2; + ea.line1 = ea.line2; + } + break; + case CMD_bunload: + case CMD_bdelete: + case CMD_bwipeout: + case CMD_buffer: + case CMD_sbuffer: + if (ea.addr_count > 1) + { + n = addr1.type; + addr1.type &= ~ADDRT_LOCAL; + if (compute_count(&addr1, firstbuf->b_fnum, + curbuf->b_fnum, lastbuf->b_fnum, FALSE) == 0) + { + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + } + else if (n & ADDRT_LOCAL) + compute_buffer_local_count(&addr1, ea); + ea.line1 = addr1.lnum; + } + + if (ea.addr_count > 0) + { + n = addr2.type; + addr2.type &= ~ADDRT_LOCAL; + switch (compute_count(&addr2, firstbuf->b_fnum, + curbuf->b_fnum, lastbuf->b_fnum, TRUE)) + { + case 2: + ea.line1 = firstbuf->b_fnum; + default: + case 1: + if (n && ADDRT_LOCAL) + compute_buffer_local_count(&addr2, ea); + ea.line2 = addr2.lnum; + break; + case 0: + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + break; + }; + } + break; + case CMD_tabclose: + case CMD_tabedit: + case CMD_tabnew: + case CMD_tabfind: + case CMD_tabmove: + case CMD_tabonly: + if (ea.addr_count == 0) + break; + else { + tabpage_T *tp; + for(tp = first_tabpage; tp != NULL; tp = tp->tp_next) + { + + last_idx++; + if (tp == curtab) + current_idx = last_idx; + } + if (compute_count(&addr2, 0, + current_idx, last_idx, FALSE) == 0) + { + errormsg = (char_u *)_(e_invrange); + goto doend; + } + if (ea.cmdidx == CMD_tabmove && addr2.type & ADDRT_LOCAL) + addr2.lnum--; + ea.line1 = ea.line2 = addr2.lnum; + } + } + } + + /* One address given: set start and end lines */ + if (ea.addr_count == 1) + { + addr1 = addr2; + ea.line1 = ea.line2; + /* ... but only implicit: really no address given */ + if (addr2.lnum == MAXLNUM) + ea.addr_count = 0; + } + + ni = ( +#ifdef FEAT_USR_CMDS + !IS_USER_CMDIDX(ea.cmdidx) && +#endif + (cmdnames[ea.cmdidx].cmd_func == ex_ni #ifdef HAVE_EX_SCRIPT_NI || cmdnames[ea.cmdidx].cmd_func == ex_script_ni #endif @@ -3339,7 +3614,7 @@ set_one_cmd_context(xp, buff) ++p; } -/* +/*. * 5. parse arguments */ if (!IS_USER_CMDIDX(ea.cmdidx)) @@ -4081,7 +4356,7 @@ skip_range(cmd, ctx) * * Return MAXLNUM when no Ex address was found. */ - static linenr_T + static addr_T get_address(ptr, skip, to_other_file) char_u **ptr; int skip; /* only skip the address, don't use it */ @@ -4093,22 +4368,26 @@ get_address(ptr, skip, to_other_file) char_u *cmd; pos_T pos; pos_T *fp; - linenr_T lnum; + addr_T addr; cmd = skipwhite(*ptr); - lnum = MAXLNUM; + addr.lnum = MAXLNUM; + addr.local = 0; + addr.type = 0; do { switch (*cmd) { case '.': /* '.' - Cursor position */ ++cmd; - lnum = curwin->w_cursor.lnum; + addr.lnum = curwin->w_cursor.lnum; + addr.type = ADDRT_CURPOS; break; case '$': /* '$' - last line */ ++cmd; - lnum = curbuf->b_ml.ml_line_count; + addr.lnum = curbuf->b_ml.ml_line_count; + addr.type = ADDRT_LAST; break; case '\'': /* ''' - mark */ @@ -4125,9 +4404,10 @@ get_address(ptr, skip, to_other_file) * used by itself: ":'M". */ fp = getmark(*cmd, to_other_file && cmd[1] == NUL); ++cmd; + addr.type = ADDRT_MARK; if (fp == (pos_T *)-1) /* Jumped to another file. */ - lnum = curwin->w_cursor.lnum; + addr.lnum = curwin->w_cursor.lnum; else { if (check_mark(fp) == FAIL) @@ -4135,7 +4415,7 @@ get_address(ptr, skip, to_other_file) cmd = NULL; goto error; } - lnum = fp->lnum; + addr.lnum = fp->lnum; } } break; @@ -4156,8 +4436,8 @@ get_address(ptr, skip, to_other_file) * When '/' or '?' follows another address, start * from there. */ - if (lnum != MAXLNUM) - curwin->w_cursor.lnum = lnum; + if (addr.lnum != MAXLNUM) + curwin->w_cursor.lnum = addr.lnum; /* * Start a forward search at the end of the line. * Start a backward search at the start of the line. @@ -4177,7 +4457,8 @@ get_address(ptr, skip, to_other_file) cmd = NULL; goto error; } - lnum = curwin->w_cursor.lnum; + addr.lnum = curwin->w_cursor.lnum; + addr.type = ADDRT_SEARCH; curwin->w_cursor = pos; /* adjust command string pointer */ cmd += searchcmdlen; @@ -4203,8 +4484,9 @@ get_address(ptr, skip, to_other_file) * When search follows another address, start from * there. */ - if (lnum != MAXLNUM) - pos.lnum = lnum; + addr.type = ADDRT_REPEAT; + if (addr.lnum != MAXLNUM) + pos.lnum = addr.lnum; else pos.lnum = curwin->w_cursor.lnum; @@ -4220,7 +4502,7 @@ get_address(ptr, skip, to_other_file) *cmd == '?' ? BACKWARD : FORWARD, (char_u *)"", 1L, SEARCH_MSG, i, (linenr_T)0, NULL) != FAIL) - lnum = pos.lnum; + addr.lnum = pos.lnum; else { cmd = NULL; @@ -4232,7 +4514,10 @@ get_address(ptr, skip, to_other_file) default: if (VIM_ISDIGIT(*cmd)) /* absolute line number */ - lnum = getdigits(&cmd); + { + addr.lnum = getdigits(&cmd); + addr.type = ADDRT_ABSOLUTE; + } } for (;;) @@ -4241,8 +4526,9 @@ get_address(ptr, skip, to_other_file) if (*cmd != '-' && *cmd != '+' && !VIM_ISDIGIT(*cmd)) break; - if (lnum == MAXLNUM) - lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ + addr.type |= ADDRT_LOCAL; + if (addr.lnum == MAXLNUM) + addr.lnum = curwin->w_cursor.lnum; /* "+1" is same as ".+1" */ if (VIM_ISDIGIT(*cmd)) i = '+'; /* "number" is same as "+number" */ else @@ -4252,15 +4538,21 @@ get_address(ptr, skip, to_other_file) else n = getdigits(&cmd); if (i == '-') - lnum -= n; + { + addr.lnum -= n; + addr.local -= n; + } else - lnum += n; + { + addr.lnum += n; + addr.local += n; + } } } while (*cmd == '/' || *cmd == '?'); error: *ptr = cmd; - return lnum; + return addr; } /* @@ -6556,6 +6848,11 @@ not_exiting() ex_quit(eap) exarg_T *eap; { + win_T *wp; + win_T *cwp; + buf_T *buf; + int wnr; + #ifdef FEAT_CMDWIN if (cmdwin_type != 0) { @@ -6569,11 +6866,28 @@ ex_quit(eap) text_locked_msg(); return; } + 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; + } #ifdef FEAT_AUTOCMD 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 && buf->b_closing)) return; #endif @@ -6606,7 +6920,7 @@ ex_quit(eap) need_mouse_correct = TRUE; # endif /* 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); #endif } } @@ -6668,6 +6982,8 @@ ex_quit_all(eap) ex_close(eap) exarg_T *eap; { + win_T *win; + int winnr = 0; # ifdef FEAT_CMDWIN if (cmdwin_type != 0) cmdwin_result = Ctrl_C; @@ -6678,7 +6994,21 @@ ex_close(eap) && !curbuf_locked() #endif ) - ex_win_close(eap->forceit, curwin, NULL); + { + 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); + } + } } # ifdef FEAT_QUICKFIX @@ -6804,6 +7134,8 @@ ex_tabonly(eap) 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 (done = 0; done < 1000; ++done) @@ -6882,9 +7214,23 @@ tabpage_close_other(tp, forceit) ex_only(eap) exarg_T *eap; { + win_T *wp; + int wnr; # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif + 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); } @@ -6906,6 +7252,9 @@ ex_all(eap) ex_hide(eap) exarg_T *eap; { + win_T *win; + int winnr = 0; + if (*eap->arg != NUL && check_nextcmd(eap->arg) == NULL) eap->errmsg = e_invarg; else @@ -6918,7 +7267,19 @@ ex_hide(eap) # ifdef FEAT_GUI need_mouse_correct = TRUE; # endif - 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); + } } #endif } @@ -8650,9 +9011,9 @@ ex_put(eap) ex_copymove(eap) exarg_T *eap; { - long n; + addr_T addr; - n = get_address(&eap->arg, FALSE, FALSE); + addr = get_address(&eap->arg, FALSE, FALSE); if (eap->arg == NULL) /* error detected */ { eap->nextcmd = NULL; @@ -8661,9 +9022,10 @@ ex_copymove(eap) get_flags(eap); /* - * move or copy lines from 'eap->line1'-'eap->line2' to below line 'n' + * move or copy lines from 'eap->line1'-'eap->line2' to below line + * 'addr.lnum' */ - if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count) + if (addr.lnum == MAXLNUM || addr.lnum < 0 || addr.lnum > curbuf->b_ml.ml_line_count) { EMSG(_(e_invaddr)); return; @@ -8671,11 +9033,11 @@ ex_copymove(eap) if (eap->cmdidx == CMD_move) { - if (do_move(eap->line1, eap->line2, n) == FAIL) + if (do_move(eap->line1, eap->line2, addr.lnum) == FAIL) return; } else - ex_copy(eap->line1, eap->line2, n); + ex_copy(eap->line1, eap->line2, addr.lnum); u_clearline(); beginline(BL_SOL | BL_FIX); ex_may_print(eap); diff --git a/src/structs.h b/src/structs.h index d241753..9b5c76b 100644 --- a/src/structs.h +++ b/src/structs.h @@ -21,6 +21,16 @@ typedef unsigned short short_u; #endif /* + * + */ +typedef struct +{ + linenr_T lnum; /* addr */ + linenr_T local; /* addr from + and - modifiers */ + int type; /* */ +} addr_T; + +/* * position in file or buffer */ typedef struct diff --git a/src/testdir/test_argument_count.in b/src/testdir/test_argument_count.in new file mode 100644 index 0000000..f45e52a --- /dev/null +++ b/src/testdir/test_argument_count.in @@ -0,0 +1,47 @@ +Tests for :[count]argument! and :[count]argdelete vim: set ft=vim : + +STARTTEST +:%argd +:argadd a b c d +:set hidden +:let buffers = [] +:augroup TEST +:au BufEnter * call add(buffers, expand('%:t')) +:augroup END +:$argu +:$-argu +:-argu +:1argu +:+2argu +:augroup TEST +:au! +:augroup END +:let arglists = [] +:.argd +:call add(arglists, argv()) +:-argd +:call add(arglists, argv()) +:$argd +:call add(arglists, argv()) +:1arga c +:1arga b +:$argu +:+arga d +:$arga x +:call add(arglists, argv()) +:$-10arga Y +:call add(arglists, argv()) +:%argd +:call add(arglists, argv()) +:arga a b c d e f +:2,$-argd +:call add(arglists, argv()) +:e! test.out +:call append(0, buffers) +:let lnr = line('$') +:call append(lnr, map(copy(arglists), 'join(v:val, " ")')) +:w +:qa! +ENDTEST + + diff --git a/src/testdir/test_argument_count.ok b/src/testdir/test_argument_count.ok new file mode 100644 index 0000000..f591bf2 --- /dev/null +++ b/src/testdir/test_argument_count.ok @@ -0,0 +1,13 @@ +d +c +b +a +c + +a b d +a d +a +a b c d x +Y a b c d x + +a f diff --git a/src/testdir/test_close_count.in b/src/testdir/test_close_count.in new file mode 100644 index 0000000..ab2b48b --- /dev/null +++ b/src/testdir/test_close_count.in @@ -0,0 +1,153 @@ +Tests for :[count]close! and :[count]hide vim: set ft=vim : + +STARTTEST +:let tests = [] +:so tiny.vim +:for i in range(5) +:new +:endfor +:4wincmd w +:close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:$close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +:2close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +:new +:new +:2wincmd w +:-2close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:2wincmd w +:+1close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:e! test.out +:call append(0, map(copy(tests), 'join(v:val, " ")')) +:w +:only! +:b1 +ENDTEST + +STARTTEST +:let tests = [] +:so tiny.vim +:for i in range(5) +:new +:endfor +:4wincmd w +:.hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:9hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +:2hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +:new +:new +:3wincmd w +:-hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:2wincmd w +:+hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:e! test.out +:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) +Go +:w +:only! +:b1 +ENDTEST + +STARTTEST +:let tests = [] +:so tiny.vim +:set hidden +:for i in range(5) +:new +:endfor +:1wincmd w +:$ hide +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:$-1 close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +:.+close! +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:e! test.out +:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) +Go +:w +:only! +:b1 +ENDTEST + +STARTTEST +:let tests = [] +:so tiny.vim +:set hidden +:for i in range(5) +:new +:endfor +:4wincmd w +c +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +1c +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +9c +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:1wincmd w +2c +:let buffers = [] +:windo call add(buffers, bufnr('%')) +:call add(tests, buffers) +:only! +:e! test.out +:call append(line('$'), map(copy(tests), 'join(v:val, " ")')) +:w +:qa! +ENDTEST + + diff --git a/src/testdir/test_close_count.ok b/src/testdir/test_close_count.ok new file mode 100644 index 0000000..6b4251d --- /dev/null +++ b/src/testdir/test_close_count.ok @@ -0,0 +1,22 @@ +6 5 4 2 1 +5 4 2 1 +5 4 2 +5 2 +7 5 2 +7 5 + +13 12 11 9 1 +12 11 9 1 +12 11 9 +12 9 +15 12 9 +15 12 + +20 19 18 17 16 +20 19 18 16 +20 18 16 + +25 24 23 21 1 +24 23 21 1 +24 23 21 +24 21 diff --git a/src/window.c b/src/window.c index b975a61..5da50be 100644 --- a/src/window.c +++ b/src/window.c @@ -199,14 +199,22 @@ newwindow: case Ctrl_Q: case 'q': reset_VIsual_and_resel(); /* stop Visual mode */ - do_cmdline_cmd((char_u *)"quit"); + STRCPY(cbuf, "quit"); + if (Prenum) + vim_snprintf((char *)cbuf + 4, sizeof(cbuf) - 5, + "%ld", Prenum); + do_cmdline_cmd(cbuf); break; /* close current window */ case Ctrl_C: case 'c': reset_VIsual_and_resel(); /* stop Visual mode */ - do_cmdline_cmd((char_u *)"close"); + STRCPY(cbuf, "close"); + if (Prenum) + vim_snprintf((char *)cbuf + 5, sizeof(cbuf) - 5, + "%ld", Prenum); + do_cmdline_cmd(cbuf); break; #if defined(FEAT_WINDOWS) && defined(FEAT_QUICKFIX) @@ -235,7 +243,11 @@ newwindow: case 'o': CHECK_CMDWIN reset_VIsual_and_resel(); /* stop Visual mode */ - do_cmdline_cmd((char_u *)"only"); + STRCPY(cbuf, "only"); + if (Prenum > 0) + vim_snprintf((char *)cbuf + 4, sizeof(cbuf) - 4, + "%ld", Prenum); + do_cmdline_cmd(cbuf); break; /* cursor to next window with wrap around */
signature.asc
Description: Digital signature