changeset 9230:f7fb117883ba v7.4.1898

commit https://github.com/vim/vim/commit/63a60ded3fd584847a05dccf058026e682abad90 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Jun 4 22:08:55 2016 +0200 patch 7.4.1898 Problem: User commands don't support modifiers. Solution: Add the <mods> item. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/829)
author Christian Brabandt <cb@256bit.org>
date Sat, 04 Jun 2016 22:15:05 +0200
parents a169b470d24d
children 05ac1a1aedd4
files runtime/doc/map.txt src/ex_docmd.c src/testdir/Make_all.mak src/testdir/test_usercommands.vim src/version.c
diffstat 5 files changed, 180 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/map.txt
+++ b/runtime/doc/map.txt
@@ -1411,6 +1411,27 @@ The valid escape sequences are
 	<bang>	(See the '-bang' attribute) Expands to a ! if the
 		command was executed with a ! modifier, otherwise
 		expands to nothing.
+						*<mods>*
+	<mods>  The command modifiers, if specified. Otherwise, expands to
+		nothing. Supported modifiers are |aboveleft|, |belowright|,
+		|botright|, |browse|, |confirm|, |hide|, |keepalt|,
+		|keepjumps|, |keepmarks|, |keeppatterns|, |lockmarks|,
+		|noswapfile|, |silent|, |tab|, |topleft|, |verbose|, and
+		|vertical|.
+		Examples: >
+		    command! -nargs=+ -complete=file MyEdit
+				\ for f in expand(<q-args>, 0, 1) |
+				\ exe '<mods> split ' . f |
+				\ endfor
+
+		    function! SpecialEdit(files, mods)
+			for f in expand(a:files, 0, 1)
+			    exe a:mods . ' split ' . f
+			endfor
+		    endfunction
+		    command! -nargs=+ -complete=file Sedit
+				\ call SpecialEdit(<q-args>, <q-mods>)
+<
 						*<reg>* *<register>*
 	<reg>	(See the '-register' attribute) The optional register,
 		if specified.  Otherwise, expands to nothing.  <register>
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -6413,6 +6413,26 @@ uc_split_args(char_u *arg, size_t *lenp)
     return buf;
 }
 
