Patch 8.1.1231
Problem:    Asking about existing swap file unnecessarily.
Solution:   When it is safe, delete the swap file.  Remove
            HAS_SWAP_EXISTS_ACTION, it is always defined. (closes #1237)
Files:      src/memline.c, src/globals.h, src/buffer.c, src/ex_cmds.c,
            src/fileio.c, src/main.c, src/testdir/test_swap.vim,
            runtime/doc/usr_11.txt, src/os_win32.c, src/proto/os_win32.pro,
            src/os_unix.c, src/proto/os_unix.pro


*** ../vim-8.1.1230/src/memline.c       2019-04-28 19:46:17.030060105 +0200
--- src/memline.c       2019-04-28 22:22:42.217091959 +0200
***************
*** 2159,2167 ****
                {
                    msg_puts(_("\n        process ID: "));
                    msg_outnum(char_to_long(b0.b0_pid));
! #if defined(UNIX)
!                   /* EMX kill() not working correctly, it seems */
!                   if (kill((pid_t)char_to_long(b0.b0_pid), 0) == 0)
                    {
                        msg_puts(_(" (STILL RUNNING)"));
  # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
--- 2159,2166 ----
                {
                    msg_puts(_("\n        process ID: "));
                    msg_outnum(char_to_long(b0.b0_pid));
! #if defined(UNIX) || defined(MSWIN)
!                   if (mch_process_running((pid_t)char_to_long(b0.b0_pid)))
                    {
                        msg_puts(_(" (STILL RUNNING)"));
  # if defined(FEAT_GUI_DIALOG) || defined(FEAT_CON_DIALOG)
***************
*** 2193,2198 ****
--- 2192,2248 ----
      return x;
  }
  
+ /*
+  * Return TRUE if the swap file looks OK and there are no changes, thus it can
+  * be safely deleted.
+  */
+     static time_t
+ swapfile_unchanged(char_u *fname)
+ {
+     stat_T        st;
+     int                   fd;
+     struct block0   b0;
+     int                   ret = TRUE;
+ #ifdef UNIX
+     long          pid;
+ #endif
+ 
+     // must be able to stat the swap file
+     if (mch_stat((char *)fname, &st) == -1)
+       return FALSE;
+ 
+     // must be able to read the first block
+     fd = mch_open((char *)fname, O_RDONLY | O_EXTRA, 0);
+     if (fd < 0)
+       return FALSE;
+     if (read_eintr(fd, &b0, sizeof(b0)) != sizeof(b0))
+     {
+       close(fd);
+       return FALSE;
+     }
+ 
+     // the ID and magic number must be correct
+     if (ml_check_b0_id(&b0) == FAIL|| b0_magic_wrong(&b0))
+       ret = FALSE;
+ 
+     // must be unchanged
+     if (b0.b0_dirty)
+       ret = FALSE;
+ 
+ #if defined(UNIX) || defined(MSWIN)
+     // process must known and not be running
+     pid = char_to_long(b0.b0_pid);
+     if (pid == 0L || mch_process_running((pid_t)pid))
+       ret = FALSE;
+ #endif
+ 
+     // TODO: Should we check if the swap file was created on the current
+     // system?  And the current user?
+ 
+     close(fd);
+     return ret;
+ }
+ 
      static int
  recov_file_names(char_u **names, char_u *path, int prepend_dot)
  {
***************
*** 4757,4765 ****
                if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
                        && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
                {
- #if defined(HAS_SWAP_EXISTS_ACTION)
                    int         choice = 0;
! #endif
  #ifdef CREATE_DUMMY_FILE
                    int         did_use_dummy = FALSE;
  
--- 4807,4814 ----
                if (differ == FALSE && !(curbuf->b_flags & BF_RECOVERED)
                        && vim_strchr(p_shm, SHM_ATTENTION) == NULL)
                {
                    int         choice = 0;
!                   stat_T      st;
  #ifdef CREATE_DUMMY_FILE
                    int         did_use_dummy = FALSE;
  
***************
*** 4779,4791 ****
  #if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || 
defined(FEAT_CON_DIALOG))
                    process_still_running = FALSE;
  #endif
  #if defined(FEAT_EVAL)
                    /*
                     * If there is an SwapExists autocommand and we can handle
                     * the response, trigger it.  It may return 0 to ask the
                     * user anyway.
                     */
!                   if (swap_exists_action != SEA_NONE
                            && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
                        choice = do_swapexists(buf, fname);
  
--- 4828,4852 ----
  #if (defined(UNIX) || defined(VMS)) && (defined(FEAT_GUI_DIALOG) || 
defined(FEAT_CON_DIALOG))
                    process_still_running = FALSE;
  #endif
+                   // It's safe to delete the swap file if all these are true:
+                   // - the edited file exists
+                   // - the swap file has no changes and looks OK
+                   if (mch_stat((char *)buf->b_fname, &st) == 0
+                                                 && swapfile_unchanged(fname))
+                   {
+                       choice = 4;
+                       if (p_verbose > 0)
+                           verb_msg(_("Found a swap file that is not useful, 
deleting it"));
+                   }
+ 
  #if defined(FEAT_EVAL)
                    /*
                     * If there is an SwapExists autocommand and we can handle
                     * the response, trigger it.  It may return 0 to ask the
                     * user anyway.
                     */
!                   if (choice == 0
!                           && swap_exists_action != SEA_NONE
                            && has_autocmd(EVENT_SWAPEXISTS, buf_fname, buf))
                        choice = do_swapexists(buf, fname);
  
***************
*** 4850,4856 ****
                    }
  #endif
  
- #if defined(HAS_SWAP_EXISTS_ACTION)
                    if (choice > 0)
                    {
                        switch (choice)
--- 4911,4916 ----
***************
*** 4880,4886 ****
                            break;
                    }
                    else
- #endif
                    {
                        msg_puts("\n");
                        if (msg_silent == 0)
--- 4940,4945 ----
*** ../vim-8.1.1230/src/globals.h       2019-04-28 19:46:17.026060122 +0200
--- src/globals.h       2019-04-28 22:14:01.975212661 +0200
***************
*** 966,972 ****
  EXTERN int    emsg_noredir INIT(= 0); /* don't redirect error messages */
  EXTERN int    cmd_silent INIT(= FALSE); /* don't echo the command line */
  
- # define HAS_SWAP_EXISTS_ACTION
  EXTERN int    swap_exists_action INIT(= SEA_NONE);
                                        /* For dialog when swap file already
                                         * exists. */
--- 966,971 ----
***************
*** 1644,1649 ****
--- 1643,1651 ----
  #endif
  
  #ifdef MSWIN
+ # ifdef PROTO
+ typedef int HINSTANCE;
+ # endif
  EXTERN int ctrl_break_was_pressed INIT(= FALSE);
  EXTERN HINSTANCE g_hinst INIT(= NULL);
  #endif
*** ../vim-8.1.1230/src/buffer.c        2019-04-28 18:04:56.054492198 +0200
--- src/buffer.c        2019-04-28 20:19:17.859717974 +0200
***************
*** 972,1014 ****
      int               dir,
      int               count)
  {
- #if defined(HAS_SWAP_EXISTS_ACTION)
      bufref_T  old_curbuf;
  
      set_bufref(&old_curbuf, curbuf);
  
      swap_exists_action = SEA_DIALOG;
- #endif
      (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
                                             start, dir, count, eap->forceit);
- #if defined(HAS_SWAP_EXISTS_ACTION)
      if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
      {
! # if defined(FEAT_EVAL)
        cleanup_T   cs;
  
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a window. */
        enter_cleanup(&cs);
! # endif
  
        /* Quitting means closing the split window, nothing else. */
        win_close(curwin, TRUE);
        swap_exists_action = SEA_NONE;
        swap_exists_did_quit = TRUE;
  
! # if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! # endif
      }
      else
        handle_swap_exists(&old_curbuf);
- #endif
  }
  
- #if defined(HAS_SWAP_EXISTS_ACTION) || defined(PROTO)
  /*
   * Handle the situation of swap_exists_action being set.
   * It is allowed for "old_curbuf" to be NULL or invalid.
--- 972,1009 ----
      int               dir,
      int               count)
  {
      bufref_T  old_curbuf;
  
      set_bufref(&old_curbuf, curbuf);
  
      swap_exists_action = SEA_DIALOG;
      (void)do_buffer(*eap->cmd == 's' ? DOBUF_SPLIT : DOBUF_GOTO,
                                             start, dir, count, eap->forceit);
      if (swap_exists_action == SEA_QUIT && *eap->cmd == 's')
      {
! #if defined(FEAT_EVAL)
        cleanup_T   cs;
  
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a window. */
        enter_cleanup(&cs);
! #endif
  
        /* Quitting means closing the split window, nothing else. */
        win_close(curwin, TRUE);
        swap_exists_action = SEA_NONE;
        swap_exists_did_quit = TRUE;
  
! #if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! #endif
      }
      else
        handle_swap_exists(&old_curbuf);
  }
  
  /*
   * Handle the situation of swap_exists_action being set.
   * It is allowed for "old_curbuf" to be NULL or invalid.
***************
*** 1016,1036 ****
      void
  handle_swap_exists(bufref_T *old_curbuf)
  {
! # if defined(FEAT_EVAL)
      cleanup_T cs;
! # endif
! # ifdef FEAT_SYN_HL
      long      old_tw = curbuf->b_p_tw;
! # endif
      buf_T     *buf;
  
      if (swap_exists_action == SEA_QUIT)
      {
! # if defined(FEAT_EVAL)
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a buffer. */
        enter_cleanup(&cs);
! # endif
  
        /* User selected Quit at ATTENTION prompt.  Go back to previous
         * buffer.  If that buffer is gone or the same as the current one,
--- 1011,1031 ----
      void
  handle_swap_exists(bufref_T *old_curbuf)
  {
! #if defined(FEAT_EVAL)
      cleanup_T cs;
! #endif
! #ifdef FEAT_SYN_HL
      long      old_tw = curbuf->b_p_tw;
! #endif
      buf_T     *buf;
  
      if (swap_exists_action == SEA_QUIT)
      {
! #if defined(FEAT_EVAL)
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a buffer. */
        enter_cleanup(&cs);
! #endif
  
        /* User selected Quit at ATTENTION prompt.  Go back to previous
         * buffer.  If that buffer is gone or the same as the current one,
***************
*** 1053,1078 ****
            // restore msg_silent, so that the command line will be shown
            msg_silent = old_msg_silent;
  
! # ifdef FEAT_SYN_HL
            if (old_tw != curbuf->b_p_tw)
                check_colorcolumn(curwin);
! # endif
        }
        /* If "old_curbuf" is NULL we are in big trouble here... */
  
! # if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! # endif
      }
      else if (swap_exists_action == SEA_RECOVER)
      {
! # if defined(FEAT_EVAL)
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a buffer. */
        enter_cleanup(&cs);
! # endif
  
        /* User selected Recover at ATTENTION prompt. */
        msg_scroll = TRUE;
--- 1048,1073 ----
            // restore msg_silent, so that the command line will be shown
            msg_silent = old_msg_silent;
  
! #ifdef FEAT_SYN_HL
            if (old_tw != curbuf->b_p_tw)
                check_colorcolumn(curwin);
! #endif
        }
        /* If "old_curbuf" is NULL we are in big trouble here... */
  
! #if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! #endif
      }
      else if (swap_exists_action == SEA_RECOVER)
      {
! #if defined(FEAT_EVAL)
        /* Reset the error/interrupt/exception state here so that
         * aborting() returns FALSE when closing a buffer. */
        enter_cleanup(&cs);
! #endif
  
        /* User selected Recover at ATTENTION prompt. */
        msg_scroll = TRUE;
***************
*** 1081,1095 ****
        cmdline_row = msg_row;
        do_modelines(0);
  
! # if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! # endif
      }
      swap_exists_action = SEA_NONE;
  }
- #endif
  
  /*
   * do_bufdel() - delete or unload buffer(s)
--- 1076,1089 ----
        cmdline_row = msg_row;
        do_modelines(0);
  
! #if defined(FEAT_EVAL)
        /* Restore the error/interrupt/exception state if not discarded by a
         * new aborting error, interrupt, or uncaught exception. */
        leave_cleanup(&cs);
! #endif
      }
      swap_exists_action = SEA_NONE;
  }
  
  /*
   * do_bufdel() - delete or unload buffer(s)
***************
*** 5259,5286 ****
                continue;
  
            /* Open the buffer in this window. */
