changeset 22699:e82579016863 v8.2.1898

patch 8.2.1898: command modifier parsing always uses global cmdmod Commit: https://github.com/vim/vim/commit/e10044015841711b989f9a898d427bcc1fdb4c32 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Oct 24 20:49:43 2020 +0200 patch 8.2.1898: command modifier parsing always uses global cmdmod Problem: Command modifier parsing always uses global cmdmod. Solution: Pass in cmdmod_T to use. Rename struct fields consistently.
author Bram Moolenaar <Bram@vim.org>
date Sat, 24 Oct 2020 21:00:05 +0200
parents 28523bc9ee71
children 9414f650a6b9
files src/arglist.c src/buffer.c src/bufwrite.c src/change.c src/cmdhist.c src/diff.c src/edit.c src/ex_cmds.c src/ex_cmds2.c src/ex_docmd.c src/ex_getln.c src/fileio.c src/filepath.c src/gui.c src/gui_gtk_x11.c src/help.c src/if_cscope.c src/indent.c src/mark.c src/memline.c src/message.c src/ops.c src/option.c src/os_unix.c src/proto/ex_docmd.pro src/quickfix.c src/register.c src/scriptfile.c src/search.c src/session.c src/structs.h src/tag.c src/terminal.c src/textformat.c src/usercmd.c src/version.c src/vim9compile.c src/window.c
diffstat 38 files changed, 292 insertions(+), 279 deletions(-) [+]
line wrap: on
line diff
--- a/src/arglist.c
+++ b/src/arglist.c
@@ -657,7 +657,7 @@ do_argfile(exarg_T *eap, int argn)
 #endif
 
 	// split window or create new tab page first
