patch 8.0.1595: no autocommand triggered before exiting

Problem:    No autocommand triggered before exiting.
Solution:   Add the ExitPre autocommand event.
diff --git a/src/Makefile b/src/Makefile
index 1b13aa9..905e3f1 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -2155,6 +2155,7 @@
 	test_eval_stuff \
 	test_ex_undo \
 	test_ex_z \
+	test_exit \
 	test_exec_while_if \
 	test_execute_func \
 	test_exists \
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 9994cb6..97bbd04 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -7187,8 +7187,35 @@
     settmode(TMODE_RAW);
 }
 
+    static int
+before_quit_autocmds(win_T *wp, int quit_all, int forceit)
+{
+    apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, wp->w_buffer);
+
+    /* Bail out when autocommands closed the window.
+     * Refuse to quit when the buffer in the last window is being closed (can
+     * only happen in autocommands). */
+    if (!win_valid(wp)
+	    || curbuf_locked()
+	    || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0))
+	return TRUE;
+
+    if (quit_all || (check_more(FALSE, forceit) == OK && only_one_window()))
+    {
+	apply_autocmds(EVENT_EXITPRE, NULL, NULL, FALSE, curbuf);
+	/* Refuse to quit when locked or when the buffer in the last window is
+	 * being closed (can only happen in autocommands). */
+	if (curbuf_locked()
+			  || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
+	    return TRUE;
+    }
+
+    return FALSE;
+}
+
 /*
  * ":quit": quit current window, quit Vim if the last window is closed.
+ * ":{nr}quit": quit window {nr}
  */
     static void
 ex_quit(exarg_T *eap)
@@ -7222,12 +7249,9 @@
     /* Refuse to quit when locked. */
     if (curbuf_locked())
 	return;
-    apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, wp->w_buffer);
-    /* Bail out when autocommands closed the window.
-     * Refuse to quit when the buffer in the last window is being closed (can
-     * only happen in autocommands). */
-    if (!win_valid(wp)
-	    || (wp->w_buffer->b_nwindows == 1 && wp->w_buffer->b_locked > 0))
+
+    /* Trigger QuitPre and maybe ExitPre */
+    if (before_quit_autocmds(wp, FALSE, eap->forceit))
 	return;
 
 #ifdef FEAT_NETBEANS_INTG
@@ -7301,10 +7325,8 @@
 	text_locked_msg();
 	return;
     }
-    apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
-    /* Refuse to quit when locked or when the buffer in the last window is
-     * being closed (can only happen in autocommands). */
-    if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
+
+    if (before_quit_autocmds(curwin, TRUE, eap->forceit))
 	return;
 
     exiting = TRUE;
@@ -7743,7 +7765,7 @@
 }
 
 /*
- * ":exit", ":xit" and ":wq": Write file and exit Vim.
+ * ":exit", ":xit" and ":wq": Write file and quite the current window.
  */
     static void
 ex_exit(exarg_T *eap)
@@ -7761,10 +7783,8 @@
 	text_locked_msg();
 	return;
     }
-    apply_autocmds(EVENT_QUITPRE, NULL, NULL, FALSE, curbuf);
-    /* Refuse to quit when locked or when the buffer in the last window is
-     * being closed (can only happen in autocommands). */
-    if (curbuf_locked() || (curbuf->b_nwindows == 1 && curbuf->b_locked > 0))
+
+    if (before_quit_autocmds(curwin, FALSE, eap->forceit))
 	return;
 
     /*
diff --git a/src/fileio.c b/src/fileio.c
index 7149a22..8331c08 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -7724,6 +7724,7 @@
     {"CursorMovedI",	EVENT_CURSORMOVEDI},
     {"DirChanged",	EVENT_DIRCHANGED},
     {"EncodingChanged",	EVENT_ENCODINGCHANGED},
+    {"ExitPre",		EVENT_EXITPRE},
     {"FileEncoding",	EVENT_ENCODINGCHANGED},
     {"FileAppendPost",	EVENT_FILEAPPENDPOST},
     {"FileAppendPre",	EVENT_FILEAPPENDPRE},
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index e3230c5..159bf1e 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -97,6 +97,7 @@
 	    test_exec_while_if.res \
 	    test_exists.res \
 	    test_exists_autocmd.res \
+	    test_exit.res \
 	    test_farsi.res \
 	    test_file_size.res \
 	    test_find_complete.res \
diff --git a/src/testdir/test_exit.vim b/src/testdir/test_exit.vim
new file mode 100644
index 0000000..8f02fd2
--- /dev/null
+++ b/src/testdir/test_exit.vim
@@ -0,0 +1,57 @@
+" Tests for exiting Vim.
+
+source shared.vim
+
+func Test_exiting()
+  let after = [
+	\ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+	\ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+	\ 'quit',
+	\ ]
+  if RunVim([], after, '')
+    call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+  endif
+  call delete('Xtestout')
+
+  let after = [
+	\ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+	\ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+	\ 'help',
+	\ 'wincmd w',
+	\ 'quit',
+	\ ]
+  if RunVim([], after, '')
+    call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+  endif
+  call delete('Xtestout')
+
+  let after = [
+	\ 'au QuitPre * call writefile(["QuitPre"], "Xtestout")',
+	\ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+	\ 'split',
+	\ 'new',
+	\ 'qall',
+	\ ]
+  if RunVim([], after, '')
+    call assert_equal(['QuitPre', 'ExitPre'], readfile('Xtestout'))
+  endif
+  call delete('Xtestout')
+
+  let after = [
+	\ 'au QuitPre * call writefile(["QuitPre"], "Xtestout", "a")',
+	\ 'au ExitPre * call writefile(["ExitPre"], "Xtestout", "a")',
+	\ 'augroup nasty',
+	\ '  au ExitPre * split',
+	\ 'augroup END',
+	\ 'quit',
+	\ 'augroup nasty',
+	\ '  au! ExitPre',
+	\ 'augroup END',
+	\ 'quit',
+	\ ]
+  if RunVim([], after, '')
+    call assert_equal(['QuitPre', 'ExitPre', 'QuitPre', 'ExitPre'],
+	  \ readfile('Xtestout'))
+  endif
+  call delete('Xtestout')
+endfunc
diff --git a/src/version.c b/src/version.c
index a6c7279..4f1c001 100644
--- a/src/version.c
+++ b/src/version.c
@@ -767,6 +767,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1595,
+/**/
     1594,
 /**/
     1593,
diff --git a/src/vim.h b/src/vim.h
index 563d328..3b458a0 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1277,6 +1277,7 @@
     EVENT_COLORSCHEME,		/* after loading a colorscheme */
     EVENT_COMPLETEDONE,		/* after finishing insert complete */
     EVENT_DIRCHANGED,		/* after changing directory as a result of user cmd */
+    EVENT_EXITPRE,		/* before exiting */
     EVENT_FILEAPPENDPOST,	/* after appending to a file */
     EVENT_FILEAPPENDPRE,	/* before appending to a file */
     EVENT_FILEAPPENDCMD,	/* append to a file using command */