- #if defined(HAS_SWAP_EXISTS_ACTION)
            swap_exists_action = SEA_DIALOG;
- #endif
            set_curbuf(buf, DOBUF_GOTO);
            if (!bufref_valid(&bufref))
            {
                /* autocommands deleted the buffer!!! */
- #if defined(HAS_SWAP_EXISTS_ACTION)
                swap_exists_action = SEA_NONE;
- #endif
                break;
            }
- #if defined(HAS_SWAP_EXISTS_ACTION)
            if (swap_exists_action == SEA_QUIT)
            {
! # if defined(FEAT_EVAL)
                cleanup_T   cs;
  
                /* Reset the error/interrupt/exception state here so that
                 * aborting() returns FALSE when closing a window. */
                enter_cleanup(&cs);
! # endif
  
                /* User selected Quit at ATTENTION prompt; close this window. */
                win_close(curwin, TRUE);
--- 5253,5275 ----
                continue;
  
            /* Open the buffer in this window. */
            swap_exists_action = SEA_DIALOG;
            set_curbuf(buf, DOBUF_GOTO);
            if (!bufref_valid(&bufref))
            {
                /* autocommands deleted the buffer!!! */
                swap_exists_action = SEA_NONE;
                break;
            }
            if (swap_exists_action == SEA_QUIT)
            {
! #if defined(FEAT_EVAL)
                cleanup_T   cs;
  
                /* Reset the error/interrupt/exception state here so that
                 * aborting() returns FALSE when closing a window. */
                enter_cleanup(&cs);
! #endif
  
                /* User selected Quit at ATTENTION prompt; close this window. */
                win_close(curwin, TRUE);
***************
*** 5288,5303 ****
                swap_exists_action = SEA_NONE;
                swap_exists_did_quit = TRUE;
  
! # if defined(FEAT_EVAL)
                /* Restore the error/interrupt/exception state if not
                 * discarded by a new aborting error, interrupt, or uncaught
                 * exception. */
                leave_cleanup(&cs);
! # endif
            }
            else
                handle_swap_exists(NULL);
- #endif
        }
  
        ui_breakcheck();