-	if (*eap->cmd == 's' || cmdmod.tab != 0)
+	if (*eap->cmd == 's' || cmdmod.cmod_tab != 0)
 	{
 	    if (win_split(0, 0) == FAIL)
 		return;
@@ -878,7 +878,7 @@ do_arg_all(
     alist_T	*alist;		// argument list to be used
     buf_T	*buf;
     tabpage_T	*tpnext;
-    int		had_tab = cmdmod.tab;
+    int		had_tab = cmdmod.cmod_tab;
     win_T	*old_curwin, *last_curwin;
     tabpage_T	*old_curtab, *last_curtab;
     win_T	*new_curwin = NULL;
@@ -1116,7 +1116,7 @@ do_arg_all(
 
 	// When ":tab" was used open a new tab for a new window repeatedly.
 	if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
-	    cmdmod.tab = 9999;
+	    cmdmod.cmod_tab = 9999;
     }
 
     // Remove the "lock" on the argument list.
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -1444,7 +1444,7 @@ do_buffer(
 	if (!forceit && bufIsChanged(buf))
 	{
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	    if ((p_confirm || cmdmod.confirm) && p_write)
+	    if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
 	    {
 		dialog_changed(buf, FALSE);
 		if (!bufref_valid(&bufref))
@@ -1634,7 +1634,7 @@ do_buffer(
     if (action == DOBUF_GOTO && !can_abandon(curbuf, forceit))
     {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	if ((p_confirm || cmdmod.confirm) && p_write)
+	if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
 	{
 	    bufref_T bufref;
 
@@ -1689,7 +1689,7 @@ set_curbuf(buf_T *buf, int action)
     bufref_T	prevbufref;
 
     setpcmark();
-    if (!cmdmod.keepalt)
+    if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 	curwin->w_alt_fnum = curbuf->b_fnum; // remember alternate file
     buflist_altfpos(curwin);			 // remember curpos
 
@@ -3435,7 +3435,7 @@ setaltfname(
 
     // Create a buffer.  'buflisted' is not set if it's a new buffer
     buf = buflist_new(ffname, sfname, lnum, 0);
-    if (buf != NULL && !cmdmod.keepalt)
+    if (buf != NULL && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 	curwin->w_alt_fnum = buf->b_fnum;
     return buf;
 }
@@ -5068,7 +5068,7 @@ ex_buffer_all(exarg_T *eap)
     int		r;
     int		count;		// Maximum number of windows to open.
     int		all;		// When TRUE also load inactive buffers.
-    int		had_tab = cmdmod.tab;
+    int		had_tab = cmdmod.cmod_tab;
     tabpage_T	*tpnext;
 
     if (eap->addr_count == 0)	// make as many windows as possible
@@ -5099,7 +5099,7 @@ ex_buffer_all(exarg_T *eap)
 	{
 	    wpnext = wp->w_next;
 	    if ((wp->w_buffer->b_nwindows > 1
-		    || ((cmdmod.split & WSP_VERT)
+		    || ((cmdmod.cmod_split & WSP_VERT)
 			? wp->w_height + wp->w_status_height < Rows - p_ch
 							    - tabline_height()
 			: wp->w_width != Columns)
@@ -5220,7 +5220,7 @@ ex_buffer_all(exarg_T *eap)
 #endif
 	// When ":tab" was used open a new tab for a new window repeatedly.
 	if (had_tab > 0 && tabpage_index(NULL) <= p_tpm)
-	    cmdmod.tab = 9999;
+	    cmdmod.cmod_tab = 9999;
     }
     --autocmd_no_enter;
     win_enter(firstwin, FALSE);		// back to first window
@@ -5547,7 +5547,7 @@ buf_hide(buf_T *buf)
 	case 'd': return FALSE;	    // "delete"
 	case 'h': return TRUE;	    // "hide"
     }
-    return (p_hid || cmdmod.hide);
+    return (p_hid || (cmdmod.cmod_flags & CMOD_HIDE));
 }
 
 /*
--- a/src/bufwrite.c
+++ b/src/bufwrite.c
@@ -883,7 +883,7 @@ buf_write(
 #endif
 				       )
 	{
-	    if (buf != NULL && cmdmod.lockmarks)
+	    if (buf != NULL && (cmdmod.cmod_flags & CMOD_LOCKMARKS))
 	    {
 		// restore the original '[ and '] positions
 		buf->b_op_start = orig_start;
@@ -967,7 +967,7 @@ buf_write(
 	    fname = buf->b_sfname;
     }
 
-    if (cmdmod.lockmarks)
+    if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
     {
 	// restore the original '[ and '] positions
 	buf->b_op_start = orig_start;
--- a/src/change.c
+++ b/src/change.c
@@ -453,7 +453,7 @@ changed_common(
 #endif
 
     // set the '. mark
-    if (!cmdmod.keepjumps)
+    if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0)
     {
 	curbuf->b_last_change.lnum = lnum;
 	curbuf->b_last_change.col = col;
--- a/src/cmdhist.c
+++ b/src/cmdhist.c
@@ -304,7 +304,7 @@ add_to_history(
     if (hislen == 0)		// no history
 	return;
 
-    if (cmdmod.keeppatterns && histype == HIST_SEARCH)
+    if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) && histype == HIST_SEARCH)
 	return;
 
     // Searches inside the same mapping overwrite each other, so that only
--- a/src/diff.c
+++ b/src/diff.c
@@ -775,7 +775,7 @@ diff_write(buf_T *buf, diffin_T *din)
 {
     int		r;
     char_u	*save_ff;
-    int		save_lockmarks;
+    int		save_cmod_flags;
 
     if (din->din_fname == NULL)
 	return diff_write_buffer(buf, din);
@@ -783,14 +783,14 @@ diff_write(buf_T *buf, diffin_T *din)
     // Always use 'fileformat' set to "unix".
     save_ff = buf->b_p_ff;
     buf->b_p_ff = vim_strsave((char_u *)FF_UNIX);
-    save_lockmarks = cmdmod.lockmarks;
+    save_cmod_flags = cmdmod.cmod_flags;
     // Writing the buffer is an implementation detail of performing the diff,
     // so it shouldn't update the '[ and '] marks.
-    cmdmod.lockmarks = TRUE;
+    cmdmod.cmod_flags |= CMOD_LOCKMARKS;
     r = buf_write(buf, din->din_fname, NULL,
 			(linenr_T)1, buf->b_ml.ml_line_count,
 			NULL, FALSE, FALSE, FALSE, TRUE);
-    cmdmod.lockmarks = save_lockmarks;
+    cmdmod.cmod_flags = save_cmod_flags;
     free_string_option(buf->b_p_ff);
     buf->b_p_ff = save_ff;
     return r;
@@ -1187,13 +1187,13 @@ ex_diffpatch(exarg_T *eap)
 #endif
 #ifdef FEAT_BROWSE
     char_u	*browseFile = NULL;
-    int		browse_flag = cmdmod.browse;
+    int		save_cmod_flags = cmdmod.cmod_flags;
 #endif
     stat_T	st;
     char_u	*esc_name = NULL;
 
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse)
+    if (cmdmod.cmod_flags & CMOD_BROWSE)
     {
 	browseFile = do_browse(0, (char_u *)_("Patch file"),
 			 eap->arg, NULL, NULL,
@@ -1201,7 +1201,7 @@ ex_diffpatch(exarg_T *eap)
 	if (browseFile == NULL)
 	    return;		// operation cancelled
 	eap->arg = browseFile;
-	cmdmod.browse = FALSE;	// don't let do_ecmd() browse again
+	cmdmod.cmod_flags &= ~CMOD_BROWSE; // don't let do_ecmd() browse again
     }
 #endif
 
@@ -1310,7 +1310,7 @@ ex_diffpatch(exarg_T *eap)
 	need_mouse_correct = TRUE;
 #endif
 	// don't use a new tab page, each tab page has its own diffs
-	cmdmod.tab = 0;
+	cmdmod.cmod_tab = 0;
 
 	if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
 	{
@@ -1355,7 +1355,7 @@ theend:
     vim_free(esc_name);
 #ifdef FEAT_BROWSE
     vim_free(browseFile);
-    cmdmod.browse = browse_flag;
+    cmdmod.cmod_flags = save_cmod_flags;
 #endif
 }
 
@@ -1377,7 +1377,7 @@ ex_diffsplit(exarg_T *eap)
     set_fraction(curwin);
 
     // don't use a new tab page, each tab page has its own diffs
-    cmdmod.tab = 0;
+    cmdmod.cmod_tab = 0;
 
     if (win_split(0, (diff_flags & DIFF_VERTICAL) ? WSP_VERT : 0) != FAIL)
     {
--- a/src/edit.c
+++ b/src/edit.c
@@ -3616,7 +3616,7 @@ ins_esc(
 	curwin->w_set_curswant = TRUE;
 
     // Remember the last Insert position in the '^ mark.
-    if (!cmdmod.keepjumps)
+    if ((cmdmod.cmod_flags & CMOD_KEEPJUMPS) == 0)
 	curbuf->b_last_insert = curwin->w_cursor;
 
     /*
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -744,7 +744,7 @@ do_move(linenr_T line1, linenr_T line2, 
 		foldMoveRange(&win->w_folds, line1, line2, dest);
 	}
 #endif
-	if (!cmdmod.lockmarks)
+	if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	{
 	    curbuf->b_op_start.lnum = dest - num_lines + 1;
 	    curbuf->b_op_end.lnum = dest;
@@ -759,13 +759,13 @@ do_move(linenr_T line1, linenr_T line2, 
 		foldMoveRange(&win->w_folds, dest + 1, line1 - 1, line2);
 	}
 #endif
-	if (!cmdmod.lockmarks)
+	if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	{
 	    curbuf->b_op_start.lnum = dest + 1;
 	    curbuf->b_op_end.lnum = dest + num_lines;
 	}
     }
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
     mark_adjust_nofold(last_line - num_lines + 1, last_line,
 					     -(last_line - dest - extra), 0L);
@@ -815,7 +815,7 @@ ex_copy(linenr_T line1, linenr_T line2, 
     char_u	*p;
 
     count = line2 - line1 + 1;
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	curbuf->b_op_start.lnum = n + 1;
 	curbuf->b_op_end.lnum = n + count;
@@ -1062,7 +1062,7 @@ do_filter(
     int		shell_flags = 0;
     pos_T	orig_start = curbuf->b_op_start;
     pos_T	orig_end = curbuf->b_op_end;
-    int		save_lockmarks = cmdmod.lockmarks;
+    int		save_cmod_flags = cmdmod.cmod_flags;
 #ifdef FEAT_FILTERPIPE
     int		stmp = p_stmp;
 #endif
@@ -1072,7 +1072,7 @@ do_filter(
 
     // Temporarily disable lockmarks since that's needed to propagate changed
     // regions of the buffer for foldUpdate(), linecount, etc.
-    cmdmod.lockmarks = 0;
+    cmdmod.cmod_flags &= ~CMOD_LOCKMARKS;
 
     cursor_save = curwin->w_cursor;
     linecount = line2 - line1 + 1;
@@ -1241,7 +1241,8 @@ do_filter(
 
 	if (do_in)
 	{
-	    if (cmdmod.keepmarks || vim_strchr(p_cpo, CPO_REMMARK) == NULL)
+	    if ((cmdmod.cmod_flags & CMOD_KEEPMARKS)
+				     || vim_strchr(p_cpo, CPO_REMMARK) == NULL)
 	    {
 		if (read_linecount >= linecount)
 		    // move all marks from old lines to new lines
@@ -1307,13 +1308,13 @@ error:
 
 filterend:
 
-    cmdmod.lockmarks = save_lockmarks;
+    cmdmod.cmod_flags = save_cmod_flags;
     if (curbuf != old_curbuf)
     {
 	--no_wait_return;
 	emsg(_("E135: *Filter* Autocommands must not change current buffer"));
     }
-    else if (cmdmod.lockmarks)
+    else if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
     {
 	curbuf->b_op_start = orig_start;
 	curbuf->b_op_end = orig_end;
@@ -1769,7 +1770,7 @@ rename_buffer(char_u *new_fname)
     if (xfname != NULL && *xfname != NUL)
     {
 	buf = buflist_new(fname, xfname, curwin->w_cursor.lnum, 0);
-	if (buf != NULL && !cmdmod.keepalt)
+	if (buf != NULL && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 	    curwin->w_alt_fnum = buf->b_fnum;
     }
     vim_free(fname);
@@ -1866,7 +1867,7 @@ do_write(exarg_T *eap)
 
     ffname = eap->arg;
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse && !exiting)
+    if ((cmdmod.cmod_flags & CMOD_BROWSE) && !exiting)
     {
 	browse_file = do_browse(BROWSE_SAVE, (char_u *)_("Save As"), ffname,
 						    NULL, NULL, NULL, curbuf);
@@ -1942,7 +1943,7 @@ do_write(exarg_T *eap)
 		&& !p_wa)
 	{
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	    if (p_confirm || cmdmod.confirm)
+	    if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))
 	    {
 		if (vim_dialog_yesno(VIM_QUESTION, NULL,
 			       (char_u *)_("Write partial file?"), 2) != VIM_YES)
@@ -2091,7 +2092,7 @@ check_overwrite(
 	    }
 #endif
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	    if (p_confirm || cmdmod.confirm)
+	    if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))
 	    {
 		char_u	buff[DIALOG_MSG_SIZE];
 
@@ -2142,7 +2143,7 @@ check_overwrite(
 	    if (r)
 	    {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-		if (p_confirm || cmdmod.confirm)
+		if (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))
 		{
 		    char_u	buff[DIALOG_MSG_SIZE];
 
@@ -2229,12 +2230,13 @@ do_wqall(exarg_T *eap)
 	    }
 #ifdef FEAT_BROWSE
 	    // ":browse wall": ask for file name if there isn't one
-	    if (buf->b_ffname == NULL && cmdmod.browse)
+	    if (buf->b_ffname == NULL && (cmdmod.cmod_flags & CMOD_BROWSE))
 		browse_save_fname(buf);
 #endif
 	    if (buf->b_ffname == NULL)
 	    {
-		semsg(_("E141: No file name for buffer %ld"), (long)buf->b_fnum);
+		semsg(_("E141: No file name for buffer %ld"),
+							    (long)buf->b_fnum);
 		++error;
 	    }
 	    else if (check_readonly(&eap->forceit, buf)
@@ -2297,7 +2299,8 @@ check_readonly(int *forceit, buf_T *buf)
 		    && check_file_readonly(buf->b_ffname, 0777))))
     {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	if ((p_confirm || cmdmod.confirm) && buf->b_fname != NULL)
+	if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))
+						       && buf->b_fname != NULL)
 	{
 	    char_u	buff[DIALOG_MSG_SIZE];
 
@@ -2501,7 +2504,7 @@ do_ecmd(
     else
     {
 #ifdef FEAT_BROWSE
-	if (cmdmod.browse && !exiting)
+	if ((cmdmod.cmod_flags & CMOD_BROWSE) && !exiting)
 	{
 	    if (
 # ifdef FEAT_GUI
@@ -2612,7 +2615,7 @@ do_ecmd(
     {
 	if (!(flags & ECMD_ADDBUF))
 	{
-	    if (!cmdmod.keepalt)
+	    if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 		curwin->w_alt_fnum = curbuf->b_fnum;
 	    if (oldwin != NULL)
 		buflist_altfpos(oldwin);
@@ -3299,14 +3302,14 @@ ex_append(exarg_T *eap)
     // eap->line2 pointed to the end of the buffer and nothing was appended)
     // "end" is set to lnum when something has been appended, otherwise
     // it is the same than "start"  -- Acevedo
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	curbuf->b_op_start.lnum = (eap->line2 < curbuf->b_ml.ml_line_count) ?
 	    eap->line2 + 1 : curbuf->b_ml.ml_line_count;
 	if (eap->cmdidx != CMD_append)
 	    --curbuf->b_op_start.lnum;
 	curbuf->b_op_end.lnum = (eap->line2 < lnum)
-						 ? lnum : curbuf->b_op_start.lnum;
+					      ? lnum : curbuf->b_op_start.lnum;
 	curbuf->b_op_start.col = curbuf->b_op_end.col = 0;
     }
     curwin->w_cursor.lnum = lnum;
@@ -3729,7 +3732,7 @@ ex_substitute(exarg_T *eap)
 	    ex_may_print(eap);
 	}
 
-	if (!cmdmod.keeppatterns)
+	if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0)
 	    save_re_pat(RE_SUBST, pat, p_magic);
 	// put pattern in history
 	add_to_history(HIST_SEARCH, pat, TRUE, NUL);
@@ -4619,7 +4622,7 @@ outofmem:
 
     if (sub_nsubs > start_nsubs)
     {
-	if (!cmdmod.lockmarks)
+	if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	{
 	    // Set the '[ and '] marks.
 	    curbuf->b_op_start.lnum = eap->line1;
@@ -5108,7 +5111,7 @@ ex_drop(exarg_T *eap)
     if (ARGCOUNT == 0)
 	return;
 
-    if (cmdmod.tab)
+    if (cmdmod.cmod_tab)
     {
 	// ":tab drop file ...": open a tab for each argument that isn't
 	// edited in a window yet.  It's like ":tab all" but without closing
@@ -5247,7 +5250,7 @@ ex_oldfiles(exarg_T *eap UNUSED)
 	got_int = FALSE;
 
 # ifdef FEAT_BROWSE_CMD
-	if (cmdmod.browse)
+	if (cmdmod.cmod_flags & CMOD_BROWSE)
 	{
 	    quit_more = FALSE;
 	    nr = prompt_for_number(FALSE);
@@ -5262,7 +5265,7 @@ ex_oldfiles(exarg_T *eap UNUSED)
 		    p = expand_env_save(p);
 		    eap->arg = p;
 		    eap->cmdidx = CMD_edit;
-		    cmdmod.browse = FALSE;
+		    cmdmod.cmod_flags &= ~CMOD_BROWSE;
 		    do_exedit(eap, NULL);
 		    vim_free(p);
 		}
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -86,7 +86,7 @@ check_changed(buf_T *buf, int flags)
 	    && (!(flags & CCGD_AW) || autowrite(buf, forceit) == FAIL))
     {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	if ((p_confirm || cmdmod.confirm) && p_write)
+	if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
 	{
 	    buf_T	*buf2;
 	    int		count = 0;
@@ -96,7 +96,7 @@ check_changed(buf_T *buf, int flags)
 		    if (bufIsChanged(buf2)
 				     && (buf2->b_ffname != NULL
 # ifdef FEAT_BROWSE
-					 || cmdmod.browse
+					 || (cmdmod.cmod_flags & CMOD_BROWSE)
 # endif
 					))
 			++count;
@@ -197,7 +197,7 @@ dialog_changed(
 	    if (bufIsChanged(buf2)
 		    && (buf2->b_ffname != NULL
 #ifdef FEAT_BROWSE
-			|| cmdmod.browse
+			|| (cmdmod.cmod_flags & CMOD_BROWSE)
 #endif
 			)
 		    && !buf2->b_p_ro)
@@ -347,7 +347,7 @@ check_changed_any(
     /*
      * When ":confirm" used, don't give an error message.
      */
-    if (!(p_confirm || cmdmod.confirm))
+    if (!(p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)))
 #endif
     {
 	// There must be a wait_return for this message, do_buffer()
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -1711,7 +1711,6 @@ do_one_cmd(
     char	*errormsg = NULL;	// error message
     char_u	*after_modifier = NULL;
     exarg_T	ea;			// Ex command arguments
-    int		save_msg_scroll = msg_scroll;
     cmdmod_T	save_cmdmod;
     int		save_reg_executing = reg_executing;
     int		ni;			// set when Not Implemented
@@ -1762,7 +1761,7 @@ do_one_cmd(
     ea.cstack = cstack;
     starts_with_colon = *skipwhite(ea.cmd) == ':';
 #endif
-    if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL)
+    if (parse_command_modifiers(&ea, &errormsg, &cmdmod, FALSE) == FAIL)
 	goto doend;
     apply_cmdmod(&cmdmod);
 
@@ -2598,7 +2597,7 @@ doend:
 			? cmdnames[(int)ea.cmdidx].cmd_name : (char_u *)NULL);
 #endif
 
-    undo_cmdmod(save_msg_scroll);
+    undo_cmdmod(&cmdmod);
     cmdmod = save_cmdmod;
     reg_executing = save_reg_executing;
 
@@ -2633,25 +2632,31 @@ ex_errmsg(char *msg, char_u *arg)
 /*
  * Parse and skip over command modifiers:
  * - update eap->cmd
- * - store flags in "cmdmod".
+ * - store flags in "cmod".
  * - Set ex_pressedreturn for an empty command line.
- * - set msg_silent for ":silent"
- * - set 'eventignore' to "all" for ":noautocmd"
  * When "skip_only" is TRUE the global variables are not changed, except for
  * "cmdmod".
+ * When "skip_only" is FALSE then undo_cmdmod() must be called later to free
+ * any cmod_filter_regmatch.regprog.
  * Call apply_cmdmod() to get the side effects of the modifiers:
  * - Increment "sandbox" for ":sandbox"
  * - set p_verbose for ":verbose"
+ * - set msg_silent for ":silent"
+ * - set 'eventignore' to "all" for ":noautocmd"
  * Return FAIL when the command is not to be executed.
  * May set "errormsg" to an error message.
  */
     int
-parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only)
+parse_command_modifiers(
+	exarg_T	    *eap,
+	char	    **errormsg,
+	cmdmod_T    *cmod,
+	int	    skip_only)
 {
     char_u  *p;
     int	    starts_with_colon = FALSE;
 
-    CLEAR_FIELD(cmdmod);
+    CLEAR_POINTER(cmod);
 
     // Repeat until no more command modifiers are found.
     for (;;)
@@ -2690,51 +2695,51 @@ parse_command_modifiers(exarg_T *eap, ch
 	    // When adding an entry, also modify cmd_exists().
 	    case 'a':	if (!checkforcmd(&eap->cmd, "aboveleft", 3))
 			    break;
-			cmdmod.split |= WSP_ABOVE;
+			cmod->cmod_split |= WSP_ABOVE;
 			continue;
 
 	    case 'b':	if (checkforcmd(&eap->cmd, "belowright", 3))
 			{
-			    cmdmod.split |= WSP_BELOW;
+			    cmod->cmod_split |= WSP_BELOW;
 			    continue;
 			}
 			if (checkforcmd(&eap->cmd, "browse", 3))
 			{
 #ifdef FEAT_BROWSE_CMD
-			    cmdmod.browse = TRUE;
+			    cmod->cmod_flags |= CMOD_BROWSE;
 #endif
 			    continue;
 			}
 			if (!checkforcmd(&eap->cmd, "botright", 2))
 			    break;
-			cmdmod.split |= WSP_BOT;
+			cmod->cmod_split |= WSP_BOT;
 			continue;
 
 	    case 'c':	if (!checkforcmd(&eap->cmd, "confirm", 4))
 			    break;
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-			cmdmod.confirm = TRUE;
+			cmod->cmod_flags |= CMOD_CONFIRM;
 #endif
 			continue;
 
 	    case 'k':	if (checkforcmd(&eap->cmd, "keepmarks", 3))
 			{
-			    cmdmod.keepmarks = TRUE;
+			    cmod->cmod_flags |= CMOD_KEEPMARKS;
 			    continue;
 			}
 			if (checkforcmd(&eap->cmd, "keepalt", 5))
 			{
-			    cmdmod.keepalt = TRUE;
+			    cmod->cmod_flags |= CMOD_KEEPALT;
 			    continue;
 			}
 			if (checkforcmd(&eap->cmd, "keeppatterns", 5))
 			{
-			    cmdmod.keeppatterns = TRUE;
+			    cmod->cmod_flags |= CMOD_KEEPPATTERNS;
 			    continue;
 			}
 			if (!checkforcmd(&eap->cmd, "keepjumps", 5))
 			    break;
-			cmdmod.keepjumps = TRUE;
+			cmod->cmod_flags |= CMOD_KEEPJUMPS;
 			continue;
 
 	    case 'f':	// only accept ":filter {pat} cmd"
@@ -2746,7 +2751,7 @@ parse_command_modifiers(exarg_T *eap, ch
 				break;
 			    if (*p == '!')
 			    {
-				cmdmod.filter_force = TRUE;
+				cmod->cmod_filter_force = TRUE;
 				p = skipwhite(p + 1);
 				if (*p == NUL || ends_excmd(*p))
 				    break;
@@ -2765,9 +2770,9 @@ parse_command_modifiers(exarg_T *eap, ch
 				break;
 			    if (!skip_only)
 			    {
-				cmdmod.filter_regmatch.regprog =
+				cmod->cmod_filter_regmatch.regprog =
 						vim_regcomp(reg_pat, RE_MAGIC);
-				if (cmdmod.filter_regmatch.regprog == NULL)
+				if (cmod->cmod_filter_regmatch.regprog == NULL)
 				    break;
 			    }
 			    eap->cmd = p;
@@ -2779,48 +2784,48 @@ parse_command_modifiers(exarg_T *eap, ch
 					       || *p == NUL || ends_excmd(*p))
 			    break;
 			eap->cmd = p;
-			cmdmod.hide = TRUE;
+			cmod->cmod_flags |= CMOD_HIDE;
 			continue;
 
 	    case 'l':	if (checkforcmd(&eap->cmd, "lockmarks", 3))
 			{
-			    cmdmod.lockmarks = TRUE;
+			    cmod->cmod_flags |= CMOD_LOCKMARKS;
 			    continue;
 			}
 
 			if (!checkforcmd(&eap->cmd, "leftabove", 5))
 			    break;
-			cmdmod.split |= WSP_ABOVE;
+			cmod->cmod_split |= WSP_ABOVE;
 			continue;
 
 	    case 'n':	if (checkforcmd(&eap->cmd, "noautocmd", 3))
 			{
-			    cmdmod.cmod_flags |= CMOD_NOAUTOCMD;
+			    cmod->cmod_flags |= CMOD_NOAUTOCMD;
 			    continue;
 			}
 			if (!checkforcmd(&eap->cmd, "noswapfile", 3))
 			    break;
-			cmdmod.noswapfile = TRUE;
+			cmod->cmod_flags |= CMOD_NOSWAPFILE;
 			continue;
 
 	    case 'r':	if (!checkforcmd(&eap->cmd, "rightbelow", 6))
 			    break;
-			cmdmod.split |= WSP_BELOW;
+			cmod->cmod_split |= WSP_BELOW;
 			continue;
 
 	    case 's':	if (checkforcmd(&eap->cmd, "sandbox", 3))
 			{
-			    cmdmod.cmod_flags |= CMOD_SANDBOX;
+			    cmod->cmod_flags |= CMOD_SANDBOX;
 			    continue;
 			}
 			if (!checkforcmd(&eap->cmd, "silent", 3))
 			    break;
-			cmdmod.cmod_flags |= CMOD_SILENT;
+			cmod->cmod_flags |= CMOD_SILENT;
 			if (*eap->cmd == '!' && !VIM_ISWHITE(eap->cmd[-1]))
 			{
 			    // ":silent!", but not "silent !cmd"
 			    eap->cmd = skipwhite(eap->cmd + 1);
-			    cmdmod.cmod_flags |= CMOD_ERRSILENT;
+			    cmod->cmod_flags |= CMOD_ERRSILENT;
 			}
 			continue;
 
@@ -2832,7 +2837,7 @@ parse_command_modifiers(exarg_T *eap, ch
 						    ADDR_TABS, eap->skip,
 						    skip_only, FALSE, 1);
 				if (tabnr == MAXLNUM)
-				    cmdmod.tab = tabpage_index(curtab) + 1;
+				    cmod->cmod_tab = tabpage_index(curtab) + 1;
 				else
 				{
 				    if (tabnr < 0 || tabnr > LAST_TAB_NR)
@@ -2840,7 +2845,7 @@ parse_command_modifiers(exarg_T *eap, ch
 					*errormsg = _(e_invrange);
 					return FAIL;
 				    }
-				    cmdmod.tab = tabnr + 1;
+				    cmod->cmod_tab = tabnr + 1;
 				}
 			    }
 			    eap->cmd = p;
@@ -2848,25 +2853,25 @@ parse_command_modifiers(exarg_T *eap, ch
 			}
 			if (!checkforcmd(&eap->cmd, "topleft", 2))
 			    break;
-			cmdmod.split |= WSP_TOP;
+			cmod->cmod_split |= WSP_TOP;
 			continue;
 
 	    case 'u':	if (!checkforcmd(&eap->cmd, "unsilent", 3))
 			    break;
-			cmdmod.cmod_flags |= CMOD_UNSILENT;
+			cmod->cmod_flags |= CMOD_UNSILENT;
 			continue;
 
 	    case 'v':	if (checkforcmd(&eap->cmd, "vertical", 4))
 			{
-			    cmdmod.split |= WSP_VERT;
+			    cmod->cmod_split |= WSP_VERT;
 			    continue;
 			}
 			if (!checkforcmd(&p, "verbose", 4))
 			    break;
 			if (vim_isdigit(*eap->cmd))
-			    cmdmod.cmod_verbose = atoi((char *)eap->cmd);
+			    cmod->cmod_verbose = atoi((char *)eap->cmd);
 			else
-			    cmdmod.cmod_verbose = 1;
+			    cmod->cmod_verbose = 1;
 			eap->cmd = p;
 			continue;
 	}
@@ -2899,7 +2904,10 @@ apply_cmdmod(cmdmod_T *cmod)
 
     if ((cmod->cmod_flags & (CMOD_SILENT | CMOD_UNSILENT))
 	    && cmod->cmod_save_msg_silent == 0)
+    {
 	cmod->cmod_save_msg_silent = msg_silent + 1;
+	cmod->cmod_save_msg_scroll = msg_scroll;
+    }
     if (cmod->cmod_flags & CMOD_SILENT)
 	++msg_silent;
     if (cmod->cmod_flags & CMOD_UNSILENT)
@@ -2911,68 +2919,68 @@ apply_cmdmod(cmdmod_T *cmod)
 	++cmod->cmod_did_esilent;
     }
 
-    if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmdmod.cmod_save_ei == NULL)
+    if ((cmod->cmod_flags & CMOD_NOAUTOCMD) && cmod->cmod_save_ei == NULL)
     {
 	// Set 'eventignore' to "all".
 	// First save the existing option value for restoring it later.
-	cmdmod.cmod_save_ei = vim_strsave(p_ei);
+	cmod->cmod_save_ei = vim_strsave(p_ei);
 	set_string_option_direct((char_u *)"ei", -1,
 					  (char_u *)"all", OPT_FREE, SID_NONE);
     }
 }
 
 /*
- * Undo and free contents of "cmdmod".
+ * Undo and free contents of "cmod".
  */
     void
-undo_cmdmod(int save_msg_scroll)
-{
-    if (cmdmod.cmod_verbose_save > 0)
-    {
-	p_verbose = cmdmod.cmod_verbose_save - 1;
-	cmdmod.cmod_verbose_save = 0;
+undo_cmdmod(cmdmod_T *cmod)
+{
+    if (cmod->cmod_verbose_save > 0)
+    {
+	p_verbose = cmod->cmod_verbose_save - 1;
+	cmod->cmod_verbose_save = 0;
     }
 
 #ifdef HAVE_SANDBOX
-    if (cmdmod.cmod_did_sandbox)
+    if (cmod->cmod_did_sandbox)
     {
 	--sandbox;
-	cmdmod.cmod_did_sandbox = FALSE;
-    }
-#endif
-
-    if (cmdmod.cmod_save_ei != NULL)
+	cmod->cmod_did_sandbox = FALSE;
+    }
+#endif
+
+    if (cmod->cmod_save_ei != NULL)
     {
 	// Restore 'eventignore' to the value before ":noautocmd".
-	set_string_option_direct((char_u *)"ei", -1, cmdmod.cmod_save_ei,
-							  OPT_FREE, SID_NONE);
-	free_string_option(cmdmod.cmod_save_ei);
-	cmdmod.cmod_save_ei = NULL;
-    }
-
-    if (cmdmod.filter_regmatch.regprog != NULL)
-	vim_regfree(cmdmod.filter_regmatch.regprog);
-
-    if (cmdmod.cmod_save_msg_silent > 0)
+	set_string_option_direct((char_u *)"ei", -1, cmod->cmod_save_ei,
+							   OPT_FREE, SID_NONE);
+	free_string_option(cmod->cmod_save_ei);
+	cmod->cmod_save_ei = NULL;
+    }
+
+    if (cmod->cmod_filter_regmatch.regprog != NULL)
+	vim_regfree(cmod->cmod_filter_regmatch.regprog);
+
+    if (cmod->cmod_save_msg_silent > 0)
     {
 	// messages could be enabled for a serious error, need to check if the
 	// counters don't become negative
-	if (!did_emsg || msg_silent > cmdmod.cmod_save_msg_silent - 1)
-	    msg_silent = cmdmod.cmod_save_msg_silent - 1;
-	emsg_silent -= cmdmod.cmod_did_esilent;
+	if (!did_emsg || msg_silent > cmod->cmod_save_msg_silent - 1)
+	    msg_silent = cmod->cmod_save_msg_silent - 1;
+	emsg_silent -= cmod->cmod_did_esilent;
 	if (emsg_silent < 0)
 	    emsg_silent = 0;
 	// Restore msg_scroll, it's set by file I/O commands, even when no
 	// message is actually displayed.
-	msg_scroll = save_msg_scroll;
+	msg_scroll = cmod->cmod_save_msg_scroll;
 
 	// "silent reg" or "silent echo x" inside "redir" leaves msg_col
 	// somewhere in the line.  Put it back in the first column.
 	if (redirecting())
 	    msg_col = 0;
 
-	cmdmod.cmod_save_msg_silent = 0;
-	cmdmod.cmod_did_esilent = 0;
+	cmod->cmod_save_msg_silent = 0;
+	cmod->cmod_did_esilent = 0;
     }
 }
 
@@ -5130,7 +5138,8 @@ check_more(
 	if (message)
 	{
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	    if ((p_confirm || cmdmod.confirm) && curbuf->b_fname != NULL)
+	    if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM))
+						    && curbuf->b_fname != NULL)
 	    {
 		char_u	buff[DIALOG_MSG_SIZE];
 
@@ -5450,7 +5459,7 @@ ex_win_close(
     if (need_hide && !buf_hide(buf) && !forceit)
     {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	if ((p_confirm || cmdmod.confirm) && p_write)
+	if ((p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
 	{
 	    bufref_T bufref;
 
@@ -6106,7 +6115,7 @@ ex_splitview(exarg_T *eap)
 #endif
 #ifdef FEAT_BROWSE
     char_u	dot_path[] = ".";
-    int		browse_flag = cmdmod.browse;
+    int		save_cmod_flags = cmdmod.cmod_flags;
 #endif
     int		use_tab = eap->cmdidx == CMD_tabedit
 		       || eap->cmdidx == CMD_tabfind
@@ -6122,7 +6131,7 @@ ex_splitview(exarg_T *eap)
 #ifdef FEAT_QUICKFIX
     // A ":split" in the quickfix window works like ":new".  Don't want two
     // quickfix windows.  But it's OK when doing ":tab split".
-    if (bt_quickfix(curbuf) && cmdmod.tab == 0)
+    if (bt_quickfix(curbuf) && cmdmod.cmod_tab == 0)
     {
 	if (eap->cmdidx == CMD_split)
 	    eap->cmdidx = CMD_new;
@@ -6145,7 +6154,7 @@ ex_splitview(exarg_T *eap)
 # endif
 #endif
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse
+    if ((cmdmod.cmod_flags & CMOD_BROWSE)
 	    && eap->cmdidx != CMD_vnew
 	    && eap->cmdidx != CMD_new)
     {
@@ -6171,7 +6180,7 @@ ex_splitview(exarg_T *eap)
 	    eap->arg = fname;
 	}
     }
-    cmdmod.browse = FALSE;	// Don't browse again in do_ecmd().
+    cmdmod.cmod_flags &= ~CMOD_BROWSE;	// Don't browse again in do_ecmd().
 #endif
 
     /*
@@ -6179,7 +6188,7 @@ ex_splitview(exarg_T *eap)
      */
     if (use_tab)
     {
-	if (win_new_tabpage(cmdmod.tab != 0 ? cmdmod.tab
+	if (win_new_tabpage(cmdmod.cmod_tab != 0 ? cmdmod.cmod_tab
 			 : eap->addr_count == 0 ? 0
 					       : (int)eap->line2 + 1) != FAIL)
 	{
@@ -6189,7 +6198,7 @@ ex_splitview(exarg_T *eap)
 	    if (curwin != old_curwin
 		    && win_valid(old_curwin)
 		    && old_curwin->w_buffer != curbuf
-		    && !cmdmod.keepalt)
+		    && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 		old_curwin->w_alt_fnum = curbuf->b_fnum;
 	}
     }
@@ -6198,11 +6207,7 @@ ex_splitview(exarg_T *eap)
     {
 	// Reset 'scrollbind' when editing another file, but keep it when
 	// doing ":split" without arguments.
-	if (*eap->arg != NUL
-# ifdef FEAT_BROWSE
-		|| cmdmod.browse
-# endif
-	   )
+	if (*eap->arg != NUL)
 	    RESET_BINDING(curwin);
 	else
 	    do_check_scrollbind(FALSE);
@@ -6210,7 +6215,7 @@ ex_splitview(exarg_T *eap)
     }
 
 # ifdef FEAT_BROWSE
-    cmdmod.browse = browse_flag;
+    cmdmod.cmod_flags = save_cmod_flags;
 # endif
 
 # if defined(FEAT_SEARCHPATH) || defined(FEAT_BROWSE)
@@ -6383,7 +6388,7 @@ ex_resize(exarg_T *eap)
     need_mouse_correct = TRUE;
 # endif
     n = atol((char *)eap->arg);
-    if (cmdmod.split & WSP_VERT)
+    if (cmdmod.cmod_split & WSP_VERT)
     {
 	if (*eap->arg == '-' || *eap->arg == '+')
 	    n += wp->w_width;
@@ -6564,7 +6569,7 @@ do_exedit(
     else if ((eap->cmdidx != CMD_split && eap->cmdidx != CMD_vsplit)
 	    || *eap->arg != NUL
 #ifdef FEAT_BROWSE
-	    || cmdmod.browse
+	    || (cmdmod.cmod_flags & CMOD_BROWSE)
 #endif
 	    )
     {
@@ -6653,7 +6658,7 @@ do_exedit(
 	    && curwin != old_curwin
 	    && win_valid(old_curwin)
 	    && old_curwin->w_buffer != curbuf
-	    && !cmdmod.keepalt)
+	    && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 	old_curwin->w_alt_fnum = curbuf->b_fnum;
 
     ex_no_reprint = TRUE;
@@ -6798,7 +6803,7 @@ ex_read(exarg_T *eap)
 	    return;
 
 #ifdef FEAT_BROWSE
-	if (cmdmod.browse)
+	if (cmdmod.cmod_flags & CMOD_BROWSE)
 	{
 	    char_u *browseFile;
 
@@ -7238,8 +7243,8 @@ ex_wincmd(exarg_T *eap)
     else if (!eap->skip)
     {
 	// Pass flags on for ":vertical wincmd ]".
-	postponed_split_flags = cmdmod.split;
-	postponed_split_tab = cmdmod.tab;
+	postponed_split_flags = cmdmod.cmod_split;
+	postponed_split_tab = cmdmod.cmod_tab;
 	do_window(*eap->arg, eap->addr_count > 0 ? eap->line2 : 0L, xchar);
 	postponed_split_flags = 0;
 	postponed_split_tab = 0;
@@ -7642,7 +7647,7 @@ ex_redir(exarg_T *eap)
 	    if (fname == NULL)
 		return;
 #ifdef FEAT_BROWSE
-	    if (cmdmod.browse)
+	    if (cmdmod.cmod_flags & CMOD_BROWSE)
 	    {
 		char_u	*browseFile;
 
@@ -8314,8 +8319,8 @@ ex_pedit(exarg_T *eap)
 ex_stag(exarg_T *eap)
 {
     postponed_split = -1;
-    postponed_split_flags = cmdmod.split;
-    postponed_split_tab = cmdmod.tab;
+    postponed_split_flags = cmdmod.cmod_split;
+    postponed_split_tab = cmdmod.cmod_tab;
     ex_tag_cmd(eap, cmdnames[eap->cmdidx].cmd_name + 1);
     postponed_split_flags = 0;
     postponed_split_tab = 0;
--- a/src/ex_getln.c
+++ b/src/ex_getln.c
@@ -195,7 +195,7 @@ do_incsearch_highlighting(
 	int		    *patlen)
 {
     char_u	*cmd;
-    cmdmod_T	save_cmdmod = cmdmod;
+    cmdmod_T	dummy_cmdmod;
     char_u	*p;
     int		delim_optional = FALSE;
     int		delim;
@@ -231,8 +231,8 @@ do_incsearch_highlighting(
     ea.cmd = ccline.cmdbuff;
     ea.addr_type = ADDR_LINES;
 
-    parse_command_modifiers(&ea, &dummy, TRUE);
-    cmdmod = save_cmdmod;
+    CLEAR_FIELD(dummy_cmdmod);
+    parse_command_modifiers(&ea, &dummy, &dummy_cmdmod, TRUE);
 
     cmd = skip_range(ea.cmd, TRUE, NULL);
     if (vim_strchr((char_u *)"sgvl", *cmd) == NULL)
@@ -4163,8 +4163,8 @@ open_cmdwin(void)
     pum_undisplay();
 
     // don't use a new tab page
-    cmdmod.tab = 0;
-    cmdmod.noswapfile = 1;
+    cmdmod.cmod_tab = 0;
+    cmdmod.cmod_flags |= CMOD_NOSWAPFILE;
 
     // Create a window for the command-line buffer.
     if (win_split((int)p_cwh, WSP_BOT) == FAIL)
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2501,7 +2501,7 @@ failed:
 	check_cursor_lnum();
 	beginline(BL_WHITE | BL_FIX);	    // on first non-blank
 
-	if (!cmdmod.lockmarks)
+	if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	{
 	    // Set '[ and '] marks to the newly read lines.
 	    curbuf->b_op_start.lnum = from + 1;
--- a/src/filepath.c
+++ b/src/filepath.c
@@ -2213,11 +2213,11 @@ do_browse(
     char_u		*fname;
     static char_u	*last_dir = NULL;    // last used directory
     char_u		*tofree = NULL;
-    int			save_browse = cmdmod.browse;
+    int			save_cmod_flags = cmdmod.cmod_flags;
 
     // Must turn off browse to avoid that autocommands will get the
     // flag too!
-    cmdmod.browse = FALSE;
+    cmdmod.cmod_flags &= ~CMOD_BROWSE;
 
     if (title == NULL || *title == NUL)
     {
@@ -2350,7 +2350,7 @@ do_browse(
     }
 
     vim_free(tofree);
-    cmdmod.browse = save_browse;
+    cmdmod.cmod_flags = save_cmod_flags;
 
     return fname;
 }
--- a/src/gui.c
+++ b/src/gui.c
@@ -864,10 +864,10 @@ gui_shell_closed(void)
     // Only exit when there are no changed files
     exiting = TRUE;
 # ifdef FEAT_BROWSE
-    cmdmod.browse = TRUE;
+    cmdmod.cmod_flags |= CMOD_BROWSE;
 # endif
 # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-    cmdmod.confirm = TRUE;
+    cmdmod.cmod_flags |= CMOD_CONFIRM;
 # endif
     // If there are changed buffers, present the user with a dialog if
     // possible, otherwise give an error message.
--- a/src/gui_gtk_x11.c
+++ b/src/gui_gtk_x11.c
@@ -2226,10 +2226,10 @@ sm_client_check_changed_any(GnomeClient	
     save_cmdmod = cmdmod;
 
 # ifdef FEAT_BROWSE
-    cmdmod.browse = TRUE;
+    cmdmod.cmod_flags |= CMOD_BROWSE;
 # endif
 # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-    cmdmod.confirm = TRUE;
+    cmdmod.cmod_flags |= CMOD_CONFIRM;
 # endif
     /*
      * If there are changed buffers, present the user with
--- a/src/help.c
+++ b/src/help.c
@@ -123,9 +123,9 @@ ex_help(exarg_T *eap)
 
     // Re-use an existing help window or open a new one.
     // Always open a new one for ":tab help".
-    if (!bt_help(curwin->w_buffer) || cmdmod.tab != 0)
+    if (!bt_help(curwin->w_buffer) || cmdmod.cmod_tab != 0)
     {
-	if (cmdmod.tab != 0)
+	if (cmdmod.cmod_tab != 0)
 	    wp = NULL;
 	else
 	    FOR_ALL_WINDOWS(wp)
@@ -148,7 +148,7 @@ ex_help(exarg_T *eap)
 	    // specified, the current window is vertically split and
 	    // narrow.
 	    n = WSP_HELP;
-	    if (cmdmod.split == 0 && curwin->w_width != Columns
+	    if (cmdmod.cmod_split == 0 && curwin->w_width != Columns
 						  && curwin->w_width < 80)
 		n |= WSP_TOP;
 	    if (win_split(0, n) == FAIL)
@@ -164,7 +164,7 @@ ex_help(exarg_T *eap)
 	    (void)do_ecmd(0, NULL, NULL, NULL, ECMD_LASTL,
 			  ECMD_HIDE + ECMD_SET_HELP,
 			  NULL);  // buffer is still open, don't store info
-	    if (!cmdmod.keepalt)
+	    if ((cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 		curwin->w_alt_fnum = alt_fnum;
 	    empty_fnum = curbuf->b_fnum;
 	}
@@ -193,7 +193,8 @@ ex_help(exarg_T *eap)
     }
 
     // keep the previous alternate file
-    if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum && !cmdmod.keepalt)
+    if (alt_fnum != 0 && curwin->w_alt_fnum == empty_fnum
+				    && (cmdmod.cmod_flags & CMOD_KEEPALT) == 0)
 	curwin->w_alt_fnum = alt_fnum;
 
 erret:
--- a/src/if_cscope.c
+++ b/src/if_cscope.c
@@ -212,8 +212,8 @@ do_cscope_general(
 	    return;
 	}
 	postponed_split = -1;
-	postponed_split_flags = cmdmod.split;
-	postponed_split_tab = cmdmod.tab;
+	postponed_split_flags = cmdmod.cmod_split;
+	postponed_split_tab = cmdmod.cmod_tab;
     }
 
     cmdp->func(eap);
--- a/src/indent.c
+++ b/src/indent.c
@@ -1049,7 +1049,7 @@ op_reindent(oparg_T *oap, int (*how)(voi
 	smsg(NGETTEXT("%ld line indented ",
 						 "%ld lines indented ", i), i);
     }
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// set '[ and '] marks
 	curbuf->b_op_start = oap->start;
--- a/src/mark.c
+++ b/src/mark.c
@@ -145,7 +145,7 @@ setpcmark(void)
 #endif
 
     // for :global the mark is set only once
-    if (global_busy || listcmd_busy || cmdmod.keepjumps)
+    if (global_busy || listcmd_busy || (cmdmod.cmod_flags & CMOD_KEEPJUMPS))
 	return;
 
     curwin->w_prev_pcmark = curwin->w_pcmark;
@@ -1068,7 +1068,7 @@ mark_adjust_internal(
     if (line2 < line1 && amount_after == 0L)	    // nothing to do
 	return;
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// named marks, lower case and upper case
 	for (i = 0; i < NMARKS; i++)
@@ -1133,7 +1133,7 @@ mark_adjust_internal(
     FOR_ALL_TAB_WINDOWS(tab, win)
     {
 #ifdef FEAT_JUMPLIST
-	if (!cmdmod.lockmarks)
+	if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	    // Marks in the jumplist.  When deleting lines, this may create
 	    // duplicate marks in the jumplist, they will be removed later.
 	    for (i = 0; i < win->w_jumplistlen; ++i)
@@ -1143,7 +1143,7 @@ mark_adjust_internal(
 
 	if (win->w_buffer == curbuf)
 	{
-	    if (!cmdmod.lockmarks)
+	    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 		// marks in the tag stack
 		for (i = 0; i < win->w_tagstacklen; i++)
 		    if (win->w_tagstack[i].fmark.fnum == fnum)
@@ -1249,7 +1249,8 @@ mark_col_adjust(
     win_T	*win;
     pos_T	*posp;
 
-    if ((col_amount == 0L && lnum_amount == 0L) || cmdmod.lockmarks)
+    if ((col_amount == 0L && lnum_amount == 0L)
+				       || (cmdmod.cmod_flags & CMOD_LOCKMARKS))
 	return; // nothing to do
 
     // named marks, lower case and upper case
--- a/src/memline.c
+++ b/src/memline.c
@@ -289,7 +289,7 @@ ml_open(buf_T *buf)
     buf->b_ml.ml_chunksize = NULL;
 #endif
 
-    if (cmdmod.noswapfile)
+    if (cmdmod.cmod_flags & CMOD_NOSWAPFILE)
 	buf->b_p_swf = FALSE;
 
     /*
@@ -635,7 +635,7 @@ ml_setname(buf_T *buf)
 	 * When 'updatecount' is 0 and 'noswapfile' there is no swap file.
 	 * For help files we will make a swap file now.
 	 */
-	if (p_uc != 0 && !cmdmod.noswapfile)
+	if (p_uc != 0 && (cmdmod.cmod_flags & CMOD_NOSWAPFILE) == 0)
 	    ml_open_file(buf);	    // create a swap file
 	return;
     }
@@ -747,7 +747,8 @@ ml_open_file(buf_T *buf)
     char_u	*dirp;
 
     mfp = buf->b_ml.ml_mfp;
-    if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf || cmdmod.noswapfile)
+    if (mfp == NULL || mfp->mf_fd >= 0 || !buf->b_p_swf
+				      || (cmdmod.cmod_flags & CMOD_NOSWAPFILE))
 	return;		// nothing to do
 
 #ifdef FEAT_SPELL
--- a/src/message.c
+++ b/src/message.c
@@ -2319,10 +2319,10 @@ message_filtered(char_u *msg)
 {
     int match;
 
-    if (cmdmod.filter_regmatch.regprog == NULL)
+    if (cmdmod.cmod_filter_regmatch.regprog == NULL)
 	return FALSE;
-    match = vim_regexec(&cmdmod.filter_regmatch, msg, (colnr_T)0);
-    return cmdmod.filter_force ? match : !match;
+    match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, (colnr_T)0);
+    return cmdmod.cmod_filter_force ? match : !match;
 }
 
 /*
--- a/src/ops.c
+++ b/src/ops.c
@@ -204,7 +204,7 @@ op_shift(oparg_T *oap, int curs_top, int
 	msg_attr_keep((char *)IObuff, 0, TRUE);
     }
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// Set "'[" and "']" marks.
 	curbuf->b_op_start = oap->start;
@@ -943,7 +943,7 @@ op_delete(oparg_T *oap)
     msgmore(curbuf->b_ml.ml_line_count - old_lcount);
 
 setmarks:
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	if (oap->block_mode)
 	{
@@ -1216,7 +1216,7 @@ op_replace(oparg_T *oap, int c)
     check_cursor();
     changed_lines(oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0L);
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// Set "'[" and "']" marks.
 	curbuf->b_op_start = oap->start;
@@ -1329,7 +1329,7 @@ op_tilde(oparg_T *oap)
 	// No change: need to remove the Visual selection
 	redraw_curbuf_later(INVERTED);
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// Set '[ and '] marks.
 	curbuf->b_op_start = oap->start;
@@ -1942,7 +1942,7 @@ do_join(
 #ifdef FEAT_PROP_POPUP
 	propcount += count_props((linenr_T) (curwin->w_cursor.lnum + t), t > 0);
 #endif
-	if (t == 0 && setmark && !cmdmod.lockmarks)
+	if (t == 0 && setmark && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	{
 	    // Set the '[ mark.
 	    curwin->w_buffer->b_op_start.lnum = curwin->w_cursor.lnum;
@@ -2088,7 +2088,7 @@ do_join(
 
     ml_replace_len(curwin->w_cursor.lnum, newp, (colnr_T)newp_len, TRUE, FALSE);
 
-    if (setmark && !cmdmod.lockmarks)
+    if (setmark && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// Set the '] mark.
 	curwin->w_buffer->b_op_end.lnum = curwin->w_cursor.lnum;
@@ -2405,7 +2405,7 @@ op_addsub(
 
 	// Set '[ mark if something changed. Keep the last end
 	// position from do_addsub().
-	if (change_cnt > 0 && !cmdmod.lockmarks)
+	if (change_cnt > 0 && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	    curbuf->b_op_start = startpos;
 
 	if (change_cnt > p_report)
@@ -2852,7 +2852,7 @@ do_addsub(
 	    --curwin->w_cursor.col;
     }
 
-    if (did_change && !cmdmod.lockmarks)
+    if (did_change && (cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// set the '[ and '] marks
 	curbuf->b_op_start = startpos;
@@ -3301,7 +3301,7 @@ op_function(oparg_T *oap UNUSED)
 	(void)call_func_retnr(p_opfunc, 1, argv);
 
 	virtual_op = save_virtual_op;
-	if (cmdmod.lockmarks)
+	if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
 	{
 	    curbuf->b_op_start = orig_start;
 	    curbuf->b_op_end = orig_end;
--- a/src/option.c
+++ b/src/option.c
@@ -1125,7 +1125,7 @@ ex_set(exarg_T *eap)
     else if (eap->cmdidx == CMD_setglobal)
 	flags = OPT_GLOBAL;
 #if defined(FEAT_EVAL) && defined(FEAT_BROWSE)
-    if (cmdmod.browse && flags == 0)
+    if ((cmdmod.cmod_flags & CMOD_BROWSE) && flags == 0)
 	ex_options(eap);
     else
 #endif
@@ -5774,7 +5774,7 @@ buf_copy_options(buf_T *buf, int flags)
 	    buf->b_p_ml_nobin = p_ml_nobin;
 	    buf->b_p_inf = p_inf;
 	    COPY_OPT_SCTX(buf, BV_INF);
-	    if (cmdmod.noswapfile)
+	    if (cmdmod.cmod_flags & CMOD_NOSWAPFILE)
 		buf->b_p_swf = FALSE;
 	    else
 	    {
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -7868,15 +7868,15 @@ clip_xterm_set_selection(Clipboard_T *cb
     static void
 xsmp_handle_interaction(SmcConn smc_conn, SmPointer client_data UNUSED)
 {
-    cmdmod_T	save_cmdmod;
+    int		save_cmod_flags;
     int		cancel_shutdown = False;
 
-    save_cmdmod = cmdmod;
-    cmdmod.confirm = TRUE;
+    save_cmod_flags = cmdmod.cmod_flags;
+    cmdmod.cmod_flags |= CMOD_CONFIRM;
     if (check_changed_any(FALSE, FALSE))
 	// Mustn't logout
 	cancel_shutdown = True;
-    cmdmod = save_cmdmod;
+    cmdmod.cmod_flags = save_cmod_flags;
     setcursor();		// position cursor
     out_flush();
 
--- a/src/proto/ex_docmd.pro
+++ b/src/proto/ex_docmd.pro
@@ -6,9 +6,9 @@ int getline_equal(char_u *(*fgetline)(in
 void *getline_cookie(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
 char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie);
 char *ex_errmsg(char *msg, char_u *arg);
-int parse_command_modifiers(exarg_T *eap, char **errormsg, int skip_only);
+int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, int skip_only);
 void apply_cmdmod(cmdmod_T *cmod);
-void undo_cmdmod(int save_msg_scroll);
+void undo_cmdmod(cmdmod_T *cmod);
 int parse_cmd_address(exarg_T *eap, char **errormsg, int silent);
 int checkforcmd(char_u **pp, char *cmd, int len);
 char_u *skip_option_env_lead(char_u *start);
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -2834,7 +2834,7 @@ jump_to_help_window(qf_info_T *qi, int n
     win_T	*wp;
     int		flags;
 
-    if (cmdmod.tab != 0 || newwin)
+    if (cmdmod.cmod_tab != 0 || newwin)
 	wp = NULL;
     else
 	wp = qf_find_help_win();
@@ -2845,7 +2845,7 @@ jump_to_help_window(qf_info_T *qi, int n
 	// Split off help window; put it at far top if no position
 	// specified, the current window is vertically split and narrow.
 	flags = WSP_HELP;
-	if (cmdmod.split == 0 && curwin->w_width != Columns
+	if (cmdmod.cmod_split == 0 && curwin->w_width != Columns
 		&& curwin->w_width < 80)
 	    flags |= WSP_TOP;
 	// If the user asks to open a new window, then copy the location list.
@@ -3278,7 +3278,8 @@ qf_jump_open_window(
     qfltype_T	qfl_type = qfl->qfl_type;
 
     // For ":helpgrep" find a help window or open one.
-    if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer) || cmdmod.tab != 0))
+    if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer)
+						      || cmdmod.cmod_tab != 0))
 	if (jump_to_help_window(qi, newwin, opened_window) == FAIL)
 	    return FAIL;
     if (old_qf_curlist != qi->qf_curlist
@@ -4125,12 +4126,12 @@ qf_open_new_cwindow(qf_info_T *qi, int h
     // The current window becomes the previous window afterwards.
     win = curwin;
 
-    if (IS_QF_STACK(qi) && cmdmod.split == 0)
+    if (IS_QF_STACK(qi) && cmdmod.cmod_split == 0)
 	// Create the new quickfix window at the very bottom, except when
 	// :belowright or :aboveleft is used.
 	win_goto(lastwin);
     // Default is to open the window below the current window
-    if (cmdmod.split == 0)
+    if (cmdmod.cmod_split == 0)
 	flags = WSP_BELOW;
     flags |= WSP_NEWLOC;
     if (win_split(height, flags) == FAIL)
@@ -4208,9 +4209,9 @@ ex_copen(exarg_T *eap)
 #endif
 
     // Find an existing quickfix window, or open a new one.
-    if (cmdmod.tab == 0)
+    if (cmdmod.cmod_tab == 0)
 	status = qf_goto_cwindow(qi, eap->addr_count != 0, height,
-						cmdmod.split & WSP_VERT);
+						cmdmod.cmod_split & WSP_VERT);
     if (status == FAIL)
 	if (qf_open_new_cwindow(qi, height) == FAIL)
 	{
@@ -5693,7 +5694,7 @@ ex_cfile(exarg_T *eap)
 
     enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse)
+    if (cmdmod.cmod_flags & CMOD_BROWSE)
     {
 	char_u *browse_file = do_browse(0, (char_u *)_("Error file"), eap->arg,
 				   NULL, NULL,
@@ -6164,7 +6165,7 @@ vgr_process_files(
 		    wipe_dummy_buffer(buf, dirname_start);
 		    buf = NULL;
 		}
-		else if (!cmdmod.hide
+		else if ((cmdmod.cmod_flags & CMOD_HIDE) == 0
 			    || buf->b_p_bh[0] == 'u'	// "unload"
 			    || buf->b_p_bh[0] == 'w'	// "wipe"
 			    || buf->b_p_bh[0] == 'd')	// "delete"
--- a/src/register.c
+++ b/src/register.c
@@ -1358,7 +1358,7 @@ op_yank(oparg_T *oap, int deleting, int 
 	}
     }
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
     {
 	// Set "'[" and "']" marks.
 	curbuf->b_op_start = oap->start;
@@ -2170,7 +2170,7 @@ error:
     curwin->w_set_curswant = TRUE;
 
 end:
-    if (cmdmod.lockmarks)
+    if (cmdmod.cmod_flags & CMOD_LOCKMARKS)
     {
 	curbuf->b_op_start = orig_start;
 	curbuf->b_op_end = orig_end;
--- a/src/scriptfile.c
+++ b/src/scriptfile.c
@@ -979,7 +979,7 @@ cmd_source(char_u *fname, exarg_T *eap)
 ex_source(exarg_T *eap)
 {
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse)
+    if (cmdmod.cmod_flags & CMOD_BROWSE)
     {
 	char_u *fname = NULL;
 
--- a/src/search.c
+++ b/src/search.c
@@ -189,7 +189,8 @@ search_regcomp(
      * Save the currently used pattern in the appropriate place,
      * unless the pattern should not be remembered.
      */
-    if (!(options & SEARCH_KEEP) && !cmdmod.keeppatterns)
+    if (!(options & SEARCH_KEEP)
+			       && (cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0)
     {
 	// search or global command
 	if (pat_save == RE_SEARCH || pat_save == RE_BOTH)
@@ -1661,7 +1662,7 @@ do_search(
     curwin->w_set_curswant = TRUE;
 
 end_do_search:
-    if ((options & SEARCH_KEEP) || cmdmod.keeppatterns)
+    if ((options & SEARCH_KEEP) || (cmdmod.cmod_flags & CMOD_KEEPPATTERNS))
 	spats[0].off = old_off;
     vim_free(strcopy);
     vim_free(msgbuf);
--- a/src/session.c
+++ b/src/session.c
@@ -1144,7 +1144,7 @@ ex_mkrc(exarg_T	*eap)
 	fname = (char_u *)EXRC_FILE;
 
 #ifdef FEAT_BROWSE
-    if (cmdmod.browse)
+    if (cmdmod.cmod_flags & CMOD_BROWSE)
     {
 	browseFile = do_browse(BROWSE_SAVE,
 # ifdef FEAT_SESSION
--- a/src/structs.h
+++ b/src/structs.h
@@ -625,24 +625,26 @@ typedef struct
  */
 typedef struct
 {
-    int		cmod_flags;		// CMOD_ flags, see below
-    int		hide;			// TRUE when ":hide" was used
-# ifdef FEAT_BROWSE_CMD
-    int		browse;			// TRUE to invoke file dialog
-# endif
-    int		split;			// flags for win_split()
-    int		tab;			// > 0 when ":tab" was used
-# if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-    int		confirm;		// TRUE to invoke yes/no dialog
-# endif
-    int		keepalt;		// TRUE when ":keepalt" was used
-    int		keepmarks;		// TRUE when ":keepmarks" was used
-    int		keepjumps;		// TRUE when ":keepjumps" was used
-    int		lockmarks;		// TRUE when ":lockmarks" was used
-    int		keeppatterns;		// TRUE when ":keeppatterns" was used
-    int		noswapfile;		// TRUE when ":noswapfile" was used
-    regmatch_T	filter_regmatch;	// set by :filter /pat/
-    int		filter_force;		// set for :filter!
+    int		cmod_flags;		// CMOD_ flags
+#define CMOD_SANDBOX	    0x0001	// ":sandbox"
+#define CMOD_SILENT	    0x0002	// ":silent"
+#define CMOD_ERRSILENT	    0x0004	// ":silent!"
+#define CMOD_UNSILENT	    0x0008	// ":unsilent"
+#define CMOD_NOAUTOCMD	    0x0010	// ":noautocmd"
+#define CMOD_HIDE	    0x0020	// ":hide"
+#define CMOD_BROWSE	    0x0040	// ":browse" - invoke file dialog
+#define CMOD_CONFIRM	    0x0080	// ":confirm" - invoke yes/no dialog
+#define CMOD_KEEPALT	    0x0100	// ":keepalt"
+#define CMOD_KEEPMARKS	    0x0200	// ":keepmarks"
+#define CMOD_KEEPJUMPS	    0x0400	// ":keepjumps"
+#define CMOD_LOCKMARKS	    0x0800	// ":lockmarks"
+#define CMOD_KEEPPATTERNS   0x1000	// ":keeppatterns"
+#define CMOD_NOSWAPFILE	    0x2000	// ":noswapfile"
+
+    int		cmod_split;		// flags for win_split()
+    int		cmod_tab;		// > 0 when ":tab" was used
+    regmatch_T	cmod_filter_regmatch;	// set by :filter /pat/
+    int		cmod_filter_force;	// set for :filter!
 
     int		cmod_verbose;		// non-zero to set 'verbose'
 
@@ -655,15 +657,10 @@ typedef struct
 					// p_verbose plus one
     int		cmod_save_msg_silent;	// if non-zero: saved value of
 					// msg_silent + 1
+    int		cmod_save_msg_scroll;	// for restoring msg_scroll
     int		cmod_did_esilent;	// incremented when emsg_silent is
 } cmdmod_T;
 
-#define CMOD_SANDBOX	0x01
-#define CMOD_SILENT	0x02
-#define CMOD_ERRSILENT	0x04
-#define CMOD_UNSILENT	0x08
-#define CMOD_NOAUTOCMD	0x10
-
 #define MF_SEED_LEN	8
 
 struct memfile
--- a/src/tag.c
+++ b/src/tag.c
@@ -3463,7 +3463,7 @@ jumpto_tag(
 	}
     }
     if (getfile_result == GETFILE_UNUSED
-				       && (postponed_split || cmdmod.tab != 0))
+				  && (postponed_split || cmdmod.cmod_tab != 0))
     {
 	if (win_split(postponed_split > 0 ? postponed_split : 0,
 						postponed_split_flags) == FAIL)
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -440,7 +440,7 @@ term_start(
     buf_T	*old_curbuf = NULL;
     int		res;
     buf_T	*newbuf;
-    int		vertical = opt->jo_vertical || (cmdmod.split & WSP_VERT);
+    int		vertical = opt->jo_vertical || (cmdmod.cmod_split & WSP_VERT);
     jobopt_T	orig_opt;  // only partly filled
 
     if (check_restricted() || check_secure())
@@ -529,7 +529,7 @@ term_start(
 	}
 
 	if (vertical)
-	    cmdmod.split |= WSP_VERT;
+	    cmdmod.cmod_split |= WSP_VERT;
 	ex_splitview(&split_ea);
 	if (curwin == old_curwin)
 	{
@@ -1592,7 +1592,8 @@ term_try_stop_job(buf_T *buf)
     char    *how = (char *)buf->b_term->tl_kill;
 
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-    if ((how == NULL || *how == NUL) && (p_confirm || cmdmod.confirm))
+    if ((how == NULL || *how == NUL)
+			  && (p_confirm || (cmdmod.cmod_flags & CMOD_CONFIRM)))
     {
 	char_u	buff[DIALOG_MSG_SIZE];
 	int	ret;
--- a/src/textformat.c
+++ b/src/textformat.c
@@ -819,7 +819,7 @@ op_format(
 	// When there is no change: need to remove the Visual selection
 	redraw_curbuf_later(INVERTED);
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	// Set '[ mark at the start of the formatted area
 	curbuf->b_op_start = oap->start;
 
@@ -839,7 +839,7 @@ op_format(
     old_line_count = curbuf->b_ml.ml_line_count - old_line_count;
     msgmore(old_line_count);
 
-    if (!cmdmod.lockmarks)
+    if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0)
 	// put '] mark on the end of the formatted area
 	curbuf->b_op_end = curwin->w_cursor;
 
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -1235,8 +1235,8 @@ add_cmd_modifier(char_u *buf, char *mod_
 }
 
 /*
- * Add modifiers from "cmdmod.split" to "buf".  Set "multi_mods" when one was
- * added.  Return the number of bytes added.
+ * Add modifiers from "cmdmod.cmod_split" to "buf".  Set "multi_mods" when one
+ * was added.  Return the number of bytes added.
  */
     size_t
 add_win_cmd_modifers(char_u *buf, int *multi_mods)
@@ -1244,23 +1244,23 @@ add_win_cmd_modifers(char_u *buf, int *m
     size_t result = 0;
 
     // :aboveleft and :leftabove
-    if (cmdmod.split & WSP_ABOVE)
+    if (cmdmod.cmod_split & WSP_ABOVE)
 	result += add_cmd_modifier(buf, "aboveleft", multi_mods);
     // :belowright and :rightbelow
-    if (cmdmod.split & WSP_BELOW)
+    if (cmdmod.cmod_split & WSP_BELOW)
 	result += add_cmd_modifier(buf, "belowright", multi_mods);
     // :botright
-    if (cmdmod.split & WSP_BOT)
+    if (cmdmod.cmod_split & WSP_BOT)
 	result += add_cmd_modifier(buf, "botright", multi_mods);
 
     // :tab
-    if (cmdmod.tab > 0)
+    if (cmdmod.cmod_tab > 0)
 	result += add_cmd_modifier(buf, "tab", multi_mods);
     // :topleft
-    if (cmdmod.split & WSP_TOP)
+    if (cmdmod.cmod_split & WSP_TOP)
 	result += add_cmd_modifier(buf, "topleft", multi_mods);
     // :vertical
-    if (cmdmod.split & WSP_VERT)
+    if (cmdmod.cmod_split & WSP_VERT)
 	result += add_cmd_modifier(buf, "vertical", multi_mods);
     return result;
 }
@@ -1454,24 +1454,24 @@ uc_check_code(
     {
 	int multi_mods = 0;
 	typedef struct {
-	    int *varp;
+	    int flag;
 	    char *name;
 	} mod_entry_T;
 	static mod_entry_T mod_entries[] = {
 #ifdef FEAT_BROWSE_CMD
-	    {&cmdmod.browse, "browse"},
+	    {CMOD_BROWSE, "browse"},
 #endif
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-	    {&cmdmod.confirm, "confirm"},
+	    {CMOD_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}
+	    {CMOD_HIDE, "hide"},
+	    {CMOD_KEEPALT, "keepalt"},
+	    {CMOD_KEEPJUMPS, "keepjumps"},
+	    {CMOD_KEEPMARKS, "keepmarks"},
+	    {CMOD_KEEPPATTERNS, "keeppatterns"},
+	    {CMOD_LOCKMARKS, "lockmarks"},
+	    {CMOD_NOSWAPFILE, "noswapfile"},
+	    {0, NULL}
 	};
 	int i;
 
@@ -1484,8 +1484,8 @@ uc_check_code(
 	}
 
 	// the modifiers that are simple flags
-	for (i = 0; mod_entries[i].varp != NULL; ++i)
-	    if (*mod_entries[i].varp)
+	for (i = 0; mod_entries[i].name != NULL; ++i)
+	    if (cmdmod.cmod_flags & mod_entries[i].flag)
 		result += add_cmd_modifier(buf, mod_entries[i].name,
 								 &multi_mods);
 
@@ -1501,7 +1501,7 @@ uc_check_code(
 	// :verbose
 	if (p_verbose > 0)
 	    result += add_cmd_modifier(buf, "verbose", &multi_mods);
-	// flags from cmdmod.split
+	// flags from cmdmod.cmod_split
 	result += add_win_cmd_modifers(buf, &multi_mods);
 	if (quote && buf != NULL)
 	{
--- a/src/version.c
+++ b/src/version.c
@@ -751,6 +751,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1898,
+/**/
     1897,
 /**/
     1896,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -1826,17 +1826,17 @@ generate_EXECCONCAT(cctx_T *cctx, int co
  * Generate any instructions for side effects of "cmdmod".
  */
     static int
-generate_cmdmods(cctx_T *cctx)
+generate_cmdmods(cctx_T *cctx, cmdmod_T *cmod)
 {
     isn_T	*isn;
 
     // TODO: use more modifiers in the command
-    if (cmdmod.cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT))
+    if (cmod->cmod_flags & (CMOD_SILENT | CMOD_ERRSILENT))
     {
 	if ((isn = generate_instr(cctx, ISN_SILENT)) == NULL)
 	    return FAIL;
-	isn->isn_arg.number = (cmdmod.cmod_flags & CMOD_ERRSILENT) != 0;
-	cctx->ctx_silent = (cmdmod.cmod_flags & CMOD_ERRSILENT) ? 2 : 1;
+	isn->isn_arg.number = (cmod->cmod_flags & CMOD_ERRSILENT) != 0;
+	cctx->ctx_silent = (cmod->cmod_flags & CMOD_ERRSILENT) ? 2 : 1;
     }
     return OK;
 }
@@ -7092,10 +7092,9 @@ compile_def_function(ufunc_T *ufunc, int
     for (;;)
     {
 	exarg_T	    ea;
-	cmdmod_T    save_cmdmod;
+	cmdmod_T    local_cmdmod;
 	int	    starts_with_colon = FALSE;
 	char_u	    *cmd;
-	int	    save_msg_scroll = msg_scroll;
 
 	// Bail out on the first error to avoid a flood of errors and report
 	// the right line number when inside try/catch.
@@ -7176,8 +7175,9 @@ compile_def_function(ufunc_T *ufunc, int
 	/*
 	 * COMMAND MODIFIERS
 	 */
-	save_cmdmod = cmdmod;
-	if (parse_command_modifiers(&ea, &errormsg, FALSE) == FAIL)
+	CLEAR_FIELD(local_cmdmod);
+	if (parse_command_modifiers(&ea, &errormsg, &local_cmdmod, FALSE)
+								       == FAIL)
 	{
 	    if (errormsg != NULL)
 		goto erret;
@@ -7185,10 +7185,8 @@ compile_def_function(ufunc_T *ufunc, int
 	    line = (char_u *)"";
 	    continue;
 	}
-	generate_cmdmods(&cctx);
-
-	undo_cmdmod(save_msg_scroll);
-	cmdmod = save_cmdmod;
+	generate_cmdmods(&cctx, &local_cmdmod);
+	undo_cmdmod(&local_cmdmod);
 
 	// Skip ":call" to get to the function name.
 	p = ea.cmd;
--- a/src/window.c
+++ b/src/window.c
@@ -615,7 +615,7 @@ wingotofile:
 #ifdef FEAT_SEARCHPATH
 		    case 'f':	    // CTRL-W gf: "gf" in a new tab page
 		    case 'F':	    // CTRL-W gF: "gF" in a new tab page
-			cmdmod.tab = tabpage_index(curtab) + 1;
+			cmdmod.cmod_tab = tabpage_index(curtab) + 1;
 			nchar = xchar;
 			goto wingotofile;
 #endif
@@ -798,7 +798,7 @@ win_split(int size, int flags)
 	return OK;
 
     // Add flags from ":vertical", ":topleft" and ":botright".
-    flags |= cmdmod.split;
+    flags |= cmdmod.cmod_split;
     if ((flags & WSP_TOP) && (flags & WSP_BOT))
     {
 	emsg(_("E442: Can't split topleft and botright at the same time"));
@@ -3568,7 +3568,8 @@ close_others(
 	    if (!r)
 	    {
 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
-		if (message && (p_confirm || cmdmod.confirm) && p_write)
+		if (message && (p_confirm
+			     || (cmdmod.cmod_flags & CMOD_CONFIRM)) && p_write)
 		{
 		    dialog_changed(wp->w_buffer, FALSE);
 		    if (!win_valid(wp))		// autocommands messed wp up
@@ -3925,11 +3926,12 @@ win_new_tabpage(int after)
     static int
 may_open_tabpage(void)
 {
-    int		n = (cmdmod.tab == 0) ? postponed_split_tab : cmdmod.tab;
+    int		n = (cmdmod.cmod_tab == 0)
+				       ? postponed_split_tab : cmdmod.cmod_tab;
 
     if (n != 0)
     {
-	cmdmod.tab = 0;	    // reset it to avoid doing it twice
+	cmdmod.cmod_tab = 0;	    // reset it to avoid doing it twice
 	postponed_split_tab = 0;
 	return win_new_tabpage(n);
     }