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 [email protected]; $(MAKE) -f Makefile [email protected] 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