--- 5277,5291 ----
                swap_exists_action = SEA_NONE;
                swap_exists_did_quit = TRUE;
  
! #if defined(FEAT_EVAL)
                /* Restore the error/interrupt/exception state if not
                 * discarded by a new aborting error, interrupt, or uncaught
                 * exception. */
                leave_cleanup(&cs);
! #endif
            }
            else
                handle_swap_exists(NULL);
        }
  
        ui_breakcheck();
*** ../vim-8.1.1230/src/ex_cmds.c       2019-04-28 19:46:17.022060143 +0200
--- src/ex_cmds.c       2019-04-28 20:19:31.859649114 +0200
***************
*** 4258,4266 ****
        topline = curwin->w_topline;
        if (!oldbuf)                        /* need to read the file */
        {
- #if defined(HAS_SWAP_EXISTS_ACTION)
            swap_exists_action = SEA_DIALOG;
- #endif
            curbuf->b_flags |= BF_CHECK_RO; /* set/reset 'ro' flag */
  
            /*
--- 4258,4264 ----
***************
*** 4273,4283 ****
            (void)open_buffer(FALSE, eap, readfile_flags);
  #endif
  
- #if defined(HAS_SWAP_EXISTS_ACTION)
            if (swap_exists_action == SEA_QUIT)
                retval = FAIL;
            handle_swap_exists(&old_curbuf);
- #endif
        }
        else
        {
--- 4271,4279 ----
*** ../vim-8.1.1230/src/fileio.c        2019-04-28 19:46:17.026060122 +0200
--- src/fileio.c        2019-04-28 20:19:41.807600177 +0200
***************
*** 684,698 ****
  #endif
      }
  
! #if defined(HAS_SWAP_EXISTS_ACTION)
!     /* If "Quit" selected at ATTENTION dialog, don't load the file */
      if (swap_exists_action == SEA_QUIT)
      {
        if (!read_buffer && !read_stdin)
            close(fd);
        return FAIL;
      }
- #endif
  
      ++no_wait_return;     /* don't wait for return yet */
  
--- 684,696 ----
  #endif
      }
  
