patch 9.1.1419: It is difficult to ignore all but some events

Problem:  It is difficult to ignore all but some events.
Solution: Add support for a "-" prefix syntax in '(win)eventignore' that
          subtracts an event from the ignored set if present
          (Luuk van Baal).

closes: #17392

Signed-off-by: Luuk van Baal <luukvbaal@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/autocmd.c b/src/autocmd.c
index 6a5f035..c8e51b2 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -803,16 +803,26 @@
     int
 event_ignored(event_T event, char_u *ei)
 {
+    int ignored = FALSE;
     while (*ei != NUL)
     {
-	if (STRNICMP(ei, "all", 3) == 0 && (ei[3] == NUL || ei[3] == ',')
-	    && (ei == p_ei || (event_tab[event].key <= 0)))
-	    return TRUE;
-	if (event_name2nr(ei, &ei) == event)
-	    return TRUE;
+	int unignore = *ei == '-';
+	ei += unignore;
+	if (STRNICMP(ei, "all", 3) == 0 && (ei[3] == NUL || ei[3] == ','))
+	{
+	    ignored = ei == p_ei || (event_tab[event].key <= 0);
+	    ei += 3 + (ei[3] == ',');
+	}
+	else if (event_name2nr(ei, &ei) == event)
+	{
+	    if (unignore)
+		return FALSE;
+	    else
+		ignored = TRUE;
+	}
     }
 
-    return FALSE;
+    return ignored;
 }
 
 /*
@@ -827,13 +837,10 @@
     while (*ei)
     {
 	if (STRNICMP(ei, "all", 3) == 0 && (ei[3] == NUL || ei[3] == ','))
-	{
-	    ei += 3;
-	    if (*ei == ',')
-		++ei;
-	}
+	    ei += 3 + (ei[3] == ',');
 	else
 	{
+	    ei += (*ei == '-');
 	    event_T event = event_name2nr(ei, &ei);
 	    if (event == NUM_EVENTS || (win && event_tab[event].key > 0))
 		return FAIL;
diff --git a/src/optionstr.c b/src/optionstr.c
index 603d0f4..d667e53 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -2248,11 +2248,18 @@
     static char_u *
 get_eventignore_name(expand_T *xp, int idx)
 {
+    int subtract = *xp->xp_pattern == '-';
     // 'eventignore(win)' allows special keyword "all" in addition to
     // all event names.
-    if (idx == 0)
+    if (!subtract && idx == 0)
 	return (char_u *)"all";
-    return get_event_name_no_group(xp, idx - 1, expand_eiw);
+
+    char_u *name = get_event_name_no_group(xp, idx - 1 + subtract, expand_eiw);
+    if (name == NULL)
+	return NULL;
+
+    sprintf((char *)IObuff, "%s%s", subtract ? "-" : "", name);
+    return IObuff;
 }
 
     int
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index 1f15453..5b9616f 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -195,9 +195,9 @@
       \		['xxx']],
       \ 'eadirection': [['', 'both', 'ver', 'hor'], ['xxx', 'ver,hor']],
       \ 'encoding': [['latin1'], ['xxx', '']],
-      \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'],
+      \ 'eventignore': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter', 'all,-WinLeave'],
       \		['xxx']],
-      \ 'eventignorewin': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter'],
+      \ 'eventignorewin': [['', 'WinEnter', 'WinLeave,winenter', 'all,WinEnter', 'all,-WinLeave'],
       \		['xxx', 'WinNew']],
       \ 'fileencoding': [['', 'latin1', 'xxx'], []],
       \ 'fileformat': [['', 'dos', 'unix', 'mac'], ['xxx']],
diff --git a/src/testdir/test_autocmd.vim b/src/testdir/test_autocmd.vim
index dfeb93f..3dc4960 100644
--- a/src/testdir/test_autocmd.vim
+++ b/src/testdir/test_autocmd.vim
@@ -5463,4 +5463,20 @@
   %bw!
 endfunc
 
+func Test_eventignore_subtract()
+  set eventignore=all,-WinEnter
+  augroup testing
+    autocmd!
+    autocmd WinEnter * ++once let s:triggered = 1
+  augroup END
+
+  new
+  call assert_equal(1, s:triggered)
+
+  set eventignore&
+  unlet! s:triggered
+  call CleanUpTestAuGroup()
+  %bw!
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 8679198..e85dd6a 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -602,6 +602,7 @@
 
   " Other string options that queries the system rather than fixed enum names
   call assert_equal(['all', 'BufAdd'], getcompletion('set eventignore=', 'cmdline')[0:1])
+  call assert_equal(['-BufAdd', '-BufCreate'], getcompletion('set eventignore=all,-', 'cmdline')[0:1])
   call assert_equal(['WinLeave', 'WinResized', 'WinScrolled'], getcompletion('set eiw=', 'cmdline')[-3:-1])
   call assert_equal('latin1', getcompletion('set fileencodings=', 'cmdline')[1])
   call assert_equal('top', getcompletion('set printoptions=', 'cmdline')[0])
diff --git a/src/version.c b/src/version.c
index 8b10cf4..6c7a2ab 100644
--- a/src/version.c
+++ b/src/version.c
@@ -710,6 +710,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1419,
+/**/
     1418,
 /**/
     1417,