+    static size_t
+add_cmd_modifier(char_u *buf, char *mod_str, int *multi_mods)
+{
+    size_t result;
+
+    result = STRLEN(mod_str);
+    if (*multi_mods)
+	result += 1;
+    if (buf != NULL)
+    {
+	if (*multi_mods)
+	    STRCAT(buf, " ");
+	STRCAT(buf, mod_str);
+    }
+
+    *multi_mods = 1;
+
+    return result;
+}
+
 /*
  * Check for a <> code in a user command.
  * "code" points to the '<'.  "len" the length of the <> (inclusive).
@@ -6436,8 +6456,8 @@ uc_check_code(
     char_u	*p = code + 1;
     size_t	l = len - 2;
     int		quote = 0;
-    enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_REGISTER,
-	ct_LT, ct_NONE } type = ct_NONE;
+    enum { ct_ARGS, ct_BANG, ct_COUNT, ct_LINE1, ct_LINE2, ct_MODS,
+	ct_REGISTER, ct_LT, ct_NONE } type = ct_NONE;
 
     if ((vim_strchr((char_u *)"qQfF", *p) != NULL) && p[1] == '-')
     {
@@ -6463,6 +6483,8 @@ uc_check_code(
 	type = ct_LT;
     else if (STRNICMP(p, "reg>", l) == 0 || STRNICMP(p, "register>", l) == 0)
 	type = ct_REGISTER;
+    else if (STRNICMP(p, "mods>", l) == 0)
+	type = ct_MODS;
 
     switch (type)
     {
@@ -6586,6 +6608,90 @@ uc_check_code(
 	break;
     }
 
+    case ct_MODS:
+    {
+	int multi_mods = 0;
+	typedef struct {
+	    int *varp;
+	    char *name;
+	} mod_entry_T;
+	static mod_entry_T mod_entries[] = {
+#ifdef FEAT_BROWSE_CMD
+	    {&cmdmod.browse, "browse"},
+#endif
+#if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
+	    {&cmdmod.confirm, "confirm"},
+#endif
+	    {&cmdmod.hide, "hide"},
+	    {&cmdmod.keepalt, "keepalt"},
+	    {&cmdmod.keepjumps, "keepjumps"},
+	    {&cmdmod.keepmarks, "keepmarks"},
+	    {&cmdmod.keeppatterns, "keeppatterns"},
+	    {&cmdmod.lockmarks, "lockmarks"},
+	    {&cmdmod.noswapfile, "noswapfile"},
+	    {NULL, NULL}
+	};
+	int i;
+
+	result = quote ? 2 : 0;
+	if (buf != NULL)
+	{
+	    if (quote)
+		*buf++ = '"';
+	    *buf = '\0';
+	}
+
+#ifdef FEAT_WINDOWS
+	/* :aboveleft and :leftabove */
+	if (cmdmod.split & WSP_ABOVE)
+	    result += add_cmd_modifier(buf, "aboveleft", &multi_mods);
+	/* :belowright and :rightbelow */
+	if (cmdmod.split & WSP_BELOW)
+	    result += add_cmd_modifier(buf, "belowright", &multi_mods);
+	/* :botright */
+	if (cmdmod.split & WSP_BOT)
+	    result += add_cmd_modifier(buf, "botright", &multi_mods);
+#endif
+
+	/* the modifiers that are simple flags */
+	for (i = 0; mod_entries[i].varp != NULL; ++i)
+	    if (*mod_entries[i].varp)
+		result += add_cmd_modifier(buf, mod_entries[i].name,
+								 &multi_mods);
+
+	/* TODO: How to support :noautocmd? */
+#ifdef HAVE_SANDBOX
+	/* TODO: How to support :sandbox?*/
+#endif
+	/* :silent */
+	if (msg_silent > 0)
+	    result += add_cmd_modifier(buf,
+		    emsg_silent > 0 ? "silent!" : "silent", &multi_mods);
+#ifdef FEAT_WINDOWS
+	/* :tab */
+	if (cmdmod.tab > 0)
+	    result += add_cmd_modifier(buf, "tab", &multi_mods);
+	/* :topleft */
+	if (cmdmod.split & WSP_TOP)
+	    result += add_cmd_modifier(buf, "topleft", &multi_mods);
+#endif
+	/* TODO: How to support :unsilent?*/
+	/* :verbose */
+	if (p_verbose > 0)
+	    result += add_cmd_modifier(buf, "verbose", &multi_mods);
+#ifdef FEAT_WINDOWS
+	/* :vertical */
+	if (cmdmod.split & WSP_VERT)
+	    result += add_cmd_modifier(buf, "vertical", &multi_mods);
+#endif
+	if (quote && buf != NULL)
+	{
+	    buf += result - 2;
+	    *buf = '"';
+	}
+	break;
+    }
+
     case ct_REGISTER:
 	result = eap->regname ? 1 : 0;
 	if (quote)
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -179,6 +179,7 @@ NEW_TESTS = test_arglist.res \
 	    test_perl.res \
 	    test_quickfix.res \
 	    test_syntax.res \
+	    test_usercommands.res \
 	    test_viminfo.res \
 	    test_viml.res \
 	    test_visual.res \
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_usercommands.vim
@@ -0,0 +1,48 @@
+" Tests for user defined commands
+
+" Test for <mods> in user defined commands
+function Test_cmdmods()
+  let g:mods = ''
+
+  command! -nargs=* MyCmd let g:mods .= '<mods> '
+
+  MyCmd
+  aboveleft MyCmd
+  belowright MyCmd
+  botright MyCmd
+  browse MyCmd
+  confirm MyCmd
+  hide MyCmd
+  keepalt MyCmd
+  keepjumps MyCmd
+  keepmarks MyCmd
+  keeppatterns MyCmd
+  lockmarks MyCmd
+  noswapfile MyCmd
+  silent MyCmd
+  tab MyCmd
+  topleft MyCmd
+  verbose MyCmd
+  vertical MyCmd
+
+  aboveleft belowright botright browse confirm hide keepalt keepjumps
+	      \ keepmarks keeppatterns lockmarks noswapfile silent tab
+	      \ topleft verbose vertical MyCmd
+
+  call assert_equal(' aboveleft belowright botright browse confirm ' .
+      \ 'hide keepalt keepjumps keepmarks keeppatterns lockmarks ' .
+      \ 'noswapfile silent tab topleft verbose vertical aboveleft ' .
+      \ 'belowright botright browse confirm hide keepalt keepjumps ' .
+      \ 'keepmarks keeppatterns lockmarks noswapfile silent tab topleft ' .
+      \ 'verbose vertical ', g:mods)
+
+  let g:mods = ''
+  command! -nargs=* MyQCmd let g:mods .= '<q-mods> '
+
+  vertical MyQCmd
+  call assert_equal('"vertical" ', g:mods)
+
+  delcommand MyCmd
+  delcommand MyQCmd
+  unlet g:mods
+endfunction
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1898,
+/**/
     1897,
 /**/
     1896,