!     // If "Quit" selected at ATTENTION dialog, don't load the file
      if (swap_exists_action == SEA_QUIT)
      {
        if (!read_buffer && !read_stdin)
            close(fd);
        return FAIL;
      }
  
      ++no_wait_return;     /* don't wait for return yet */
  
*** ../vim-8.1.1230/src/main.c  2019-04-28 19:46:17.030060105 +0200
--- src/main.c  2019-04-28 20:21:01.743207196 +0200
***************
*** 50,58 ****
  static void exe_commands(mparm_T *parmp);
  static void source_startup_scripts(mparm_T *parmp);
  static void main_start_gui(void);
- # if defined(HAS_SWAP_EXISTS_ACTION)
  static void check_swap_exists_action(void);
- # endif
  # ifdef FEAT_EVAL
  static void set_progpath(char_u *argv0);
  # endif
--- 50,56 ----
***************
*** 784,802 ****
       */
      if (params.tagname != NULL)
      {
- #if defined(HAS_SWAP_EXISTS_ACTION)
        swap_exists_did_quit = FALSE;
- #endif
  
        vim_snprintf((char *)IObuff, IOSIZE, "ta %s", params.tagname);
        do_cmdline_cmd(IObuff);
        TIME_MSG("jumping to tag");
  
- #if defined(HAS_SWAP_EXISTS_ACTION)
        /* If the user doesn't want to edit the file then we quit here. */
        if (swap_exists_did_quit)
            getout(1);
- #endif
      }
  
      /* Execute any "+", "-c" and "-S" arguments. */
