On 15:51 Sun 10 Aug , Bram Moolenaar wrote: > > I wrote: > > > Marcin Szamotulski wrote: > > > > > I wrote a patch which adds [count] to :colse, :hide and ^Wc normal > > > command. When given the window with window number [count] will be > > > closed/hidden. Sometimes I want to close not the current window but > > > another one, this command let to do that without switching windows > > > without ^Ww normal command. > > > > Nice idea. I would find ":1close" and ":9close" the most useful, > > closing the first and last window. Looks like the code does take the > > last window when the count is more than the number of windows. This > > isn't obvious in the documentation, adding these two as an example will > > make them found quicker. And perhaps :hide docs should refer to the > > explanation of [count] in :close. > > > > How about a test? > > Thinking about this, it would also be very nice to be able to close the > next or previous window: > > :+1close > :-1close > > And there is this entry in the todo list: > > Can't easily close the help window, like ":pc" closes the > preview window and ":ccl" closes the quickfix window. Add > ":hclose". (Chris Gaal) > Patch for :helpclose, Christian Brabandt, 2010 Sep 6. > > Looks like I'm a bit behind including patches...
Here is the patch. As a bonus: :$close " will close the last window :$-close " will close the penultimate window :.close " the same as :close :%close, :/pattern/close, :*close, ... " will emit E16 error There are probably a few other commands that could benefit with a similar approach. Best regards, Marcin Szamotulski
diff -r 7090d7f160f7 runtime/doc/windows.txt --- a/runtime/doc/windows.txt Sat Jul 26 13:40:44 2014 +0200 +++ b/runtime/doc/windows.txt Sun Aug 10 19:32:26 2014 +0100 @@ -279,12 +279,23 @@ 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. - |tab-page|. +:[count]clo[se][!] + Close current window if [count] is not given, otherwise close + window with window number equal to [count]. 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|. If [count] is greater than + the last window number the last window will be closed: > + :1close " close the first window + :$close " close the last window + :9close " close the last window + " if there are less than 9 windows opened + :-close " close the previews window + :+close " close the next window + :+2close " will also work as expected +< 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 +309,14 @@ 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 |:close| 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. diff -r 7090d7f160f7 src/Makefile --- a/src/Makefile Sat Jul 26 13:40:44 2014 +0200 +++ b/src/Makefile Sun Aug 10 19:32:26 2014 +0100 @@ -1894,7 +1894,7 @@ 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 test108: cd testdir; rm $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) testclean: diff -r 7090d7f160f7 src/ex_cmds.h --- a/src/ex_cmds.h Sat Jul 26 13:40:44 2014 +0200 +++ b/src/ex_cmds.h Sun Aug 10 19:32:26 2014 +0100 @@ -232,7 +232,7 @@ EX(CMD_clast, "clast", ex_cc, RANGE|NOTADR|COUNT|TRLBAR|BANG), EX(CMD_close, "close", ex_close, - BANG|TRLBAR|CMDWIN), + BANG|RANGE|NOTADR|COUNT|TRLBAR|CMDWIN), EX(CMD_cmap, "cmap", ex_map, EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN), EX(CMD_cmapclear, "cmapclear", ex_mapclear, @@ -428,7 +428,7 @@ EX(CMD_highlight, "highlight", ex_highlight, BANG|EXTRA|TRLBAR|SBOXOK|CMDWIN), EX(CMD_hide, "hide", ex_hide, - BANG|EXTRA|NOTRLCOM), + BANG|RANGE|NOTADR|COUNT|EXTRA|NOTRLCOM), EX(CMD_history, "history", ex_history, EXTRA|TRLBAR|CMDWIN), EX(CMD_insert, "insert", ex_append, @@ -1206,3 +1206,13 @@ #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 -r 7090d7f160f7 src/ex_docmd.c --- a/src/ex_docmd.c Sat Jul 26 13:40:44 2014 +0200 +++ b/src/ex_docmd.c Sun Aug 10 19:32:26 2014 +0100 @@ -128,7 +128,7 @@ #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) \ @@ -1712,6 +1712,7 @@ void *cookie; /* argument for fgetline() */ { char_u *p; + addr_T addr; linenr_T lnum; long n; char_u *errormsg = NULL; /* error message */ @@ -1725,6 +1726,7 @@ #endif cmdmod_T save_cmdmod; int ni; /* set when Not Implemented */ + win_T *wp; vim_memset(&ea, 0, sizeof(ea)); ea.line1 = 1; @@ -2020,10 +2022,10 @@ 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); + addr = get_address(&ea.cmd, ea.skip, ea.addr_count == 0); if (ea.cmd == NULL) /* error detected */ goto doend; - if (lnum == MAXLNUM) + if (addr.lnum == MAXLNUM) { if (*ea.cmd == '%') /* '%' - all lines */ { @@ -2031,6 +2033,7 @@ ea.line1 = 1; ea.line2 = curbuf->b_ml.ml_line_count; ++ea.addr_count; + addr.type |= ADDRT_ALL; } /* '*' - visual area */ else if (*ea.cmd == '*' && vim_strchr(p_cpo, CPO_STAR) == NULL) @@ -2053,7 +2056,7 @@ } } else - ea.line2 = lnum; + ea.line2 = addr.lnum; ea.addr_count++; if (*ea.cmd == ';') @@ -2071,7 +2074,7 @@ { ea.line1 = ea.line2; /* ... but only implicit: really no address given */ - if (lnum == MAXLNUM) + if (addr.lnum == MAXLNUM) ea.addr_count = 0; } @@ -2170,6 +2173,59 @@ goto doend; } + /* + * for some commands addr might be used not as a line number + */ + if (ea.addr_count > 0) + { + if (ea.cmdidx == CMD_close || ea.cmdidx == CMD_hide) + { + if ( addr.type & ADDRT_MARK || + addr.type & ADDRT_SEARCH || + addr.type & ADDRT_REPEAT || + addr.type & ADDRT_ALL || + addr.type & ADDRT_VISUAL) + { + /* emit E16 */ + errormsg = (char_u *)_(e_invrange); + goto doend; + } + if (addr.type & ADDRT_LAST) + { + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) + lnum++; + if (addr.type & ADDRT_LOCAL) + { + lnum += addr.local; + /* avoid E16 if address is negative */ + if (lnum <= 0) + lnum = 1; + } + ea.line1 = ea.line2 = addr.lnum = lnum; + } + else if ((addr.type & ADDRT_LOCAL || addr.type & ADDRT_CURPOS) && + !(addr.type & ADDRT_ABSOLUTE)) + { + lnum = 0; + for (wp = firstwin; wp != NULL; wp = wp->w_next) + { + lnum++; + if (wp == curwin) + break; + } + if (addr.type & ADDRT_LOCAL) + { + lnum = lnum + addr.local; + /* avoid E16 if address is negative */ + if (lnum <= 0) + lnum = 1; + } + ea.line1 = ea.line2 = addr.lnum = lnum; + } + } + } + ni = ( #ifdef FEAT_USR_CMDS !USER_CMDIDX(ea.cmdidx) && @@ -3338,7 +3394,7 @@ ++p; } -/* +/*. * 5. parse arguments */ #ifdef FEAT_USR_CMDS @@ -4082,7 +4138,7 @@ * * 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 */ @@ -4094,22 +4150,26 @@ 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 */ @@ -4126,9 +4186,10 @@ * 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) @@ -4136,7 +4197,7 @@ cmd = NULL; goto error; } - lnum = fp->lnum; + addr.lnum = fp->lnum; } } break; @@ -4157,8 +4218,8 @@ * 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. @@ -4178,7 +4239,8 @@ 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; @@ -4204,8 +4266,9 @@ * 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; @@ -4221,7 +4284,7 @@ *cmd == '?' ? BACKWARD : FORWARD, (char_u *)"", 1L, SEARCH_MSG, i, (linenr_T)0, NULL) != FAIL) - lnum = pos.lnum; + addr.lnum = pos.lnum; else { cmd = NULL; @@ -4233,7 +4296,10 @@ default: if (VIM_ISDIGIT(*cmd)) /* absolute line number */ - lnum = getdigits(&cmd); + { + addr.lnum = getdigits(&cmd); + addr.type = ADDRT_ABSOLUTE; + } } for (;;) @@ -4242,8 +4308,9 @@ 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 @@ -4253,15 +4320,21 @@ 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; } /* @@ -6657,6 +6730,8 @@ ex_close(eap) exarg_T *eap; { + win_T *win; + int winnr = 0; # ifdef FEAT_CMDWIN if (cmdwin_type != 0) cmdwin_result = Ctrl_C; @@ -6667,7 +6742,21 @@ && !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 @@ -6895,6 +6984,9 @@ 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 @@ -6907,7 +6999,19 @@ # 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 } @@ -8639,9 +8743,9 @@ ex_copymove(eap) exarg_T *eap; { - long n; - - n = get_address(&eap->arg, FALSE, FALSE); + addr_T addr; + + addr = get_address(&eap->arg, FALSE, FALSE); if (eap->arg == NULL) /* error detected */ { eap->nextcmd = NULL; @@ -8650,9 +8754,10 @@ 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; @@ -8660,11 +8765,11 @@ 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 -r 7090d7f160f7 src/structs.h --- a/src/structs.h Sat Jul 26 13:40:44 2014 +0200 +++ b/src/structs.h Sun Aug 10 19:32:26 2014 +0100 @@ -21,6 +21,16 @@ #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 -r 7090d7f160f7 src/testdir/test108.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testdir/test108.in Sun Aug 10 19:32:26 2014 +0100 @@ -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) +:9close! +: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 +:3wincmd 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 -r 7090d7f160f7 src/testdir/test108.ok --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/testdir/test108.ok Sun Aug 10 19:32:26 2014 +0100 @@ -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 -r 7090d7f160f7 src/window.c --- a/src/window.c Sat Jul 26 13:40:44 2014 +0200 +++ b/src/window.c Sun Aug 10 19:32:26 2014 +0100 @@ -206,7 +206,11 @@ 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)
signature.asc
Description: Digital signature