--- 782,796 ----
***************
*** 2625,2644 ****
  {
      int           i;
  
! #if defined(HAS_SWAP_EXISTS_ACTION)
!     /* When getting the ATTENTION prompt here, use a dialog */
      swap_exists_action = SEA_DIALOG;
! #endif
      no_wait_return = TRUE;
      i = msg_didany;
      set_buflisted(TRUE);
!     (void)open_buffer(TRUE, NULL, 0); /* create memfile and read file */
      no_wait_return = FALSE;
      msg_didany = i;
      TIME_MSG("reading stdin");
! #if defined(HAS_SWAP_EXISTS_ACTION)
      check_swap_exists_action();
- #endif
  #if !(defined(AMIGA) || defined(MACOS_X))
      /*
       * Close stdin and dup it from stderr.  Required for GPM to work
--- 2619,2636 ----
  {
      int           i;
  
!     // When getting the ATTENTION prompt here, use a dialog
      swap_exists_action = SEA_DIALOG;
! 
      no_wait_return = TRUE;
      i = msg_didany;
      set_buflisted(TRUE);
!     (void)open_buffer(TRUE, NULL, 0); // create memfile and read file
      no_wait_return = FALSE;
      msg_didany = i;
      TIME_MSG("reading stdin");
! 
      check_swap_exists_action();
  #if !(defined(AMIGA) || defined(MACOS_X))
      /*
       * Close stdin and dup it from stderr.  Required for GPM to work
***************
*** 2741,2756 ****
                if (p_fdls >= 0)
                    curwin->w_p_fdl = p_fdls;
  #endif
! #if defined(HAS_SWAP_EXISTS_ACTION)
!               /* When getting the ATTENTION prompt here, use a dialog */
                swap_exists_action = SEA_DIALOG;
! #endif
                set_buflisted(TRUE);
  
                /* create memfile, read file */
                (void)open_buffer(FALSE, NULL, 0);
  
- #if defined(HAS_SWAP_EXISTS_ACTION)
                if (swap_exists_action == SEA_QUIT)
                {
                    if (got_int || only_one_window())
--- 2733,2746 ----
                if (p_fdls >= 0)
                    curwin->w_p_fdl = p_fdls;
  #endif
!               // When getting the ATTENTION prompt here, use a dialog
                swap_exists_action = SEA_DIALOG;
! 
                set_buflisted(TRUE);
  
                /* create memfile, read file */
                (void)open_buffer(FALSE, NULL, 0);
  
                if (swap_exists_action == SEA_QUIT)
                {
                    if (got_int || only_one_window())
***************
*** 2768,2774 ****
                }
                else
                    handle_swap_exists(NULL);
- #endif
                dorewind = TRUE;                /* start again */
            }
            ui_breakcheck();
--- 2758,2763 ----
***************
*** 2865,2877 ****
            curwin->w_arg_idx = arg_idx;
            /* Edit file from arg list, if there is one.  When "Quit" selected
             * at the ATTENTION prompt close the window. */
- # ifdef HAS_SWAP_EXISTS_ACTION
            swap_exists_did_quit = FALSE;
- # endif
            (void)do_ecmd(0, arg_idx < GARGCOUNT
                          ? alist_name(&GARGLIST[arg_idx]) : NULL,
                          NULL, NULL, ECMD_LASTL, ECMD_HIDE, curwin);
- # ifdef HAS_SWAP_EXISTS_ACTION
            if (swap_exists_did_quit)
            {
                /* abort or quit selected */
--- 2854,2863 ----
***************
*** 2884,2890 ****
                win_close(curwin, TRUE);
                advance = FALSE;
            }
- # endif
            if (arg_idx == GARGCOUNT - 1)
                arg_had_last = TRUE;
            ++arg_idx;
--- 2870,2875 ----
***************
*** 3485,3491 ****
        mch_exit(0);
  }
  
- #if defined(HAS_SWAP_EXISTS_ACTION)
  /*
   * Check the result of the ATTENTION dialog:
   * When "Quit" selected, exit Vim.
--- 3470,3475 ----
***************
*** 3498,3504 ****
        getout(1);
      handle_swap_exists(NULL);
  }
- #endif
  
  #endif /* NO_VIM_MAIN */
  
--- 3482,3487 ----
*** ../vim-8.1.1230/src/testdir/test_swap.vim   2019-01-27 14:29:20.724544960 
+0100
--- src/testdir/test_swap.vim   2019-04-28 21:50:37.397318520 +0200
***************
*** 164,166 ****
--- 164,222 ----
    call delete('Xtest2')
    call delete('Xtest3')
  endfunc
+ 
+ func Test_swapfile_delete()
+   autocmd! SwapExists
+   function s:swap_exists()
+     let v:swapchoice = s:swap_choice
+     let s:swapname = v:swapname
+     let s:filename = expand('<afile>')
+   endfunc
+   augroup test_swapfile_delete
+     autocmd!
+     autocmd SwapExists * call s:swap_exists()
+   augroup END
+ 
+ 
+   " Create a valid swapfile by editing a file.
+   split XswapfileText
+   call setline(1, ['one', 'two', 'three'])
+   write  " file is written, not modified
+   " read the swapfile as a Blob
+   let swapfile_name = swapname('%')
+   let swapfile_bytes = readfile(swapfile_name, 'B')
+ 
+   " Close the file and recreate the swap file.
+   " Now editing the file will run into the process still existing
+   quit
+   call writefile(swapfile_bytes, swapfile_name)
+   let s:swap_choice = 'e'
+   let s:swapname = ''
+   split XswapfileText
+   quit
+   call assert_equal(swapfile_name, s:swapname)
+ 
+   " Write the swapfile with a modified PID, now it will be automatically
+   " deleted. Process one should never be Vim.
+   let swapfile_bytes[24:27] = 0z01000000
+   call writefile(swapfile_bytes, swapfile_name)
+   let s:swapname = ''
+   split XswapfileText
+   quit
+   call assert_equal('', s:swapname)
+ 
+   " Now set the modified flag, the swap file will not be deleted
+   let swapfile_bytes[28 + 80 + 899] = 0x55
+   call writefile(swapfile_bytes, swapfile_name)
+   let s:swapname = ''
+   split XswapfileText
+   quit
+   call assert_equal(swapfile_name, s:swapname)
+ 
+   call delete('XswapfileText')
+   call delete(swapfile_name)
+   augroup test_swapfile_delete
+     autocmd!
+   augroup END
+   augroup! test_swapfile_delete
+ endfunc
*** ../vim-8.1.1230/runtime/doc/usr_11.txt      2018-05-17 13:42:03.000000000 
+0200
--- runtime/doc/usr_11.txt      2019-04-28 21:58:09.667057415 +0200
***************
*** 120,126 ****
  USING A SPECIFIC SWAP FILE
  
  If you know which swap file needs to be used, you can recover by giving the
! swap file name.  Vim will then finds out the name of the original file from
  the swap file.
  
  Example: >
--- 120,126 ----
  USING A SPECIFIC SWAP FILE
  
  If you know which swap file needs to be used, you can recover by giving the
! swap file name.  Vim will then find out the name of the original file from
  the swap file.
  
  Example: >
***************
*** 205,210 ****
--- 205,217 ----
        NEWER than swap file! ~
  
  
+ NOTE that in the following situation Vim knows the swap file is not useful and
+ will automatically delete it:
+ - The file is a valid swap file (Magic number is correct).
+ - The flag that the file was modified is not set.
+ - The process is not running.
+ 
+ 
  UNREADABLE SWAP FILE
  
  Sometimes the line
***************
*** 284,289 ****
--- 291,297 ----
  'shortmess' option.  But it's very unusual that you need this.
  
  For remarks about encryption and the swap file, see |:recover-crypt|.
+ For programatic access to the swap file, see |swapinfo()|.
  
  ==============================================================================
  *11.4*        Further reading
*** ../vim-8.1.1230/src/os_win32.c      2019-04-28 19:46:17.034060084 +0200
--- src/os_win32.c      2019-04-28 22:11:28.811767431 +0200
***************
*** 2903,2908 ****
--- 2903,2925 ----
      return (long)GetCurrentProcessId();
  }
  
+ /*
+  * return TRUE if process "pid" is still running
+  */
+     int
+ mch_process_running(pid_t pid)
+ {
+     HANDLE  hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, (DWORD)pid);
+     DWORD   status = 0;
+     int           ret = FALSE;
+ 
+     if (hProcess == NULL)
+       return FALSE;  // might not have access
+     if (GetExitCodeProcess(hProcess, &status) )
+       ret = status == STILL_ACTIVE;
+     CloseHandle(hProcess);
+     return ret;
+ }
  
  /*
   * Get name of current directory into buffer 'buf' of length 'len' bytes.
*** ../vim-8.1.1230/src/proto/os_win32.pro      2019-04-28 19:46:17.034060084 
+0200
--- src/proto/os_win32.pro      2019-04-28 22:14:17.599153672 +0200
***************
*** 19,24 ****
--- 19,25 ----
  int mch_get_user_name(char_u *s, int len);
  void mch_get_host_name(char_u *s, int len);
  long mch_get_pid(void);
+ int mch_process_running(pid_t pid);
  int mch_dirname(char_u *buf, int len);
  long mch_getperm(char_u *name);
  int mch_setperm(char_u *name, long perm);
*** ../vim-8.1.1230/src/os_unix.c       2019-04-04 20:13:06.001014760 +0200
--- src/os_unix.c       2019-04-28 22:19:41.013860198 +0200
***************
*** 2393,2398 ****
--- 2393,2408 ----
      return (long)getpid();
  }
  
+ /*
+  * return TRUE if process "pid" is still running
+  */
+     int
+ mch_process_running(pid_t pid)
+ {
+     // EMX kill() not working correctly, it seems
+     return kill(pid, 0) == 0;
+ }
+ 
  #if !defined(HAVE_STRERROR) && defined(USE_GETCWD)
      static char *
  strerror(int err)
*** ../vim-8.1.1230/src/proto/os_unix.pro       2019-01-20 15:30:36.893328693 
+0100
--- src/proto/os_unix.pro       2019-04-28 22:19:14.453970686 +0200
***************
*** 27,32 ****
--- 27,33 ----
  int mch_get_uname(uid_t uid, char_u *s, int len);
  void mch_get_host_name(char_u *s, int len);
  long mch_get_pid(void);
+ int mch_process_running(pid_t pid);
  int mch_dirname(char_u *buf, int len);
  int mch_FullName(char_u *fname, char_u *buf, int len, int force);
  int mch_isFullName(char_u *fname);
*** ../vim-8.1.1230/src/version.c       2019-04-28 19:46:17.034060084 +0200
--- src/version.c       2019-04-28 22:20:54.909549767 +0200
***************
*** 769,770 ****
--- 769,772 ----
  {   /* Add new patch number below this line */
+ /**/
+     1231,
  /**/

-- 
ARTHUR:        What?
BLACK KNIGHT:  None shall pass.
ARTHUR:        I have no quarrel with you, good Sir knight, but I must cross
               this bridge.
BLACK KNIGHT:  Then you shall die.
                                  The Quest for the Holy Grail (Monty Python)

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui